Skip to main content

Python wrappers for selected MESA routines

Project description

pyfortmesa Repo Status Version PyPI Docs Python MESA License

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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pyfortmesa-0.6.0.tar.gz (98.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pyfortmesa-0.6.0-py3-none-any.whl (23.0 kB view details)

Uploaded Python 3

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

Hashes for pyfortmesa-0.6.0.tar.gz
Algorithm Hash digest
SHA256 b8974a38a7c6c29d83bcced6331d7c400fb67b8eaf7eb6f63cc8696fa845cf6c
MD5 d62885c43baacf4bbf943b37eb7836a7
BLAKE2b-256 3cac1b5c42b8e4086515be63ae41af40c2742e93b0aaaa2a1a1efd41dc55b035

See more details on using hashes here.

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

Hashes for pyfortmesa-0.6.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b6f17c77f8b173ed4639bd774abe14cf7d5aa83b16f660c07c8aea5d99450486
MD5 34f14def0929b4b3195791417ddf6719
BLAKE2b-256 fd1b29dd1b722b4e1ac007f4cbac5d3b9b22385c0316f5335f63c41c5cb274cc

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page