Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,14 +128,14 @@ The `[project.scripts]` entry in `pyproject.toml` registers `zalmoxis` as
`zalmoxis.solver:main`. This bypasses `load_zalmoxis_config()` and is useful
mainly for in-process callers; humans should prefer `python -m zalmoxis`.

Outputs (under `output/`):
Outputs (under `output/`, or the existing folder `[Output] output_dir` names):

- `planet_profile.txt`: six-column TSV with r, ρ, M(r), P(r), g(r), T(r).
- `calculated_planet_mass_radius.txt`: appended one-line summary per run.
- `zalmoxis.log`: per-run log (overwritten each invocation).
- Optional debug: `density_profiles.txt`, `pressure_profiles.txt` per Picard
iteration when the Python logging level is `DEBUG`, into the folder that the
config key `debug_profile_dir` names (the command-line run uses `output/`).
config key `debug_profile_dir` names (the command-line run uses its output folder, `output_dir`).

Recommended workflow:

Expand Down
71 changes: 42 additions & 29 deletions docs/How-to/configuration.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/How-to/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ This error indicates that the tabulated EOS data files have not been downloaded.

### A `data/` link points nowhere

Each folder in `data/` is a link into `$FWL_DATA`. After `fwl-io prune` removes a superseded version, or after `$FWL_DATA` moves, a link can point at a folder that no longer exists. The error names the cause, `Data file ... is missing: .../data/<folder> links to ..., which does not exist`: for an EOS table it is the first ERROR line in `output/zalmoxis.log` (the run itself stops with a `StructureSolveError`), and for a melting curve it is in the traceback. Run `bash tools/setup/get_zalmoxis.sh` again with `FWL_DATA` set: it fetches what is missing and replaces every link it made, every dangling link and every empty folder; a folder with files in it, or a link to another place, is kept and listed at the end with the line that removes it; remove it and run the script again.
Each folder in `data/` is a link into `$FWL_DATA`. After `fwl-io prune` removes a superseded version, or after `$FWL_DATA` moves, a link can point at a folder that no longer exists. The error names the cause, `Data file ... is missing: .../data/<folder> links to ..., which does not exist`: for an EOS table it is the first ERROR line in `zalmoxis.log` of the output folder (`output/`, or `[Output] output_dir`) (the run itself stops with a `StructureSolveError`), and for a melting curve it is in the traceback. Run `bash tools/setup/get_zalmoxis.sh` again with `FWL_DATA` set: it fetches what is missing and replaces every link it made, every dangling link and every empty folder; a folder with files in it, or a link to another place, is kept and listed at the end with the line that removes it; remove it and run the script again.

### Import errors

