Skip to content

Keep the escape floor off a frozen mantle and book desiccation - #953

Merged
timlichtenberg merged 12 commits into
mainfrom
tl/escape-floor-crystallized
Oct 4, 2026
Merged

timlichtenberg merged 12 commits into
mainfrom
tl/escape-floor-crystallized

Conversation

@timlichtenberg

@timlichtenberg timlichtenberg commented Oct 3, 2026 •

Copy link
Copy Markdown
Member

Description

On a mantle frozen with params.stop.solid.freeze_volatiles, escape draws only from the atmosphere and no outgassing solve follows. The escape floor still set an element total to zero once it fell below outgas.mass_thresh, while that element's atmosphere column kept its mass and kept escaping. The element total and its reservoirs then disagreed with no error, and the per-element closure check in #928 stops a run on exactly this state.

This PR keeps the floor off on a frozen mantle, so the total falls with its atmosphere until desiccation. Desiccation then empties the atmosphere and the melt of every species and element, noble gases included, and keeps the mass in the solid mantle: each total becomes its solid share, limited to the total before the call. The removed mass is booked in a new cumulative helpfile column M_desiccated and, with the Zalmoxis structure, in M_volatile_change. The desiccation gate leaves M_desiccated out of the loss it compares with escape, so a desiccated run is still desiccated after a resume. A non-finite element total now refuses desiccation with an error instead of being written over with zero.

What changes in a run:

  • A frozen mantle with an element below mass_thresh: the element keeps escaping from the atmosphere instead of being removed from the total in one step.
  • A desiccated run: the noble gases leave the atmosphere and the melt with the other elements (at most the noble inventory at desiccation), the removed mass appears in M_desiccated, and a solid share stays in the totals. CALLIOPE holds no solid reservoir, so its totals still end at 0; the solid share is non-zero with atmodeller condensates and with the trapping of Trap volatiles in the solid mantle behind the freezing front #928.
  • A run that never desiccates and never floors an element on a frozen mantle is unchanged. M_desiccated is 0 throughout, and an older helpfile resumes with it at 0.

The mass_thresh description now states where the threshold acts.

Validation of changes

On macOS with Python 3.12:

  • Unit and smoke tiers: 4923 passed, 27 skipped.
  • A coupled Zalmoxis, Aragog and CALLIOPE run without escape gives a helpfile and interior snapshots identical to main, apart from the runtime column (877 columns, 10 snapshots), with M_desiccated at 0 in every row.
  • A dry Zalmoxis run that escapes to desiccation on a frozen mantle: since the freeze, the element budget is off by 2.8e16 kg on main and by less than 300 kg on this branch. M_volatile_change at desiccation equals the value on main and equals minus the sum of escaped and desiccated mass.
  • Applied to the last row of a trapping run of Trap volatiles in the solid mantle behind the freezing front #928, desiccation leaves the element solid columns unchanged, sets each total to its solid share, and removes 2.96e18 kg, the atmosphere and melt mass.
  • The same run resumed after desiccation stays desiccated at every step, and its volatile and ledger columns are identical to the continuous run. Resumed before desiccation, it desiccates at the same row.

Checklist

  • I have followed the contributing guidelines
  • My code follows the style guidelines of this project
  • I have performed a self-review of my code
  • My changes generate no new warnings or errors
  • I have checked that the tests still pass on my computer
  • I have updated the docs, as appropriate
  • I have added tests for these changes, as appropriate
  • I have checked that all dependencies have been updated, as required

calc_new_elements sets a non-noble element that escapes below outgas.mass_thresh to zero, so that the outgassing solve after it does not see a trace budget. On a frozen mantle no solve follows: run_crystallized only rescales the atmosphere by the escaped mass, so a zeroed total left the element's atmosphere in place. The element then kept escaping from a total of zero, its share of every later step was never debited, so the other elements' totals fell faster than their atmospheres and esc_kg_cumulative missed that loss.

run_escape now passes floor=not atmosphere_only, so on a frozen mantle the totals decay with the atmosphere and every element keeps total = atm + liquid + solid. Steps with a repartitioning solve keep the floor.
run_desiccated zeroes the outgassing keys, which hold the element totals only for O, since escape owns the others. On a frozen mantle the totals now decay with the atmosphere instead of being floored, so a desiccated planet kept H, C and N totals below outgas.mass_thresh with every column at zero. run_desiccated now also sets every non-noble element total to zero; noble-gas totals keep their value.
…ation

The mass_thresh description, the run_escape and calc_unfract_fluxes docstrings, the construct_guess docstring and the accretion strip docstring now say that escape zeroes a non-noble element below the threshold only on a molten mantle, and what the threshold does elsewhere. The config reference is regenerated.

