Skip to content

Picket-fence longwave radiation: multi-planet correlated-k scheme, hi-fi Earth LW, and the discovery-story docs#207

Merged
JoyMonteiro merged 129 commits into
developfrom
feature/picket-fence-radiation
Jun 5, 2026
Merged

Picket-fence longwave radiation: multi-planet correlated-k scheme, hi-fi Earth LW, and the discovery-story docs#207
JoyMonteiro merged 129 commits into
developfrom
feature/picket-fence-radiation

Conversation

@JoyMonteiro

Copy link
Copy Markdown
Member

Summary

This branch adds the picket-fence longwave radiation scheme to climt and the
work built on top of it. Highlights, oldest → newest:

  • Picket-fence correlated-k radiation (PicketFenceLongwave / SW), a
    multi-planet non-grey scheme with a two-stream solver, plus the
    Chaverot→Exo_k→climt table pipeline and downsampled opacity tables (Earth,
    Titan, TRAPPIST-1e, …).
  • Numba performance work — the optical-depth/Planck assembly hot loops are
    @njit-compiled; the faithful 14-band scheme runs faster than RRTMG,
    bit-for-bit.
  • Sub-project A — CO₂-adjustable hi-fi Earth LW table (earth_low_res_lw):
    14 bands × 8 g-points, decoupled log-X H₂O continuum, runtime CO₂ axis
    (10–10 000 ppm, log-k interpolated). Moist-RCE surface bias vs RRTMG cut from
    +11.9 K to +2.0 K.
  • Sub-project B — the discovery-story docs (this session): the first Quarto
    Experiments post (docs/experiments/2026-06-05-picket-fence-co2-bands/)
    telling the correlated-k warm-bias investigation, a pre-executed companion
    notebook, a robust θ-curvature tropopause locator
    (scripts/experiments/tropopause.py), a hash-gated artifact regenerator
    (scripts/build_experiments.py + make experiments), and minimal
    forward-compatible Quarto scaffolding.

Specs and plans for each piece live under docs/superpowers/.

Test Plan

  • pytest (full suite in the climt env)
  • pytest tests/test_tropopause.py tests/test_build_experiments.py — B's new units (8 tests)
  • make experiments && make experiments-check — artifacts regenerate and are idempotent
  • quarto render docs/experiments/2026-06-05-picket-fence-co2-bands/index.qmd — post + embedded notebook render, citations resolve
  • Spot-check PicketFenceLongwave against RRTMG on the moist-RCE case (before/after tables)

🤖 Generated with Claude Code

JoyMonteiro and others added 30 commits April 12, 2026 20:41
Design spec covers a dual-mode (Parmentier + correlated-k) intermediate
radiation scheme for climt with shared solver kernels, pure Python + numba
acceleration, and extensible opacity table format. Student project brief
describes calibrating Parmentier picket-fence coefficients for terrestrial
atmospheres (Earth, Mars, Venus) using linepyline.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…plementation plan

Design spec covers dual-mode (Parmentier + correlated-k) picket-fence
radiation with LW and SW components, cloud hooks, and numba acceleration.
Student project brief details calibrating Parmentier coefficients for
terrestrial atmospheres (Earth, Mars, Venus).
Implementation plan has 10 tasks covering the full build.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implement Task 2 of the picket fence radiation scheme.
- Add shared utilities for heating rates and column amounts.
- Add LW transport kernel with diffusivity approximation.
- Add unit tests for the kernel.

Co-Authored-By: Gemini CLI <noreply@google.com>
Implement Task 3 of the picket fence radiation scheme.
- Add Parmentier gas optics module with coefficient interpolation.
- Add solar composition coefficients for Parmentier mode.
- Add unit tests for the optics module.

Co-Authored-By: Gemini CLI <noreply@google.com>
… mode

Implement Task 4 of the picket fence radiation scheme.
- Add PicketFenceLongwave component that uses Parmentier gas optics mode.
- Export PicketFenceLongwave from climt._components.
- Compute column T_eff using internal and irradiation temperatures.
- Add comprehensive unit tests covering heating rate and flux consistency.

