VULCAN in PROTEUS
VULCAN serves as the atmospheric chemistry module within the PROTEUS framework, computing steady-state photochemical and thermochemical mixing-ratio profiles from the temperature–pressure structure produced by AGNI at each chemistry step. This page describes the data flow between PROTEUS and VULCAN: what inputs are prepared, how VULCAN is configured and invoked, and how the results are stored and passed back.
The source code for this coupling lives in the
vulcan dispatcher
(run_vulcan) and the outer
chemistry wrapper
(run_chemistry) inside PROTEUS. A description and
flowchart
of the broader PROTEUS architecture can be found
here.
Scheduling modes
VULCAN is called according to config.atmos_chem.when:
'offline': runs once as a post-processing step after the main PROTEUS loop, using the final atmospheric state.'online': runs at every data-write snapshot during the main simulation loop, producing one output file per snapshot.'manually': chemistry is skipped entirely; the user manages when to run it.
The flowchart below describes run_vulcan directly and applies to both offline and
online modes; differences are noted where they arise.
AGNI-only support
VULCAN chemistry is only supported when atmos_clim.module = "agni". Using any
other climate module causes run_vulcan to log a warning and return False without
running.
Step-by-step flow
The following flowchart describes each chemistry run in PROTEUS step-by-step. The source code for this diagram can be found in the VULCAN dispatcher in PROTEUS.
flowchart TD
Start([<b>Start of chemistry step</b>])
Guard1{"AGNI used?"}
Abort1["<b>Abort</b> with warning"]
PrepDir["Prepare output directory\n<code>output/offchem/</code>"]
ReadAtmos["<b>Read atmosphere data:</b>\nRead <em>p</em>, <em>T</em>, <em>VMR</em>s, <em>Kzz</em>\nfrom AGNI output at <code>hf_row['Time']</code>"]
WriteInputs["<b>Write VULCAN input files</b>:\n<code>star.dat</code> (stellar spectrum)\n<code>profile.dat</code> (<em>T</em>-<em>P</em>-<em>Kzz</em>)\n<code>vmrs.dat</code> (mixing ratios)"]
BuildConfig["<b>Build VULCAN config:</b>\nSet network, species, boundary\nconditions, transport, convergence\nand time-stepping parameters"]
MakeFuns{"<code>make_funs = true</code> <b>and</b> not already compiled?"}
Compile["<b>vulcan.make_chem_funs.make_all</b>\n(skipped in online mode\nafter first snapshot)"]
RunVULCAN["<b>vulcan.run_vulcan</b>\nIntegrate chemical kinetics to steady state"]
CheckOutput{"Output pickle\nexists?"}
Fail["<b>Fail</b> with warning"]
ParseOutput["<b>Load pickle:</b>\nExtract <em>T</em>, <em>p</em>, <em>z</em>, <em>Kzz</em> and per-species <em>VMR</em> arrays"]
WriteCSV["<b>Write human-readable CSV</b>\n<code>vulcan.csv</code> (offline)\n<code>vulcan_{year}.csv</code> (online)"]
Done([<b>Success</b>])
Start --> Guard1
Guard1 -->|no| Abort1
Guard1 -->|yes| PrepDir
PrepDir --> ReadAtmos
ReadAtmos --> WriteInputs
WriteInputs --> BuildConfig
BuildConfig --> MakeFuns
MakeFuns -->|yes| Compile
MakeFuns -->|no| RunVULCAN
Compile --> RunVULCAN
RunVULCAN --> CheckOutput
CheckOutput -->|no| Fail
CheckOutput -->|yes| ParseOutput
ParseOutput --> WriteCSV
WriteCSV --> Done
Inputs read from PROTEUS
Unit conventions
VULCAN uses CGS units internally. The dispatcher converts pressures (Pa → dyne cm\(^{-2}\), \(\times\)10), altitudes (m → cm, \(\times\) 100), and eddy diffusivities (m\(^{2}\) s\(^{-1}\) → cm\(^{2}\) s\(^{-1}\), \(\times\) 10\(^{4}\)) on the way in, and reverses those conversions when parsing the output pickle.
At each call, the dispatcher reads the current atmospheric state produced by AGNI via
read_atmosphere_data, requesting the following keys:
| Key | Description | Treatment |
|---|---|---|
pl |
Pressure at level edges (Pa) | \(\times\)10 → dyne cm\(^{-2}\) |
tmpl |
Temperature at level edges (K) | Clipped to ≥ 180 K |
Kzz |
Eddy diffusivity profile (m\(^{2}\) s\(^{-1}\)) | \(\times\)10\(^{4}\) → cm\(^{2}\) s\(^{-1}\) |
{gas}_vmr |
Per-species VMR profile | Written directly to vmrs.dat |
VMRs
VMRs are stored as individual {gas}_vmr keys (e.g. H2O_vmr, CH4_vmr) that
are iterated when writing vmrs.dat. The x_gas entry in extra_keys requests
this family of keys from PROTEUS.
The stellar spectrum is read from the nearest-year .sflux file in output/data/
and scaled from the planet's orbital distance to the stellar surface
(\(\times\)separation^2 / R_star^2) before being clipped and written to star.dat. VULCAN
then re-scales it internally from the stellar surface to the orbital distance.
PROTEUS → VULCAN configuration
The dispatcher translates several PROTEUS config attributes into VULCAN config attributes. The key mappings are:
| PROTEUS config | Effect on VULCAN config |
|---|---|
atmos_chem.vulcan.network |
Selects network file and atom_list (see table below) |
atmos_chem.photo_on |
vcfg.use_photo; also selects photo vs thermo network for CHO/NCHO |
atmos_chem.vulcan.ini_mix = 'profile' |
vcfg.ini_mix = 'table' (reads from vmrs.dat) |
atmos_chem.vulcan.ini_mix (other) |
vcfg.ini_mix = 'const_mix' |
atmos_chem.vulcan.fix_surf = True |
vcfg.use_fix_sp_bot = const_mix (surface VMRs held fixed) |
atmos_chem.vulcan.fix_surf = False |
vcfg.use_fix_sp_bot = {} (free lower boundary) |
atmos_chem.Kzz_const (not None) |
vcfg.Kzz_prof = 'const'; vcfg.const_Kzz = Kzz_const |
atmos_chem.Kzz_const = None |
vcfg.Kzz_prof = 'file' (reads from profile.dat) |
atmos_chem.moldiff_on |
vcfg.use_moldiff |
atmos_chem.updraft_const |
vcfg.const_vz |
orbit.zenith_angle |
vcfg.sl_angle (converted to radians) |
orbit.s0_factor |
vcfg.f_diurnal |
atmos_chem.vulcan.yconv_cri |
vcfg.yconv_cri |
atmos_chem.vulcan.slope_cri |
vcfg.slope_cri |
The background gas (vcfg.atm_base) is chosen automatically as the most abundant of
H\(_2\), N\(_2\), O\(_2\), and CO\(_2\) in the current atmosphere.
Network options
config.atmos_chem.vulcan.network |
Network file | Elements |
|---|---|---|
'CHO' |
CHO_photo_network.txt or CHO_thermo_network.txt |
H, O, C |
'NCHO' |
NCHO_photo_network.txt or NCHO_thermo_network.txt |
H, O, C, N |
'SNCHO' |
SNCHO_photo_network.txt (always) |
H, O, C, N, S |
Output files
All files are written to output/offchem/.
| File | Mode | Contents |
|---|---|---|
vulcan.pkl |
offline | Full VULCAN result object (binary pickle) |
vulcan.csv |
offline | T, p, z, Kzz, and per-species VMRs (human-readable) |
vulcan_{year}.pkl |
online | Per-snapshot pickle (year = integer simulation year) |
vulcan_{year}.csv |
online | Per-snapshot CSV |
CSV column order
Columns appear in this order: tmp, p, z, Kzz, then one column per chemical
species (excluding any species whose name contains _, i.e. condensates). Arrays are
flipped to surface-first ordering to match AGNI's convention.
| Column | Units | Source in pickle |
|---|---|---|
tmp |
K | result['atm']['Tco'] |
p |
Pa | result['atm']['pco'] ÷ 10 |
z |
m | result['atm']['zco'][:-1] ÷ 100 |
Kzz |
cm\(^{2}\) s\(^{-1}\) | result['atm']['Kzz'], prepended with surface value |
{species} |
VMR | result['variable']['ymix'][:, i] for each gas |
Online vs offline: key differences
Offline (when = "offline") |
Online (when = "online") |
|
|---|---|---|
| When called | Once, after the main loop exits | At every data-write snapshot |
| Output directory | Wiped and recreated each call | Created once; reused across snapshots |
| Output filenames | vulcan.pkl, vulcan.csv |
vulcan_{year}.pkl, vulcan_{year}.csv |
| Network compilation | Runs if make_funs = True |
Runs on first snapshot only (tracked via function attribute _made) |