This directory contains the internal CKDMIP workflow for NLPQ experiments. The workflow is controlled by one YAML file and runs one domain/band job at a time. Generated data, CKDMIP files, models, logs, and plots are not part of the source tree.
Create a Python environment and install the local requirements:
python -m pip install -r requirements.txtInstall the py2sess version that includes TwoStreamEss.forward_flux when
running rt-aware training:
git clone <py2sess-repo-url> /path/to/py2sess
cd /path/to/py2sess
python -m pip install -e ".[torch]"Build or install the CKDMIP tools and set the YAML paths.ckdmip_bin value to
the directory containing ckdmip_sw and ckdmip_lw.
This repo is scoped to training, freezing, exporting, and verifying NLPQ methods against CKDMIP data. It is not intended to reproduce every external baseline or make runtime-speedup claims. External comparisons, such as RRTMG, should be handled in downstream analysis from the saved CKDMIP-format outputs.
The det and rt-aware paths support longwave and shortwave. det is regular
native-index binning. rt-aware trains a frozen assignment with py2sess
forward_flux as the differentiable flux/heating teacher when
rt.train_teacher: py2sess. Longwave uses the thermal source terms. Shortwave
uses py2sess solar forward_flux flux-only training with first-order
correction enabled by default, plane-parallel geometry, absorption optical
depth, Rayleigh optical depth, CKDMIP solar irradiance, configured
rt.mu_values, and surface albedo. SW compressed optics default to direct-beam
absorption closure at nlpq.sw_tau_mu_ref and solar-weighted arithmetic
Rayleigh closure, so training and CKDMIP export use the same source-aware
moments. SW heating loss uses net-flux divergence; SW flux loss still compares
upwelling and downwelling fluxes to avoid cancellation. Formal validation and
final scoring still use CKDMIP ckdmip_lw or ckdmip_sw, not py2sess.
LW export optionally blends the default per-layer transmittance closure with
a TOA-anchored path-transmittance closure (nlpq.lw_tau_mode: path_blend) to
correct a systematic one-sided flux/heating bias; the blend weight is a fixed
offline pressure-coordinate rule (nlpq.lw_lambda_rule: ramp or
top_taper), never fitted online or on Eval-2. See
docs/lw_path_closure.md for the closure definition and production
constraints, and docs/lw_lambda_taper_report.md for the calibrated default.
The main rt-aware-path method is assignment-only with flux, heating, and
source/path-aware training losses. rt-aware-current keeps the same teacher
but disables the path loss for method comparison. rt-aware-nn is available
for manual YAML runs only when species-level CKDMIP optical depths are present.
Copy and edit the longwave det + rt-aware-current + rt-aware-path example:
cp configs/example.yaml run_lw_band04.yamlFor a shortwave det + rt-aware-current + rt-aware-path run, start from:
cp configs/example_sw.yaml run_sw_band02.yamlFor a shortwave deterministic-only run, start from:
cp configs/example_sw_det.yaml run_sw_band02.yamlTo include the neural optical-depth residual in a manual run, edit the copied YAML:
nlpq:
methods: [det, rt-aware-path, rt-aware-nn]
training:
nn_steps: 200Set these paths in the YAML:
paths.data_root: local or shared CKDMIP data directory.paths.run_root: output directory for run products.paths.ckdmip_bin: directory with CKDMIP executables.paths.py2sess_repo: py2sess checkout, required forrt-aware.
The example configs use repo-local ignored directories so dry-run commands are safe to run immediately. For real HPC runs, change these paths to shared scratch/project storage before downloading data or launching training.
For large CKDMIP bands, keep training.load_dtype: float32, set
training.load_workers near the number of allocated CPU cores, and keep
training.py2sess_max_rows finite to avoid native-reference RT memory spikes.
run.scenarios accepts a list, e.g. [present, future, preindustrial, glacialmax]. The loader applies the standard CKDMIP trace-gas scaling for each
named scenario (and single-gas perturbations such as co2-560). Training
(dev_tune/final_train) always fits one frozen NLPQ artifact using only the
first scenario in the list, since retraining per scenario would mean
re-downloading and re-processing full native spectra once per scenario for no
benefit. final_test then evaluates that one frozen artifact against every
scenario in the list, writing scenario-scoped outputs
(ckdmip_inputs/{method}_q{Q}_{scenario}.nc, etc.) into one aggregated
final_test_metrics.csv with a scenario column, never overwriting results
across scenarios.
The split is fixed by default:
split:
dev:
train_profiles: "0-39"
val_profiles: "40-49"
final:
train_profiles: "0-49"
test_dataset: evaluation2Development tuning uses only Evaluation-1 profiles 0-39 for fitting and 40-49 for frozen validation. The final model is retrained on all 50 Evaluation-1 profiles and Evaluation-2 is used only once for final testing.
AWS/local readiness checks:
python scripts/aws_preflight.py \
--config run_lw_band04.yaml \
--json-out runs/_aws_logs/preflight.jsonUse --require-data after the CKDMIP files have been downloaded. For AWS
setup details, see aws/README.md. The AWS wrapper can run multiple YAMLs and
write per-stage logs/manifests:
python scripts/aws_run_batch.py \
--config run_lw_band04.yaml \
--config run_sw_band02.yaml \
--stages preflight download dev_tune final_train final_test plot reportPreflight:
python scripts/run_ckdmip_nlpq.py \
--config run_lw_band04.yaml \
--stage preflightPlan downloads without writing raw data:
python scripts/download_ckdmip_data.py \
--config run_lw_band04.yaml \
--dry-runAdd --estimate-size to query remote file sizes while writing the same plan.
For parallel downloads, launch disjoint shards with --num-shards N and
--shard-index i.
Run the full workflow:
python scripts/run_ckdmip_nlpq.py \
--config run_lw_band04.yaml \
--stage allOn Slurm:
sbatch slurm/download_band.sbatch /absolute/path/to/run_lw_band04.yaml
sbatch slurm/run_band_all.sbatch /absolute/path/to/run_lw_band04.yamlRun products are written under:
runs/{domain}/bandXX/{run_id}/
Important files include:
download_plan.csvmetrics/{domain}_bandXX_dev_tuning_candidates.csvmetrics/{domain}_bandXX_dev_tuning_ranked.csvselected_settings.yamlselected_settings.jsonmodels/{domain}_bandXX_{method}_q{Q}_dev.npzmodels/{domain}_bandXX_{method}_q{Q}_final.npzckdmip_inputs/{domain}_bandXX_{method}_q{Q}.ncckdmip_fluxes/{domain}_bandXX_{method}_q{Q}_fluxes.ncckdmip_inputs/{domain}_bandXX_{method}_q{Q}.namproduction_tables/{domain}_bandXX_{method}_q{Q}_final_table.npzvertical/{domain}_bandXX_train_vertical_outputs.npzvertical/{domain}_bandXX_val_vertical_outputs.npzvertical/{domain}_bandXX_test_vertical_outputs.npzreports/{domain}_bandXX_final_report.mdmanifest_{domain}_bandXX.json
All output names include the domain and band id. When run.scenarios lists
more than one scenario, final_test outputs are additionally scoped per
scenario (ckdmip_inputs/{scenario}/..., vertical/..._{scenario}...).
dev_tune writes validation vertical outputs for the selected candidate.
final_train retrains the selected model on all Evaluation-1 profiles, fits a
frozen production table alongside it, then runs CKDMIP RT on that train set to
write train vertical outputs.
final_test never retrains; it only replays a frozen artifact against
Evaluation-2 (or whichever split.final.test_dataset names). It supports two
modes via run.final_test_mode:
production_table_only(default): predicts Q-point optical depth from the frozen production table using only atmospheric-state fields (pressure_hl,temperature_hl,mole_fraction_fl) already present in the truth/flux file. This is the operationally realistic evaluation — a real forecast model never has native line-by-line spectra available, so this is the only mode that reflects how the compressed CKD scheme would actually be deployed. It also never needs to download or read Evaluation-2 native spectra (run.download_mode: truth_onlypairs naturally with it).native_assignment: loads the frozen NLPQ model and applies its fixed pseudo-line assignment directly to Evaluation-2's native spectra. This is a diagnostic-only upper bound on how good the pseudo-line clustering itself is, assuming native spectra were available; it requires downloading and reading the full Evaluation-2 native spectra set. Use it deliberately for diagnostics, not as the default scoring path.
Neither mode ever fits or retrains on Evaluation-2 data — the frozen
assignment/table always comes from Evaluation-1 training only, so using
Evaluation-2 as model input in native_assignment mode is not leakage (the
truth flux target stays separate and is only used afterward to score the
result). The distinction is about production realism, not about leakage.
- Missing CKDMIP executables fail preflight.
- Missing py2sess or missing
TwoStreamEss.forward_fluxfails preflight whenrt-awareis requested. - Missing official CKDMIP spectra or flux truth fails outside download/dry-run stages.
- SW
rt-awarerequires official CKDMIP Rayleigh optical depth and solar irradiance unlessrt.allow_zero_rayleigh: trueis explicitly set for a diagnostic run. - SW
rt-awareuses py2sessforward_fluxflux-only training with solar first-order correction by default. Keeprt.sw_include_fo: trueandrt.sw_plane_parallel: trueunless running a diagnostic ablation. - Evaluation-2 must not appear in tuning.
- Train/validation profile leakage is rejected.
- Dev tuning exports frozen candidates, runs CKDMIP RT, and ranks on flux and
heating metrics when
tuning.require_ckdmip_rt_for_selectionis true. - Formal compressed evaluation requires official CKDMIP spectra, flux truth, CKDMIP executables, and the domain-specific source terms required by CKDMIP CKD mode.
- Full-band
Q=MCKDMIP RT is not a required gate for large bands; identity checks are unit-test or small-window diagnostics. - At finite Q, deterministic compression preserves only configured intra-cluster
moments.
rt-aware-pathadds LW source/escape and SW cumulative direct-beam path losses during training; official validation still determines whether the finite-Q closure preserves fluxes or heating. - The current
rt-aware-pathclosure learns only the hard native-to-Q assignment. NN optical-depth residuals are in the separatert-aware-nnmethod. rt-aware-nnrequires species-levelspecies_tau_native; official CKDMIP spectra loading provides this, and custom NPZ batches must include it.- The current compressed model is a frozen assignment applied to native optical depths; inference still requires CKDMIP/LBL spectra.
- py2sess training uses a hydrostatic pressure-temperature height grid for the geometry argument. Final scoring still uses the CKDMIP executable.
- LW truth flux files prefer CKDMIP
fluxes-4anglewhen available, matching the CKDMIP RT namelist used by this workflow.