Python wrappers for selected MESA routines
Project description
pyfortmesa

Author: Ebraheem Farag
⚠️ Warning: Experimental ⚠️
This package is under active development and the Python API may still change.
pyfortmesa is a focused Python wrapper for selected MESA microphysics calls.
It reads and calls selected MESA modules, currently const, chem, eos, and
kap, with a Python API for scalar calls and batched profile calls.
This is not a general MESA module reader. The point is to make repeated eos/kap calls from Python cheap enough to use inside real model-building code: cache the MESA setup, keep handles alive, batch zones into one Fortran call, and let OpenMP parallelize the zone loop. For general access to arbitrary MESA modules, use pyMesa.
pyfortmesa does not build or install MESA. Build MESA separately, then point
MESA_DIR at that tree.
Documentation
Documentation: https://debraheem.github.io/pyfortmesa/
The site is built with MkDocs from the files under docs/ and published with
GitHub Pages. The docs footer links back to the GitHub repository.
Useful docs and examples:
- Installation:
docs/installation.md - Usage examples:
docs/usage.md - MESA module reference:
docs/modules/README.md - Test runner notes:
docs/testing.md - Development commands:
docs/developing.md - Docs publishing:
docs/publishing.md - Simple MESA work example:
tests/work/README.md - MESA test scripts:
tests/mesa/README.md
For local docs builds and GitHub Pages publishing notes, see
docs/developing.md and docs/publishing.md.
Installation
Choose the install based on what you want to run. The examples below call MESA
eos and kap, so they need the ./mk mesa build installed, not the
plain Python install.
./mk and ./mk mesa are different builds. ./mk builds the plain package.
That is enough for imports, docs, and checks that do not call MESA. ./mk mesa
builds the pyfortmesa wheel with the compiled wrappers needed for MESA
eos and kap calls, and for ./test mesa.
Python install
Use this when you want to import pyfortmesa, read the docs, or use code
that does not call MESA's compiled const, chem, eos, or kap routines.
Install the released Python package from PyPI:
python -m pip install pyfortmesa
To install an exact source tag from GitHub instead:
python -m pip install "git+https://github.com/Debraheem/pyfortmesa.git@v0.6.0"
Or install from a local checkout:
python -m pip install .
This installs the Python files and numpy. It does not compile or include the
MESA wrapper extension modules, so it will not run the eos/kap examples below.
A quick import check is:
python -m pyfortmesa
Expected output:
pyfortmesa: MESA wrapper package
public module: pyfortmesa.mesa
MESA wrapper install
Use this path when Python code will call MESA const, chem, eos, or kap.
A wheel is just Python's built install file. This repo uses a local wheel
because the compiled wrappers must be built against the exact MESA tree and
compiler setup on your machine.
From a checkout:
python -m pip install --upgrade pip
python -m pip install -r requirements.txt
export MESASDK_ROOT=/Applications/mesasdk
source "$MESASDK_ROOT/bin/mesasdk_init.sh"
export MESA_DIR=/path/to/current/mesa
./clean
./mk mesa
./install
./clean removes old local build output before the MESA build. That is useful
when switching between builds or changing MESA_DIR.
MESA must be built with shared module libraries. A current MESA development
tree usually has this already. For a release tree, check
$MESA_DIR/utils/makefile_header; if it says USE_SHARED = NO, set
USE_SHARED = YES, then rebuild MESA with ./clean and ./install.
Static-only MESA builds are not supported.
./mk mesa finds the MESA pkg-config files under MESA_DIR, sets
PKG_CONFIG_PATH for this build, and writes dist/pyfortmesa-*.whl.
./install installs the newest wheel from dist/ into the Python environment
running the command. After that, the usage examples below should work in that
environment.
More build commands, including conda run -n pyfortmesa forms, are in
docs/developing.md.
Testing
Run the checks that do not call MESA:
./test
After installing the ./mk mesa wheel, run the MESA checks and profile
timing suite:
./test mesa
The standard saved model timing report can also be run directly:
tests/mesa/run_profile_timing_suite.sh
The timing report prints compact tables. Raw per-run logs and timing JSON are
temporary by default; set PYFORTMESA_PROFILE_REPORT_DIR to keep them. The
committed deterministic baseline is
tests/test_output/golden/quick_test_output.txt. MESA timings are not golden
files because they depend on the local MESA build and machine.
It's fast!
The profile timing suite uses a saved 20 Msun MESA test suite model after core helium burning:
star/test_suite/20M_pre_ms_to_core_collapse/standard_after_core_he_burn.mod
That model has 880 zones and 22 isotopes. The numbers below are from one local
run with warmup = 1 and repeat = 5, so absolute times depend on the machine
and MESA build. The useful point is the scaling: batch the zones into one
Fortran call, keep MESA handles alive, and let OpenMP parallelize the zone loop.
single run summary, OMP_NUM_THREADS=10:
physics global_s profile_s ms/profile eos/s kap/s
eos 0.725953 0.717115 2.479 3.550e+05 -
kap 0.778931 0.770056 2.709 - 3.248e+05
eos-kap 0.756551 0.747703 2.688 3.274e+05 3.274e+05
combined eos+kap thread sweep:
threads ms/profile speedup efficiency eos/s kap/s
1 19.692 1.00 1.00 4.469e+04 4.469e+04
2 10.358 1.90 0.95 8.496e+04 8.496e+04
4 5.437 3.62 0.91 1.618e+05 1.618e+05
6 3.686 5.34 0.89 2.387e+05 2.387e+05
8 2.919 6.75 0.84 3.015e+05 3.015e+05
10 2.679 7.35 0.74 3.285e+05 3.285e+05
The kap timing includes the eos electron state call required by MESA
kap_get. When both eos and kap are needed for the same profile, the combined
eos_kap_profile path computes the eos state once per zone and then passes it
to kap.
Usage
The examples in this section call MESA, so install the ./mk mesa wheel
before running them.
Example eos and kap call
from pyfortmesa import mesa
mesa.set_cache_root(".")
mesa.set_inlist("inlist_eos_and_kap")
mix = mesa.composition({"h1": 0.70, "he4": 0.28, "c12": 0.02})
eos = mesa.Eos()
kap = mesa.Kap()
T_eos = 1.0e7 # K
rho_eos = 1.0e2 # g/cm^3
T_kap = 1.0e6 # K
rho_kap = 1.0e-7 # g/cm^3
eos_out = eos.dt_full(T=T_eos, Rho=rho_eos, comp=mix)
kap_out = kap.opacity_full(T=T_kap, Rho=rho_kap, comp=mix)
print(eos_out["results"]["lnPgas"])
print(kap_out["kappa"])
mesa.shutdown()
mesa.set_inlist(...) should be called before the first eos or kap call in a
Python process. The file can contain both &eos and &kap namelists.
mix is a scalar-call composition object. It stores the isotope names, matching
MESA chem_id values, and one mass-fraction vector. Scalar helpers accept it as
comp=mix.
Profile example
For profile work, do not call scalar eos or kap once per zone from Python. Batch
the profile and let the Fortran wrapper run the zone loop. Profile helpers take
the composition in split form: chem_id_values gives the isotope order, and
xa gives the mass fractions with shape (species, nzones).
export OMP_NUM_THREADS=10
python run_microphysics.py
import numpy as np
from pyfortmesa import mesa
mesa.set_cache_root(".")
mesa.set_inlist("inlist_eos_and_kap")
isotope_names = ("h1", "he4", "c12")
chem_id_values = mesa.iso_ids(isotope_names)
kap = mesa.Kap()
def profile_xa(xa_by_zone):
# solver layout: (nzones, species)
# pyfortmesa profile layout: (species, nzones)
return np.asfortranarray(np.asarray(xa_by_zone, dtype=np.float64).T)
try:
for T, rho, xa_by_zone in profiles:
out = kap.eos_kap_profile(
T, rho, chem_id_values, profile_xa(xa_by_zone), output="dict"
)
gamma1 = out["results"]["gamma1"]
kappa = out["kappa"]
finally:
mesa.shutdown()
For a fixed-composition eos profile on an arbitrary base-10 logT/logRho
track, build one Composition and pass its 1D xa vector. The wrapper
broadcasts fixed compositions over zones. Use input_mode="log10" when the
arrays are base-10 logs:
log_rho = np.linspace(-2.0, 8.0, 1000)
log_T = np.linspace(3.0, 8.0, 1000)
mix = mesa.composition({"h1": 0.70, "he4": 0.28, "c12": 0.02})
out = mesa.Eos().dt_profile(log_T, log_rho, mix.chem_id, mix.xa, input_mode="log10")
For kap profile work with physical arrays, pass the temperature and density profiles directly:
T = np.linspace(6.0e5, 2.5e6, 1000)
rho = np.full_like(T, 1.0e-7)
out = mesa.Kap().eos_kap_profile(T, rho, mix.chem_id, mix.xa)
If the caller already stores base-10 logT and logRho, pass those arrays
directly and set input_mode="log10":
log_T = np.linspace(5.8, 6.4, 1000)
log_rho = np.full_like(log_T, -7.0)
out = mesa.Kap().eos_kap_profile(log_T, log_rho, mix.chem_id, mix.xa, input_mode="log10")
Use input_mode="log" for natural-log arrays and input_mode="log10" for
base-10 arrays. The older *_from_logs(...) helpers are compatibility aliases
for natural-log input.
Use mesa.Eos().dt_profile(...) for eos profile work. Use
mesa.Kap().opacity_profile(...) for opacity work. When both eos and kap
are needed for the same zones, prefer mesa.Kap().eos_kap_profile(...) so the
eos state is computed once per zone and then passed to kap.
Cite
If you use pyfortmesa, please cite it as:
@software{Farag_pyfortmesa_2026,
author = {Farag, Ebraheem},
title = {{pyfortmesa}},
url = {https://github.com/Debraheem/pyfortmesa},
version = {0.6.0},
year = {2026}
}
License
pyfortmesa is distributed under the GNU Lesser General Public License v3.0
only. The ./mk mesa build links against a separately built MESA tree
supplied by the user.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pyfortmesa-0.6.0.tar.gz.
File metadata
- Download URL: pyfortmesa-0.6.0.tar.gz
- Upload date:
- Size: 98.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b8974a38a7c6c29d83bcced6331d7c400fb67b8eaf7eb6f63cc8696fa845cf6c
|
|
| MD5 |
d62885c43baacf4bbf943b37eb7836a7
|
|
| BLAKE2b-256 |
3cac1b5c42b8e4086515be63ae41af40c2742e93b0aaaa2a1a1efd41dc55b035
|
File details
Details for the file pyfortmesa-0.6.0-py3-none-any.whl.
File metadata
- Download URL: pyfortmesa-0.6.0-py3-none-any.whl
- Upload date:
- Size: 23.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b6f17c77f8b173ed4639bd774abe14cf7d5aa83b16f660c07c8aea5d99450486
|
|
| MD5 |
34f14def0929b4b3195791417ddf6719
|
|
| BLAKE2b-256 |
fd1b29dd1b722b4e1ac007f4cbac5d3b9b22385c0316f5335f63c41c5cb274cc
|