What happens
Once the mantle has solidified, outgas.wrapper.run_crystallized scales every species in gas_list by a single retained fraction, (m_atm - esc_step_kg) / m_atm. Meanwhile escape.wrapper.calc_new_elements debits the whole-planet elemental totals one element at a time, and separately zeroes any non-noble element whose new total falls below outgas.mass_thresh.
Those two act at different granularities. An element can therefore be driven to exactly zero in *_kg_total by the depletion floor while the gas species carrying it survives in *_kg_atm at close to its previous mass, because the uniform rescale only ever removes the aggregate escaped fraction from it.
The docstring of run_crystallized states that sizing the loss from the atmosphere in both places "keeps the per-element *_kg_total and the atmospheric reservoirs mutually consistent for every escape.reservoir setting". The floor is a second mechanism acting on the totals alone, so that does not hold.
Reproducing it
Needs escape.reservoir = "outgas", params.stop.solid.freeze_volatiles = true, and an element sitting just above outgas.mass_thresh while another dominates the column. With mass_thresh = 1e16:
H_kg_atm = H_kg_total = 1.0e22, dominant
O_kg_atm = O_kg_total = 1.02e16, just above the floor
M_atm = 1.0e22, O2_kg_atm = 2.55e14
- an escape step applying about 5.0e20 kg, which is well inside the per-step cap
O's share of that loss is roughly 5.1e14 kg, which takes O_kg_total to about 9.7e15, under the floor, so it snaps to zero and the full 1.02e16 kg leaves. The rescale then multiplies O2_kg_atm by 0.95. The planet ends the step holding no oxygen at all in its elemental budget and 2.42e14 kg of O2 in its atmosphere.
Why it is worth fixing
Chemistry is frozen in that regime, so nothing reconciles the two afterwards and the disagreement persists for the rest of the run. utils.coupler.assert_mass_conservation does not catch it: the M_vol_atm check compares the species sum against itself after the rescale, and M_atm <= M_planet is a gross bound that a per-species discrepancy does not violate. So it is silent.
A possible fix
Have calc_new_elements report which elements the floor truncated, and have run_crystallized zero the species carrying those elements rather than only scaling them. That is a signature change on a path every run with freeze_volatiles traverses, so it is worth doing on its own rather than alongside something else.
Scope
This is pre-existing and not introduced by any current branch. How often it is reached in practice is unmeasured; I found it while looking at the escape accounting, not from a run that went wrong.
What happens
Once the mantle has solidified,
outgas.wrapper.run_crystallizedscales every species ingas_listby a single retained fraction,(m_atm - esc_step_kg) / m_atm. Meanwhileescape.wrapper.calc_new_elementsdebits the whole-planet elemental totals one element at a time, and separately zeroes any non-noble element whose new total falls belowoutgas.mass_thresh.Those two act at different granularities. An element can therefore be driven to exactly zero in
*_kg_totalby the depletion floor while the gas species carrying it survives in*_kg_atmat close to its previous mass, because the uniform rescale only ever removes the aggregate escaped fraction from it.The docstring of
run_crystallizedstates that sizing the loss from the atmosphere in both places "keeps the per-element*_kg_totaland the atmospheric reservoirs mutually consistent for everyescape.reservoirsetting". The floor is a second mechanism acting on the totals alone, so that does not hold.Reproducing it
Needs
escape.reservoir = "outgas",params.stop.solid.freeze_volatiles = true, and an element sitting just aboveoutgas.mass_threshwhile another dominates the column. Withmass_thresh = 1e16:H_kg_atm = H_kg_total = 1.0e22, dominantO_kg_atm = O_kg_total = 1.02e16, just above the floorM_atm = 1.0e22,O2_kg_atm = 2.55e14O's share of that loss is roughly 5.1e14 kg, which takes
O_kg_totalto about 9.7e15, under the floor, so it snaps to zero and the full 1.02e16 kg leaves. The rescale then multipliesO2_kg_atmby 0.95. The planet ends the step holding no oxygen at all in its elemental budget and 2.42e14 kg of O2 in its atmosphere.Why it is worth fixing
Chemistry is frozen in that regime, so nothing reconciles the two afterwards and the disagreement persists for the rest of the run.
utils.coupler.assert_mass_conservationdoes not catch it: theM_vol_atmcheck compares the species sum against itself after the rescale, andM_atm <= M_planetis a gross bound that a per-species discrepancy does not violate. So it is silent.A possible fix
Have
calc_new_elementsreport which elements the floor truncated, and haverun_crystallizedzero the species carrying those elements rather than only scaling them. That is a signature change on a path every run withfreeze_volatilestraverses, so it is worth doing on its own rather than alongside something else.Scope
This is pre-existing and not introduced by any current branch. How often it is reached in practice is unmeasured; I found it while looking at the escape accounting, not from a run that went wrong.