Initial commit
This commit is contained in:
81
A题/ZJ_v2/validation.py
Normal file
81
A题/ZJ_v2/validation.py
Normal file
@@ -0,0 +1,81 @@
|
||||
"""
|
||||
Validation utilities for figure quality control
|
||||
"""
|
||||
|
||||
import os
|
||||
import numpy as np
|
||||
from scipy import stats
|
||||
|
||||
def validate_figure_output(fig_num, output_files, computed_metrics, validation_flags, config):
|
||||
"""
|
||||
Validate figure output against quality thresholds
|
||||
|
||||
Args:
|
||||
fig_num: Figure number (1-15)
|
||||
output_files: List of generated file paths
|
||||
computed_metrics: Dictionary of computed metrics
|
||||
validation_flags: Dictionary of boolean validation flags
|
||||
config: Configuration dictionary with validation thresholds
|
||||
|
||||
Returns:
|
||||
dict: Validation result with pass/fail status
|
||||
"""
|
||||
|
||||
result = {
|
||||
"figure": f"Fig{fig_num:02d}",
|
||||
"output_files": output_files,
|
||||
"metrics": computed_metrics,
|
||||
"flags": validation_flags,
|
||||
"pass": True,
|
||||
"errors": []
|
||||
}
|
||||
|
||||
# Check file existence
|
||||
for filepath in output_files:
|
||||
if not os.path.exists(filepath):
|
||||
result["pass"] = False
|
||||
result["errors"].append(f"File not found: {filepath}")
|
||||
elif os.path.getsize(filepath) == 0:
|
||||
result["pass"] = False
|
||||
result["errors"].append(f"Empty file: {filepath}")
|
||||
|
||||
# Figure-specific validation
|
||||
validation_thresholds = config.get('validation', {})
|
||||
|
||||
if fig_num == 3: # OCV fitting
|
||||
r2 = computed_metrics.get('r2', 0)
|
||||
r2_min = validation_thresholds.get('fig03_r2_min', 0.99)
|
||||
if r2 < r2_min:
|
||||
result["pass"] = False
|
||||
result["errors"].append(f"R² too low: {r2:.4f} < {r2_min}")
|
||||
|
||||
elif fig_num == 7: # Baseline validation
|
||||
v_i_corr = computed_metrics.get('v_i_correlation', 0)
|
||||
corr_max = validation_thresholds.get('fig07_v_i_corr_max', -0.5)
|
||||
if v_i_corr > corr_max:
|
||||
result["pass"] = False
|
||||
result["errors"].append(f"V-I correlation not negative enough: {v_i_corr:.3f} > {corr_max}")
|
||||
|
||||
elif fig_num == 9: # Scenario comparison
|
||||
if 'delta_tte_match' in validation_flags:
|
||||
if not validation_flags['delta_tte_match']:
|
||||
result["pass"] = False
|
||||
result["errors"].append("ΔTTE annotation mismatch")
|
||||
|
||||
elif fig_num == 13: # Survival curve
|
||||
if 'survival_monotonic' in validation_flags:
|
||||
if not validation_flags['survival_monotonic']:
|
||||
result["pass"] = False
|
||||
result["errors"].append("Survival curve not monotonic")
|
||||
|
||||
return result
|
||||
|
||||
def compute_r2(y_true, y_pred):
|
||||
"""Compute R-squared coefficient of determination"""
|
||||
ss_res = np.sum((y_true - y_pred) ** 2)
|
||||
ss_tot = np.sum((y_true - np.mean(y_true)) ** 2)
|
||||
return 1 - (ss_res / ss_tot)
|
||||
|
||||
def check_monotonic_decreasing(arr):
|
||||
"""Check if array is monotonically decreasing"""
|
||||
return np.all(np.diff(arr) <= 0)
|
||||
Reference in New Issue
Block a user