A new test escapes an H2 and N2 atmosphere over a frozen mantle at the default threshold until desiccation, checking per-element closure and the escape ledger at every step and an empty row after desiccation. The desiccation test asserts the noble columns as well and compares against a seed value.
run_desiccated empties every element total with its columns, noble gases included, and books the mass it removes: in a new cumulative helpfile column M_desiccated, and in M_volatile_change so the Zalmoxis target loses it too. check_desiccation leaves M_desiccated out of the loss its escape-balance gate compares, so a desiccated row passes the same check again on resume. A helpfile written before the column resumes with it at zero.

The mass_thresh description and the accretion strip docstring say that the element floor is off only on a mantle frozen with freeze_volatiles. Tests run frozen escape to desiccation for a large and a small inventory, checking that initial = totals + escaped + removed, that the Zalmoxis target follows the totals, and that the row is still desiccated when checked again.
check_desiccation sums the current element totals with readable_total, which skips a non-finite total as run_desiccated does, so a row gives the same verdict before and after run_desiccated, in the loop and on resume; a non-finite M_desiccated reads as zero. Taking the escape baseline now clears M_desiccated together with esc_kg_cumulative, since mass removed before the baseline is not part of it.

The rules files and the accretion-escape integration identity include the mass removed at desiccation. New tests cover an unreadable total, a second run_desiccated, a structure without Zalmoxis and the baseline reset.
check_desiccation logs an error and refuses when any element total is not finite, and run_desiccated leaves such a total as it is instead of writing zero over it, so the upstream fault stays visible. The helpers it uses are imported at module level.

The mass_thresh description says which elements outgassing treats as absent below it and that noble gases are exempt; the construct_guess docstring states its noble-gas case. New tests cover an unreadable total, a non-finite M_desiccated, the desiccation latch on resume and the in-loop latch.
@timlichtenberg
timlichtenberg requested a review from a team as a code owner October 3, 2026 20:45
@codecov

codecov Bot commented Oct 3, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 95.54%. Comparing base (a2c5c17) to head (28e90a3).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #953      +/-   ##
==========================================
- Coverage   95.55%   95.54%   -0.01%     
==========================================
  Files         127      127              
  Lines       21129    21160      +31     
  Branches     3588     3595       +7     
==========================================
+ Hits        20189    20217      +28     
- Misses        936      943       +7     
+ Partials        4        0       -4     
Flag Coverage Δ
nightly 95.53% <100.00%> (+0.08%) ⬆️
unit-tests 92.16% <100.00%> (+0.02%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

run_desiccated empties the atmosphere and the melt of every species and element, noble gases included, keeps the solid columns, and sets each total to its solid share. Only the atmosphere and melt mass is booked in M_desiccated and the Zalmoxis target. The totals that remain are below the outgassing threshold as before, so the desiccation check still passes on the written row.
The species totals are set from their solid columns through explicit per-species keys, which the output reference resolves, and the solid-share tests compare against named values.
The kept share of each element and species is its solid column limited to [0, total before the call], and a non-finite solid column keeps nothing. The solid column, kg and mol, is set to the kept share, so no total rises, the booked mass is not negative and a desiccated row passes check_desiccation again. A non-finite total stays as it is, with a NaN mol total.

The helpfile scanner resolves the templated run_desiccated keys over the gas and element lists. Tests cover a stale solid column above the total, non-finite and negative solid columns, unreadable Fe and He totals, and a gate margin that refuses a row booking nothing.
Where the kept share is 0, the mol total and mol solid of a species are 0, also when the mol solid column was non-finite; only a non-finite kg total gives a NaN mol total. A non-finite M_desiccated on entry is booked from 0, as check_desiccation reads it, so the written row passes the check again.

The solid columns are written for every finite total and the mol solid for every finite mol value. Tests cover a non-finite mol solid with nothing kept, a non-finite ledger on entry, the warning for a non-finite solid column, the mol solid of an unreadable species, and that no mol column is written for an element; the clamp cases have scenario ids.
@timlichtenberg
timlichtenberg merged commit 26f73aa into main Oct 4, 2026
46 of 47 checks passed
@timlichtenberg
timlichtenberg deleted the tl/escape-floor-crystallized branch October 4, 2026 08:12
IKisvardai added a commit that referenced this pull request Oct 5, 2026
Brings in the frozen-mantle escape floor and the booked desiccation (#953),
fwl-aragog 26.10.03 (#952), the impact and escape bookkeeping fixes (#950,
#951), the shared install-script library (#864) and the full-precision
helpfile.

Desiccation now follows #953: the atmosphere is emptied and booked in
M_desiccated, and each total becomes the share its mantle holds. With trapping
on, the melt is kept as well as the solid, so that mass a remelt returns
stays in the planet however many steps the remelt takes; that replaces the
branch's own hold_in_mantle. The escape floor keeps main's frozen-mantle
switch and floors at the locked mass. The chemistry stage passes the new
initial flag to the dummy backend, the escape module imports the trapping
helpers where it uses them to avoid an import cycle, and the Aragog
cross-check builds its stand-in on the evaluator so the new phase-boundary
lookup runs. The helpfile registry and golden trajectory keep both sides'
columns, and the output reference is regenerated.
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