Coupling to PROTEUS
This page is the practical recipe for using CALLIOPE inside a PROTEUS coupled run: which TOML blocks matter, which knobs are documented where, and which combinations are known to be safe.
For the underlying control flow (per-iteration sequence diagram, what the wrapper passes to equilibrium_atmosphere(), how warm-starts are constructed, what gets written back into hf_row), see the theory page.
Minimal [outgas] block
[outgas]
module = "calliope" # or "atmodeller" or "dummy"
fO2_shift_IW = 0.0 # log10 shift relative to IW buffer
mass_thresh = 1e16 # kg; doubles as the absolute mass-balance
# tolerance and the per-element zero threshold
T_floor = 700.0 # K, magma temperatures below this are clipped
solver_rtol = 1e-4 # relative tolerance on mass balance
solver_atol = 1e-6 # fsolve step tolerance (mapped to xtol, not atol)
h2_binodal = false # apply Rogers+2025 H2-MgSiO3 binodal override
[outgas.calliope]
include_H2O = true
include_CO2 = true
include_N2 = true
include_S2 = true
include_SO2 = true
include_H2S = true
include_NH3 = true
include_H2 = true
include_CH4 = true
include_CO = true
solubility = true # if false, force Phi_global = 0 (no melt dissolution)
The four primary species (H2O, CO2, N2, S2) must be included; the wrapper will refuse to run with any of them set to false. The seven secondary species can be disabled individually if you want a constrained sub-system (e.g. include_NH3 = false to suppress ammonia chemistry).
Choosing the elemental-budget mode
CALLIOPE needs total H, C, N, S inventories in kilograms. PROTEUS gives you two ways to specify them via [planet]:
[planet]
volatile_mode = "elements" # or "gas_prs"
volatile_reservoir = "mantle" # or "mantle+core"; sets the reservoir for ppmw
volatile_mode = "elements" (most common)
[planet.elements]
use_metallicity = false # if true, scales C/N/S to H from solar abundances
H_mode = "oceans" # "oceans" | "ppmw" | "kg"
H_budget = 1.0 # interpreted per H_mode
C_mode = "C/H" # "C/H" | "ppmw" | "kg"
C_budget = 0.1
N_mode = "ppmw"
N_budget = 2.0
S_mode = "ppmw"
S_budget = 200.0
The wrapper translates these into the four budget fields CALLIOPE expects:
H_mode = "oceans"βhydrogen_earth_oceans = H_budgetH_mode = "ppmw"βH_kg = H_budget * 1e-6 * M_reservoirH_mode = "kg"βH_kg = H_budget
C, N, S follow the same pattern; C/H is interpreted as a mass ratio relative to H.
volatile_mode = "gas_prs" (initial-pressure mode)
[planet]
volatile_mode = "gas_prs"
[planet.gas_prs]
H2O = 220.0 # bar
CO2 = 100.0
N2 = 1.0
S2 = 0.01
# secondary species default to 0.0 unless explicitly set
When volatile_mode = "gas_prs", the wrapper calls get_target_from_pressures(ddict) to back out the elemental inventory implied by the prescribed initial atmosphere; on every subsequent iteration the same elemental inventory is preserved.
Redox state
fO2_shift_IW is in \(\log_{10}\) units relative to the O'Neill & Eggins (2002) IW buffer. Common reference values:
| \(\Delta\mathrm{IW}\) | Description |
|---|---|
| \(-5\) | Highly reduced (Mercury-like, Cartier & Wood 2019) |
| \(-3\) | Reduced (Mars-mantle estimates, Wadhwa 2001) |
| \(-1\) | Moderately reduced |
| \(0\) | At iron-wΓΌstite buffer (core formation equilibrium at depth) |
| \(+3.5\) | Sossi et al. (2020) preferred Earth's mantle \(f_{\mathrm{O}_2}\) (their \(\Delta\mathrm{IW} = +3.5 \pm 0.5\)) |
| \(+4\) | CALLIOPE PROTEUS-side default; near-modern Earth upper mantle (within FMQ\(\,\pm\,2\) per Frost & McCammon 2008) |
The Sossi et al. (2020) compilation places Earth's near-surface mantle at \(\Delta\mathrm{IW} \approx +3\) to \(+5\) (their preferred value \(+3.5\)); CALLIOPE defaults sit at \(\Delta\mathrm{IW} = 4.0\), consistent with a modern terrestrial composition.
Solver tolerances
The PROTEUS wrapper hard-codes a few solver knobs that override the CALLIOPE library defaults:
| Wrapper override | Value | Reason |
|---|---|---|
nguess |
\(10^3\) | The PROTEUS warm-start almost always lands on the right basin in the first attempt; \(10^3\) Monte-Carlo restarts is plenty of margin without spending wall-time on degenerate cases. |
nsolve |
\(3 \times 10^3\) | Per-restart fsolve iteration cap. |
opt_solver |
False |
Skip the alternating-solver fallback; if fsolve cannot converge from a warm start, it almost always means an upstream bug rather than a basin-of-attraction problem. |
print_result |
False |
Suppress the per-call INFO log; the PROTEUS main loop already prints the partial pressures. |
The TOML field names map to equilibrium_atmosphere keyword arguments as follows:
| TOML field | Solver argument | Role |
|---|---|---|
solver_rtol |
rtol |
Relative tolerance on the elemental mass-balance residual. |
solver_atol |
xtol |
Step tolerance on the inner fsolve Powell-hybrid iteration. The name is historical; it does not set the absolute mass-balance tolerance. |
mass_thresh |
atol |
Absolute tolerance on mass balance, in kg. Also the per-element threshold below which a species' inventory is treated as zero. |
Warm-start behaviour
For Time > 1 yr, the wrapper builds p_guess from the previous-iteration H2O_bar, CO2_bar, N2_bar, S2_bar rows. For Time = 0 (first call) the wrapper passes p_guess = None and lets CALLIOPE's Monte-Carlo initial-guess generator find the basin. If an element's target inventory drops below mass_thresh, the corresponding p_guess is forced to zero so that the solver does not waste iterations chasing a vanishing species.
Common pitfalls
Missing required volatileat startup: one of H2O / CO2 / N2 / S2 is set toinclude = false. Fix: re-enable it (it can still be set to a tiny initial pressure if you want to suppress its mass).Could not find solution for volatile abundancesmid-run: CALLIOPE exhausted itsnguessMonte-Carlo restarts. Almost always caused by an upstream NaN or unphysical state inhf_row(e.g.T_magma < T_floorafter AGNI failed,M_mantle = 0after a structure-solve failure). Inspectproteus_00.logfor the iteration immediately before the CALLIOPE failure; do not bumpnguessblindly.- Atmosphere mass collapses to zero without escape accounting it: the
check_desiccationgate inproteus.outgas.wrapperwill refuse to mark the planet desiccated if the loss is unexplained by cumulative escape. This is by design: a real desiccation event must be supported by tracked atmospheric escape, so the gate firing means an upstream module silently zeroed the atmosphere and the failure is upstream of CALLIOPE. Hydrogen inventory must be > 0:H_budget = 0orH_modemistyped. CALLIOPE refuses to solve a zero-H system because the speciation is degenerate.- Solubility off but
Phi_global > 0: not an error, but the wrapper will silently forcePhi_global = 0when[outgas.calliope].solubility = false, so dissolved masses will all be zero regardless of the live melt fraction.
Next step
For what the wrapper actually does on each iteration (sequence diagram, mapping table, hf_row keys), read Coupling to PROTEUS (theory).