Co-Authored-By: Gemini CLI <noreply@google.com>
…alues

Implement Task 9 of the picket fence radiation scheme.
- Add default values for irradiation_temperature and internal_temperature.
- Set domain to atmosphere_horizontal to ensure proper output dimensions.
- Validate that all existing tests pass with the new defaults.

Co-Authored-By: Gemini CLI <noreply@google.com>
…d interpolation

Implement Task 5 of the picket fence radiation scheme.
- Add correlated-k module.
- Generate and load synthetic 2-band LW test table.
- Implement bilinear interpolation for k-coefficients.
- Compute optical depths per gas amount.

Co-Authored-By: Gemini CLI <noreply@google.com>
Implement Task 6 of the picket fence radiation scheme.
- Update PicketFenceLongwave to support correlated_k optics.
- Dynamically generate input properties from gas names in table.
- Use compute_ck_optical_depth for layer opacities.
- Calculate Planck sources using temperature-dependent fractions.
- Add unit tests for correlated_k mode execution and energy sum.

Co-Authored-By: Gemini CLI <noreply@google.com>
Implement Task 7 of the picket fence radiation scheme.
- Create SW two-stream kernel handling direct beam attenuation.
- Add corresponding tests for zero optical depth and total absorption.

Co-Authored-By: Gemini CLI <noreply@google.com>
…r mode

Implement Task 8 of the picket fence radiation scheme.
- Add PicketFenceShortwave using the new sw_two_stream kernel.
- Include Parmentier mode mapping (3 visible bands).
- Expose PicketFenceShortwave in the components interface.
- Add SW-specific tests including nighttime zero-flux behavior.

Co-Authored-By: Gemini CLI <noreply@google.com>
…d hook

Implement Task 10 of the picket fence radiation scheme.
- Add test combining PicketFenceLongwave and PicketFenceShortwave.
- Ensure proper energy balance and reasonable heating/cooling.
- Add test to verify cloud optical depth interacts with fluxes properly.

Co-Authored-By: Gemini CLI <noreply@google.com>
- Use standard net_flux (up - down) for SW heating rate to ensure proper heating rather than cooling.
- This was identified during the LW+SW integration tests.

Co-Authored-By: Gemini CLI <noreply@google.com>
Co-Authored-By: Gemini CLI <noreply@google.com>
Wire Freedman 2014 Rosseland mean opacity fit (replacing placeholder
kappa_R constants), add surface emissivity and cloud optical depth
inputs to LW component, add earth-sun distance factor to SW, fix gas
unit handling (mole fraction vs kg/kg), add diffusivity factor D=1.66
to LW kernel, correct SW reflected flux attenuation, and make band
counts configurable in initialization.py so get_default_state works
with any radiation scheme.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add module to load stellar spectra from bundled .npz files and integrate
over arbitrary wavenumber bands, needed for correlated-k SW mode.
Includes approximate Lean & DeLand (2012) quiet-sun spectrum.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…d-k table

- Replace direct-beam-only SW kernel with Meador & Weaver two-stream solver
  using delta-Eddington scaling and adding method (Task 1)
- Add ESFT gas overlap method for multi-gas correlated-k with combined
  g-point weights, update LW component to handle ESFT returns (Task 2)
- Create SW correlated-k test table with solar_source_per_gpoint and
  rayleigh_coefficient fields (Task 4)
- Mark completed plan steps for tasks 1-4

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Enable PicketFenceShortwave(optics="correlated_k", table="test_2band_sw")
which loads the SW k-table, computes absorption optical depths per
band/g-point, adds Rayleigh scattering, and passes everything to the
two-stream solver. Includes tests for basic operation, band-sum
consistency, and nighttime zero-flux.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… design spec

