Review index · Download raw source
reference/cloud/finalize_audit.py
1"""Audit completed outputs, retain limitations and produce release receipts."""2from pathlib import Path3import json,math,csv,datetime,hashlib,sys4import numpy as np5from cylinder_mc import sha,rotate6H=Path(__file__).resolve().parent7def read(p):return json.loads(p.read_text(encoding="utf-8"),parse_constant=lambda x:(_ for _ in ()).throw(ValueError("Nonfinite JSON:"+x)))8def dump(p,x):p.write_text(json.dumps(x,indent=2,allow_nan=False),encoding="utf-8")9def sem(v):return float(np.std(v,ddof=1)/np.sqrt(len(v)))if len(v)>1 else 0.10def main():11 m=read(H/"production/run_manifest.json");r=read(H/"cloud_results.json");v=read(H/"validation/validation_results.json");q=read(H/"production/phase_and_geometry_QA.json")12 c=read(H/"validation/cone_control/summary.json");cross=read(H/"validation/cloudscat_control/comparison.json")13 batches=[];kernel_errors=[];kernel_negative=[];radius_controls=[]14 for case in r["cases"]:15 raw=read(H/case["batch_info_file"])["batches"];hist=np.load(H/case["batch_kernel_file"])["batch_mass_relative"]16 for b,h in zip(raw,hist):17 if b["total_tau"]:batches.append(b)18 kernel_errors.append(abs(float(h.sum())-b["scattered_relative_to_vacuum"]))19 kernel_negative.append(float(h.min()))20 stats={"nonvacuum_cases":sum(x["total_vertical_cloud_tau"]>0 for x in r["cases"]),"analytic_vacuum_cases":sum(x["analytic_vacuum_case"]for x in r["cases"]),21 "independent_batches":len(batches),"transport_packets":sum(x["n_packets"]for x in batches),22 "max_abs_weighted_energy_residual_per_packet":max(abs(x["energy_balance_residual_per_packet"])for x in batches),23 "truncated_packets":sum(x["truncated_packet_count"]for x in batches),24 "all_packets_escaped_or_explicitly_truncated":all(x["escaped_packet_count"]+x["truncated_packet_count"]==x["n_packets"]for x in batches),25 "negative_delay_beyond_tolerance_count":sum(x["negative_delay_beyond_tolerance_count"]for x in batches),26 "minimum_scattered_delay_us":min(x["min_scattered_delay_s"]for x in batches if x["min_scattered_delay_s"]is not None)*1e6,27 "maximum_direction_norm_error":max(x["max_direction_norm_error"]for x in batches),28 "maximum_response_overflow_relative_to_vacuum":max(x["response_overflow_relative_to_vacuum"]for x in batches),29 "max_abs_kernel_sum_error":max(kernel_errors),"minimum_response_bin_mass":min(kernel_negative),30 "high_point_nadir_SE_cases":sum("high_point_nadir_MC_uncertainty"in x["quality_flags"]for x in r["cases"]),31 "GHM_nonuniform_convergence_flag_cases":sum("GHM_rare_path_convergence_not_uniformly_established"in x["quality_flags"]for x in r["cases"]),32 "source_proposal_weighted_launch_mean_range":[min(x["weighted_launch_mean"]for x in batches),max(x["weighted_launch_mean"]for x in batches)]}33 rng=np.random.default_rng(77887);dirs=rng.normal(size=(10000,3));dirs/=np.linalg.norm(dirs,axis=1)[:,None];dirs[:6]=[[0,0,1],[0,0,-1],[1,0,0],[-1,0,0],[0,1,0],[0,-1,0]]34 mu=rng.uniform(-1,1,len(dirs));turned=rotate(dirs,mu,rng.uniform(0,2*np.pi,len(dirs)))35 rotation={"max_abs_scatter_cosine_error":float(np.max(abs(np.einsum("ij,ij->i",dirs,turned)-mu))),"max_abs_norm_error":float(np.max(abs(np.linalg.norm(turned,axis=1)-1)))}36 controls=v["representative_controls"]37 packet=[]38 for ph in ["ghm","hg"]:39 primary=next(x for x in r["cases"]if x["case_id"]==f"{ph}_z15_tau10p0")40 larger=next(x for x in controls if x["label"]==f"{ph}_larger_packets")41 packet.append({"phase":ph,"primary_packets":primary["packet_count"],"primary_gain":primary["total_relative_to_vacuum"],"primary_SE":primary["total_mc_standard_error"],42 "larger_packets":larger["n_packets_per_batch"]*larger["batches"],"larger_gain":larger["mean_gain"],"larger_SE":larger["gain_batch_standard_error"],43 "qualification":"Additional packets do not establish uniform GHM point-nadir convergence. HG representative control is stable."})44 controls_summary={"status":"EXECUTED_CONDITIONAL_TESTS_WITH_UNRESOLVED_GHM_POINT_NADIR_CONVERGENCE",45 "production_accounting":stats,"packet_count_controls":packet,"source_cone_control":c,46 "radius_controls":[x for x in controls if "_radius"in x["label"]],47 "source_importance_controls":[x for x in controls if "_importance"in x["label"]],48 "single_scatter_reference":v["single_scatter_integral"],"time_bin_sensitivity":v["time_bin_sensitivity"],49 "matched_CloudScat_HG":cross,"negative_truncation_control":v["negative_control"],50 "interpretation":"Phase normalization, sampling, geometry, accounting and matched ideal-HG code controls pass. GHM point-nadir rare paths remain nonuniformly converged; no physical GHM/HG timing bias is inferred."}51 dump(H/"validation_summary.json",controls_summary)52 failures=read(H/"retained_failures.json")53 failures.extend([54 {"stage":"analytic vacuum bookkeeping","failure":"N=1 sample standard deviation produced NaN; a random single-direction escape value could be mistaken for an analytic expectation.","resolution":"Original records retained as TXT; vacuum metadata repaired. Released analytic vacuum has no MCbatches and expected upward fraction0.5. No nonvacuum trajectory changed."},55 {"stage":"matched-control script first attempt","failure":"Missing space in a conditional expression caused SyntaxError before control execution.","resolution":"Corrected and rerun; both control cases completed. Error text retained here."},56 {"stage":"GHM packet convergence","failure":"Increasing packet count changes some point-nadir estimates more than finite-batch SEM would suggest. Rare forward paths can be unseen in smaller runs.","resolution":"Unresolved numerical limitation; all nonzero GHM cases flagged. Original grid and controls retained; no physical rise-time bias or validated classifier claimed."},57 {"stage":"bounded1degree source-cone control","failure":"Unbiased weighted-source checks pass, but the cone control does not remove multiple-scattering rare-path variance.","resolution":"Retained control; not substituted for primary data. One batch has up to"+str(c["max_top10_contribution_fraction"])+" of scattered estimate in its10largest packet contributions."},58 {"stage":"radius convergence","failure":"GHM radius15/30/60km comparisons are too noisy to certify radius independence.","resolution":"Retain curves and errors; label as physical-domain sensitivity,not proof of convergence."}59 ])60 failures=list({x.get("stage",str(i)):x for i,x in enumerate(failures)}.values())61 dump(H/"retained_failures.json",failures)62 qa={"generated_utc":datetime.datetime.now(datetime.timezone.utc).isoformat(),"status":"LIMITED_NUMERICAL_PASS_HG_CONTROLS_PASS_GHM_CONVERGENCE_REMAINS",63 "production":stats,"phase_sampling_and_geometry_QA":"production/phase_and_geometry_QA.json",64 "phase_sampling_pass":all(x["pass"]for x in q["phases"].values()),"geometry_pass":q["all_geometry_tests_pass"],65 "rotation_check":rotation,"direct_and_inverse_square":v["direct_tests"]+[v["vacuum_inverse_square"]],66 "deterministic_single_scatter":v["single_scatter_integral"],"cone_weight_checks_pass":all(x["pass_5SE"]for x in c["source_sampling_checks"]),67 "matched_HG_independent_code_controls_pass":all(x["within_3SE"]for x in cross["cases"]),68 "cross_code_scope":"Two exactly parameter-matched idealHG cases only. Shared timingpostprocessor is not an independent timing-analysis validation. GHM, realclouds, gases, polarization and sourceinference remain unvalidated.",69 "time_bin_max_rise_difference_1_to_4us":max(abs(v["time_bin_sensitivity"]["records"][i]["rise_10_90_us"]-v["time_bin_sensitivity"]["records"][i+4]["rise_10_90_us"])for i in [0,1]),70 "time_bin_qualification":"Same1us trajectories regrouped; isolates bin placement. It does not test rare-path convergence or all geometries.",71 "packet_count_controls":packet,"unresolved":["GHM point-nadir rare-path convergence and nonlinear timing uncertainty","UV icehabit,roughness,size-distribution and interpolation representativeness","Realice absorption and atmospheric Rayleigh/ozone/aerosol paths","3D cloud structure and source angular/temporal/spectral distribution","Observed noisy onset, eventpopulation classifier and flight detection rates"],72 "raw_LUT_redistributed":False,"original_full_nc_sha256":m["phase_input"]["original_full_nc_sha256"],"private_subset_sha256":m["phase_input"]["input_sha256"],73 "private_LUT_extraction_verified_against_full_NetCDF":True,"extraction_fields":["wavelength_nm","theta_deg","reff_um","phase","ssa","ext_km_inverse"],"raw_extraction_output_written":False,74 "source_code":{"executed_production_engine_sha256":m["engine_sha256"],"production_snapshot_matches":sha(H/"production/engine_snapshot.py")==m["engine_sha256"],75 "executed_runner_sha256":m["runner_sha256"],"runner_snapshot_matches":sha(H/"production/runner_snapshot.py")==m["runner_sha256"],76 "current_engine_sha256":sha(H/"cylinder_mc.py"),"current_postprocess_sha256":sha(H/"postprocess.py"),"timing_module_sha256":sha(H/"timing_metrics.py"),77 "post_run_code_changes":"Vacuum metadata fix, source-cone diagnosticoption and per-packet tail diagnostics. Default nonvacuum physical walk unchanged. Executed snapshots retained."},78 "validation_seed_qualification":"Six independent seeds within each condition. The validation label-codepoint seed function gives identical seeds to radius15/60km controls; these cross-condition trajectories share random streams. No independent-difference significance is inferred for radius comparisons.",79 "retained_failure_file":"retained_failures.json","runtime":{"production_elapsed_s":m["elapsed_s"],"bounded_validation_elapsed_s":v["wall_s"],"cone_control_elapsed_s":c["wall_s"]},80 "checks_not_performed":["Independent-code comparison for the tabulated GHM phase","Native UV phase-grid or icehabit convergence","Physical atmosphere or realcloud validation","Classifier validation against measured labelled events"],81 "counts_note":"Production has14.4million nonvacuum histories. Auxiliary validation and cross-code batches are separate from the plotted primary grid; source-only/angular draws are not transport histories."}82 dump(H/"QA.json",qa)83 # Strict JSON plus native-kernel consistency assertions.84 parsed=085 for p in H.rglob("*.json"):read(p);parsed+=186 scripts=[]87 for p in H.rglob("*.py"):compile(p.read_text(encoding="utf-8"),str(p),"exec");scripts.append(str(p.relative_to(H)))88 assert stats["transport_packets"]==14400000 and stats["independent_batches"]==28889 assert stats["truncated_packets"]==0 and stats["negative_delay_beyond_tolerance_count"]==090 assert stats["max_abs_kernel_sum_error"]<1e-10 and stats["minimum_response_bin_mass"]>=091 assert qa["phase_sampling_pass"] and qa["geometry_pass"] and qa["matched_HG_independent_code_controls_pass"]92 with(H/"validation_controls.csv").open("w",newline="",encoding="utf-8")as f:93 fields=["label","n_packets_per_batch","batches","mean_gain","gain_batch_standard_error","truncated_packets"]94 w=csv.DictWriter(f,fieldnames=fields);w.writeheader()95 for x in controls:w.writerow({k:x[k]for k in fields})96 w.writerow({"label":"ghm1degree_cone","n_packets_per_batch":c["packets_per_batch"],"batches":c["batches"],"mean_gain":c["mean_gain"],"gain_batch_standard_error":c["batch_standard_error"],"truncated_packets":0})97 qa["file_integrity_checks"]={"strict_json_files_parsed":parsed,"python_scripts_compile_without_pyc":scripts,"native_kernel_mass_and_energy_assertions_pass":True}98 dump(H/"QA.json",qa)99 print(json.dumps({"status":qa["status"],"production":stats,"matched_HG_controls_pass":qa["matched_HG_independent_code_controls_pass"],"json_files":parsed,"scripts":len(scripts)}))100if __name__=="__main__":main()101