Expand Down
19 changes: 12 additions & 7 deletions docs/How-to/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Run the default configuration (1 Earth-mass planet with a PALEOS iron core and M
python -m zalmoxis -c input/default.toml
```

Output files appear in `output/`. The PALEOS data files must be downloaded first (see [installation](installation.md)).
Output files appear in `output/`, or in the folder `[Output] output_dir` names. The PALEOS data files must be downloaded first (see [installation](installation.md)).

## What happens when you run Zalmoxis

Expand Down Expand Up @@ -50,21 +50,24 @@ For the full list of parameters (EOS selection, temperature modes, solver settin

## Output files

All output files are written to the `output/` directory (created automatically on first run). The directory structure looks like:
`python -m zalmoxis` writes all its files into its output folder: the existing folder that `[Output] output_dir` names, or else `output/` of the Zalmoxis root (created on the first run). The folder looks like:

```
output/
├── planet_profile.txt # radial profiles (single run)
├── planet_profile5.0.txt # radial profiles (batch run, mass in filename)
├── calculated_planet_mass_radius.txt # summary: mass and radius per run
├── planet_profile.png # 6-panel structure plot (if plots_enabled)
├── grid_results/ # grid runner output (if using run_grid)
│ ├── grid_summary.csv
│ └── *.json
├── mantle_PT_profile.pdf # mantle P-T plot (if plots_enabled and the mantle EOS uses melting curves)
├── zalmoxis.log # log of python -m zalmoxis
├── pressure_profiles.txt # iteration diagnostics (DEBUG, command-line run)
└── density_profiles.txt # iteration diagnostics (DEBUG, command-line run)
```

The grid runner `tools/grids/run_grid.py` does not use `output_dir`. It writes `grid_summary.csv`, a `<label>.json` result per grid point and, with `[output] save_profiles = true`, a `<label>.csv` profile per grid point into the folder that `[output] dir` of the grid file names, relative to the Zalmoxis root, by default `output/grid_results/`. It loads its base config with `load_zalmoxis_config`, which checks `output_dir`, so a base config that sets `output_dir` must still name an existing, writable folder, although the grid runner writes nothing there.

The EOS caches are written outside the output folder: the binary cache `<table>.cache.pkl` beside each unified PALEOS table file (under `data/` for the downloaded tables), and the PALEOS API cache in `data/EOS_PALEOS_API/` of the Zalmoxis root.

### Profile files

When `data_enabled = true` (the default), the solver writes radial profiles as tab-separated text:
Expand Down Expand Up @@ -103,7 +106,7 @@ When the Python logging level is set to `DEBUG` and the configuration names a fo
- **`pressure_profiles.txt`**: Pressure vs. radius for every iteration of the pressure adjustment loop.
- **`density_profiles.txt`**: Density vs. radius for every iteration.

Enable with `logging.getLogger('fwl.zalmoxis').setLevel(logging.DEBUG)`. Set `debug_profile_dir` in the `[Output]` table of the TOML file, or as a key of the configuration dict that you pass to `solver.main()`; it must name a folder that exists. `load_zalmoxis_config` checks the key; `solver.main()` does not, so call `validate_config` on a dict that you build yourself. The command-line run (`python -m zalmoxis`) sets the key to `output/` when it is not set; it logs at `INFO`, so it writes the files only when the level of `fwl.zalmoxis` is `DEBUG`. Without the key, a `DEBUG` solve logs and writes no profile file. These files are useful for diagnosing convergence behavior. They grow large quickly (about 50 MB each for a 1 Earth-mass planet). The files start again at the first pressure solve of each structure solve (each call of `_solve`, so each Newton step and each retry of `solver.main()`), so after a run they hold the last structure solve; a later run below `DEBUG` or without the key leaves them as they are.
Enable with `logging.getLogger('fwl.zalmoxis').setLevel(logging.DEBUG)`. Set `debug_profile_dir` in the `[Output]` table of the TOML file, or as a key of the configuration dict that you pass to `solver.main()`; it must name a folder that exists. `load_zalmoxis_config` checks the key; `solver.main()` does not, so call `validate_config` on a dict that you build yourself. The command-line run (`python -m zalmoxis`) sets the key to its output folder, `output_dir`, when it is not set; it logs at `INFO`, so it writes the files only when the level of `fwl.zalmoxis` is `DEBUG`. Without the key, a `DEBUG` solve logs and writes no profile file. These files are useful for diagnosing convergence behavior. They grow large quickly (about 50 MB each for a 1 Earth-mass planet). The files start again at the first pressure solve of each structure solve (each call of `_solve`, so each Newton step and each retry of `solver.main()`), so after a run they hold the last structure solve; a later run below `DEBUG` or without the key leaves them as they are.

Adjust `tolerance_outer`, `tolerance_inner`, `max_iterations_outer`, `max_iterations_inner` in the `[IterativeProcess]` block (see [Configuration](configuration.md#iterativeprocess)) if convergence is slow.

Expand All @@ -116,10 +119,12 @@ When `plots_enabled = true` in the `[Output]` section, Zalmoxis automatically ge
plots_enabled = true
```

This produces a six-panel figure showing the radial profiles of density, pressure, temperature, gravity, phase state, and mass enclosed:
The profile plot is a six-panel figure showing the radial profiles of density, pressure, temperature, gravity, phase state, and mass enclosed:

![Example profile plot](../img/example_profile_plot.png)

A call of `post_processing` with `id_mass` puts the mass label into the names of the plot files, as it does for the profiles (`planet_profile5.0.png`, `mantle_PT_profile5.0.pdf`).

**Example**: 1 $M_\oplus$ planet with a PALEOS iron core and MgSiO$_3$ mantle at $T_s$ = 3000 K (adiabatic mode). The dashed vertical line marks the core-mantle boundary (CMB).

- **Density** (top left): drops from ~14,000 kg/m$^3$ at the center (iron core) to ~3,000 kg/m$^3$ at the surface (silicate mantle). The sharp step at the CMB reflects the iron-to-silicate transition.
Expand Down
24 changes: 14 additions & 10 deletions docs/Tutorials/firstrun.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# First run

This tutorial walks a 1 $M_\oplus$ rocky planet through Zalmoxis end to end.
By the end you will have written a minimal config file, run the structure solver, plotted a radial density profile, and verified the result against the [Zeng et al. (2019)](https://ui.adsabs.harvard.edu/abs/2019PNAS..116.9723Z) Earth-like mass-radius curve and the [Seager et al. (2007)](https://ui.adsabs.harvard.edu/abs/2007ApJ...669.1279S) tabulated density profile.
This tutorial takes a 1 $M_\oplus$ rocky planet through Zalmoxis from start to finish.
By the end you will have written a minimal config file, run the structure solver, plotted a radial density profile, and verified the result against the Zeng et al. (2019)[^cite-zeng2019] Earth-like mass-radius curve and the Seager et al. (2007)[^cite-seager2007] tabulated density profile.

You should already have Zalmoxis installed in a working conda environment.
If not, follow [Installation](../How-to/installation.md) first; the steps below assume `python -m zalmoxis` runs without an `ImportError`.
Expand Down Expand Up @@ -31,7 +31,7 @@ export FWL_DATA=/path/to/fwl_data
bash tools/setup/get_zalmoxis.sh
```

This fetches the Seager+2007 lookups, PALEOS tables and Zeng+2019 reference curves into `$FWL_DATA`, links each folder of `data/` inside the repository to them, and creates an empty `output/` directory.
This fetches the Seager et al. (2007)[^cite-seager2007] lookups, PALEOS tables and Zeng et al. (2019)[^cite-zeng2019] reference curves into `$FWL_DATA`, links each folder of `data/` inside the repository to them, and creates an empty `output/` directory.
You should now see populated subdirectories under `data/`, for example `data/EOS_Seager2007/` and `data/EOS_PALEOS_iron/`.

!!! note "Within PROTEUS"
Expand Down Expand Up @@ -81,7 +81,7 @@ A few notes on what each block does:
`temperature_mode = "adiabatic"` integrates the layer adiabats with `surface_temperature` as the upper boundary and `center_temperature` as the initial guess for the inner boundary.
Other choices are `"isothermal"`, `"linear"`, and `"prescribed"` (reads `temperature_profile_file`); see [Configuration](../How-to/configuration.md) for the full list.
- `[EOS]` selects the per-layer equation of state.
`PALEOS:iron` and `PALEOS:MgSiO3` are unified multi-phase PALEOS tables ([Attia et al. (2026)](https://ui.adsabs.harvard.edu/abs/2026arXiv260503741A/abstract)) that handle pressures up to 100 TPa and masses up to 50 $M_\oplus$.
`PALEOS:iron` and `PALEOS:MgSiO3` are the unified multi-phase PALEOS tables of Attia et al. (2026)[^cite-attia2026]; they handle pressures up to 100 TPa and masses up to 50 $M_\oplus$.
`ice_layer = ""` keeps the model two-layer (core + mantle).
- `[Calculations]` controls the radial grid resolution.
150 points is enough for a 3 % radius match; double it for tighter convergence at high mass.
Expand All @@ -104,7 +104,7 @@ Runtime on a recent laptop is roughly 30 to 90 seconds for this configuration.
Most of that goes into the outermost mass-radius loop; it iterates a Picard step on the central pressure until the surface mass and pressure both match their targets.
The solver has three nested loops: a structure ODE for `(M(r), g(r), P(r))` (innermost), a density Picard iteration that re-evaluates the EOS at the new `(P, T)`, and the outer mass-radius loop just mentioned.

Progress goes to `output/zalmoxis.log` (the path is hard-coded in `src/zalmoxis/__main__.py`).
Progress goes to `output/zalmoxis.log`, or to `zalmoxis.log` in the folder `[Output] output_dir` names.
On a successful run you should see lines along the lines of:

```console
Expand All @@ -117,7 +117,7 @@ INFO - Pressure at Center: 3.65e+11 Pa
INFO - Overall Convergence Status: True with Pressure: True, Density: True, Mass: True
```

Note that the "Earth radii" comparison uses Zalmoxis's reference value `earth_radius = 6.335e6` m (Seager+2007 volumetric mean), not the IAU 6.371e6 m.
Note that the "Earth radii" comparison uses Zalmoxis's reference value `earth_radius = 6.335e6` m (the volumetric mean of Seager et al. (2007)[^cite-seager2007]), not the IAU 6.371e6 m.
That convention is intentional and matches the Seager reference data shipped in `data/`.

If the final line shows `Convergence Status: False`, see [Convergence failures](../How-to/installation.md#convergence-failures) for the standard remedies (looser tolerance, larger pressure bracket, or a different mantle EOS for high-mass configurations).
Expand All @@ -128,7 +128,7 @@ After a successful run the `output/` directory contains:

| File | Contents |
| --- | --- |
| `zalmoxis.log` | Run log (overwritten on every run, `filemode='w'`). |
| `zalmoxis.log` | Run log (overwritten on every run). |
| `planet_profile.txt` | Radial profile. Six tab-separated columns: radius (m), density (kg m$^{-3}$), gravity (m s$^{-2}$), pressure (Pa), temperature (K), enclosed mass (kg). Header line begins with `#`. |
| `calculated_planet_mass_radius.txt` | One row appended per run: total mass (kg) and total radius (m). |

Expand Down Expand Up @@ -168,7 +168,7 @@ You should see a sharp density jump near $r \approx 3500$ km (the core-mantle bo
The smoke test `tests/test_MR_rocky.py::test_rocky_1Mearth_vs_zeng_and_seager` exercises the same code path you just ran, with two reference checks bolted on.
You can reproduce them by hand.

**Mass-radius (Zeng+2019).**
**Mass-radius after Zeng et al. (2019)[^cite-zeng2019].**
The reference curve `data/mass_radius_curves/massradiusEarthlikeRocky.txt` is an Earth-like rocky composition (32.5 % iron core, 67.5 % MgSiO3 mantle, 300 K).
Interpolate it at your computed mass and compare:

Expand All @@ -194,7 +194,7 @@ print(f'M = {m_e:.3f} M_earth, R = {r_e:.3f} R_earth, '
The smoke test asserts `rtol = 0.03` (3 %).
Your run should be well inside that envelope.

**Density profile (Seager+2007).**
**Density profile after Seager et al. (2007)[^cite-seager2007].**
The file `data/radial_profiles/radiusdensitySeagerEarthbymass.txt` carries tabulated Earth-mass density profiles from the same paper.
Loading the 1 $M_\oplus$ slice and overlaying it on your `planet_profile.txt` should match within 10 % everywhere except for a narrow band around the core-mantle boundary.
The CMB lies between Seager's grid points, so interpolating across the discontinuity inflates the residual artificially; the smoke test masks $\pm 3$ grid points around any density jump greater than 2000 kg m$^{-3}$ before comparing.
Expand Down Expand Up @@ -234,7 +234,7 @@ Outputs land in `output/grid_firstrun/`:
- `<label>.json`: per-run summary mirroring the CSV row;
- `<label>.csv`: per-run radial profile (because `save_profiles = true`); a six-column body with SI-unit columns plus a `# key: value` comment header that records the EOS strings, melting-curve ids, and convergence flag.

Filter to converged rows (`converged == True`) and overlay the three radii on the Zeng+2019 curve to check that you reproduce the expected shallow $R \propto M^{0.27}$ slope for rocky bodies in this mass range.
Filter to converged rows (`converged == True`) and overlay the three radii on the Zeng et al. (2019)[^cite-zeng2019] curve to check that you reproduce the expected shallow $R \propto M^{0.27}$ slope for rocky bodies in this mass range.
The `tools/grids/plot_grid.py` helper does this for you:

```console
Expand All @@ -249,3 +249,7 @@ Browse `input/grids/` for richer examples: `mass_radius.toml` is a 7-point versi
- For the equations behind the structure ODE, the EOS dispatch, and the mushy-zone mixing model, read [Model overview](../Explanations/model.md) and [Equation of state physics](../Explanations/eos_physics.md).
- For the function-call coupling used when Zalmoxis runs inside PROTEUS (the `python -m zalmoxis` invocation in this tutorial does *not* apply there), read [Coupling Zalmoxis to PROTEUS](../How-to/proteus_coupling.md) and [Coupling to PROTEUS (theory)](../Explanations/proteus_coupling.md).
- For first-principles verification cases (analytic polytropes, hydrostatic equilibrium tests, mass conservation), read the [Validation](../Validation/index.md) tab.

[^cite-zeng2019]: L. Zeng, S. B. Jacobsen, D. D. Sasselov, M. I. Petaev, A. Vanderburg, M. Lopez-Morales, J. Perez-Mercader, T. R. Mattsson, G. Li, M. Z. Heising, A. S. Bonomo, M. Damasso, T. A. Berger, H. Cao, A. Levi, R. D. Wordsworth, *[Growth model interpretation of planet size distribution](https://doi.org/10.1073/pnas.1812905116)*, Proceedings of the National Academy of Sciences, 116(20), 9723-9728, 2019. [SciX](https://scixplorer.org/abs/2019PNAS..116.9723Z/abstract).
[^cite-seager2007]: S. Seager, M. Kuchner, C. A. Hier-Majumder, B. Militzer, *[Mass-Radius Relationships for Solid Exoplanets](https://doi.org/10.1086/521346)*, The Astrophysical Journal, 669(2), 1279-1297, 2007. [SciX](https://scixplorer.org/abs/2007ApJ...669.1279S/abstract).
[^cite-attia2026]: M. Attia, T. Lichtenberg, E. Jungová, M. Sastre, *[PALEOS: Multiphase equations of state and mass-radius relations for exoplanet interiors](https://doi.org/10.1051/0004-6361/202660790)*, Astronomy and Astrophysics, 713, A225, 2026. [SciX](https://scixplorer.org/abs/2026A%26A...713A.225A/abstract).
1 change: 1 addition & 0 deletions input/default.toml
Original file line number Diff line number Diff line change
Expand Up @@ -147,4 +147,5 @@ target_surface_pressure = 101325 # Target surface pressure (Pa); default 1 a
[Output]
data_enabled = true # Write radial profiles to output/
plots_enabled = false # Generate profile plots after the run
# output_dir = '/path/to/folder' # Output folder (an existing folder); default output/ of the Zalmoxis root
# debug_profile_dir = '/path/to/folder' # Existing folder (absolute, or relative to the working directory) for the per-iteration profiles of a DEBUG run
Loading
Loading