Add Section 6.5 covering optional intermediate diagnostics
(diagnostics_level flag), single-column entry points, kernel
decomposition guidelines, and worked Jupyter notebook plans.
Update Section 11 to reference the new notebooks.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Rename sw_two_stream → _sw_two_stream_core (keeps @njit), add plain-Python
sw_two_stream wrapper that returns per-layer R/T, direct beam profile, and
delta-scaled optical properties at diagnostics_level 1 and 2.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Thin convenience wrappers that reshape 1D inputs into (nband=1, ngpt=1,
nlev, ncol=1) format, call the underlying sw_two_stream/lw_transport
kernels, and return named-result dicts — so students never need to think
about band/gpoint/column dimensions.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…dd lw diagnostics test

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit introduces the following changes:

- Extracted MOLAR_MASS and MOLAR_MASS_DRY_AIR to common.py for reuse across SW and LW components.

- Removed lw_single_column and sw_single_column wrappers, opting for component-level pedagogical diagnostics instead.

- Wired in load_stellar_spectrum logic for the SW Parmentier mode.

- Added tests for flux_adjustment_for_earth_sun_distance and correlated-k modes.

- Updated documentation plans and specs to reflect the changes in pedagogical approach.

Co-Authored-By: Gemini CLI <noreply@google.com>
…ating rate diagnostics

Adds component-level per-band pedagogical diagnostics to the picket-fence radiation scheme. The LW and SW components now return per-band optical depths and heating rates as part of the standard diagnostics dict, computed transparently within the array_call methods.

Co-Authored-By: Gemini CLI <noreply@google.com>
Implements support for cloud scattering in the shortwave component. PicketFenceShortwave now accepts shortwave_optical_thickness_due_to_cloud, single_scattering_albedo_due_to_cloud, and cloud_asymmetry_parameter as inputs. These are combined with gas optical properties using two-stream combination rules before the solver.

Co-Authored-By: Gemini CLI <noreply@google.com>
…ofiles

Introduces load_atmospheric_properties() and reset_atmospheric_properties() to easily switch between planetary constants (g, Cp, molar masses, etc.). Includes built-in TOML profiles for Earth, Mars, and hot Jupiters, and supports loading custom TOML files. Uses a snapshot stack to allow reliable restoration of previous constants.

Co-Authored-By: Gemini CLI <noreply@google.com>
JoyMonteiro and others added 28 commits June 4, 2026 23:02
Final hotspot after the optical-depth kernel: the per-(band,gpt,level,col)
Planck source loop was pure Python (~95% of the remaining call). njit it the
same way (bit-for-bit vs frozen oracle). PF-LW 100-col: 203ms -> 5.7ms, now
faster than RRTMG-LW (6.6ms). Total improvement 3068ms -> 5.7ms (~540x).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… flip done

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…s-neutral)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Part 2 no longer (wrongly) gated on linepyline import — it runs PF log-k vs
linear-k in the climt env and compares against pre-generated LBL spectra.
lbl_olr_tiebreak.py --co2 <ppm> writes lbl_olr_spec_moist_co2_<ppm>ppm.npz.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ity-free)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Approved brainstorming output for sub-project B: discovery-driven Sphinx
page + climt-env companion notebook telling the PF longwave warm-bias
story (correlated-k failure mode + fix). Decisions: advanced-undergrad
audience; page = standalone story, notebook = re-runnable evidence;
theta-curvature tropopause helper as the only new code; single figure
script; JupyterLite interactivity deferred to the Pyodide spec.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reconcile B with the climt-website spec (2026-05-18): docs move from
Sphinx to a Quarto GH Pages site where the picket-fence saga is the first
Experiments post. B now delivers that post (docs/experiments/<date>-
picket-fence-co2-bands/index.qmd) plus minimal forward-compatible Quarto
scaffolding (_quarto.yml, references.bib, build_experiments.py, make
experiments), the companion notebook as a Try-it-yourself include, the
sources.yml artifact pipeline, and the tropopause helper. Pyodide
deferral delegated to the website spec's live-cells follow-up. Full
website migration stays out of scope.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Task-by-task plan: theta-curvature tropopause helper (TDD), hash-gated
build_experiments.py (TDD), minimal Quarto scaffolding + make experiments,
--save/--out hooks on existing RCE/bench/kg scripts, single figure
generator, experiment sources.yml + regenerated artifacts, companion
notebook (pre-executed), the index.qmd Experiments post, and final
render/cross-reference wiring.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ipeline

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two 200-day moist-RCE runs reproduce the headline contrast: before-table
PF-RRTMG dT_sfc=+11.9K (q_sfc 6.5 vs 2.0 g/kg), after-table +2.05K with
co-located tropopauses. throughput: PF 56.6 vs RRTMG 65.3 us/col.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Pressure axis was upside-down (1000 hPa at top): invert_yaxis() was called
per-subplot inside the loop, but sharey=True meant the second call undid the
first. Invert once after the loop. Regenerated the figure artifacts.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ted)

