Make GEOS-Chem H2O a met-driven constant (fixed) species - #227
Open
xk-y wants to merge 3 commits into
Open
Conversation
… coupling * GEOSChemGasPhase H2O moves @species -> @parameters (isconstantspecies=true, alongside H2/N2/O2). Compiled coupled states 274->273. * GC<->GEOSFP: param_to_var(:T,:num_density,:H2O) + Magnus-equation c.H2O ~ f(A3dyn RH). The explicit O1D + H2O --> 2OH OH source now sees real per-cell humidity instead of holding H2O at a single constant (1.84e7 ppb), which overestimates OH aloft where H2O is 100-1000x lower. The NEI mapping expansion is submitted separately. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
H2O must be observed (met-driven), not a state, in the coupled GC+NEI+GEOSFP system. Met-driven H2O assertions only; the NEI assertions are submitted separately. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…rence) The 274->273 met-driven H2O state change shifts solver roundoff on the O1D->O3 finite-difference sensitivity, a near-cancellation quantity that at the old default tolerance + 10% perturbation sat at/below the solver accuracy floor (so it was noise that drifted with any structural change). Same fix as PR EarthSciML#222 for OH/HO2: reltol=abstol=1e-10 + 50% perturbation lifts the signal ~80x above the floor; the converged reference value is -4.411157e-7 (measured on this branch: -4.411015e-7, 3e-5 rel diff, rtol=0.01 has ample margin). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
38 tasks
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #227 +/- ##
==========================================
- Coverage 87.42% 87.29% -0.13%
==========================================
Files 20 20
Lines 1463 1472 +9
==========================================
+ Hits 1279 1285 +6
- Misses 184 187 +3
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
This was referenced Jul 10, 2026
Open
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
STATE-VECTOR CHANGE · breaking (274 → 273 states)
Motivation
Atmospheric H2O is determined by meteorology, not by gas-phase chemistry — GEOS-Chem Fortran accordingly treats it (with H2/N2/O2) as a fixed species set from met each timestep (met-driven fixed species), never integrated. The port instead carries H2O as a chemistry state, and since no chemical reaction meaningfully produces or destroys it, it simply stays frozen at its IC of 1.84e7 ppb at every model level. That is a boundary-layer mixing ratio; real upper-troposphere humidity is 100–1000× lower. The concrete failure: the explicit
O1D + H2O → 2OHsource then sees boundary-layer water aloft and grossly overproduces OH in the free troposphere in coupled multi-level runs.Change
geoschem_fullchem.jl: H2O@species→@parameterswithisconstantspecies=true(alongside H2/N2/O2, which upstream already treats exactly this way — H2O was the one fixed species left behind as a state).EarthSciDataExt.jl: GEOSFP coupling addsparam_to_var(:H2O)+ Magnus-equationH2O ~ f(A3dyn₊RH, P, T), so coupled runs get real per-cell humidity.Why this departs from the current design
The species-vs-parameter choice is not cosmetic: as a state, H2O can only be set by a (single, scalar) initial condition, so every coupled run inherits the frozen-constant error; as an
isconstantspeciesparameter it is promoted to a met-driven observed variable byparam_to_var— the same mechanism the SuperFast↔GEOSFP coupling already uses. Uncoupled behavior is unchanged (the parameter default is the same 1.84e7 ppb the state was frozen at); only the coupled system gains correct humidity.Upstream test change (O1D reference value)
The
O1D sensitivity to O3reference value moves8.1606e-7 → −4.4112e-7, with a robustified protocol (reltol=abstol=1e-10, 50% perturbation, rtol 0.01) — the same treatment the merged FastJX-interpolation PR (#222) applied to the OH/HO2 sensitivity tests in this file. The quantity is a near-cancellation finite difference of two O3 ≈ 20 ppb endpoints; at the old default tolerance + 10% perturbation the difference sits at the solver accuracy floor, so the reference value pinned solver noise (it does not even reproduce its sign under converged integration) and drifts with any structural change to the system — including this PR's 274→273 state change, which is numerically a no-op for this box test. Under the tightened protocol the value is converged and reproducible: −4.4112e-7 on one branch (which additionally adds the heterogeneous-uptake parameters) and −4.4110e-7 on this branch — two structurally different compiled systems agreeing to <5e-5 relative, well inside the rtol=0.01 test margin. The committed reference constant deliberately pins the shared cross-branch converged value (−4.411157e-7) rather than this branch's own last digit, so the same test ships unchanged across the related branches; either value passes at rtol 0.01.Validation
New test (
EarthSciData_test.jl) asserts the invariant directly: H2O is not a state, and H2O appears as an observed variable in the coupled system. The compiled coupled state count drops 274 → 273 (measured on this branch, not separately asserted — the not-a-state test is the stable form of the same guarantee). FullPkg.testgreen (rc=0) in the upstream environment on this branch.Notes
Shipped as its own PR (not bundled with the NEI mapping change) so it can be reviewed / discussed independently. Minor version bump.
Figure
Left: H2O carried as a chemistry state freezes at its boundary-layer IC (1.84e7 ppb) at every level, while met-driven H2O follows GEOSFP humidity down ~2 orders of magnitude with altitude. Right: the frozen/real ratio reaches ~x158 near the model top, where
O1D + H2O -> 2OHthen over-produces OH in the free troposphere. (Domain+time-mean, Mar 10-12 reference run.)Part of the coordinated cross-repo update tracked in #225.