synthe_py¶
Pure-Python SYNTHE spectrum synthesis engine. synthe_py computes atomic and
molecular line opacity and solves the LTE radiative-transfer equation to produce
a synthetic spectrum from a converged model atmosphere.
The top-level entry point is the opacity engine, which orchestrates wavelength
grid construction, line selection, profile accumulation, and the JOSH radiative
transfer solver. Most users invoke it indirectly through
pykurucz.run_synthe_py().
See also:
Configuration¶
Configuration models for the Python SYNTHE pipeline.
Attributes¶
DEFAULT_WAVELENGTH
module-attribute
¶
DEFAULT_WAVELENGTH: Tuple[float, float, float] = (300.0, 1800.0, 300000.0)
Default wavelength grid (start, end, resolving power).
Classes¶
WavelengthGrid
dataclass
¶
WavelengthGrid(start: float, end: float, resolution: float, velocity_microturb: float = 0.0, vacuum: bool = True)
Defines the spectral sampling to synthesise.
LineDataConfig
dataclass
¶
LineDataConfig(atomic_catalog: Path, molecular_catalogs: List[Path] = list(), include_predicted: bool = False, cache_directory: Optional[Path] = None, allow_tfort_runtime: bool = False, molecular_line_dirs: List[Path] = list(), include_tio: bool = True, include_h2o: bool = False, tio_bin_path: Optional[Path] = None, h2o_bin_path: Optional[Path] = None)
Controls which line lists are included in the synthesis.
Note: Populations are computed from Saha-Boltzmann equations (no fort.10 dependency). Line opacity is computed from first principles using the atomic catalog.
Attributes¶
molecular_line_dirs
class-attribute
instance-attribute
¶
molecular_line_dirs: List[Path] = field(default_factory=list)
Directories containing Kurucz ASCII molecular .dat/.asc files.
include_tio
class-attribute
instance-attribute
¶
include_tio: bool = True
Include Schwenke TiO binary line list (rschwenk) when the binary is found.
include_h2o
class-attribute
instance-attribute
¶
include_h2o: bool = False
Include Partridge-Schwenke H2O binary line list (rh2ofast) when the binary is found. Disabled by default: the Fortran reference tfort.12 has all 12.6M H2O records with out-of-range NBUFF values, so Fortran synthe.for effectively skips every H2O line. Enable with --h2o if using a corrected H2O compilation.
tio_bin_path
class-attribute
instance-attribute
¶
tio_bin_path: Optional[Path] = None
Explicit path to schwenke.bin (or eschwenke.bin). Auto-located if None.
h2o_bin_path
class-attribute
instance-attribute
¶
h2o_bin_path: Optional[Path] = None
Explicit path to h2ofastfix.bin. Auto-located if None.
AtmosphereInput
dataclass
¶
AtmosphereInput(model_path: Path, format: str = 'atlas12', npz_path: Optional[Path] = None)
Describes the input model atmosphere.
OutputConfig
dataclass
¶
OutputConfig(spec_path: Path, diagnostics_path: Optional[Path] = None)
Specifies the artefacts produced by the pipeline.
SynthesisConfig
dataclass
¶
SynthesisConfig(wavelength_grid: WavelengthGrid, line_data: LineDataConfig, atmosphere: AtmosphereInput, output: OutputConfig, cutoff: float = 0.001, linout: int = 30, nlte: bool = False, scattering_iterations: int = 8, scattering_tolerance: float = 0.001, rhoxj_scale: float = 0.0, log_level: str = 'INFO', enable_helium_wings: bool = True, skip_hydrogen_wings: bool = False, line_filter: bool = True, wavelength_subsample: int = 1, n_workers: Optional[int] = None)
Global settings for a SYNTHE run.
Methods:¶
from_cli
classmethod
¶
from_cli(spec_path: Path, diagnostics_path: Optional[Path], atmosphere_path: Path, atomic_catalog: Path, wl_start: float, wl_end: float, resolution: float, velocity_microturb: float = 0.0, vacuum: bool = True, cutoff: float = 0.001, linout: int = 30, nlte: bool = False, scattering_iterations: int = 8, scattering_tolerance: float = 0.001, rhoxj_scale: float = 0.0, enable_helium_wings: bool = True, skip_hydrogen_wings: bool = False, line_filter: bool = True, wavelength_subsample: int = 1, npz_path: Optional[Path] = None, n_workers: Optional[int] = None, allow_tfort_runtime: bool = False, molecular_line_dirs: Optional[List[Path]] = None, include_tio: bool = True, include_h2o: bool = True, tio_bin_path: Optional[Path] = None, h2o_bin_path: Optional[Path] = None) -> 'SynthesisConfig'
Helper for the default CLI entry point.
Functions:¶
discover_default_molecular_line_directories
¶
discover_default_molecular_line_directories() -> List[Path]
Return data/molecules inside the pykurucz repo if it exists.
The data/ directory is populated by running
scripts/download_data.py once. If the directory is absent or empty,
returns an empty list (atomic-line synthesis only).
Engine — Opacity¶
Engine — Radiative Transfer¶
LTE radiative transfer helpers using the Kurucz JOSH solver.
Functions:¶
solve_lte_spectrum
¶
solve_lte_spectrum(wavelength_nm: ndarray, temperature: ndarray, column_mass: ndarray, cont_abs: ndarray, cont_scat: ndarray, line_opacity: ndarray, line_scattering: ndarray, line_source: Optional[ndarray] = None, n_workers: Optional[int] = None) -> Tuple[np.ndarray, np.ndarray]
Solve LTE radiative transfer for a spectrum.
Parameters¶
wavelength_nm: Wavelength array (nm) temperature: Temperature array (K) for each depth column_mass: Column mass array (g/cm²) for each depth cont_abs: Continuum absorption opacity (n_depths, n_wavelengths) cont_scat: Continuum scattering opacity (n_depths, n_wavelengths) line_opacity: Line absorption opacity (n_depths, n_wavelengths) line_scattering: Line scattering opacity (n_depths, n_wavelengths) line_source: Optional line source function (n_depths, n_wavelengths) n_workers: Number of parallel workers. If None or 1, uses sequential processing. If > 1, uses multiprocessing.
Returns¶
flux_total: Total flux (HNU) for each wavelength flux_cont: Continuum flux (HNU) for each wavelength
I/O — Atmosphere¶
Atmosphere file handling for the Python SYNTHE pipeline.
Classes¶
AtmosphereModel
dataclass
¶
AtmosphereModel(depth: ndarray, temperature: ndarray, gas_pressure: ndarray, electron_density: ndarray, mass_density: ndarray, turbulent_velocity: ndarray, metadata: Dict[str, str], tkev: Optional[ndarray] = None, tk: Optional[ndarray] = None, tlog: Optional[ndarray] = None, hkt: Optional[ndarray] = None, continuum_tables: Optional[ContinuumTables] = None, continuum_frequency: Optional[ndarray] = None, continuum_wledge: Optional[ndarray] = None, continuum_half_edge: Optional[ndarray] = None, continuum_delta_edge: Optional[ndarray] = None, continuum_abs_coeff: Optional[ndarray] = None, continuum_scat_coeff: Optional[ndarray] = None, continuum_coeff_log10: bool = False, hckt: Optional[ndarray] = None, txnxn: Optional[ndarray] = None, xnf_h: Optional[ndarray] = None, xnf_he1: Optional[ndarray] = None, xnf_he2: Optional[ndarray] = None, xnf_h2: Optional[ndarray] = None, xnfph: Optional[ndarray] = None, dopph: Optional[ndarray] = None, cont_absorption: Optional[ndarray] = None, cont_scattering: Optional[ndarray] = None, line_source_lower: Optional[ndarray] = None, line_source_upper: Optional[ndarray] = None, population_per_ion: Optional[ndarray] = None, doppler_per_ion: Optional[ndarray] = None, xabund: Optional[ndarray] = None, bhyd: Optional[ndarray] = None, bc1: Optional[ndarray] = None, bc2: Optional[ndarray] = None, bsi1: Optional[ndarray] = None, bsi2: Optional[ndarray] = None, xnatm: Optional[ndarray] = None, atlas_tables: Optional[Dict[str, ndarray]] = None, xnfpc: Optional[ndarray] = None, xnfpmg: Optional[ndarray] = None, xnfpsi: Optional[ndarray] = None, xnfpal: Optional[ndarray] = None, xnfpfe: Optional[ndarray] = None, xnfpch: Optional[ndarray] = None, xnfpoh: Optional[ndarray] = None)
Structured representation of a 1D stellar atmosphere.
Functions:¶
load_cached
¶
load_cached(path: Path) -> AtmosphereModel
Load a cached numpy .npz representation of the atmosphere.
save_cached
¶
save_cached(model: AtmosphereModel, path: Path) -> None
Persist the atmosphere to an .npz archive.
iterate_layers
¶
iterate_layers(model: AtmosphereModel) -> Iterable[int]
Yield layer indices in order of increasing optical depth.
I/O — Export¶
Export utilities for SYNTHE outputs.
Classes¶
Functions:¶
write_spec_file
¶
write_spec_file(result: SynthResult, destination: Path) -> None
Write the synthesized spectrum to a .spec file.
The legacy Fortran code emitted three columns per row: wavelength, emergent flux, and continuum flux. The Python reimplementation produces the same layout for drop-in comparability.
I/O — spectrv¶
Helpers for parsing spectrv input cards.
Classes¶
SpectrvParams
dataclass
¶
SpectrvParams(rhoxj: float, ph1: float, pc1: float, psi1: float, prddop: float, prdpow: float)
Subset of the spectrv control parameters used in the LTE run.
Functions:¶
load
¶
load(path: Path) -> SpectrvParams
Parse the standard spectrv input deck (e.g. spectrv_std.input).
Physics — Continuum Opacity¶
Continuum opacity calculations mirroring the legacy SYNTHE algorithm.
Classes¶
Functions:¶
interpolate_continuum
¶
interpolate_continuum(tables: ContinuumTables, wavelengths: ndarray) -> np.ndarray
Reproduce the DO 2005 loop filling CONTINUUM(NBUFF).
finalize_continuum
¶
finalize_continuum(log_continuum: ndarray) -> np.ndarray
Apply the final 10** conversion (loop 2006).
build_continuum_grid
¶
build_continuum_grid(atmosphere: 'AtmosphereModel', wavelength_grid: ndarray) -> np.ndarray
Compute continuum opacity for each layer using legacy interpolation.
build_depth_continuum
¶
build_depth_continuum(atmosphere: 'AtmosphereModel', wavelength_grid: ndarray) -> tuple[np.ndarray, np.ndarray, Optional[np.ndarray], Optional[np.ndarray]]
Return per-depth continuum absorption, scattering, and optional line sources.
This function matches Fortran's approach: uses log10 coefficients (CONTABS/CONTSCAT) from fort.10, interpolates them, then converts to linear with 10**. Requires wledge and cont_abs_coeff/cont_scat_coeff to be present in the atmosphere model.
Physics — Populations¶
Population and state computations for atmosphere layers.
Classes¶
DepthState
dataclass
¶
DepthState(boltzmann_factor: ndarray, doppler_width: ndarray, turbulence_width: float, electron_density: float, temperature: float, continuum_opacity: ndarray, hckt: float, txnxn: float, hydrogen: Optional[HydrogenDepthState] = None)
Derived physical quantities for one atmospheric depth.
Populations
dataclass
¶
Populations(layers: Dict[int, DepthState])
Holds precomputed populations for all depths.
Functions:¶
compute_depth_state
¶
compute_depth_state(atmosphere: AtmosphereModel, line_wavelengths: ndarray, excitation_energy: ndarray, microturb_kms: float, elements: Optional[ndarray] = None) -> Populations
Compute LTE-like populations and Doppler widths per depth.
CRITICAL FIX (Dec 2025): Use element-specific atomic masses for thermal velocity. Fortran xnfpelsyn.for line 488: DOPPLE = SQRT(2*TK/ATMASS(NELEM)/1.660D-24 + ...) Previous Python code used hydrogen mass for all elements, causing: - Fe lines: Doppler widths 7.5x too large (sqrt(56) factor) - This affects wing profiles and total line opacity
Physics — Line Broadening¶
Physics — JOSH Solver¶
Functions:¶
solve_josh_flux
¶
solve_josh_flux(acont: ndarray, scont: ndarray, aline: ndarray, sline: ndarray, sigmac: ndarray, sigmal: ndarray, column_mass: ndarray) -> float
Compute the emergent flux for a single frequency using the JOSH solver.
Option 2: Use higher precision arithmetic when alpha (scattering) is large to reduce numerical errors. This is especially important when alpha > 0.1.