15 cells reproducing the discovery story from the regenerated _artifacts/:
symptom (+11.91K, broken tropopause), k(g) shelf+cliff (+ pure-Python toy),
line-by-line culprit isolation, before/after RCE (+2.0K, co-located), and the
fast-vs-faithful throughput. Self-check asserts pass against the artifacts.
Includes the Pyodide live-cell boundary map.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Discovery-driven narrative (symptom -> primer -> culprit -> dead-ends -> two
root causes -> payoff), advanced-undergrad voice, layered via Quarto callouts.
Embeds the four regenerated hero figures and the companion notebook; cites
Mlawer 1997/2012 and Parmentier 2014. Uses the regenerated theta-curvature
tropopause numbers (the old 583 hPa marker is reframed as the motivating
artifact). Renders clean under quarto.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Remove unused imports (njit/prange/CondensibleParams; dead set_num_*_bands
re-export), an unused local (nT), and blank-line whitespace (W293/W391/E303).
Ignore E241 (column alignment in the correlated-k interpolation kernels and
constant tables is intentional and readable), consistent with the existing
relaxed whitespace policy.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The picket-fence optics modules (parmentier, correlated_k, stellar) and
_core/initialization import importlib_resources to load packaged .npz/.nc
data, but it was never in install_requires, so CI's editable install failed
collection with ModuleNotFoundError on every platform. Declare it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The fallback njit (used when numba is absent, e.g. CI and Pyodide) took a
required positional arg, so @njit(parallel=True) on the optimized kernels
raised 'njit() missing 1 required positional argument'. Support both bare and
parametrized decorator forms. Fixes test-collection on numba-free environments.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
CI had no numba installed, so it only ever exercised the pure-Python njit
fallback. The component tests are written to run with numba JIT active
(test_components notes NUMBA_DISABLE_JIT must not be set). Install numba in
CI so it tests the real compiled path, matching local development.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Bring previously-untracked project artifacts under version control: CLAUDE.md,
scripts/augment_graph.py, the documented experiment scripts, the remaining
superpowers plans + band-refinement log + release plan, PLUG_AND_PLAY_ARCHITECTURE,
the corr-k explainer note, and the HD209458b reproduction test + reference data.

Gitignore scratch: debug_data/ (3.8 GB of regenerable outputs), .ipynb_checkpoints/,
Quarto *_files/ render intermediates, and local AI-assistant configs (.claude/,
.gemini/, GEMINI.md). Personal experiments and scratch outputs were moved under
debug_data/scripts/ (preserved on disk, untracked).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- netcdf4: the pf_table_builder tests read .nc via xarray, which needs a
  NetCDF backend; CI had none (runtime loading uses scipy.io.netcdf and is
  unaffected). Dev-only dependency.
- Register a 'slow' pytest marker and run CI with -m 'not slow'. Mark the
  HD209458b RCE-to-equilibrium test (~150k steps) slow. RCE/integration tests
  are run on demand (pytest -m slow), not in routine CI.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Commit earth_hifi_lw.nc: a shipped correlated-k table that
  test_picket_fence_lw::test_shipped_earth_hifi_lw_is_co2_adjustable loads
  (was untracked, so CI couldn't find it).
- Mark tests/pf_table_builder/test_kappa_sampling.py slow: it needs the
  line-by-line stack (linepyline + its numba_stats dep), i.e. table-building
  tooling run on demand, not in routine CI.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@JoyMonteiro JoyMonteiro merged commit 016851b into develop Jun 5, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant