kap¶
Status: active in the ./mk mesa build.
Purpose: call MESA kap for known density, temperature, and static composition.
The wrapper calls eos first so kap receives the MESA electron quantities required
by kap_get.
Fast start¶
from pyfortmesa import mesa
mesa.set_inlist("inlist_eos_and_kap")
mix = mesa.composition({"h1": 0.70, "he4": 0.28, "c12": 0.02})
kap = mesa.Kap()
out = kap.opacity_full(T=1.0e6, Rho=1.0e-7, comp=mix)
print(out["kappa"])
print(out["kap_fracs"])
kap controls¶
mesa.Kap(...) stores Python-side controls that are applied before each opacity
call. The underlying MESA handle is process-persistent.
kap = mesa.Kap(
use_type2=True,
zbase=0.02,
use_zbase_for_type1=True,
)
Control precedence:
MESA kap.defaults
-> optional shared inlist from mesa.set_inlist(...)
-> optional Python overrides from mesa.Kap(...)
| control | units | meaning |
|---|---|---|
use_type2 |
bool | enable MESA Type2 opacity controls |
zbase |
mass fraction | base metallicity used by Type2 controls |
use_zbase_for_type1 |
bool | use zbase for Type1 controls |
type2_full_off_X |
mass fraction | Type2 full-off hydrogen threshold |
type2_full_on_X |
mass fraction | Type2 full-on hydrogen threshold |
type2_full_off_dZ |
mass fraction | Type2 full-off composition threshold |
type2_full_on_dZ |
mass fraction | Type2 full-on composition threshold |
None means leave the corresponding MESA value unchanged. If no inlist is set
and no Python override is given, pyfortmesa keeps Type2 off so ordinary kap
calls do not require zbase.
Public API¶
mesa.kap_opacity(...) and mesa.Kap().opacity(...)¶
Signature:
mesa.kap_opacity(
T: float,
Rho: float,
comp: Composition | Mapping[str, float] | Iterable[float] | None = None,
*,
use_type2: bool | None = None,
zbase: float | None = None,
use_zbase_for_type1: bool | None = None,
type2_full_off_X: float | None = None,
type2_full_on_X: float | None = None,
type2_full_off_dZ: float | None = None,
type2_full_on_dZ: float | None = None,
) -> dict[str, float]
Inputs:
| argument | units | shape | meaning |
|---|---|---|---|
T |
K | scalar | temperature |
Rho |
g cm^-3 |
scalar | density |
comp |
mass fraction | scalar composition | Composition, isotope mapping, legacy vector, or None |
| kap controls | mixed | scalar | optional Python overrides listed above |
Returns:
| key | units | meaning |
|---|---|---|
kappa |
cm^2 g^-1 |
Rosseland mean opacity |
dlnkap_dlnRho |
dimensionless | derivative at constant T |
dlnkap_dlnT |
dimensionless | derivative at constant Rho |
Example:
small = mesa.Kap().opacity(T=1.0e6, Rho=1.0e-7, comp=mix)
print(small["kappa"])
mesa.kap_opacity_raw(...) and mesa.Kap().opacity_raw(...)¶
Signature:
mesa.kap_opacity_raw(
T: float,
Rho: float,
chem_id_values: Iterable[int],
xa: Iterable[float],
*,
validate: bool = False,
use_type2: bool | None = None,
zbase: float | None = None,
use_zbase_for_type1: bool | None = None,
type2_full_off_X: float | None = None,
type2_full_on_X: float | None = None,
type2_full_off_dZ: float | None = None,
type2_full_on_dZ: float | None = None,
) -> tuple[float, float, float]
This is the scalar fast path for callers with precomputed chem_id_values and
xa. It returns:
kappa, dlnkap_dlnRho, dlnkap_dlnT
Example:
kap = mesa.Kap()
kap.opacity_raw(T=1.0e6, Rho=1.0e-7, chem_id_values=mix.chem_id, xa=mix.xa)
for T, rho in scalar_points:
kappa, dkap_dlnrho, dkap_dlnt = kap.opacity_raw(T, rho, mix.chem_id, mix.xa)
Use validate=True when accepting untrusted arrays. Keep it False for hot
loops where chem_id_values and xa were prepared once by mesa.composition.
mesa.eos_kap_raw(...) and mesa.Kap().eos_kap_raw(...)¶
Signature:
mesa.eos_kap_raw(
T: float,
Rho: float,
chem_id_values: Iterable[int],
xa: Iterable[float],
*,
validate: bool = False,
use_type2: bool | None = None,
zbase: float | None = None,
use_zbase_for_type1: bool | None = None,
type2_full_off_X: float | None = None,
type2_full_on_X: float | None = None,
type2_full_off_dZ: float | None = None,
type2_full_on_dZ: float | None = None,
) -> tuple[np.ndarray, float, float, float]
This is the scalar fused eos+kap fast path. It calls eos once, returns the eos result vector, and passes the electron state from that eos call to kap.
Returns:
results, kappa, dlnkap_dlnRho, dlnkap_dlnT
results uses mesa.EOS_RESULT_NAMES order.
Example:
kap = mesa.Kap()
results, kappa, dkap_dlnrho, dkap_dlnt = kap.eos_kap_raw(
T=1.0e6, Rho=1.0e-7, chem_id_values=mix.chem_id, xa=mix.xa
)
i_gamma1 = mesa.EOS_RESULT_NAMES.index("gamma1")
gamma1 = results[i_gamma1]
Use this instead of calling eos.dt_raw(...) and kap.opacity_raw(...) when a
scalar loop needs both eos and kap outputs for the same state.
mesa.kap_opacity_full(...) and mesa.Kap().opacity_full(...)¶
Signature:
mesa.kap_opacity_full(
T: float,
Rho: float,
comp: Composition | Mapping[str, float] | Iterable[float] | None = None,
*,
use_type2: bool | None = None,
zbase: float | None = None,
use_zbase_for_type1: bool | None = None,
type2_full_off_X: float | None = None,
type2_full_on_X: float | None = None,
type2_full_off_dZ: float | None = None,
type2_full_on_dZ: float | None = None,
) -> dict[str, float | dict[str, float]]
Inputs are the same as kap_opacity(...).
Returns:
| key | shape | meaning |
|---|---|---|
kappa |
scalar | Rosseland mean opacity |
dlnkap_dlnRho |
scalar | derivative at constant T |
dlnkap_dlnT |
scalar | derivative at constant Rho |
kap_fracs |
dict | opacity-source fractions |
dlnkap_dxa |
dict by isotope name | composition derivatives |
kap_fracs keys:
lowT, highT, Type2, Compton
Example:
kap_type2 = mesa.Kap(use_type2=True, zbase=0.02)
full = kap_type2.opacity_full(T=1.0e6, Rho=1.0e-7, comp=mix)
print(full["kap_fracs"]["Type2"])
print(full["dlnkap_dxa"]["h1"])
mesa.kap_opacity_full_raw(...) and mesa.Kap().opacity_full_raw(...)¶
Signature:
mesa.kap_opacity_full_raw(
T: float,
Rho: float,
chem_id_values: Iterable[int],
xa: Iterable[float],
*,
validate: bool = False,
use_type2: bool | None = None,
zbase: float | None = None,
use_zbase_for_type1: bool | None = None,
type2_full_off_X: float | None = None,
type2_full_on_X: float | None = None,
type2_full_off_dZ: float | None = None,
type2_full_on_dZ: float | None = None,
) -> tuple[float, float, float, np.ndarray, np.ndarray]
Returns:
kappa, dlnkap_dlnRho, dlnkap_dlnT, kap_fracs, dlnkap_dxa
kap_fracs uses mesa.KAP_FRAC_NAMES order. dlnkap_dxa follows the input
chem_id_values/xa species order.
Example:
kappa, dkap_dlnrho, dkap_dlnt, kap_fracs, dkap_dxa = mesa.Kap(
use_type2=True, zbase=0.02
).opacity_full_raw(1.0e6, 1.0e-7, mix.chem_id, mix.xa)
mesa.kap_opacity_profile(...) and mesa.Kap().opacity_profile(...)¶
Signature:
mesa.kap_opacity_profile(
T: Iterable[float],
Rho: Iterable[float],
chem_id_values: Iterable[int],
xa: object,
*,
input_mode: str = "value",
use_type2: bool | None = None,
zbase: float | None = None,
use_zbase_for_type1: bool | None = None,
type2_full_off_X: float | None = None,
type2_full_on_X: float | None = None,
type2_full_off_dZ: float | None = None,
type2_full_on_dZ: float | None = None,
) -> dict[str, object]
Inputs:
| argument | units | shape | meaning |
|---|---|---|---|
T |
K | (nzones,) |
temperature profile |
Rho |
g cm^-3 |
(nzones,) |
density profile |
chem_id_values |
MESA id | (species,) |
isotope ids in xa row order |
xa |
mass fraction | (species,) or (species, nzones) |
fixed composition or zone mass fractions, Fortran-ordered preferred |
input_mode |
selector | scalar | "value" for physical inputs, "log" for natural logs, "log10" for base-10 logs |
Returns profile arrays:
T
Rho
kappa
dlnkap_dlnRho
dlnkap_dlnT
Fixed-composition profile example with physical T and Rho arrays:
T = np.linspace(6.0e5, 2.5e6, 1000)
rho = np.full_like(T, 1.0e-7)
profile = mesa.Kap().opacity_profile(T, rho, mix.chem_id, mix.xa)
opacity = profile["kappa"]
If the caller already stores base-10 logT and logRho, pass those arrays
directly:
log_T = np.linspace(5.8, 6.4, 1000)
log_rho = np.full_like(log_T, -7.0)
profile = mesa.Kap().opacity_profile(log_T, log_rho, mix.chem_id, mix.xa, input_mode="log10")
mesa.kap_opacity_profile_from_logs(...)¶
Signature:
mesa.kap_opacity_profile_from_logs(
lnT: Iterable[float],
lnd: Iterable[float],
chem_id_values: Iterable[int],
xa: object,
*,
use_type2: bool | None = None,
zbase: float | None = None,
use_zbase_for_type1: bool | None = None,
type2_full_off_X: float | None = None,
type2_full_on_X: float | None = None,
type2_full_off_dZ: float | None = None,
type2_full_on_dZ: float | None = None,
) -> dict[str, object]
Inputs are the same profile layout as kap_opacity_profile(...), except lnT
and lnd are natural logs. Use this when the caller already has natural-log
columns.
mesa.eos_kap_profile(...) and mesa.Kap().eos_kap_profile(...)¶
Signature:
mesa.eos_kap_profile(
T: Iterable[float],
Rho: Iterable[float],
chem_id_values: Iterable[int],
xa: object,
*,
input_mode: str = "value",
output: str = "raw",
use_type2: bool | None = None,
zbase: float | None = None,
use_zbase_for_type1: bool | None = None,
type2_full_off_X: float | None = None,
type2_full_on_X: float | None = None,
type2_full_off_dZ: float | None = None,
type2_full_on_dZ: float | None = None,
) -> dict[str, object]
This is the preferred profile path when both eos and kap outputs are needed. It computes the eos state once per zone and passes that state to kap.
Returns:
T
Rho
results # raw eos matrix, shape (n_eos_results, nzones)
result_names # row names for results
kappa
dlnkap_dlnRho
dlnkap_dlnT
Example:
combined = mesa.Kap().eos_kap_profile(T, rho, mix.chem_id, mix.xa, output="dict")
gamma1 = combined["results"]["gamma1"]
kappa = combined["kappa"]
Pass output="dict" when interactive code needs combined["results"]["gamma1"].
mesa.eos_kap_profile_from_logs(...)¶
Signature:
mesa.eos_kap_profile_from_logs(
lnT: Iterable[float],
lnd: Iterable[float],
chem_id_values: Iterable[int],
xa: object,
*,
use_type2: bool | None = None,
zbase: float | None = None,
use_zbase_for_type1: bool | None = None,
type2_full_off_X: float | None = None,
type2_full_on_X: float | None = None,
type2_full_off_dZ: float | None = None,
type2_full_on_dZ: float | None = None,
) -> dict[str, object]
Compatibility alias for eos_kap_profile(..., input_mode="log").
Output schemas¶
Use schema helpers to inspect expected field names, units, and shapes without calling MESA:
print(mesa.format_output_schema("kap_opacity_full", species=mix.names))
print(mesa.format_output_schema("eos_kap_profile"))
Source mapping¶
$MESA_DIR/kap/public/kap_lib.f90
$MESA_DIR/kap/public/kap_def.f90
src/pyfortmesa/fortran/kap/mesa_kap_public.f90
src/pyfortmesa/mesa.py
src/pyfortmesa/mesa_support.py
Fortran wrappers:
mesa_kap_composition_with_controls -> kap_get
mesa_kap_composition_full_with_controls -> kap_get
mesa_eos_kap_composition_with_controls -> eos and kap_get once per scalar point
mesa_kap_profile -> eos state then kap_get once per profile zone
mesa_kap_profile_from_logs -> compatibility wrapper for natural-log inputs
mesa_eos_kap_profile -> eos and kap_get once per profile zone
mesa_eos_kap_profile_from_logs -> compatibility wrapper for natural-log inputs
mesa_kap_shutdown -> free handle, optionally kap_shutdown
mesa_kap_composition and mesa_kap_composition_full still exist as lower
level no-control Fortran wrappers, but the public Python API uses the
_with_controls wrappers because they cover both default and override cases.
Common mistakes¶
input_mode="log"means natural log; useinput_mode="log10"for base-10logTandlogRho.- Pass log-space inputs with
input_mode; do not exponentiate them in Python just to call the physical-value path. - Scalar helpers accept
comp=mix; profile helpers requirechem_id_valuesandxa(species,)orxa(species, nzones). mesa.Kap(...)creates a Python control object, not an independent MESA handle per object.
Not included¶
| MESA item | Reason |
|---|---|
kap_init, alloc_kap_handle, free_kap_handle |
Managed internally by pyfortmesa handles and mesa.shutdown(...). |
kap_ptr |
Exposes MESA pointer state; not safe or useful for normal Python calls. |
kap_setup_tables, call_load_op_master |
Table-loading internals; normal use goes through kap_get. |
kap_setup_hooks |
Requires callback/hook design; not part of the current pure microphysics API. |
| mono-opacity routines | Specialized workflow; add only with a concrete mono-opacity example and tests. |
| conductive, Compton, and radiative sub-opacity routines | The current public call exposes total kap_get plus fractions. Sub-opacity APIs need a separate design. |
| Mombarg routines | Specialized grid/table workflow; not current scope. |
kap_get_control_namelist, kap_set_control_namelist |
Current control path is mesa.set_inlist(...) plus Python Kap(...) overrides. |
mesa_kap_sample_composition |
Legacy/sample Fortran wrapper; prefer named Composition path for user code. |