The slug Python API

slugpy wraps the compiled C++ core (exposed as the private _slug extension module, built by CMake – see The slug C++ API for its own API documentation) and adds pure-Python analysis code of its own for reading and post-processing slug output files.

The Pure Python Layer

slugpy: the Python frontend for slug.

copyright:

Copyright (c) 2026 Mark Krumholz

slugpy.compute_isochrones(time: float | list[float] | ndarray | Quantity, simcontrols: SimControls | None = None, filters: str | list[str] | FilterCollection | None = None, masses: list[float] | ndarray | Quantity | None = None, nmass: int = 100, phot_system: PhotSystem | None = None, feh: float = 0.0, **simcontrols_kwargs: object) → tuple[Quantity, dict[str, Quantity]][source]

Compute isochrones end to end: tracks -> isochrone -> spectra -> photometry.

Parameters:
  • time (float, array_like of float, or astropy.units.Quantity) – Time(s) at which to compute isochrones. A plain float or array_like is interpreted as being in years; an astropy Quantity (scalar or array) may carry any unit of time.

  • simcontrols (SimControls, optional) – Simulation controls providing the IMF, [Fe/H] distribution, tracks, and spectral synthesizer to use. If None (the default), one is constructed from simcontrols_kwargs (or default-constructed, if none are given).

  • filters (str, list of str, or FilterCollection, optional) – The filter(s) to compute photometry with. A str or list of str is used to construct a FilterCollection (see phot_system below); a FilterCollection is used directly. If None (the default), no photometry is computed.

  • masses (array_like of float or astropy.units.Quantity, optional) – Stellar masses at which to evaluate each isochrone. An array_like is interpreted as being in Msun; a Quantity array may carry any unit of mass. If None (the default), set to nmass values, log-spaced from the minimum to the maximum mass of simcontrols.imf.

  • nmass (int, default 100) – Number of stellar masses to use, log-spaced between simcontrols.imf’s own minimum and maximum mass. Ignored if masses is given.

  • phot_system (PhotSystem, optional) – The photometric system to pass to the FilterCollection constructor when filters is a str or list of str; ignored otherwise. Defaults to PhotSystem.Flambda.

  • feh (float, default 0.0) – [Fe/H] to compute the isochrone at. Used only if simcontrols.feH is not a delta distribution (i.e. its getMin() and getMax() differ); if it is a delta distribution, that single value is used instead and feh is ignored.

  • **simcontrols_kwargs – Additional keywords, passed on to the SimControls constructor. Ignored if simcontrols is given.

Returns:

  • astropy.units.Quantity – The stellar masses each isochrone was evaluated at: masses itself (converted to Msun), or, if masses was not given, the nmass log-spaced values this function constructed instead. A 1D Quantity array of length nmass.

  • dict of str to astropy.units.Quantity – One key per stellar property returned by the isochrone (“mass”, “mdot”, “log_L”, “log_Teff”, “h_surf”, “he_surf”, “c_surf”, “n_surf”, “o_surf”), plus one key per filter name (if filters is not None). Each value is a 2D Quantity array of shape (ntimes, nmass), indexed the same way as time and the first return value. Entries for a mass outside the isochrone’s valid range at a given time are NaN.

Raises:

RuntimeError – If simcontrols.specsyn is None (i.e. no spectral synthesizer was configured).

slugpy.compute_tracks(masses: list[float] | ndarray | Quantity, time: float | list[float] | ndarray | Quantity | None = None, simcontrols: SimControls | None = None, filters: str | list[str] | FilterCollection | None = None, ntimes: int = 100, phot_system: PhotSystem | None = None, feh: float = 0.0, **simcontrols_kwargs: object) → tuple[Quantity, dict[str, Quantity]][source]

Compute stellar evolution tracks end to end: tracks -> spectra -> photometry.

Parameters:
  • masses (array_like of float or astropy.units.Quantity) – Stellar masses to evaluate a track for. An array_like is interpreted as being in Msun; a Quantity array may carry any unit of mass.

  • time (float, array_like of float, or astropy.units.Quantity, optional) – Time(s) at which to evaluate each track. A plain float or array_like is interpreted as being in years; an astropy Quantity (scalar or array) may carry any unit of time. If None (the default), set to ntimes values, log-spaced from 1e5 yr to the maximum age spanned by simcontrols.tracks (its own logTMax()).

  • simcontrols (SimControls, optional) – Simulation controls providing the [Fe/H] distribution, tracks, and spectral synthesizer to use. If None (the default), one is constructed from simcontrols_kwargs (or default-constructed, if none are given).

  • filters (str, list of str, or FilterCollection, optional) – The filter(s) to compute photometry with. A str or list of str is used to construct a FilterCollection (see phot_system below); a FilterCollection is used directly. If None (the default), no photometry is computed.

  • ntimes (int, default 100) – Number of times to use, log-spaced between 1e5 yr and simcontrols.tracks’s own maximum age. Ignored if time is given.

  • phot_system (PhotSystem, optional) – The photometric system to pass to the FilterCollection constructor when filters is a str or list of str; ignored otherwise. Defaults to PhotSystem.Flambda.

  • feh (float, default 0.0) – [Fe/H] to compute the track at. Used only if simcontrols.feH is not a delta distribution (i.e. its getMin() and getMax() differ); if it is a delta distribution, that single value is used instead and feh is ignored.

  • **simcontrols_kwargs – Additional keywords, passed on to the SimControls constructor. Ignored if simcontrols is given.

Returns:

  • astropy.units.Quantity – The times each track was evaluated at: time itself (converted to yr), or, if time was not given, the ntimes log-spaced values this function constructed instead. A 1D Quantity array of length ntimes.

  • dict of str to astropy.units.Quantity – One key per stellar property returned by the track (“mass”, “mdot”, “log_L”, “log_Teff”, “h_surf”, “he_surf”, “c_surf”, “n_surf”, “o_surf”), plus one key per filter name (if filters is not None). Each value is a 2D Quantity array of shape (nmass, ntimes), indexed the same way as masses and the first return value. Entries for a mass outside simcontrols.tracks’s own mass range, or a time outside a given mass’s own track range, are NaN.

Raises:

RuntimeError – If simcontrols.specsyn is None (i.e. no spectral synthesizer was configured).

slugpy.consolidate_checkpoints(model_name: str, out_dir: str | PathLike[str] | None = None, cleanup: bool = False) → Path[source]

Merge the checkpoints of a checkpointed slug run into one file.

Parameters:
  • model_name (str) – The run’s model name (output.model_name in its input deck).

  • out_dir (str or os.PathLike, optional) – The directory holding the run’s output (output.out_dir in its input deck). Defaults to the current working directory.

  • cleanup (bool, optional) – If True, delete the individual checkpoints once the consolidated file has been written and verified. Defaults to False.

Returns:

Path of the consolidated file, out_dir/model_name.h5.

Return type:

pathlib.Path

Raises:
  • FileNotFoundError – If out_dir holds no checkpoints of model_name.

  • FileExistsError – If out_dir/model_name.h5 already exists, or is created by something else while this function is running.

  • ValueError – If the checkpoint files do not all have the same HDF5 group and dataset structure, or if any of them lacks the trials_completed attribute slug writes when it closes a checkpoint (meaning the file was never closed cleanly – e.g. the run is still going, or crashed while writing it).

  • RuntimeError – If the consolidated file fails verification against the checkpoints. Nothing is written to out_dir/model_name.h5, and nothing is deleted, in that case.

Notes

Checkpoints are found the same way slug finds them when restarting a run (see OutputManagerH5::restartSetup()): every model_name_chkNNNNN.h5 file, or model_name_chkNNNNN/ directory of per-thread/per-rank files, in out_dir, with the file taking precedence if both exist for the same NNNNN.

Every dataset with an unlimited dimension holds one row per output record (cluster, galaxy, time, …), and its rows from every file are concatenated, in checkpoint order. Everything else – top-level attributes (trials_completed, restart_uid, rng_state, …), the input deck, fixed datasets such as wavelength grids, and every group’s and dataset’s attributes – is taken from the final checkpoint.

The consolidated file is written under a temporary name and only renamed to model_name.h5 after every row of it has been read back and compared against the checkpoints. Note that slug_reader, given a model name, prefers checkpoints to model_name.h5 whenever any exist, so it reads the consolidated file in preference to the checkpoints only once they are removed (cleanup=True), or if it is given the path to model_name.h5 directly. Likewise, once the checkpoints are removed, a run can no longer be restarted from them.

slugpy.phot_convert(phot: Quantity, phot_to: str, wl: Quantity | float | None = None, filt: Filter | None = None) → Quantity[source]

Convert a photometric Quantity from its own system to another.

Parameters:
  • phot (astropy.units.Quantity) – The photometry to convert; its own unit determines the source photometric system (see _detect_phot_system()).

  • phot_to (str) – The photometric system to convert phot to: one of “Flambda”, “Fnu”, “ST”, “AB”, or “Vega”.

  • wl (astropy.units.Quantity or float, optional) – The wavelength(s) at which phot is evaluated (a plain float is interpreted as Angstrom); broadcast against phot, so e.g. a whole spectrum can be converted in one call by passing matching phot and wl arrays. Required only if the (phot_from, phot_to) pair actually depends on wavelength – every pair except Fnu<->AB, Flambda<->ST, and Flambda<->Vega.

  • filt (Filter, optional) – A filter whose fluxVega() gives the Vega zero point to use; required if phot’s own system or phot_to is “Vega”, ignored otherwise.

Returns:

phot converted to phot_to, with phot_to’s own unit attached. Returns phot unchanged if it is already in phot_to’s system.

Return type:

astropy.units.Quantity

Raises:
  • ValueError – If phot’s unit doesn’t match a recognized photometric system, if wl is required (see above) but not given, or if filt is required (phot’s own system or phot_to is “Vega”) but not given.

  • RuntimeError – If phot_to is not a recognized photometric system.

slugpy.read(filename: str) → slug_reader[source]

Open a slug HDF5 output file for lazy reading.

Parameters:

filename (str) – Path to the slug HDF5 output file to open.

Returns:

A lazy reader for filename.

Return type:

slug_reader

slugpy.run_sim(controls: SimControls | str, progress: bool = True, restart: bool = False) → slug_reader | None[source]

Run a slug simulation end to end, exactly as the slug command-line executable does.

Parameters:
  • controls (SimControls or str) – Either an already-built SimControls object, used directly, or the text of a slug TOML input deck, or a path to one on disk (see SimControls’s own constructor for the exact string- parsing rule), used to construct one. Passing a SimControls object directly lets a simulation be driven entirely from Python – via SimControls’s own constructor keyword arguments and setters – without ever writing an input deck to text.

  • progress (bool, default True) – Whether to show a progress bar (see slugpy.progress) tracking trials completed while the simulation runs.

  • restart (bool, default False) – Whether this run should resume a previous, interrupted run of the same model_name/out_dir from its most recent checkpoint, rather than starting a new one from trial 0 (see OutputManagerH5’s own docstring for the full detail, and SimCluster.run/SimGalaxy.run’s own docstrings for how the starting trial is chosen). Only valid with HDF5 output and a non-zero output.checkpoint_interval in controls – passing True with ASCII output raises RuntimeError, mirroring the slug command-line executable’s own –restart/-R check.

Returns:

A lazy reader for the HDF5 output file this simulation produced, or None if this simulation’s own output mode is ASCII rather than HDF5 – ASCII output cannot currently be read back this way (a UserWarning is issued in that case; see Details below).

Return type:

slug_reader or None

Notes

Mirrors main.cpp’s own control flow: obtains a SimControls (either controls itself, or one built from it), an OutputManagerH5 or OutputManagerAscii from it (matching sim_controls.outputMode()), and – depending on sim_controls.simType() – a SimCluster or SimGalaxy, which it then runs.

The progress bar (when enabled) is driven by run_with_progress: run() itself executes on a background thread, while this calling thread polls the running SimCluster/SimGalaxy’s own trialsCompleted() against nTrial() every 0.2s (see run_with_progress’s own docstring for why the polling has to happen on this thread rather than a separate watcher thread). This is safe because run() releases the GIL for its own entire duration (see SimCluster.run/SimGalaxy.run’s own pybind docstrings), so polling this thread is never blocked by it, and the OpenMP worker threads run() uses internally never touch Python or the GIL at all. Note that when restart is True, trialsCompleted() only counts trials run by this call, not ones a previous, resumed run already completed – so the progress bar’s own denominator (nTrial()) can look larger than what this call alone will actually run.

ASCII output is meant for small, human-readable output rather than batch processing, so there is no ASCII counterpart to slug_reader (yet – this may change in the future). A deck requesting it still runs to completion, and its output files are still written, but this function has nothing to return for them, so it warns and returns None rather than trying to read back a file that was never written.

Output Readers

class slugpy.slug_reader.slug_reader(filename: str)[source]

A lazy reader for slug HDF5 output, spread across one file or many (checkpointed and/or h5divided output – see filename below). Metadata is read on construction; the output data itself (cluster properties, spectra, photometry, …) is only read from disk when a caller actually asks for it, and only ever one underlying file at a time – see slug_group_reader’s own docstring.

Parameters:

filename (str) – Either a path to a single slug HDF5 output file (if it ends in “.h5” or “.hdf5”), or a run’s own model name (really, outDir/ model_name together, with no extension) to search for and aggregate every checkpoint (and, within each, every OpenMP thread’s and/or MPI rank’s own file, if not yet consolidated) that run left behind – see _find_output_files’s own docstring for the exact search rule, which mirrors OutputManagerH5::restartSetup()’s own.

Variables:
  • slug_hash (str) – Git commit hash of the slug build that produced this output.

  • date (str) – Date the run that produced this output started, as YYYY-MM-DD.

  • time (str) – Time of day the run that produced this output started.

  • rng_state (str) – Serialized state of the random number generator at the start of the run, one space-separated pcg64 state per thread.

  • trials_completed (int or None) – Number of trials the run that produced this output had completed as of its own most recent checkpoint (see OutputManagerH5::closeOutputFile()’s own “trials_completed” attribute) – unlike slug_hash/date/time/rng_state above, this (and restart_uid below) is read from the last checkpoint specifically, not just any one file, since – unlike those – it differs from one checkpoint to the next. None if this output predates checkpointing (no such attribute at all), or if its own most recent checkpoint was still open (being written to) when this was read, rather than already closed (read-only).

  • restart_uid (int or None) – The utils::uniqueID() value a restart of this run would resume from, as of the same checkpoint trials_completed was read from (see OutputManagerH5::closeOutputFile()’s own “restart_uid” attribute) – same None cases as trials_completed (read-only). Under MPI, each rank’s own output file has its own restart_uid (see the SLUG documentation’s own note on this, in “Output Files and Format”); this is read from the lowest-numbered rank’s file specifically (rank 0’s, if present), not some run-wide value – there isn’t one, since each rank’s own ID numbering runs in its own, non-overlapping range.

  • input_deck (tomlkit.TOMLDocument) – The input deck used to produce this file, read from the input_deck group’s toml dataset and parsed on first access (read-only).

  • clusters (slug_group_reader or None) – Lazy reader for the clusters group’s datasets (target_mass, birth_mass, …), or None if this file has no clusters group (read-only).

  • cluster_spectra (slug_spectra_reader or None) – Lazy reader for the cluster_spectra group’s datasets (wl, spec, …), including nebular emission data (spec_neb, line_labels, neb_lines, …) if this file’s own simulation requested it – see slug_spectra_reader’s own docstring – or None if this file has no cluster_spectra group (read-only).

  • cluster_phot (slug_phot_reader or None) – Lazy reader for the cluster_phot group’s per-filter photometry (indexable by filter name, e.g. cluster_phot[“Lbol”]; “_ex”, “_neb”, and “_neb_ex” suffixes select extincted, nebular- inclusive, and nebular-inclusive-and-extincted variants – see slug_phot_reader’s own docstring), or None if this file has no cluster_phot group (read-only).

  • galaxy (slug_group_reader or None) – Lazy reader for the galaxy group’s datasets (target_mass, actual_mass, …), or None if this file has no galaxy group – only a galaxy-type simulation ever has one (read-only).

  • galaxy_spectra (slug_spectra_reader or None) – Lazy reader for the galaxy_spectra group’s datasets (wl, spec, …), including nebular emission data (spec_neb, line_labels, neb_lines, …) if this file’s own simulation requested it – see slug_spectra_reader’s own docstring – or None if this file has no galaxy_spectra group (read-only).

  • galaxy_phot (slug_phot_reader or None) – Lazy reader for the galaxy_phot group’s per-filter photometry (indexable by filter name, e.g. galaxy_phot[“Lbol”]; “_ex”, “_neb”, and “_neb_ex” suffixes select extincted, nebular- inclusive, and nebular-inclusive-and-extincted variants – see slug_phot_reader’s own docstring), or None if this file has no galaxy_phot group (read-only).

  • cluster_cloudy (slug_group_reader or None) – Lazy reader for the cluster_cloudy group’s datasets (uid, time, nII, …), written by run_cloudy(spec_type=”cluster”), or None if this file has no cluster_cloudy group (read-only).

  • galaxy_cloudy (slug_group_reader or None) – Lazy reader for the galaxy_cloudy group’s datasets (trial, time, nII, …), written by run_cloudy(spec_type=”galaxy”), or None if this file has no galaxy_cloudy group (read-only).

  • cluster_yields (slug_yields_reader or None) – Lazy reader for the cluster_yields group’s per-isotope nucleosynthetic yields (indexable by isotope name, e.g. cluster_yields[“Fe56”], or, if cluster_yields.decomposed is True, by a (channel, model, isotope) triple – see slug_yields_reader’s own docstring), or None if this file has no cluster_yields group (read-only).

  • galaxy_yields (slug_yields_reader or None) – Lazy reader for the galaxy_yields group’s per-isotope nucleosynthetic yields, indexed the same way as cluster_yields, or None if this file has no galaxy_yields group (read-only).

  • cluster_feedback (slug_group_reader or None) – Lazy reader for the cluster_feedback group’s datasets (trial, time, uid, n_sn, mdot_wind, pdot_wind, edot_wind), or None if this file has no cluster_feedback group (read-only).

  • galaxy_feedback (slug_group_reader or None) – Lazy reader for the galaxy_feedback group’s datasets (as for cluster_feedback, minus uid), or None if this file has no galaxy_feedback group (read-only).

  • isotopes (list of str or None) – Alias for cluster_yields.isotopes if this file has a cluster_yields group, else for galaxy_yields.isotopes if this file has a galaxy_yields group, else None (read-only).

  • filters (list of str or None) – Alias for cluster_phot.filters if this file has a cluster_phot group, else for galaxy_phot.filters if this file has a galaxy_phot group, else None (read-only).

  • filter_units (list of str or None) – Alias for cluster_phot.filter_units if this file has a cluster_phot group, else for galaxy_phot.filter_units if this file has a galaxy_phot group, else None (read-only).

  • controls (SimControls) – Simulation controls parsed from this file’s own input_deck, built the first time this property is accessed and cached thereafter; used by get_cluster() to reconstruct clusters (read-only).

__init__(filename: str) → None[source]
property cluster_cloudy: slug_group_reader | None

lazy reader for the cluster_cloudy group’s datasets (uid, time, nII, …, and – where available – the continuum and line data run_cloudy wrote), built the first time this property is accessed and cached thereafter, or None if this file has no cluster_cloudy group (e.g. run_cloudy has never been called with spec_type=”cluster” on this file).

Type:

slug_group_reader or None

property cluster_feedback: slug_group_reader | None

lazy reader for the cluster_feedback group’s datasets – trial, time, uid, n_sn (cumulative number of supernovae), and the stellar wind mass, momentum, and energy fluxes mdot_wind (Msun/yr), pdot_wind (Msun km/s/yr), and edot_wind (Lsun) – built the first time this property is accessed and cached thereafter, or None if this file has no cluster_feedback group.

Type:

slug_group_reader or None

property cluster_phot: slug_phot_reader | None

lazy reader for the cluster_phot group’s per-filter photometry, built the first time this property is accessed and cached thereafter, or None if this file has no cluster_phot group.

Type:

slug_phot_reader or None

property cluster_spectra: slug_spectra_reader | None

lazy reader for the cluster_spectra group’s datasets (including nebular emission data – spec_neb, line_labels, neb_lines, … – if this file’s own simulation requested it; see slug_spectra_reader’s own docstring), built the first time this property is accessed and cached thereafter, or None if this file has no cluster_spectra group.

Type:

slug_spectra_reader or None

property cluster_yields: slug_yields_reader | None

lazy reader for the cluster_yields group’s per-isotope nucleosynthetic yields, built the first time this property is accessed and cached thereafter, or None if this file has no cluster_yields group.

Type:

slug_yields_reader or None

property clusters: slug_group_reader | None

lazy reader for the clusters group’s datasets, built the first time this property is accessed and cached thereafter, or None if this file has no clusters group.

Type:

slug_group_reader or None

property controls: SimControls

simulation controls parsed from this file’s own input_deck, built the first time this property is accessed and cached thereafter.

Type:

SimControls

property filter_units: list[str] | None

alias for cluster_phot.filter_units if this file has a cluster_phot group, else for galaxy_phot.filter_units if this file has a galaxy_phot group, else None (read-only).

Type:

list of str or None

property filters: list[str] | None

alias for cluster_phot.filters if this file has a cluster_phot group, else for galaxy_phot.filters if this file has a galaxy_phot group, else None (read-only).

Type:

list of str or None

property galaxy: slug_group_reader | None

lazy reader for the galaxy group’s datasets, built the first time this property is accessed and cached thereafter, or None if this file has no galaxy group (only a galaxy-type simulation ever has one).

Type:

slug_group_reader or None

property galaxy_cloudy: slug_group_reader | None

lazy reader for the galaxy_cloudy group’s datasets (trial, time, nII, …, and – where available – the continuum and line data run_cloudy wrote), built the first time this property is accessed and cached thereafter, or None if this file has no galaxy_cloudy group (e.g. run_cloudy has never been called with spec_type=”galaxy” on this file).

Type:

slug_group_reader or None

property galaxy_feedback: slug_group_reader | None

lazy reader for the galaxy_feedback group’s datasets (as for cluster_feedback, minus uid), built the first time this property is accessed and cached thereafter, or None if this file has no galaxy_feedback group (only a galaxy-type simulation ever has one).

Type:

slug_group_reader or None

property galaxy_phot: slug_phot_reader | None

lazy reader for the galaxy_phot group’s per-filter photometry, built the first time this property is accessed and cached thereafter, or None if this file has no galaxy_phot group.

Type:

slug_phot_reader or None

property galaxy_spectra: slug_spectra_reader | None

lazy reader for the galaxy_spectra group’s datasets (including nebular emission data – spec_neb, line_labels, neb_lines, … – if this file’s own simulation requested it; see slug_spectra_reader’s own docstring), built the first time this property is accessed and cached thereafter, or None if this file has no galaxy_spectra group.

Type:

slug_spectra_reader or None

property galaxy_yields: slug_yields_reader | None

lazy reader for the galaxy_yields group’s per-isotope nucleosynthetic yields, built the first time this property is accessed and cached thereafter, or None if this file has no galaxy_yields group.

Type:

slug_yields_reader or None

get_cluster(uid: int) → Cluster[source]

Reconstruct one cluster from this file’s clusters group.

Parameters:

uid (int) – Unique ID of the cluster to reconstruct (see clusters[“uid”]).

Returns:

A Cluster built from this cluster’s own target_mass and rng_state, so its birth-time draws – birthMass(), starMasses(), feH(), aV() – are reproduced bit-for-bit; not yet advanced to any output time.

Return type:

Cluster

Raises:
  • RuntimeError – If this file has no clusters group.

  • KeyError – If uid is not one of this file’s clusters.

Notes

Built from this reader’s own controls property – see its own docstring on how (and how cheaply) that’s constructed.

get_filter(filter_name: str) → Filter[source]

Get a Filter object for one of this file’s own filters.

Parameters:

filter_name (str) – Name of the filter to get; must be one of this file’s own filters (see filters).

Returns:

The requested filter – see cluster_phot.get_filter()’s own docstring for how it’s constructed and cached.

Return type:

Filter

Raises:
  • RuntimeError – If this file has no cluster_phot group.

  • KeyError – If filter_name is not one of this file’s own filters.

property input_deck: TOMLDocument

the input deck used to produce this output, parsed from the first file’s own input_deck group’s toml dataset the first time this property is accessed, and cached thereafter.

Type:

tomlkit.TOMLDocument

property isotopes: list[str] | None

alias for cluster_yields.isotopes if this file has a cluster_yields group, else for galaxy_yields.isotopes if this file has a galaxy_yields group, else None (read-only).

Type:

list of str or None

phot_convert(phot_to: str) → None[source]

Convert every cached filter’s photometry to a new photometric system, in place. A no-op if this file has no cluster_phot group.

Parameters:

phot_to (str) – The photometric system to convert to: one of “Flambda”, “Fnu”, “ST”, “AB”, or “Vega”.

Notes

Thin wrapper around cluster_phot.phot_convert() – see its own docstring for exactly which entries get converted and how.

run_cloudy(spec_type: Literal['cluster', 'galaxy'], uid: int | list[int] | None = None, trial: int | list[int] | None = None, time: float | Quantity | list[float | Quantity] | None = None, nII: Quantity | float | None = None, r0: Quantity | float | None = None, r1: Quantity | float | None = None, U: Quantity | float | None = None, U0: Quantity | float | None = None, Omega: Quantity | float | None = None, model_name: str | None = None, temp_dir: str | Path = 'cloudy_tmp', template: str | Path | None = None, warn: bool = True, fix_quantity: Literal['nII', 'r0', 'r1', 'U', 'U0', 'Omega'] | None = None, r0safety: float = 0.01, cloudy_path: str | Path | None = None, max_workers: int | None = None, overwrite: bool = False, save_temp: bool = False, progress: bool = True, executor: Executor | None = None) → bool | list[bool][source]

Write cloudy input decks for one or more of this file’s own spectra, run cloudy on each of them, and save the results of every successful run into this file’s own cluster_cloudy or galaxy_cloudy group.

Parameters:
  • spec_type ({"cluster", "galaxy"}) – Which kind of spectrum to use.

  • uid (int or list of int, optional) – Unique ID(s) of the cluster spectrum/spectra to use; only meaningful if spec_type is “cluster”. If omitted, every cluster matching time (or every cluster, if time is also omitted) is used.

  • trial (int or list of int, optional) – Trial number(s) of the galaxy spectrum/spectra to use; only meaningful if spec_type is “galaxy”. If omitted, every trial matching time (or every trial, if time is also omitted) is used.

  • time (float, astropy.units.Quantity, or list of either, optional) – Output time(s) to use, in yr if a bare float. If omitted, every output time matching uid/trial (or every output time, if those are also omitted) is used.

  • nII (astropy.units.Quantity or float, optional) – Two of these six must be given to fully specify the physical conditions of the HII region (see hiiregparam); if none are given, nII = 100 cm^-3 and U = 10^-2.5 are used as reasonable defaults.

  • r0 (astropy.units.Quantity or float, optional) – Two of these six must be given to fully specify the physical conditions of the HII region (see hiiregparam); if none are given, nII = 100 cm^-3 and U = 10^-2.5 are used as reasonable defaults.

  • r1 (astropy.units.Quantity or float, optional) – Two of these six must be given to fully specify the physical conditions of the HII region (see hiiregparam); if none are given, nII = 100 cm^-3 and U = 10^-2.5 are used as reasonable defaults.

  • U (astropy.units.Quantity or float, optional) – Two of these six must be given to fully specify the physical conditions of the HII region (see hiiregparam); if none are given, nII = 100 cm^-3 and U = 10^-2.5 are used as reasonable defaults.

  • U0 (astropy.units.Quantity or float, optional) – Two of these six must be given to fully specify the physical conditions of the HII region (see hiiregparam); if none are given, nII = 100 cm^-3 and U = 10^-2.5 are used as reasonable defaults.

  • Omega (astropy.units.Quantity or float, optional) – Two of these six must be given to fully specify the physical conditions of the HII region (see hiiregparam); if none are given, nII = 100 cm^-3 and U = 10^-2.5 are used as reasonable defaults.

  • model_name (str, optional) – Base name for the written input deck(s); defaults to this file’s own output.model_name.

  • temp_dir (str or pathlib.Path, default "cloudy_tmp") – Directory to write the input deck(s) and cloudy’s own output into. A relative path (the default) is resolved against this file’s own directory, not the current working directory, so cloudy’s scratch files never land alongside (or get confused with) the HDF5 output itself; pass an absolute path to place it somewhere else entirely. See save_temp below for whether this directory is kept.

  • template (str or pathlib.Path, optional) – Path to the cloudy input template to use; see write_cloudy_input’s own default.

  • warn (bool, default True) – Passed through to hiiregparam.

  • fix_quantity ({"nII", "r0", "r1", "U", "U0", "Omega"}, optional) – Passed through to hiiregparam.

  • r0safety (float, default 0.01) – Passed through to hiiregparam.

  • cloudy_path (str or pathlib.Path, optional) – Path to the cloudy executable. If omitted, it is looked up as $CLOUDY_DIR/cloudy.exe (see find_cloudy_executable).

  • max_workers (int, optional) – Maximum number of cloudy processes to run at once. Defaults to the number of available CPUs; pass a smaller value to leave some cores free. Ignored if executor is given.

  • overwrite (bool, default False) – By default, a matching spectrum whose id/time and all six hiiregparam values (nII, r0, r1, U, U0, Omega) exactly match an already-stored cluster_cloudy/galaxy_cloudy row is skipped – no deck is written and cloudy is not run for it – and counted as a success, since its data are already stored. Pass True to instead always rerun cloudy for every matching spectrum, replacing any such already-stored row with the new run’s results.

  • save_temp (bool, default False) – By default, temp_dir (input decks, and every file cloudy itself wrote into it) is deleted once every matching spectrum has been processed and its results (if any) written to this file, regardless of whether any individual run succeeded or failed. Pass True to keep temp_dir instead, e.g. to inspect a failed run’s own cloudy output.

  • progress (bool, default True) – Whether to show a progress bar (see slugpy.progress) tracking decks completed. A no-op if every matching spectrum is skipped as an already-stored duplicate (see overwrite above).

  • executor (concurrent.futures.Executor, optional) – An already-running executor to submit this call’s own cloudy runs into, instead of a private max_workers-sized pool of this call’s own (see run_cloudy_decks). Pass this to share one pool’s own worker threads across multiple run_cloudy calls – e.g. concurrent calls on different slug_reader instances for different files, each run from its own driver thread – so an idle worker immediately picks up whichever file’s work is next, rather than each call’s own private pool leaving workers idle once its own matching spectra run out while other files’ work is still queued elsewhere. This call still blocks until every matching spectrum here has completed; executor itself is left running for the caller to manage.

Returns:

Whether each matching spectrum’s cloudy run succeeded: a skipped duplicate (see overwrite above) counts as a success without cloudy having been run at all, and everything else is judged by whether its own captured stdout’s last non-blank line contains “Cloudy exited OK” (see cloudy_run_succeeded). A single bool if exactly one spectrum matched, otherwise a list of bool in the same order as the matched spectra were processed. This call blocks until every matching spectrum’s cloudy run (skipped duplicates aside) has completed.

Return type:

bool or list of bool

Raises:
  • ValueError – If spec_type is “cluster” and trial is given, or spec_type is “galaxy” and uid is given; if no spectrum matches uid/trial/time; if spec_type is “cluster” and no matching cluster is found in the clusters group; or if this file’s own stars.FeH entry (for spec_type “galaxy”) is neither a number nor a PDF file path.

  • RuntimeError – If the cloudy executable cannot be located (see find_cloudy_executable), or if this reader spans more than one underlying HDF5 file (checkpointed and/or h5divided output – see this class’s own docstring): there is no single file to write new cluster_cloudy/galaxy_cloudy rows into in that case, so this refuses up front rather than guessing one.

Notes

For each matching spectrum, the ionizing photon rate Q(HI) is taken directly from this file’s own cluster_phot/galaxy_phot group if it has a “Q(HI)” filter; otherwise it is computed from the spectrum itself via FilterIdeal(“Q(HI)”).phot(). For spec_type “cluster”, [Fe/H] is taken from the matching cluster’s own entry in the clusters group. For spec_type “galaxy”, [Fe/H] is instead the expectation value of this file’s own stars.FeH distribution (or its fixed value, if stars.FeH is not a distribution) – a single population-level value used for every matching galaxy spectrum, since there is no single [Fe/H] value for a galaxy the way there is for a cluster. Cloudy input decks for every matching spectrum are written before any of them are run, and the cloudy executable is located before any decks are written, so a missing executable is reported without writing partial output.

Every successful run’s own physical conditions (nII, r0, r1, U, U0, Omega) and, where its own deck produced one, emergent continuum (wavelength grid plus incident/transmitted/emitted/ transmitted+emitted luminosity) and emission lines (wavelength, 4-character label, and observable luminosity of every line with emergent luminosity above 1e10 erg/s – see read_cloudy_linearr) are appended as new rows to this file’s own cluster_cloudy (spec_type “cluster”) or galaxy_cloudy (spec_type “galaxy”) group, creating it on first use (this reader’s own self._groups is refreshed afterward, so a newly- created group is discoverable through cluster_cloudy/ galaxy_cloudy right away); this only happens if at least one run in this call succeeded, so a call where every run fails leaves the file untouched.

Duplicate detection (and, with overwrite=True, replacement) is keyed on an exact match of id/time and all six hiiregparam values against what’s already stored – not just id/time alone – so the same spectrum rerun with different physical conditions is always treated as a new, independent run rather than a duplicate. With overwrite=True, a matched row is only actually replaced once its own rerun succeeds: a failed rerun leaves the previously-stored row untouched.

temp_dir is only ever deleted if this call actually wrote at least one deck into it – a call where every match was skipped as an already-stored duplicate never creates or touches temp_dir at all.

class slugpy.slug_group_reader.slug_group_reader(file_paths: list[str], group_name: str)[source]

A lazy reader for one group, spread across one or more slug HDF5 output files (see slug_reader’s own docstring for when a group reader spans more than one file: checkpointed and/or h5divided output). Dataset names are read from the first file on construction; each dataset itself is only read from disk the first time it is requested via __getitem__, and attached to its “units” attribute as an astropy Quantity – unless that attribute is an empty string (the dataset has no physical unit, e.g. it’s a dimensionless count, or non-numeric data like a serialized RNG state) or is not a single string at all (e.g. cluster_phot’s phot/phot_extinct datasets, whose “units” attribute is one string per column, since each filter can have its own unit), in which case it is returned as a plain numpy array instead.

Every file is opened only for the duration of each individual read (never held open between calls), so this never holds more than one file open at a time regardless of how many files it spans – see slug_reader’s own docstring for why.

A dataset that spans more than one file is read from every file and concatenated along its own first axis (one row per trial/time, so this is what “every trial from every file, pooled together” means) – but only if the dataset is extensible (an unlimited maximum extent on some axis; see isExtensibleDataset() on the C++ side, which this mirrors exactly): a handful of datasets (e.g. “wl”, “line_wl”, “line_label”) are instead fixed, shared metadata, physically identical in every file a given run produced, and so are read from the first file only, not concatenated – reading a non-extensible dataset from every file and pasting the (identical) copies together would silently produce nonsense (e.g. an N-times duplicated wavelength grid, for N constituent files).

Parameters:
  • file_paths (list of str) – Path(s) to the open slug HDF5 output file(s) containing this group; every one is assumed to share the identical group/ dataset layout (each was built by the same simulation’s own openOutputFile() call, once per checkpoint/thread – see OutputManagerH5’s own header comment).

  • group_name (str) – Name of the group within each file to read.

__getitem__(key: str) → ndarray | Quantity[source]

Return one dataset from this group, as an astropy Quantity.

Parameters:

key (str) – Name of the dataset to return.

Returns:

The requested dataset, read from disk (and cached) on first access: a Quantity if it has a single physical unit, or a plain array if its “units” attribute is absent, empty, or not a single string. Pooled across every one of this reader’s own files if the dataset is extensible (see this class’s own docstring); otherwise read from the first file alone.

Return type:

astropy.units.Quantity or numpy.ndarray

Raises:

KeyError – If key is not one of this group’s dataset names.

__init__(file_paths: list[str], group_name: str) → None[source]
keys() → KeysView[str][source]

Return the names of the datasets available in this group.

Returns:

Names of every dataset in this group, whether or not it has been read from disk yet.

Return type:

KeysView of str

class slugpy.slug_phot_reader.slug_phot_reader(file_paths: list[str], group_name: str, registry_name: str | None = None)[source]

A lazy reader for the cluster_phot group of a slug HDF5 output file. Extends slug_group_reader with per-filter access: indexing by a filter name (e.g. “HST.WFC3_UVIS1.F555W”) returns that filter’s photometry as an astropy Quantity, read from the phot dataset’s column for that filter on first access and cached thereafter. Three suffixes select the same filter’s photometry from a different dataset instead: “_ex” (e.g. “HST.WFC3_UVIS1.F555W_ex”) for the extincted photometry, from phot_extinct; “_neb” for photometry that includes nebular emission, from phot_neb; and “_neb_ex” for nebular emission with extinction also applied, from phot_neb_extinct. phot_neb/ phot_neb_extinct exist only if this file’s own simulation requested nebular emission (see SimControls.nebular); like phot_extinct, they cover only “real” filters, not the synthetic “Lbol” entry phot itself may also carry – requesting a suffixed key for a filter absent from the underlying dataset raises IndexError, not KeyError. Any other key falls through to slug_group_reader’s own __getitem__ (e.g. “trial”, “time”, “uid”).

Parameters:
  • file_paths (list of str) – Path(s) to the open slug HDF5 output file(s) containing this group – see slug_group_reader’s own docstring.

  • group_name (str) – Name of the group within each file to read.

  • registry_name (str, optional) – Name of the filter registry file to resolve tabulated filter names against (see get_filter()); if omitted, uses FilterCollection’s own built-in default registry.

Variables:
  • filters (list of str) – Names of the filters this group has photometry for, in the order used to index the phot/phot_extinct datasets (read-only).

  • filter_units (list of str) – Units of each filter’s photometry, in the same order as filters (read-only).

  • filter_collection (FilterCollection) – A PhotSystem.Vega FilterCollection, initially empty, that get_filter() lazily adds filters to on request (read-only).

__getitem__(key: str) → ndarray | Quantity[source]

Return one filter’s photometry, or fall through to slug_group_reader.__getitem__ for a non-filter key.

Parameters:

key (str) – A filter name (e.g. “HST.WFC3_UVIS1.F555W”); that same name with “_ex”, “_neb”, or “_neb_ex” appended for its extincted, nebular-inclusive, or nebular-inclusive-and- extincted counterpart (e.g. “HST.WFC3_UVIS1.F555W_neb_ex”); or any dataset name from the underlying group (e.g. “trial”, “time”, “uid”).

Returns:

The requested photometry or dataset, read from disk (and cached) on first access.

Return type:

astropy.units.Quantity or numpy.ndarray

Raises:
  • KeyError – If key is neither a known filter name (with or without a trailing “_ex”/”_neb”/”_neb_ex”) nor a dataset name in this group; also if key names a known filter name plus a suffix whose underlying dataset does not exist for this file at all (e.g. “_neb” when this file’s own simulation did not request nebular emission, so there is no phot_neb dataset at all – as opposed to IndexError below, where that dataset exists but has no column for this particular filter).

  • IndexError – If key names a known filter name plus a suffix, but the underlying dataset (phot_extinct/phot_neb/ phot_neb_extinct) has no column for that filter – e.g. the synthetic “Lbol” entry phot itself may carry, which none of the other three datasets cover.

__init__(file_paths: list[str], group_name: str, registry_name: str | None = None) → None[source]
property filter_collection: FilterCollection

a PhotSystem.Vega FilterCollection, initially empty, that get_filter() lazily adds filters to on request (read-only).

Type:

FilterCollection

property filter_units: list[str]

units of each filter’s photometry, in the same order as filters (read-only).

Type:

list of str

property filters: list[str]

names of the filters this group has photometry for, in the order used to index the phot/phot_extinct datasets (read-only).

Type:

list of str

get_filter(filter_name: str) → Filter[source]

Get a Filter object for one of this group’s own filters, constructing (and caching, on filter_collection) it on first request.

Parameters:

filter_name (str) – Name of the filter to get; must be one of this group’s own filters (see filters).

Returns:

The requested filter, as whichever concrete type (FilterIdeal or FilterTabulated) it actually is, from filter_collection.

Return type:

Filter

Raises:
  • KeyError – If filter_name is not one of this group’s own filters.

  • RuntimeError – If filter_name is one of this group’s own filters (e.g. “Lbol”) but does not itself match a recognized tabulated- or idealized-filter naming convention, so it cannot actually be constructed as a Filter.

phot_convert(phot_to: str) → None[source]

Convert every cached filter’s photometry to a new photometric system, in place.

Parameters:

phot_to (str) – The photometric system to convert to: one of “Flambda”, “Fnu”, “ST”, “AB”, or “Vega”.

Notes

Every entry of _phot, _phot_extinct, _phot_neb, and _phot_neb_extinct (whichever of the latter three exist for this file) is read (triggering its usual lazy load from disk, if not already cached) and, if its current unit is one phot_convert.phot_convert() recognizes, replaced with its own conversion to phot_to – so subsequent __getitem__ calls for that filter return the converted value. Entries with a non-photometric unit (Lbol’s Lsun, or an idealized filter’s photon/s) are left untouched, as is any entry already in phot_to’s own system. A conversion that needs a wavelength or a Vega zero point gets it from get_filter(filter_name) – see its own docstring on how (and from where) that filter gets built.

class slugpy.slug_spectra_reader.slug_spectra_reader(file_paths: list[str], group_name: str)[source]

A lazy reader for the cluster_spectra/galaxy_spectra group of a slug HDF5 output file. Extends slug_group_reader with two differences. First, the “line_label” dataset (present only if this file’s own simulation requested nebular emission) is decoded from raw HDF5 bytes into plain Python str, both via the line_labels property and __getitem__(“line_label”), rather than the raw byte-string numpy array slug_group_reader’s own generic __getitem__ would otherwise return. Second, indexing by a (label, wl) pair (e.g. spectra[“HI”, 6563.0]) returns that one specific nebular emission line’s own luminosity from neb_lines, read on first access and cached thereafter, exactly mirroring slug_phot_reader’s own per-filter access; append “_ex” to label (e.g. spectra[“HI_ex”, 6563.0]) for the same line’s extincted luminosity, from neb_lines_extinct, instead – see line_index for why label and wl together, not label alone, identify one specific line. Every plain string key (wl, spec, spec_neb, spec_extinct, spec_neb_extinct, line_wl, neb_lines, neb_lines_extinct, trial, time, uid, …) falls through to slug_group_reader’s own __getitem__ unchanged, letting a caller read every line’s luminosity at once (e.g. spectra[“neb_lines”]) just as easily as one line at a time.

Parameters:
  • file_paths (list of str) – Path(s) to the open slug HDF5 output file(s) containing this group – see slug_group_reader’s own docstring.

  • group_name (str) – Name of the group within each file to read.

Variables:

line_labels (list of str or None) – Label of each of this group’s own nebular emission lines (see neb_lines/neb_lines_extinct), in the same order as line_wl’s own entries and neb_lines/neb_lines_extinct’s own second axis, decoded to plain Python str. None if this file’s own simulation did not request nebular emission (no line_label dataset at all) (read-only). A label identifies the species producing a line (e.g. “HI”), not one specific line – a single species produces many lines at different wavelengths, so several entries can share one label; the (label, wl) pair is unique, which is exactly what line_index(), line_luminosity(), and __getitem__’s own (label, wl)-tuple indexing key on.

__getitem__(key: str | tuple[str, float | Quantity]) → ndarray | Quantity[source]

Return one dataset from this group, one specific nebular emission line’s own luminosity, or the decoded “line_label” array.

Parameters:

key (str, or tuple of (str, float or astropy.units.Quantity)) – A (label, wl) pair (e.g. (“HI”, 6563.0), or equivalently spectra[“HI”, 6563.0] via Python’s own multi-subscript sugar) identifying one specific nebular emission line (see line_index) – label with “_ex” appended (e.g. (“HI_ex”, 6563.0)) selects that same line’s extincted luminosity instead. Otherwise, a dataset name: “line_label” (decoded, see line_labels), or any other name from the underlying group (e.g. “wl”, “spec”, “neb_lines”, “trial”).

Returns:

A (label, wl) key returns that line’s own luminosity across every stored trial/time, from neb_lines (or neb_lines_extinct, for a label ending “_ex”), read on first access and cached thereafter – see line_luminosity’s own identical return value. “line_label” returns a numpy array of the same decoded strings as line_labels. Every other string key falls through to slug_group_reader’s own __getitem__.

Return type:

astropy.units.Quantity or numpy.ndarray

Raises:

KeyError – For a (label, wl) key: see line_index’s own docstring. For a string key: if key is not one of this group’s dataset names.

__init__(file_paths: list[str], group_name: str) → None[source]
line_index(label: str, wl: float | Quantity) → int[source]

Find the position of one specific nebular emission line.

Parameters:
  • label (str) – Species label producing this line (see line_labels) – not unique on its own, since one species produces many lines at different wavelengths.

  • wl (float or astropy.units.Quantity) – Wavelength of this line, in Angstrom if a bare float, matched against line_wl to within a relative tolerance of 1e-9 (see this class’s own line_labels docstring for why label and wl together, not label alone, identify one specific line; the tolerance accommodates float rounding from converting a Quantity given in a different unit, not genuine ambiguity between two close-but-distinct lines).

Returns:

Index into line_wl/line_labels, and the second axis of neb_lines/neb_lines_extinct, for the line matching both label and wl.

Return type:

int

Raises:

KeyError – If this group has no nebular line data at all (line_labels is None), or no line matches both label and wl.

property line_labels: list[str] | None

label of each of this group’s own nebular emission lines, decoded to plain Python str, or None if this file’s own simulation did not request nebular emission (read-only).

Type:

list of str or None

line_luminosity(label: str, wl: float | Quantity, extinct: bool = False) → ndarray | Quantity[source]

Get one nebular emission line’s own luminosity, across every stored trial/time.

A named, more discoverable alternative to indexing directly with a (label, wl) tuple (see __getitem__) – both call the same underlying lookup, so e.g. spectra.line_luminosity(“HI”, 6563.0) and spectra[“HI”, 6563.0] are exactly equivalent.

Parameters:
  • label (str) – Species label producing this line (see line_index).

  • wl (float or astropy.units.Quantity) – Wavelength of this line, in Angstrom if a bare float (see line_index).

  • extinct (bool, default False) – If True, return the extincted luminosity from neb_lines_extinct instead of neb_lines.

Returns:

neb_lines[:, i] (or neb_lines_extinct[:, i] if extinct is True), where i is line_index(label, wl).

Return type:

astropy.units.Quantity

Raises:

KeyError – See line_index’s own docstring. Also raised if extinct is True but this group has no neb_lines_extinct dataset (no extinction curve was requested for this simulation).

class slugpy.slug_yields_reader.slug_yields_reader(file_paths: list[str], group_name: str, registry_name: str | None = None)[source]

A lazy reader for the cluster_yields/galaxy_yields group of a slug HDF5 output file. Extends slug_group_reader with per-isotope access: indexing by an isotope name (e.g. “Fe56”, matched case- insensitively and with or without a space before the mass number – see __getitem__’s own docstring) returns that isotope’s yield, read from the yields dataset’s own column(s) for that isotope on first access and cached thereafter. If this group’s own decomposed attribute is True, indexing can instead take a (channel, model, isotope) triple, letting a caller select just the channel(s) and/or model(s) it wants rather than every channel the isotope was tabulated for. A string key naming one of this group’s own raw dataset names (e.g. “trial”, “time”, “uid”, “yields”) falls through to slug_group_reader’s own __getitem__ instead, mirroring slug_phot_reader’s identical fallback for a non-filter key.

Parameters:
  • file_paths (list of str) – Path(s) to the open slug HDF5 output file(s) containing this group – see slug_group_reader’s own docstring.

  • group_name (str) – Name of the group within each file to read.

  • registry_name (str, optional) – Accepted for signature parity with slug_phot_reader; currently unused, since nothing here resolves a name against a yield registry the way slug_phot_reader.get_filter() does against a filter registry.

Variables:
  • isotopes (list of str) – Names of the isotopes this group has yields for (e.g. “H1”, “Fe56”), in the order used to index the yields dataset’s own isotope axis (read-only).

  • channels (list of str) – Which nucleosynthetic channel (e.g. “ccsn”) each entry of models below came from, in the same order as the yields dataset’s own channel axis – meaningful only if decomposed is True (read-only).

  • models (list of str) – Which yield model (e.g. “sukhbold16”) was used for each channel entry above, same order (read-only).

  • decomposed (bool) – Whether the yields dataset’s own columns are broken out one (channel, isotope) pair at a time (True) or summed over every channel, one column per isotope (False) – see __getitem__’s own docstring for how this changes what a key means (read-only).

__getitem__(key: str | Sequence[str]) → ndarray | Quantity[source]

Return one isotope’s yield, selecting a subset of channels/ models if decomposed and key names them.

Parameters:

key (str or sequence of 3 str) –

A string key naming one of this group’s own raw dataset names (e.g. “trial”, “time”, “uid”, “yields”) falls through to slug_group_reader.__getitem__ instead of being treated as an isotope name – mirrors slug_phot_reader’s own identical fallback for a non-filter key.

Otherwise, if decomposed is False, must be a bare isotope name (see _resolve_isotope for the accepted spellings); the returned Quantity is 1D, one entry per trial/time, summed over every channel.

If decomposed is True, key can either be:

  • A bare isotope name, in which case the full 2D array (one row per trial/time, one column per channel, in the same order as channels/models) is returned.

  • A (channel, model, isotope) triple of strings, in which case channel/model are matched against this group’s own channels/models – an empty string (“”) for either matches every channel/model – and only the matching columns are returned: a 1D array if exactly one channel matches, otherwise a 2D array (one row per trial/time, one column per match, in channels/models order).

Returns:

The requested yield, in Msun, read from disk (and cached, keyed by isotope) on first access.

Return type:

astropy.units.Quantity

Raises:
  • TypeError – If decomposed is False and key is not a string, or if key is neither a string nor a sequence of exactly 3 strings.

  • KeyError – If key (or key[2], for a triple) does not match any entry of isotopes (see _resolve_isotope); or key is a triple whose (channel, model) does not match any entry of channels/models.

__init__(file_paths: list[str], group_name: str, registry_name: str | None = None) → None[source]
property channels: list[str]

which nucleosynthetic channel each entry of models came from, same order (read-only).

Type:

list of str

property decomposed: bool

whether the yields dataset’s own columns are broken out one (channel, isotope) pair at a time (True) or summed over every channel (False) – see __getitem__’s own docstring (read-only).

Type:

bool

property isotopes: list[str]

names of the isotopes this group has yields for, in the order used to index the yields dataset’s own isotope axis (read-only).

Type:

list of str

property models: list[str]

which yield model was used for each channel entry, same order as channels (read-only).

Type:

list of str

Running Cloudy (slugpy.cloudy)

slugpy.cloudy: interface between slug and the cloudy photoionization code.

Pure-Python additions related to running cloudy on slug spectra and ingesting its output live in their own modules under this subpackage.

copyright:

Copyright (c) 2026 Mark Krumholz

class slugpy.cloudy.CloudyRunResult(id_val: int, time: float, nII: Quantity, r0: Quantity, r1: Quantity, U: Quantity, U0: Quantity, Omega: Quantity, continuum: tuple[Quantity, Quantity, Quantity, Quantity, Quantity] | None, lines: tuple[Quantity, list[str], Quantity] | None)[source]

The result of one successfully-completed cloudy run, ready to be written into a slug HDF5 output file’s cluster_cloudy/galaxy_cloudy group.

Variables:
  • id_val (int) – uid (cluster mode) or trial (galaxy mode) this run belongs to.

  • time (float) – Output time, in yr.

  • Omega (nII, r0, r1, U, U0,) – The physical conditions of the HII region used for this run (see hiiregparam).

  • continuum (tuple of astropy.units.Quantity, optional) – (wl, inc, trans, emit, trans_emit), as returned by read_cloudy_continuum, or None if this run’s deck had no “save last continuum” output.

  • lines (tuple, optional) – (line_wl, line_label, line_lum), as returned by read_cloudy_linearr, or None if this run’s deck had no “save last line array” output.

__init__(id_val: int, time: float, nII: Quantity, r0: Quantity, r1: Quantity, U: Quantity, U0: Quantity, Omega: Quantity, continuum: tuple[Quantity, Quantity, Quantity, Quantity, Quantity] | None, lines: tuple[Quantity, list[str], Quantity] | None) → None
slugpy.cloudy.cloudy_run_succeeded(out_path: str | Path) → bool[source]

Determine whether a cloudy run completed successfully.

Parameters:

out_path (str or pathlib.Path) – Path to the file cloudy’s own stdout/stderr were captured into (see run_cloudy_deck).

Returns:

True if the last non-blank line of out_path contains “Cloudy exited OK” (cloudy’s own success message, e.g. “[Stop in cdMain at maincl.cpp:590, Cloudy exited OK]”), False otherwise – including if out_path doesn’t exist or is empty.

Return type:

bool

slugpy.cloudy.find_cloudy_executable(cloudy_path: str | Path | None = None) → Path[source]

Locate the cloudy executable.

Parameters:

cloudy_path (str or pathlib.Path, optional) – Explicit path to the cloudy executable. If omitted, the executable is looked up as $CLOUDY_DIR/cloudy.exe.

Returns:

Absolute path to the cloudy executable.

Return type:

pathlib.Path

Raises:

RuntimeError – If cloudy_path is omitted and the CLOUDY_DIR environment variable is not set, or if the resolved path is not an executable file.

class slugpy.cloudy.hiiregparam(qH0: Quantity, nII: Quantity | None = None, r0: Quantity | None = None, r1: Quantity | None = None, U: Quantity | float | None = None, U0: Quantity | float | None = None, Omega: Quantity | float | None = None, t: Quantity | None = None, n0: Quantity | None = None, warn: bool = True, fix_quantity: Literal['nII', 'r0', 'r1', 'U', 'U0', 'Omega'] | None = None, r0safety: float = 0.01)[source]

Derive the physical parameters of an HII region from any two of them.

Parameters:
  • qH0 (astropy.units.Quantity) – Ionizing luminosity of the exciting stars, in photons/s (or any equivalent rate).

  • nII (astropy.units.Quantity, optional) – Number density of H nuclei, convertible to cm^-3.

  • r0 (astropy.units.Quantity, optional) – Inner radius, convertible to cm.

  • r1 (astropy.units.Quantity, optional) – Outer radius, convertible to cm.

  • U (astropy.units.Quantity or float, optional) – Volume-averaged ionization parameter (dimensionless).

  • U0 (astropy.units.Quantity or float, optional) – Ionization parameter at the inner radius (dimensionless).

  • Omega (astropy.units.Quantity or float, optional) – Wind parameter (dimensionless).

  • t (astropy.units.Quantity, optional) – HII region age, convertible to Myr; if set, n0 and Omega must be set also, and r1 is derived from the Krumholz & Matzner (2009) expansion solution (see rKM()) rather than being one of the two parameters below.

  • n0 (astropy.units.Quantity, optional) – Number density of H nuclei in the medium the HII region is expanding into, convertible to cm^-3; if set, t and Omega must be set also.

  • warn (bool, default True) – If True, warn and correct if the input parameter values are outside the physically allowed range; if False, raise ValueError instead.

  • fix_quantity ({"nII", "r0", "r1", "U", "U0", "Omega"}, optional) – If warn is True, which quantity to adjust to bring the inputs into the allowed range; only used for the pairs where an out-of-range combination is actually possible (nII+U, r1+nII, r1+U, U+U0, and the r0 >= r1 ordering check).

  • r0safety (float, default 0.01) – If nonzero, a fractional margin of safety of this size is added when correcting quantities, to avoid landing exactly at the physical boundary (e.g. r0 = 0 or Omega = 0).

Variables:
  • nII (astropy.units.Quantity) – Number density of H nuclei, in cm^-3.

  • r0 (astropy.units.Quantity) – Inner radius, in cm.

  • r1 (astropy.units.Quantity) – Outer radius, in cm.

  • U (astropy.units.Quantity) – Volume-averaged ionization parameter (dimensionless).

  • U0 (astropy.units.Quantity) – Ionization parameter at the inner radius (dimensionless).

  • Omega (astropy.units.Quantity) – Wind parameter (dimensionless).

Notes

Upon instantiation, the caller must set either (1) exactly two of the six parameters (nII, r0, r1, U, U0, Omega) – all pairwise combinations are allowed except (r0, U) and (r1, U0), neither of which defines a unique solution – or (2) the combination (t, n0, Omega).

Internally, every combination is solved by first deriving the canonical pair (nII, Omega); every other quantity is then computed from that pair via a small set of directly-verified formulas. This keeps every one of the 13 valid combinations mutually consistent with each other by construction, rather than relying on a separate closed-form shortcut for each pair.

References

The wind-driven HII region model (the relations among nII, r0, r1, U, U0, and Omega) is from Krumholz et al. (2015, MNRAS, 452, 1447): http://adsabs.harvard.edu/abs/2015MNRAS.452.1447K.

The characteristic radius/timescale used by rch(), zeta(), and rKM() is from Krumholz & Matzner (2009, ApJ, 703, 1352): https://ui.adsabs.harvard.edu/abs/2009ApJ…703.1352K/abstract.

property Omega: Quantity

wind parameter (dimensionless).

Type:

astropy.units.Quantity

property U: Quantity

volume-averaged ionization parameter (dimensionless).

Type:

astropy.units.Quantity

property U0: Quantity

ionization parameter at the inner radius (dimensionless).

Type:

astropy.units.Quantity

__init__(qH0: Quantity, nII: Quantity | None = None, r0: Quantity | None = None, r1: Quantity | None = None, U: Quantity | float | None = None, U0: Quantity | float | None = None, Omega: Quantity | float | None = None, t: Quantity | None = None, n0: Quantity | None = None, warn: bool = True, fix_quantity: Literal['nII', 'r0', 'r1', 'U', 'U0', 'Omega'] | None = None, r0safety: float = 0.01) → None[source]
property nII: Quantity

number density of H nuclei, in cm^-3.

Type:

astropy.units.Quantity

property r0: Quantity

inner radius, in cm.

Type:

astropy.units.Quantity

property r1: Quantity

outer radius, in cm.

Type:

astropy.units.Quantity

rKM(t: Quantity, n: Quantity) → Quantity[source]

Compute the Krumholz & Matzner (2009) HII region expansion radius.

Parameters:
  • t (astropy.units.Quantity) – HII region age, convertible to Myr.

  • n (astropy.units.Quantity) – Number density of the medium the HII region is expanding into, convertible to cm^-3.

Returns:

The radius predicted by Krumholz & Matzner (2009) for an HII region of age t expanding into a medium of density n, in cm.

Return type:

astropy.units.Quantity

rS() → Quantity[source]

Compute the Stromgren radius.

Returns:

The Stromgren radius, in cm.

Return type:

astropy.units.Quantity

rch() → Quantity[source]

Compute the Krumholz & Matzner (2009) characteristic radius.

Returns:

r_ch, in cm – the radius inside which radiation pressure is dynamically significant.

Return type:

astropy.units.Quantity

zeta() → Quantity[source]

Compute the Krumholz & Matzner (2009) zeta parameter.

Returns:

zeta = r_ch / r1 (dimensionless). Values of zeta >> 1 imply that radiation pressure is dynamically significant.

Return type:

astropy.units.Quantity

slugpy.cloudy.read_cloudy_continuum(path: str | Path) → tuple[Quantity, Quantity, Quantity, Quantity, Quantity][source]

Read a cloudy continuum output, produced by a “save last continuum” command in the input deck.

Parameters:

path (str or pathlib.Path) – Path to the continuum output file.

Returns:

  • wl (astropy.units.Quantity) – Wavelength, in Angstrom, ascending.

  • inc, trans, emit, trans_emit (astropy.units.Quantity) – Incident, transmitted, emitted, and transmitted+emitted continuum luminosity, in erg/s/Angstrom, each the same length and in the same order as wl.

Notes

Cloudy’s own continuum file has one header line (starting with “#”, automatically skipped, along with any other comment lines) followed by one row per grid point: photon energy in Rydberg, then incident/transmitted/DiffOut/net-transmitted as nu*L_nu (erg/s), in that column order, plus additional columns this function ignores. Energy increases monotonically down the file, i.e. wavelength decreases, so rows are reversed to return an ascending-wavelength grid. nu*L_nu is converted to L_lambda via L_lambda = (nu*L_nu) / wl, which is exact once wl is already expressed in the same length unit (Angstrom) the result is wanted in.

slugpy.cloudy.read_cloudy_linearr(path: str | Path) → tuple[Quantity, list[str], Quantity][source]

Read a cloudy line array output, produced by a “save last line array” command in the input deck.

Parameters:

path (str or pathlib.Path) – Path to the line array output file.

Returns:

  • line_wl (astropy.units.Quantity) – Wavelength of each kept line, in Angstrom.

  • line_label (list of str) – Human-readable element-symbol-plus-Roman-numeral label identifying each kept line, translated from cloudy’s own 4-character mnemonic (e.g. “H 1” -> “HI”, “S 3” -> “SIII”) – see MAX_LINE_LABEL_LENGTH for the longest such label this can produce.

  • line_lum (astropy.units.Quantity) – Emergent (observable) luminosity of each kept line, in erg/s.

Notes

Cloudy’s own line array file is tab-separated, with one header line (skipped) followed by one row per entry: wavelength [Angstrom], a combined field whose first 9 characters are a fixed-width line label (a 4-character mnemonic followed by 5 characters that are blank for the line’s own total, or otherwise identify which physical process this row is one contribution to), log10(intrinsic luminosity) [erg/s], log10(emergent luminosity) [erg/s], and a (largely undocumented) type code this function ignores.

An entry is kept only if (1) its label’s last 5 characters are all blank – i.e. it’s the line’s own total, not one physical process’s contribution to it – (2) its 4-character mnemonic matches the true atomic-line form “XXNN” (element symbol followed by ionization stage; see _MNEMONIC_RE), excluding cloudy’s own pseudo-lines (band/flux aggregates it also reports in the same file, under labels that don’t take this form), and (3) its emergent luminosity exceeds 1e10 erg/s, which excludes physically negligible lines. A kept row’s mnemonic is then translated into a human-readable label: its first two characters (the element symbol, stripped of any padding space) unchanged, followed directly (no separator) by its last two characters (the ionization stage) converted to a Roman numeral – e.g. cloudy’s “H 1” becomes “HI”, and “S 3” becomes “SIII”.

slugpy.cloudy.run_cloudy_deck(input_path: str | Path, cloudy_exe: str | Path) → Path[source]

Run cloudy on a single input deck.

Parameters:
  • input_path (str or pathlib.Path) – Path to the cloudy input deck to run (as written by write_cloudy_input).

  • cloudy_exe (str or pathlib.Path) – Path to the cloudy executable to run (see find_cloudy_executable).

Returns:

Path to the file that cloudy’s own stdout/stderr were captured into: input_path with its suffix replaced by “.out”. Cloudy’s own output files (e.g. .con/.linearr, as requested by the input deck’s own “save” commands) are written alongside input_path, since cloudy is run with input_path’s own parent directory as its working directory.

Return type:

pathlib.Path

Notes

cloudy is invoked with the input deck piped in on stdin (cloudy.exe < deck.in), not as a command-line argument – passing it as an argument causes cloudy to double-prefix its own output filenames.

slugpy.cloudy.run_cloudy_decks(input_paths: Sequence[str | Path], cloudy_exe: str | Path, max_workers: int | None = None, progress: bool = True, executor: Executor | None = None) → list[Path][source]

Run cloudy concurrently on multiple input decks.

Parameters:
  • input_paths (sequence of str or pathlib.Path) – Paths to the cloudy input decks to run.

  • cloudy_exe (str or pathlib.Path) – Path to the cloudy executable to run (see find_cloudy_executable).

  • max_workers (int, optional) – Maximum number of cloudy processes to run at once. Defaults to the number of available CPUs. Ignored if executor is given.

  • progress (bool, default True) – Whether to show a progress bar (see slugpy.progress) tracking decks completed. A no-op if input_paths is empty.

  • executor (concurrent.futures.Executor, optional) – An already-running executor to submit this call’s own runs into, instead of creating (and, once this call returns, shutting down) a private max_workers-sized ThreadPoolExecutor. Pass this to share one pool’s own worker threads across multiple run_cloudy_decks calls – e.g. several slug_reader.run_cloudy calls for different files, run concurrently from different driver threads – so an idle worker immediately picks up whichever call’s work is next, rather than each call’s own private pool leaving workers idle once its own input_paths run out while other calls’ work is still queued elsewhere. This call still blocks until its own input_paths have all completed; executor itself is left running for the caller to manage.

Returns:

The path each deck’s own captured stdout/stderr was written to (see run_cloudy_deck), in the same order as input_paths.

Return type:

list of pathlib.Path

Notes

Runs are dispatched onto a concurrent.futures.ThreadPoolExecutor rather than a ProcessPoolExecutor: each worker just blocks on an external cloudy subprocess and releases the GIL while doing so, so threads are enough, and avoid the pickling overhead of processes. At most max_workers decks run at once; as each finishes, the next queued one is launched, until all of input_paths have been run.

slugpy.cloudy.write_cloudy_h5_results(h5_path: str | Path, group_name: str, id_key: str, results: Sequence[CloudyRunResult]) → None[source]

Append cloudy run results to an HDF5 file’s own cluster_cloudy or galaxy_cloudy group, creating the group (and its datasets) if this is the first time it’s been written to.

Parameters:
  • h5_path (str or pathlib.Path) – Path to the slug HDF5 output file to write into. Opened and closed by this function – the caller is responsible for not holding its own handle to the same file open at the same time.

  • group_name (str) – Name of the group to write into: “cluster_cloudy” or “galaxy_cloudy”.

  • id_key (str) – Name of the id dataset: “uid” or “trial”.

  • results (sequence of CloudyRunResult) – The results to append, one row per entry. A no-op if empty.

Notes

Each result becomes one row in id_key/time/nII/r0/r1/U/U0/Omega, all extensible 1-D datasets. If any result (in this call, or from an earlier one) has continuum data, the group also gets wl (the shared wavelength grid) and spec_inc/spec_trans/spec_emit/ spec_trans_emit (one row per result, aligned with the datasets above – results with no continuum of their own get an all-zero row). Cloudy’s own continuum grid always shares the same maximum wavelength and grid spacing across runs, but the minimum wavelength can vary; if a result’s own grid is shorter than what’s already stored, its row is zero-padded at the low-wavelength end to align with the stored (longer) grid. If a result’s grid is instead longer than what’s already stored, the wavelength grid and every already-stored row are rewritten to the new, longer grid (zero-padded the same way) before appending.

If any result (in this call, or an earlier one) has line data, the group also gets line_wl and line_label (the shared, ascending- sorted list of every distinct line wavelength seen from any result with line data, one label per wavelength) and line_lum (one row per result, aligned with the datasets above, giving that result’s own luminosity at every wavelength in line_wl – zero at any wavelength that result’s own run didn’t report, including an all-zero row for a result with no line data of its own). Different cloudy runs need not report the same set of lines, so – exactly like the wavelength grid in _grow_wavelength_grid – if a result’s own lines include a wavelength not already in line_wl, line_wl (and every already-stored line_lum row) is grown and remapped onto the new, merged wavelength list before appending.

slugpy.cloudy.write_cloudy_input(wl: Quantity, spec: Quantity, qH0: Quantity, hp: hiiregparam, feh: float, output_path: str | Path, template: str | Path | None = None) → Path[source]

Write a cloudy input deck for a single spectrum.

Parameters:
  • wl (astropy.units.Quantity) – Wavelength grid of the spectrum, convertible to Angstrom.

  • spec (astropy.units.Quantity) – The spectrum itself, convertible to erg/s/Angstrom, on the same grid as wl.

  • qH0 (astropy.units.Quantity) – Ionizing photon rate of the spectrum, in photons/s (or any equivalent rate) – normally the same value used to construct hp.

  • hp (hiiregparam) – The physical conditions of the HII region – only nII and r0 are actually used (as the “hden”/”radius” commands).

  • feh (float) – [Fe/H] of the stellar population, used to set the nebular metallicity via cloudy’s own “metals and grains” command (which wants a metallicity relative to Solar, not a log value, so this writes 10**feh).

  • output_path (str or pathlib.Path) – Path to write the cloudy input deck to. cloudy’s own output files (named by substituting $OUTPUT_FILENAME in the template) use output_path’s own stem (no directory, no extension), so cloudy should be run with its working directory set to output_path’s own parent.

  • template (str or pathlib.Path, optional) – Path to the cloudy input template to use; defaults to DEFAULT_TEMPLATE (data/cloudy/cloudy.in_grid_template).

Returns:

output_path, for convenience chaining.

Return type:

pathlib.Path

Notes

Follows examples/cloudy_slug/cloudy_slug.py’s own historical approach (from slug2) for writing the physical-condition commands and the spectral shape: the template is copied through verbatim (substituting $OUTPUT_FILENAME), then hden/radius/metals and grains/Q(H) commands are appended, followed by the spectrum itself as an “interpolate”/”continue” table in log10(frequency [Hz]), log10(L_nu [erg/s/Hz]) pairs, padded at both ends with a flux floor so cloudy treats everything outside the spectrum’s own wavelength range as negligible rather than undefined. The floor is set per padding frequency so that nu*L_nu there – the actual characteristic energy at that frequency, not L_nu alone – is 4 dex below the real spectrum’s own minimum nu*L_nu; a frequency-independent L_nu floor would leave nu*L_nu at the padding points (~6 dex in frequency from the real data) large enough to dominate the total energy budget.

slugpy.cloudy.cloudy_input.DEFAULT_TEMPLATE: Path

Path to the default cloudy input template bundled with slug (data/cloudy/cloudy.in_grid_template), which write_cloudy_input() uses when no template is given. Its location in a source checkout vs. a pip-installed copy is resolved by _default_template().

The Compiled Core (slugpy._slug)

Every class and function listed here is also importable directly from slugpy itself (e.g. slugpy.SimControls, not just slugpy._slug.SimControls).

slug Python frontend (compiled extension; see the slugpy package for the public interface)

class slugpy._slug.Cluster

A single, coeval (mono-age) star cluster.

A Cluster is formed instantaneously, with a target mass and a set of stellar masses drawn from the IMF, then evolved forward in time via advance(), which updates its living/dead stellar masses, spectrum, photometry, and bolometric luminosity as the population ages.

__init__(self: slugpy._slug.Cluster, mass: SupportsFloat | SupportsIndex, uid: SupportsInt | SupportsIndex = 0, time: SupportsFloat | SupportsIndex = 0.0, controls: object = None, rng_state: object = None) → None

Construct a Cluster.

Parameters:
  • mass (float) – Target cluster mass, in Msun.

  • uid (int, optional) – Unique identifier for this cluster. Defaults to 0.

  • time (float, optional) – Cluster formation time, in yr. Defaults to 0.

  • controls (SimControls, optional) – Simulation controls (physics settings and control-flow settings together); controls must outlive this Cluster, and every value this Cluster reads from it (e.g. its integrator tolerances) is read live, not snapshotted, so changing controls after this Cluster is built takes effect immediately. Defaults to slug’s own shared, bundled-default SimControls (built from src/pybind/assets/PyDefaults.toml the first time it is needed, and reused after that – see SimControls()’s own default path), letting a caller do e.g. cl = slug.Cluster(1e3) without building a SimControls at all.

  • rng_state (bytes, optional) – Serialized pcg64 rng state (see Cluster.rngState() in the C++ API; from Python, typically a value previously read back from an output file’s clusters/rng dataset) to draw this cluster’s star masses (and feh/aV, if applicable) from, in place of the live rng stream – so the resulting starMasses()/birthMass() come out bitwise identical to whatever cluster originally produced this state. If omitted, mass/feh/aV are all drawn live instead, as normal.

Raises:

RuntimeError – If rng_state is longer than the fixed-width buffer a serialized rng state is stored in (128 bytes) – in practice, only possible if rng_state did not actually come from a previous Cluster’s own rngState().

advance(self: slugpy._slug.Cluster, t: SupportsFloat | SupportsIndex) → None

Advance the cluster in time.

Parameters:

t (float) – Time to which to advance, in yr.

birthMass(self: slugpy._slug.Cluster) → float

Return the cluster’s actual mass at birth.

Returns:

birth_mass – Actual cluster mass at birth, in Msun.

Return type:

float

deadStarDeathTimes(self: slugpy._slug.Cluster) → list[float]

Return the death times of stars that died in the most recent advance() call.

Returns:

death_times – Death time of each entry of deadStarMasses(), in the same order.

Return type:

list of float

deadStarMasses(self: slugpy._slug.Cluster) → list[float]

Return the list of dead stellar masses.

Returns:

masses – Masses of dead stars, in Msun.

Return type:

list of float

feH(self: slugpy._slug.Cluster) → float

Return the cluster’s [Fe/H].

Returns:

feh

Return type:

float

formTime(self: slugpy._slug.Cluster) → float

Return the cluster’s formation time.

Returns:

form_time – Cluster formation time, in yr.

Return type:

float

isDisrupted(self: slugpy._slug.Cluster) → bool

Return whether the cluster has disrupted.

Returns:

disrupted

Return type:

bool

lbol(self: slugpy._slug.Cluster) → float

Return the cluster’s bolometric luminosity.

Returns:

lbol – The population’s total bolometric luminosity, in Lsun, at the current time, or 0 if no bolometric luminosity has ever been computed (SimControls.computeLbol() is False).

Return type:

float

phot(self: slugpy._slug.Cluster) → list[float]

Return the cluster’s photometry.

Returns:

phot – The photometric value computed from spec() by each filter in SimControls.filters(), in the same order as FilterCollection.filterNames()/filterUnits(), or an empty list if no filter collection was requested (SimControls.filters() is None).

Return type:

list of float

spec(self: slugpy._slug.Cluster) → list[float]

Return the cluster’s continuously-sampled spectrum.

Returns:

spec – The spectrum of the non-stochastically-sampled part of the population, on the wavelength grid of the simulation’s spectral synthesizer, or an empty list if no spectral synthesizer was requested.

Return type:

list of float

starDeathTimes(self: slugpy._slug.Cluster) → list[float]

Return the death time of every currently-alive star.

Returns:

death_times – Death time of each entry of starMasses(), in the same order – not, in general, starMasses()’s own order (both are kept sorted together by death time internally, not by mass).

Return type:

list of float

starMasses(self: slugpy._slug.Cluster) → list[float]

Return the current list of living stellar masses.

Returns:

masses – Masses of currently alive stars, in Msun.

Return type:

list of float

targetMass(self: slugpy._slug.Cluster) → float

Return the cluster’s target mass.

Returns:

target_mass – Target cluster mass, in Msun.

Return type:

float

tracks(self: slugpy._slug.Cluster) → slugpy._slug.Tracks2D

Return the stellar tracks at this cluster’s [Fe/H].

Returns:

tracks

Return type:

Tracks2D

uid(self: slugpy._slug.Cluster) → int

Return the cluster’s unique identifier.

Returns:

uid

Return type:

int

class slugpy._slug.Extinct

A dust extinction curve, interpolated onto its SimControls’s own spectral-synthesis wavelength grid.

Built from a named curve in an extinction curve registry. The curve is normalized so that a V-band extinction of A_V = 1 mag corresponds to its own native shape; only the shape matters, since a caller scales it by whatever A_V is actually applied.

__init__(self: slugpy._slug.Extinct, extinct_name: str, controls: object = None, registry_name: str = 'data/extinct/extinct.toml') → None

Construct an Extinct from a named registry entry.

Parameters:
  • extinct_name (str) – Name of the extinction curve to load (e.g. “Calzetti_starburst”).

  • controls (SimControls, optional) – Simulation controls this Extinct reads its wavelength grid (controls.specsyn.wl, which controls.specsyn must therefore provide), redshift (see wlObs()), and, if a nebular emission grid was requested (SimControls.nebular), its field-star A_V distribution (SimControls.avDistField) from, live, for the rest of its lifetime. If None (the default), uses slug’s own shared, bundled-default SimControls (built from src/pybind/assets/PyDefaults.toml the first time it is needed, and reused after that – see SimControls()’s own default path), rather than a minimal, all-C++-defaults one: unlike most other classes’ own optional controls argument, Extinct always needs a real spectral synthesizer to provide a wavelength grid, which a minimal SimControls does not have.

  • registry_name (str, optional) – Path to the extinction curve registry file. Default is the package’s default registry (data/extinct/extinct.toml).

Raises:

RuntimeError – If extinct_name is not found in the registry, the registry/HDF5 file cannot be read, or controls.specsyn is None.

applyExtinction(self: slugpy._slug.Extinct, A_V: SupportsFloat | SupportsIndex, spec: collections.abc.Sequence[SupportsFloat | SupportsIndex]) → list[float]

Apply this extinction curve to a spectrum.

Parameters:
  • A_V (float) – V-band extinction to apply, in magnitudes.

  • spec (list of float) – Spectrum to extinguish, tabulated on exactly this Extinct’s own SimControls.specsyn.wl.

Returns:

spec_ext – The extinguished spectrum, on the wavelength grid returned by wl(). spec’s first wlOffset() elements (falling outside this curve’s own wavelength coverage) are discarded; each remaining element is multiplied by exp(-A_V * extinct()) at the corresponding wavelength.

Return type:

list of float

applyExtinctionCts(self: slugpy._slug.Extinct, spec: collections.abc.Sequence[SupportsFloat | SupportsIndex], nebular: bool = False) → list[float]

Apply this extinction curve’s own expected attenuation to a continuously-distributed population’s spectrum.

Unlike applyExtinction(), which attenuates a single star (or cluster) with one known A_V, this is for a population whose members are not individually tracked, so there is no single A_V to apply – instead, each element of spec is multiplied by the expectation value of exp(-A_V * extinct()) over the field-star A_V distribution (SimControls.avDistField). If nebular is True, the expectation value is instead of exp(-A_V f * extinct()), over both that distribution and the nebular-to-stellar extinction ratio f (SimControls.avNebFac).

Parameters:
  • spec (list of float) – Spectrum to extinguish, tabulated on exactly this Extinct’s own SimControls.specsyn.wl – see applyExtinction()’s own spec parameter.

  • nebular (bool, optional) – Whether spec is nebular emission, to be extinguished by the nebular extinction (see above) rather than the stellar one. Defaults to False.

Returns:

spec_ext – The expected extinguished spectrum, on the wavelength grid returned by wl().

Return type:

list of float

applyExtinctionCtsLines(self: slugpy._slug.Extinct, line_lum: collections.abc.Sequence[SupportsFloat | SupportsIndex]) → list[float]

Apply this extinction curve’s own expected attenuation to a continuously-distributed population’s line luminosities.

Line-luminosity analog of applyExtinctionCts() – see its own docstring; each element of line_lum is multiplied by the expectation value of exp(-A_V f * extinctLines) over the field-star A_V distribution (SimControls.avDistField) and the nebular-to-stellar extinction ratio f (SimControls.avNebFac), since lines are always nebular emission.

Parameters:

line_lum (list of float) – Luminosity of each line, in erg/s – see applyExtinctionLines()’s own line_lum parameter.

Returns:

line_lum_ext – The expected extinguished line luminosities, in the same order as line_lum.

Return type:

list of float

applyExtinctionLines(self: slugpy._slug.Extinct, A_V: SupportsFloat | SupportsIndex, line_lum: collections.abc.Sequence[SupportsFloat | SupportsIndex]) → list[float]

Apply this extinction curve to a set of nebular emission line luminosities.

Parameters:
  • A_V (float) – V-band extinction to apply, in magnitudes.

  • line_lum (list of float) – Luminosity of each of this Extinct’s own SimControls’s nebular emission grid’s lines, in erg/s. Pass an empty list (getting back an empty result) if that SimControls has no nebular emission grid (its nebular property is None).

Returns:

line_lum_ext – The extinguished line luminosities, in the same order as line_lum. Unlike applyExtinction(), no elements are dropped: a line outside the native curve’s own wavelength coverage reads an extinction of 0 (no attenuation) rather than being excluded.

Return type:

list of float

extinct(self: slugpy._slug.Extinct) → list[float]

Get the interpolated extinction curve.

Returns:

extinct – Extinction curve, in arbitrary units, interpolated onto wl() and normalized to a V-band extinction of 1 mag.

Return type:

list of float

extinctDat(self: slugpy._slug.Extinct) → list[float]

Get the native extinction curve.

Returns:

extinct_dat – Extinction curve, in arbitrary units, at each wavelength in wlDat().

Return type:

list of float

loadCurve(self: slugpy._slug.Extinct, extinct_name: str, registry_name: str = 'data/extinct/extinct.toml') → None

Read a named extinction curve from a registry entry, and rebuild every cached quantity from it.

Parameters:
  • extinct_name (str) – Name of the extinction curve to load (e.g. “Calzetti_starburst”).

  • registry_name (str, optional) – Path to the extinction curve registry file. Default is the package’s default registry (data/extinct/extinct.toml).

Raises:

RuntimeError – If extinct_name is not found in the registry, the registry/HDF5 file cannot be read, or this Extinct’s own SimControls.specsyn is None.

Notes

Reads extinct_name’s own native (wavelength, kappa) tabulation from registry_name’s HDF5 file into wlDat()/extinctDat() – the actual cost of loading a different curve from disk, as opposed to merely re- deriving the cached quantities from a curve already loaded (see rebuildCache()) – then always finishes by calling rebuildCache(), so the cached quantities are never left stale relative to the newly- loaded curve. Lets an already-constructed Extinct be pointed at a different curve (e.g. after its SimControls’s own extinct.model changes) without building a new one.

rebuildCache(self: slugpy._slug.Extinct) → None

Recompute every cached quantity derived from this curve’s data and its SimControls.

Raises:

RuntimeError – If this Extinct’s own SimControls.specsyn is None.

Notes

Interpolates the native curve data onto SimControls.specsyn.wl, clipped to its own coverage (see wl()); interpolates it onto every nebular emission line’s own wavelength too, if a nebular emission grid was requested (SimControls.nebular is not None); normalizes both to a V-band extinction of 1 mag; and recomputes the field-star expectation values applyExtinctionCts()/applyExtinctionCtsLines() use from SimControls.avDistField and SimControls.avNebFac. Call this (rather than loadCurve()) after this Extinct’s own SimControls has its spectral synthesizer, nebular emission grid, or field-star A_V distribution change, to bring these cached quantities back in sync with them, without re-reading the curve itself from disk.

wl(self: slugpy._slug.Extinct) → list[float]

Get the interpolated wavelength grid.

Returns:

wl – This Extinct’s own SimControls.specsyn.wl, clipped to wlDat()’s own [min, max] coverage.

Return type:

list of float

wlDat(self: slugpy._slug.Extinct) → list[float]

Get the native extinction curve wavelength grid.

Returns:

wl_dat – Wavelength grid, in Angstrom, as read directly from the registry entry.

Return type:

list of float

wlObs(self: slugpy._slug.Extinct) → list[float]

Get the observed-frame interpolated wavelength grid.

Returns:

wl_obs – wl(), redshifted by (1 + z), with z read live from the SimControls this Extinct was built from.

Return type:

list of float

wlOffset(self: slugpy._slug.Extinct) → int

Get the number of leading elements chopped off this Extinct’s own SimControls.specsyn.wl.

Returns:

wl_offset – The number of leading elements of this Extinct’s own SimControls.specsyn.wl that fell below the native curve’s own coverage and so are absent from wl()/extinct(). Lets a caller line up a spectrum tabulated on that same wavelength grid with wl()’s own, narrower grid, exactly as applyExtinction() does internally.

Return type:

int

class slugpy._slug.Filter

Abstract base class representing a photometric filter.

Defines the common interface for computing the photometric response of a spectrum to a filter, however that filter’s own response is actually represented. Abstract – Python code only ever encounters a Filter through one of its concrete subclasses, FilterIdeal or FilterTabulated, either constructed directly or returned by FilterCollection.getFilter()/filters().

__init__(*args, **kwargs)
fluxVega(self: slugpy._slug.Filter) → float

Get this filter’s mean Vega flux.

Returns:

flux_vega – The filter-mean flux of Vega in this filter, in erg/s/cm^2/Angstrom, as populated when this filter was built as part of a FilterCollection with phot_system = PhotSystem.Vega (0 if it was never populated).

Return type:

float

name(self: slugpy._slug.Filter) → str

Get the name of this filter.

Returns:

name

Return type:

str

phot(self: slugpy._slug.Filter, wl: collections.abc.Sequence[SupportsFloat | SupportsIndex], spec: collections.abc.Sequence[SupportsFloat | SupportsIndex]) → float

Compute the photometric response of this filter to a spectrum.

Parameters:
  • wl (list of float) – The wavelength grid, in Angstrom, on which spec is computed.

  • spec (list of float) – The spectrum to which to compute the photometric response.

Returns:

value – The photometric response, in erg/s/cm^2/Angstrom if photCount() is False, or photons/s if photCount() is True. The exact formula depends on the concrete filter type – see FilterIdeal.phot()/FilterTabulated.phot() for specifics.

Return type:

float

photCount(self: slugpy._slug.Filter) → bool

Get whether this filter returns photon counts.

Returns:

phot_count – True if this filter returns photon counts rather than F_lambda values, false otherwise.

Return type:

bool

wlPivot(self: slugpy._slug.Filter) → float

Get this filter’s pivot wavelength.

Returns:

wl_pivot – A single characteristic wavelength for this filter, in Angstrom – used, e.g., to convert a phot() value into other flux/magnitude systems, since phot() itself collapses a filter’s response to a single number with no wavelength of its own. The exact definition depends on the concrete filter type – see FilterIdeal.wlPivot()/FilterTabulated.wlPivot() for specifics.

Return type:

float

wlSupport(self: slugpy._slug.Filter) → tuple[float, float]

Get the wavelength range over which this filter’s response is nonzero.

Returns:

wl_support – The (minimum, maximum) wavelength, in Angstrom, outside of which this filter’s response is exactly zero. The minimum may be 0 and the maximum infinite, for a filter whose passband has no finite lower or upper end (e.g. a Q(*) ionization-threshold filter). For a FilterTabulated, zero-response padding at either end of the table is excluded.

Return type:

tuple of (float, float)

class slugpy._slug.FilterCollection

Holds the set of photometric filters for which photometry will be computed.

Constructed from a list of filter names, each parsed to determine whether it names a tabulated filter (resolved against a filter registry) or an idealized filter, building the corresponding Filter for each. phot() then evaluates every filter in the collection against a spectrum in one call, converting each energy-flux filter’s result to the requested photometric system.

__init__(self: slugpy._slug.FilterCollection, filter_names: collections.abc.Sequence[str], phot_system: slugpy._slug.PhotSystem, registry: str = 'data/filters/filters.toml') → None

Construct a FilterCollection from a list of filter names.

Parameters:
  • filter_names (list of str) – Names of the filters to include; each must be either a tabulated-filter name (facility.filter or facility.instrument. filter, the latter’s instrument omitted only for a facility with exactly one instrument in the registry – see FilterTabulated) or an idealized-filter name (ideal_energy_X_Y, ideal_phot_X_Y, or Q(…) – see FilterIdeal).

  • phot_system (PhotSystem) – The photometric system phot() converts energy-flux (photCount() == False) filters’ results into.

  • registry (str, optional) – Name of the filter registry file to resolve tabulated filter names against.

Raises:

RuntimeError – If any entry of filter_names does not match a recognized tabulated- or idealized-filter naming convention, or if constructing the corresponding filter itself throws.

Notes

If phot_system is PhotSystem.Vega, each non-photCount() filter’s Vega zero point is computed lazily, from the global Vega reference spectrum, the first time it is actually needed – see Filter.fluxVega().

addFilter(*args, **kwargs)

Overloaded function.

  1. addFilter(self: slugpy._slug.FilterCollection, name: str, registry: str = ‘data/filters/filters.toml’) -> None

Parse a filter name and add the resulting filter to this collection.

Parameters:
  • name (str) – Name of the filter to add; see the constructor’s own filter_names parameter for the recognized naming conventions.

  • registry (str, optional) – Name of the filter registry file to resolve a tabulated filter name against; unused for an idealized filter name.

Raises:

RuntimeError – If name does not match a recognized tabulated- or idealized-filter naming convention, or if constructing the corresponding filter itself throws.

Notes

Unlike a filter named in the constructor’s own filter_names, a filter added this way is not given a fluxVega() even if this collection’s phot_system is PhotSystem.Vega – the constructor sets fluxVega() in a second pass, after every filter named in filter_names has been built, which this single-filter entry point has no equivalent of yet.

  1. addFilter(self: slugpy._slug.FilterCollection, filter: slugpy._slug.Filter) -> None

Add an already-constructed filter to this collection.

Parameters:

filter (FilterIdeal or FilterTabulated) – The filter to add; ownership is transferred to this FilterCollection, so filter is no longer usable from Python after this call.

Notes

Lets a caller build a filter directly, via FilterIdeal’s or FilterTabulated’s own constructor, and add it to this collection rather than by name via the other addFilter() overload. Like that overload, does not set the newly added filter’s fluxVega() on a PhotSystem.Vega collection – see its own docstring.

filterNames(self: slugpy._slug.FilterCollection) → list[str]

Get the names of every filter in this collection.

Returns:

names – The name of every filter, in the same order as phot()/filterUnits().

Return type:

list of str

filterUnits(self: slugpy._slug.FilterCollection) → list[str]

Get the units of every filter’s phot() value.

Returns:

units – For a photCount() filter: “photon/s”; for an energy-flux filter: “erg/(s Angstrom)” (Flambda), “erg/(s Hz)” (Fnu), “mag(ST)” (ST), “mag(AB)” (AB), or “mag” (Vega – astropy has no dedicated Vega-magnitude unit), matching this collection’s phot_system – in the same order as phot()/filterNames().

Return type:

list of str

filters(self: slugpy._slug.FilterCollection) → list[slugpy._slug.Filter]

Get every filter in this collection.

Returns:

filters – Every filter in this collection, each as whichever concrete type it actually is, in the same order as phot()/filterNames()/filterUnits().

Return type:

list of FilterIdeal or FilterTabulated

getFilter(*args, **kwargs)

Overloaded function.

  1. getFilter(self: slugpy._slug.FilterCollection, i: typing.SupportsInt | typing.SupportsIndex) -> slugpy._slug.Filter

Get a single filter by index.

Parameters:
  • i (int) – Index of the filter to get, in the same order as phot()/filterNames()/filterUnits().

  • name (str) – Name to search for; must exactly match one entry of filterNames().

Returns:

filter – The i’th filter, as whichever concrete type it actually is.

Return type:

FilterIdeal or FilterTabulated

Raises:
  • IndexError – If i is out of range.

  • 2. getFilter(self – slugpy._slug.FilterCollection, name: str) -> slugpy._slug.Filter:

  • Get a single filter by name. –

  • RuntimeError – If no filter’s name() matches name.

Returns:

filter – The filter whose name() exactly matches name, as whichever concrete type it actually is.

Return type:

FilterIdeal or FilterTabulated

phot(self: slugpy._slug.FilterCollection, wl: collections.abc.Sequence[SupportsFloat | SupportsIndex], spec: collections.abc.Sequence[SupportsFloat | SupportsIndex], wl_full: collections.abc.Sequence[SupportsFloat | SupportsIndex] | None = None) → list[float]

Compute the photometric response of every filter in this collection to a spectrum.

Parameters:
  • wl (list of float) – The wavelength grid, in Angstrom, on which spec is computed.

  • spec (list of float) – The spectrum to which to compute the photometric response.

  • wl_full (list of float or None, optional) – The full wavelength grid, in Angstrom, of which wl is a contiguous, ascending sub-range (e.g. the stellar spectral grid, when wl is that grid chopped to an extinction curve’s own coverage); only its first and last elements are used. Default None, meaning wl itself is the full grid.

Returns:

values – One value per filter, in the same order as filterNames()/filterUnits(): for a photCount() filter, the raw photon-count value (PhotSystem conversions apply only to energy fluxes); for an energy-flux filter, the value converted to this collection’s phot_system. If wl_full is given, a filter whose response (see Filter.wlSupport()) overlaps any part of wl_full’s range that lies outside wl’s is NaN, since the spectrum there is unknown rather than zero; a filter lying entirely outside wl_full is computed as usual.

Return type:

list of float

class slugpy._slug.FilterIdeal

An idealized photometric filter whose response is a top-hat function of wavelength.

A FilterIdeal’s response is exactly 1 within [wl_min, wl_max] and exactly 0 everywhere else – useful both for idealized experiments and for computing photon fluxes above (or between) particular ionization thresholds, without needing a real instrument’s tabulated response curve.

__init__(self: slugpy._slug.FilterIdeal, name: str) → None

Construct a FilterIdeal by parsing its name.

Parameters:

name (str) –

Name of this filter; must match one of the recognized ideal-filter naming conventions:

  1. ideal_<kind>_X_Y, where X and Y are wavelengths in Angstrom (Y may also be “inf”, meaning no upper bound) giving wlMin() and wlMax() respectively, and <kind> is either “energy” (an energy-flux filter, photCount() is False) or “phot” (a photon-counting filter, photCount() is True).

  2. Q(<spec>), where <spec> is an atomic symbol followed by a Roman numeral giving the ionization state in astronomical notation (e.g. Q(HI) = photons that ionize neutral hydrogen). Ionizing photons have wavelength below the ionization threshold lambda = h*c/IP, so the filter is set to wlMin() = 0 (no lower bound), wlMax() = h*c/IP (the ionization-threshold wavelength), and photCount() = True.

Raises:

RuntimeError – If name does not match either recognized convention, or if the requested ionization potential is not available.

phot(self: slugpy._slug.FilterIdeal, wl: collections.abc.Sequence[SupportsFloat | SupportsIndex], spec: collections.abc.Sequence[SupportsFloat | SupportsIndex]) → float

Compute the photometric response of this filter to a spectrum.

Parameters:
  • wl (list of float) – The wavelength grid, in Angstrom.

  • spec (list of float) – The spectrum, in erg/s/Angstrom.

Returns:

value – If photCount() is False: the mean value of spec over the filter’s passband [wlMin(), wlMax()] on a log-wavelength basis, in erg/s/Angstrom, over the intersection of [wlMin(), wlMax()] with the supplied wavelength grid. If photCount() is True: the total photon-count rate, in photons/s, over the same range.

Return type:

float

wlMax(self: slugpy._slug.FilterIdeal) → float

Get the maximum wavelength of this filter’s response.

Returns:

wl_max – The maximum wavelength of this filter’s response, in Angstrom.

Return type:

float

wlMin(self: slugpy._slug.FilterIdeal) → float

Get the minimum wavelength of this filter’s response.

Returns:

wl_min – The minimum wavelength of this filter’s response, in Angstrom.

Return type:

float

wlPivot(self: slugpy._slug.FilterIdeal) → float

Get this filter’s pivot wavelength.

Returns:

wl_pivot – The midpoint of [wlMin(), wlMax()]; wlMax() if wlMin() is 0 (as for a Q(*) ionization-threshold filter, whose passband has no finite lower end), or wlMin() if wlMax() is infinite (as for an ideal_phot_X_inf filter, whose passband has no finite upper end).

Return type:

float

class slugpy._slug.FilterTabulated

A photometric filter whose response is tabulated as a function of wavelength.

__init__(*args, **kwargs)

Overloaded function.

  1. __init__(self: slugpy._slug.FilterTabulated, name: str, wl: collections.abc.Sequence[typing.SupportsFloat | typing.SupportsIndex], response: collections.abc.Sequence[typing.SupportsFloat | typing.SupportsIndex], wl_pivot: typing.SupportsFloat | typing.SupportsIndex) -> None

Construct a FilterTabulated directly from a tabulated response.

Parameters:
  • name (str) – Name of this filter, for output purposes.

  • wl (list of float) – Wavelengths at which the response is tabulated, in Angstrom.

  • response (list of float) – Filter response at each wavelength in wl.

  • wl_pivot (float) – This filter’s pivot wavelength, in Angstrom.

Notes

A FilterTabulated always returns an energy flux (photCount() is always False).

  1. __init__(self: slugpy._slug.FilterTabulated, facility: str, instrument: str, filter: str, registry: str = ‘data/filters/filters.toml’) -> None

Construct a FilterTabulated from an entry in a filter registry.

Parameters:
  • facility (str) – Facility that operates the instrument the filter belongs to (e.g. “HST”).

  • instrument (str) – Instrument the filter belongs to (e.g. “ACS_WFC”).

  • filter (str) – Name of the filter (e.g. “F435W”).

  • registry (str, optional) – Name of the filter registry file to resolve facility/instrument/ filter against.

Notes

name() is set to “facility.instrument.filter”.

Raises:

RuntimeError – If the facility/instrument/filter is not found in the registry.

norm(self: slugpy._slug.FilterTabulated) → float

Get the integral of the filter response with respect to ln(wavelength).

Returns:

norm

Return type:

float

phot(self: slugpy._slug.FilterTabulated, wl: collections.abc.Sequence[SupportsFloat | SupportsIndex], spec: collections.abc.Sequence[SupportsFloat | SupportsIndex]) → float

Compute the photometric response of this filter to a spectrum.

Parameters:
  • wl (list of float) – The wavelength grid, in Angstrom, on which spec is computed.

  • spec (list of float) – The spectrum to which to compute the photometric response.

Returns:

value – The photometric response, in erg/s/cm^2/Angstrom.

Return type:

float

response(self: slugpy._slug.FilterTabulated) → slugpy._slug.Interpolator1DScalar

Get the interpolator built from the tabulated response.

Returns:

response – The interpolator built from ln(wl()) and responseData(), as used internally by phot().

Return type:

Interpolator1DScalar

responseData(self: slugpy._slug.FilterTabulated) → list[float]

Get the tabulated filter response data.

Returns:

response_data – The filter response at each wavelength in wl().

Return type:

list of float

wl(self: slugpy._slug.FilterTabulated) → list[float]

Get the wavelengths at which the response is tabulated.

Returns:

wl – The wavelength grid, in Angstrom.

Return type:

list of float

wlPivot(self: slugpy._slug.FilterTabulated) → float

Get this filter’s pivot wavelength.

Returns:

wl_pivot – The pivot wavelength, in Angstrom – either supplied directly (the (name, wl, response, wl_pivot) constructor) or read from the registry entry’s wl_ref field (the registry constructor).

Return type:

float

class slugpy._slug.Galaxy

A galaxy, built from a time-evolving population of star clusters.

Unlike a Cluster, which represents a single mono-age population, a Galaxy represents an entire, continuously star-forming system: advance() draws new clusters as time passes, advances every cluster formed so far (whether still bound or already disrupted), and sums their individual spectra, photometry, and bolometric luminosities into this Galaxy’s own totals.

__init__(self: slugpy._slug.Galaxy, controls: object = None) → None

Construct a Galaxy.

Parameters:

controls (SimControls, optional) – Simulation controls (physics settings and control-flow settings together); controls must outlive this Galaxy, and every value this Galaxy reads from it (e.g. sfr()/cmf()) is read live, not snapshotted, so changing controls after this Galaxy is built takes effect the next time advance() runs. Defaults to slug’s own shared, bundled-default SimControls (built from src/pybind/assets/PyDefaults.toml the first time it is needed, and reused after that – see SimControls()’s own default path), letting a caller do e.g. gal = slug.Galaxy() without building a SimControls at all.

Notes

curTime()/lbol()/targetMass()/actualMass() all start at 0, and clusters()/disruptedClusters()/spec()/specExtinct()/phot()/ photExtinct() all start empty – no clusters exist, and no spectrum/photometry has been computed, until the first call to advance().

actualMass(self: slugpy._slug.Galaxy) → float

Return the total actual mass of clusters formed so far.

Returns:

actual_mass – The sum, over every advance() call so far, of the target mass of every cluster actually drawn from SimControls.cmf() during that call, in Msun.

Return type:

float

advance(self: slugpy._slug.Galaxy, t: SupportsFloat | SupportsIndex) → None

Advance the galaxy in time.

Parameters:

t (float) – Time to which to advance, in yr; must be >= curTime().

clusters(self: slugpy._slug.Galaxy) → list[slugpy._slug.Cluster]

Return the galaxy’s currently-alive (non-disrupted) clusters.

Returns:

clusters – The clusters formed so far that have not yet disrupted. Each Cluster in the returned list is a live reference into this Galaxy (not a copy), so mutating one (e.g. via advance()) is reflected here, and the returned Clusters must not outlive this Galaxy.

Return type:

list of Cluster

curTime(self: slugpy._slug.Galaxy) → float

Return the galaxy’s current time.

Returns:

cur_time – Current simulation time, in yr.

Return type:

float

disruptedClusters(self: slugpy._slug.Galaxy) → list[slugpy._slug.Cluster]

Return the galaxy’s disrupted clusters.

Returns:

clusters – The clusters formed so far that have already disrupted – see clusters()’s own comment on the returned Clusters’ lifetime.

Return type:

list of Cluster

lbol(self: slugpy._slug.Galaxy) → float

Return the galaxy’s bolometric luminosity.

Returns:

lbol – The sum of lbol() over every cluster in clusters() and disruptedClusters(), in Lsun, at the current time, or 0 if no bolometric luminosity has ever been computed (SimControls.computeLbol() is False).

Return type:

float

phot(self: slugpy._slug.Galaxy) → list[float]

Return the galaxy’s photometry.

Returns:

phot – The photometric value computed from spec() by each filter in SimControls.filters(), in the same order as FilterCollection.filterNames()/filterUnits(), or an empty list if no filter collection was requested.

Return type:

list of float

photExtinct(self: slugpy._slug.Galaxy) → list[float]

Return the galaxy’s extincted photometry.

Returns:

phot_extinct – The photometric value computed from specExtinct() by each filter in SimControls.filters(), in the same order as phot(); an empty list if no extinction curve or filter collection was requested.

Return type:

list of float

spec(self: slugpy._slug.Galaxy) → list[float]

Return the galaxy’s continuously-sampled spectrum.

Returns:

spec – The sum of spec() over every cluster in clusters() and disruptedClusters(), on the wavelength grid of the simulation’s spectral synthesizer, or an empty list if no spectral synthesizer was requested.

Return type:

list of float

specExtinct(self: slugpy._slug.Galaxy) → list[float]

Return the galaxy’s extincted spectrum.

Returns:

spec_extinct – The sum of specExtinct() over every cluster in clusters() and disruptedClusters(); an empty list if no extinction curve was requested, or spec() itself is empty.

Return type:

list of float

targetMass(self: slugpy._slug.Galaxy) → float

Return the total target mass of clusters formed so far.

Returns:

target_mass – The sum, over every advance() call so far, of the target mass of clusters that should have formed, in Msun – may differ from actualMass() due to stochastic sampling from SimControls.cmf().

Return type:

float

class slugpy._slug.Interpolator1D

A 1D interpolator over every interpolated stellar-track quantity at once.

Interpolates one or more tabulated functions of a single independent variable x (e.g. stellar age), evaluating all of them together at a query point. See Interpolator1DScalar for the single-quantity version.

__init__(self: slugpy._slug.Interpolator1D, x: collections.abc.Sequence[SupportsFloat | SupportsIndex], f: Annotated[collections.abc.Sequence[collections.abc.Sequence[SupportsFloat | SupportsIndex]], 'FixedSize(9)']) → None

Construct an Interpolator1D.

Parameters:
  • x (list of float) – Locations of the sample points, in strictly increasing order.

  • f (list of list of float) – Values of the sample points to interpolate: a sequence containing exactly as many arrays as the number of quantities this interpolator was built for, each the same length as x.

Raises:

RuntimeError – If x is not sorted in increasing order, if x and f are not the same length, or if too few distinct points remain (after removing duplicates) to build an interpolator.

xMax(self: slugpy._slug.Interpolator1D) → float

Get the maximum allowed value of x.

Returns:

xmax – The maximum value of x for which interpolation is valid.

Return type:

float

xMin(self: slugpy._slug.Interpolator1D) → float

Get the minimum allowed value of x.

Returns:

xmin – The minimum value of x for which interpolation is valid.

Return type:

float

xRange(self: slugpy._slug.Interpolator1D) → tuple[float, float]

Get the allowed range of x.

Returns:

xrange – A 2-element tuple (xmin, xmax) giving the allowed range of x.

Return type:

tuple of float

class slugpy._slug.Interpolator1DScalar

A 1D interpolator over a single tabulated quantity.

Interpolates one tabulated function of a single independent variable x (e.g. a filter’s response as a function of ln(wavelength)) – the single-quantity counterpart of Interpolator1D, which interpolates several quantities together at once.

__init__(*args, **kwargs)
xMax(self: slugpy._slug.Interpolator1DScalar) → float

Get the maximum allowed value of x.

Returns:

xmax – The maximum value of x for which interpolation is valid.

Return type:

float

xMin(self: slugpy._slug.Interpolator1DScalar) → float

Get the minimum allowed value of x.

Returns:

xmin – The minimum value of x for which interpolation is valid.

Return type:

float

xRange(self: slugpy._slug.Interpolator1DScalar) → tuple[float, float]

Get the allowed range of x.

Returns:

xrange – A 2-element tuple (xmin, xmax) giving the allowed range of x.

Return type:

tuple of float

class slugpy._slug.IsotopeData

One isotope’s identity and radioactive decay data.

Every instance returned anywhere in this module (isotopeTable(), YieldChannel.isotopes()/isotopesOrig(), Yields.isotopes()) is a reference into the single, global isotope table, resolved once at program startup – so two calls naming the same (Z, A) always return objects comparing equal by identity from C++’s own perspective, and neither this module nor a caller ever constructs one directly (there is no exposed constructor).

A(self: slugpy._slug.IsotopeData) → int

Get the mass number.

Returns:

A – The mass number.

Return type:

int

Z(self: slugpy._slug.IsotopeData) → int

Get the atomic number.

Returns:

Z – The atomic number.

Return type:

int

__init__(*args, **kwargs)
label(self: slugpy._slug.IsotopeData) → str

Get this isotope formatted as “<symbol><A>”.

Returns:

label – The element symbol immediately followed by the mass number, e.g. “Fe56”, “H1”, “Na22”.

Return type:

str

lifetime(self: slugpy._slug.IsotopeData) → float

Get the radioactive decay lifetime.

Returns:

lifetime – Radioactive decay lifetime in years; 0 indicates a stable isotope.

Return type:

float

stable(self: slugpy._slug.IsotopeData) → bool

Check whether this isotope is stable.

Returns:

stable – True if lifetime() == 0.

Return type:

bool

class slugpy._slug.Nebular

Nebular emission line and continuum luminosity per ionizing photon, from a pre-computed cloudy grid.

Looks up a pre-computed “quick and dirty” nebular emission grid for one track set, and provides the line and continuum luminosity per ionizing photon it holds, as a function of [Fe/H] and (for a cluster) age – so that slug can add nebular emission to a stellar spectrum without running cloudy itself.

__init__(self: slugpy._slug.Nebular, table_name: str, track_name: str, controls: slugpy._slug.SimControls, vvcrit: SupportsFloat | SupportsIndex = 0.0) → None

Construct a Nebular object, loading one track set’s own cloudy grid.

Parameters:
  • table_name (str) – Path to the nebular emission table to load this track set’s own grid from (e.g. “data/nebular/nebular.h5”).

  • track_name (str) – Name of the track set this nebular grid is for; used only during construction (to locate this track set’s own cloudy grid data inside table_name), not retained afterward.

  • controls (SimControls) – Simulation controls (physics and control-flow settings); also the source of the simulation wavelength grid the continuum luminosity grids are resampled onto (controls.specsyn().wl()), so that grid need not be passed in separately. controls.specsyn() must therefore be set (non-None) before constructing a Nebular from it – unlike Extinct’s own controls argument, there is no optional/ default fallback here (this mirrors the C++ constructor, which likewise gives table_name/track_name/controls no default of their own). Stored by reference: this SimControls must outlive the returned Nebular.

  • vvcrit (float, optional) – Rotation rate v/vcrit of the track set. Default is 0.0.

Raises:
  • ValueError – If controls.specsyn() is None.

  • RuntimeError – If table_name cannot be found, track_name has no group of its own in it, or – for any of that group’s own [Fe/H] values – no v/vcrit subgroup matches vvcrit exactly, or controls’s own nebular log(U) control falls outside the range of log(U) values actually tabulated for a given [Fe/H]/v/vcrit combination.

getCluster(self: slugpy._slug.Nebular, spec: collections.abc.Sequence[SupportsFloat | SupportsIndex], feh: SupportsFloat | SupportsIndex, age: SupportsFloat | SupportsIndex) → tuple[list[float], list[float]]

Add one cluster’s own nebular emission to an input stellar spectrum.

Same as getGalaxy(), but interpolated in cluster age as well as [Fe/H] – except that, for age above this table’s own tabulated age range, the returned line luminosities are all zero and the returned spectrum is just spec with every bin at or below the H-ionization edge zeroed (the same edge-zeroing getGalaxy() applies, with no continuum or line emission added).

Parameters:
  • spec (list of float) – Input stellar spectrum, on this object’s own wavelength grid, in erg/s/Angstrom.

  • feh (float) – [Fe/H] of the cluster spec was computed for.

  • age (float) – Cluster age, in yr.

Returns:

  • spec_neb (list of float) – The stellar + nebular continuum + nebular line spectrum, on the same wavelength grid as spec, in erg/s/Angstrom.

  • line_lum (list of float) – Luminosity of each of lineWl()’s own lines, in erg/s.

Raises:

RuntimeError – If feh falls outside this Nebular’s own tabulated [Fe/H] range. (age has no such failure mode: below the table’s own minimum age is pinned to that minimum, and above its own maximum takes the early-return path described above.)

getGalaxy(self: slugpy._slug.Nebular, spec: collections.abc.Sequence[SupportsFloat | SupportsIndex], feh: SupportsFloat | SupportsIndex) → tuple[list[float], list[float]]

Add whole-galaxy nebular emission to an input stellar spectrum.

Q(HI) (the H-ionizing photon rate) is read off spec, then discounted by controls’s own nebular coverage fraction (the fraction of ionizing photons actually absorbed by the nebula, rather than lost to dust grains or escaping the observational aperture); every added quantity scales with that discounted rate. The continuum is added everywhere; the input spectrum itself is kept only above the H-ionization edge (shorter wavelengths are zeroed, since a real HII region reprocesses essentially all ionizing stellar flux); lines are deposited around their own central wavelength.

Parameters:
  • spec (list of float) – Input stellar spectrum, on this object’s own wavelength grid (i.e. the controls.specsyn().wl() this Nebular was built from), in erg/s/Angstrom.

  • feh (float) – [Fe/H] of the stellar population spec was computed for.

Returns:

  • spec_neb (list of float) – The stellar + nebular continuum + nebular line spectrum, on the same wavelength grid as spec, in erg/s/Angstrom.

  • line_lum (list of float) – Luminosity of each of lineWl()’s own lines, in erg/s.

Raises:

RuntimeError – If feh falls outside this Nebular’s own tabulated [Fe/H] range.

lineLabel(self: slugpy._slug.Nebular) → list[str]

Get the label of each of this Nebular’s own nebular emission lines.

Returns:

line_label – One label per line, in the same order as lineWl().

Return type:

list of str

lineWl(self: slugpy._slug.Nebular) → list[float]

Get the wavelength of each of this Nebular’s own nebular emission lines.

Returns:

line_wl – Wavelength, in Angstrom, of each line, in the table’s own line ordering (the same order as lineLabel()).

Return type:

list of float

class slugpy._slug.OutputManager

Abstract base class to manage writing simulation outputs to disk.

Defines the interface and behavior shared by both output formats; the format-specific work is implemented by the OutputManagerH5 and OutputManagerAscii subclasses. No constructor is exposed here – Python code only ever encounters an OutputManager through one of those two concrete subclasses, constructed directly.

__init__(*args, **kwargs)
class slugpy._slug.OutputManagerAscii

ASCII-output specialization of OutputManager.

__init__(self: slugpy._slug.OutputManagerAscii, sim_controls: slugpy._slug.SimControls) → None

Open the ascii output files and write their headers.

Parameters:

sim_controls (SimControls) – Simulation controls (physics settings and control-flow settings together); sim_controls must outlive this OutputManagerAscii, and every value it reads from sim_controls (e.g. outDir()/modelName(), read once here, at construction) reflects sim_controls’s state at this moment, not any later change. sim_controls.inputDeckStr() is written verbatim into the <model_name>_summary.txt file’s own header, so a file this OutputManagerAscii produces always records exactly the deck that actually built sim_controls (empty if sim_controls was itself built with no input deck at all).

Raises:

RuntimeError – If any output file this would create (<model_name>_summary.txt, and – depending on what sim_controls requested – <model_name>_clusters.txt/_cluster_spectra.txt/_cluster_phot.txt) already exists or cannot be opened.

class slugpy._slug.OutputManagerH5

HDF5-output specialization of OutputManager.

__init__(self: slugpy._slug.OutputManagerH5, sim_controls: slugpy._slug.SimControls, restart: bool = False) → None

Open an HDF5 output file and write its header.

Parameters:
  • sim_controls (SimControls) – Simulation controls (physics settings and control-flow settings together); sim_controls must outlive this OutputManagerH5, and every value it reads from sim_controls (e.g. outDir()/modelName(), read once here, at construction) reflects sim_controls’s state at this moment, not any later change. sim_controls.inputDeckStr() is written verbatim into the output file’s own input_deck group, so a file this OutputManagerH5 produces always records exactly the deck that actually built sim_controls (empty if sim_controls was itself built with no input deck at all).

  • restart (bool, default False) – Whether this run is resuming a previous, interrupted run from its most recent checkpoint, rather than starting a new one from scratch. If True, scans sim_controls.outDir() for the most recent checkpoint left behind by a previous run of the same model_name/ out_dir and resumes numbering checkpoints from just after it, instead of starting over at checkpoint 0 – see the C++ OutputManagerH5::restartSetup()’s own documentation for the full detail. Only meaningful with HDF5 output and a non-zero output.checkpoint_interval in sim_controls.

Raises:

RuntimeError – If the output file (sim_controls.outDir()/sim_controls.modelName() + “.h5”) already exists, or if restart is True and sim_controls.outputMode() is ascii.

class slugpy._slug.PDF

A probability distribution composed of one or more segments.

May or may not be properly normalized (so that the integral over all segments is unity). Provides methods for sampling from the distribution and computing various integrals and expectation values from it. No constructor is exposed on PDF itself: a PDF is only ever obtained from Python either by way of another bound object that owns one (e.g. SimControls.imf) or via the module-level parsePDFDescriptor() function.

__init__(*args, **kwargs)
draw(*args, **kwargs)

Overloaded function.

  1. draw(self: slugpy._slug.PDF, n_draw: typing.SupportsInt | typing.SupportsIndex, a: typing.SupportsFloat | typing.SupportsIndex = -1.7976931348623157e+308, b: typing.SupportsFloat | typing.SupportsIndex = 1.7976931348623157e+308) -> list[float]

Draw multiple random values from this PDF.

Parameters:
  • n_draw (int) – Number of samples to draw.

  • a (float, optional) – Lower limit of the sampling range; defaults to this PDF’s own lower limit.

  • b (float, optional) – Upper limit of the sampling range; defaults to this PDF’s own upper limit.

  • a – Lower limit of the sampling range; defaults to this PDF’s own lower limit.

  • b – Upper limit of the sampling range; defaults to this PDF’s own upper limit.

Returns:

  • values (list of float)

  • 2. draw(self (slugpy._slug.PDF, a: typing.SupportsFloat | typing.SupportsIndex = -1.7976931348623157e+308, b: typing.SupportsFloat | typing.SupportsIndex = 1.7976931348623157e+308) -> float)

  • Draw a single random value from this PDF.

Returns:

value

Return type:

float

drawTarget(self: slugpy._slug.PDF, target: SupportsFloat | SupportsIndex, a: SupportsFloat | SupportsIndex = -1.7976931348623157e+308, b: SupportsFloat | SupportsIndex = 1.7976931348623157e+308) → list[float]

Draw random values from this PDF targeting a fixed total.

Parameters:
  • target (float) – Target total to draw.

  • a (float, optional) – Lower limit of the sampling range; defaults to this PDF’s own lower limit.

  • b (float, optional) – Upper limit of the sampling range; defaults to this PDF’s own upper limit.

Returns:

values

Return type:

list of float

expectationValue(*args, **kwargs)

Overloaded function.

  1. expectationValue(self: slugpy._slug.PDF) -> float

Get the expectation value of this PDF over its entire range.

Returns:

  • value (float)

  • 2. expectationValue(self (slugpy._slug.PDF, a: typing.SupportsFloat | typing.SupportsIndex, b: typing.SupportsFloat | typing.SupportsIndex) -> float)

  • Get the expectation value of this PDF over a given range.

Parameters:
  • a (float) – Lower limit of the range; clamped to this PDF’s own lower limit if below it.

  • b (float) – Upper limit of the range; clamped to this PDF’s own upper limit if above it.

Returns:

value

Return type:

float

getMax(self: slugpy._slug.PDF) → float

Get the upper limit of this PDF.

Returns:

max

Return type:

float

getMin(self: slugpy._slug.PDF) → float

Get the lower limit of this PDF.

Returns:

min

Return type:

float

getWeights(self: slugpy._slug.PDF) → list[float]

Get the weights of this PDF’s segments.

Returns:

weights

Return type:

list of float

integral(*args, **kwargs)

Overloaded function.

  1. integral(self: slugpy._slug.PDF) -> float

Get the integral of this PDF over its entire range.

Returns:

  • value (float)

  • 2. integral(self (slugpy._slug.PDF, a: typing.SupportsFloat | typing.SupportsIndex, b: typing.SupportsFloat | typing.SupportsIndex) -> float)

  • Get the integral of this PDF over a given range.

Parameters:
  • a (float) – Lower limit of the range; clamped to this PDF’s own lower limit if below it.

  • b (float) – Upper limit of the range; clamped to this PDF’s own upper limit if above it.

Returns:

value

Return type:

float

normalizePDF(self: slugpy._slug.PDF) → None

Normalize this PDF, so its segment weights sum to unity.

normalized(self: slugpy._slug.PDF) → bool

Check whether this PDF is normalized.

Returns:

normalized

Return type:

bool

property sampling

This PDF’s sampling method.

One of “stop_nearest”, “stop_before”, “stop_after”, “stop_50”, “number”, “poisson”, or “sorted_sampling” – the same vocabulary a PDF descriptor file’s own “sampling” line uses. May also read back as “none” for a PDF whose sampling method was never set, but “none” itself cannot be assigned.

Raises:

RuntimeError – On assignment, if the value is not one of the recognized sampling method strings above.

valid(self: slugpy._slug.PDF) → bool

Check whether this PDF is initialized and usable.

Returns:

valid

Return type:

bool

slugpy._slug.PhotConvert(phot_from: str, phot_to: str, flux_in: Annotated[numpy.typing.ArrayLike, numpy.float64], wl: Annotated[numpy.typing.ArrayLike, numpy.float64], filter: object = None) → object

Convert a flux, specific luminosity, or magnitude from one photometric system to another.

Parameters:
  • phot_from (str) – The photometric system flux_in is expressed in: one of “Flambda”, “Fnu”, “ST”, “AB”, or “Vega”.

  • phot_to (str) – The photometric system to convert flux_in to; same recognized values as phot_from.

  • flux_in (float or array_like of float) – The input value(s) – despite the name, not necessarily a flux: in erg/s/cm^2/Angstrom (if phot_from is “Flambda”) or erg/s/cm^2/Hz (if phot_from is “Fnu”) if it genuinely is a flux, but just as often a specific luminosity in erg/s/Angstrom or erg/s/Hz respectively (with no particular distance baked in – e.g. a simulated spectrum straight from slug), or a magnitude (if phot_from is “ST”, “AB”, or “Vega”). Converting a Flambda/Fnu-side value to or from one of the magnitude systems (ST, AB, Vega) always treats it as a specific luminosity, dividing or multiplying by 4*pi*(10 pc)^2 to adopt the same standard 10 pc distance the absolute-magnitude scale itself is defined at; the direct Flambda <-> Fnu conversion never does this, so it works identically whether flux_in genuinely is a flux or a specific luminosity.

  • wl (float or array_like of float) – The wavelength(s), in Angstrom, at which flux_in is evaluated; unused by conversions that don’t depend on wavelength, but required for a uniform signature. Broadcast against flux_in, so e.g. a whole spectrum can be converted in one call by passing matching flux_in and wl arrays.

  • filter (FilterIdeal or FilterTabulated, optional) – A filter whose fluxVega() gives the Vega zero point to use; required if phot_from or phot_to is “Vega” (fluxVega() is computed lazily, so this may trigger loading the global Vega reference spectrum – see Filter.fluxVega()), ignored otherwise. Unlike flux_in, fluxVega() is always a genuine flux (from the real, already-at-Earth Vega reference spectrum), never a specific luminosity.

Returns:

flux_out – flux_in converted to phot_to, in the units/magnitude convention phot_to specifies (see flux_in’s own docstring). Returns flux_in unchanged if phot_from and phot_to are the same system.

Return type:

float or numpy.ndarray of float

Raises:

RuntimeError – If phot_from or phot_to is not a recognized photometric system, or if phot_from or phot_to is “Vega” and filter is not given.

class slugpy._slug.PhotSystem

A photometric system.

Determines the units a computed photometric value is expressed in – either a physical flux (Flambda, Fnu) or a magnitude on one of several magnitude scales (ST, AB, Vega).

Members:

Flambda : Flux per unit wavelength

Fnu : Flux per unit frequency

ST : The ST magnitude system

AB : The AB magnitude system

Vega : The Vega magnitude system

AB = <PhotSystem.AB: 3>
Flambda = <PhotSystem.Flambda: 0>
Fnu = <PhotSystem.Fnu: 1>
ST = <PhotSystem.ST: 2>
Vega = <PhotSystem.Vega: 4>
__init__(self: slugpy._slug.PhotSystem, value: SupportsInt | SupportsIndex) → None
PhotSystem.name -> str
property value
class slugpy._slug.SimCluster

Drives a cluster-type simulation end to end.

__init__(self: slugpy._slug.SimCluster, sim_controls: slugpy._slug.SimControls, output_manager: object, restart: bool = False) → None

Construct a SimCluster to drive a cluster-type simulation end to end.

Parameters:
  • sim_controls (SimControls) – Simulation controls (physics settings and control-flow settings together); sim_controls must outlive this SimCluster.

  • output_manager (OutputManagerH5 or OutputManagerAscii) – Output manager to which simulation results should be written; ownership is transferred to this SimCluster, so output_manager is no longer usable from Python after this call.

  • restart (bool, default False) – Whether this run is resuming a previous, interrupted run from its most recent checkpoint; see run()’s own docstring. output_manager must itself have already been constructed with its own equivalent restart flag set (see OutputManagerH5’s own constructor); nothing here enforces that the two agree.

run(self: slugpy._slug.SimCluster) → int

Run the simulation.

Returns:

0 if every trial completed normally; 143 (128 + SIGTERM) if a SIGTERM was caught and this stopped early instead, with fewer than sim_controls.nTrial() trials completed – see trialsCompleted() to find out how many, and this SimCluster’s own C++ run() comment for the full detail on when and how that can happen.

Return type:

int

Notes

Runs sim_controls.nTrial() independent trials – each drawing a cluster from sim_controls’s own cmf(), advancing it through every one of sim_controls’s own output times, and writing its properties, spectrum, and photometry to output_manager as it goes (see SimCluster’s own C++ documentation for the full per-trial sequence) – exactly as the slug command-line executable does for a cluster-type input deck. Blocks until every trial completes, which may take anywhere from seconds to hours depending on n_trial and the simulation’s own physics settings; releases the GIL for the duration, so this does not block other Python threads, and so the OpenMP parallelization this loop uses internally (if slug was built with OpenMP support) can actually make use of multiple cores. If this SimCluster was constructed with restart = True, starts from the trial number output_manager reports already completed (its own restartTrialsDone()) rather than from trial 0.

trialsCompleted(self: slugpy._slug.SimCluster) → int

Return the number of trials completed so far.

Returns:

Number of trials this simulation has finished running, out of sim_controls.nTrial() total.

Return type:

int

Notes

Safe to call from another thread while run() is still executing (e.g. to drive a progress bar), since run() releases the GIL for its own entire duration and this itself is a fast, non-blocking read.

class slugpy._slug.SimControls

Holds simulation control-flow information and physics settings.

Bundles together both control-flow settings (I/O, trial count, output timing) and physics choices (IMF, tracks, spectral synthesis) for a simulation – almost every other object slug builds (Cluster, Galaxy, SimCluster, SimGalaxy, the output managers, every spectral synthesizer) needs both together, and reads many of its own settings (e.g. the integrator tolerances) live from this object rather than a snapshot taken at construction time, so a SimControls must outlive anything built from it.

class OutputMode

The format this SimControls’s own output will be written in.

Members:

h5 : HDF5 output

h5divided : Same as h5, but skips the final consolidation step when built with OpenMP, leaving one HDF5 file per thread

ascii : ASCII output

__init__(self: slugpy._slug.SimControls.OutputMode, value: SupportsInt | SupportsIndex) → None
ascii = <OutputMode.ascii: 2>
h5 = <OutputMode.h5: 0>
h5divided = <OutputMode.h5divided: 1>
SimControls.OutputMode.name -> str
property value
class SimType

The type of simulation this SimControls describes.

Members:

cluster : Cluster simulation

galaxy : Galaxy simulation

none : Dummy value, before a real simulation type has been set

__init__(self: slugpy._slug.SimControls.SimType, value: SupportsInt | SupportsIndex) → None
cluster = <SimType.cluster: 0>
galaxy = <SimType.galaxy: 1>
SimControls.SimType.name -> str
none = <SimType.none: 2>
property value
__init__(self: slugpy._slug.SimControls, path: str = '', sim_type: str = 'cluster', imf: object = None, cmf: object = None, feH: object = None, clf: object = None, sfr: object = None, computeLbol: object = None, specsyn: object = None, filters: object = None, tracks: object = None, minStochMass: object = None, intRelTol: object = None, intAbsTol: object = None, intMaxIter: object = None) → None

Construct a SimControls object by parsing a slug input deck.

Parameters:
  • path (str, optional) – Either the text of a slug TOML input deck, or a path to one on disk. Tried first as literal TOML text (via toml::parse); if that fails to parse, tried again as a file path instead (via toml::parse_file) – so e.g. a path like “deck.toml” (not valid TOML on its own) falls through to being read as a file, while a string like “n_trial = 10” (a path that could never exist) is used directly as the deck’s own content. If path parses successfully as literal TOML text, every other argument below is ignored – there is no sim_type key to cross-check outside of the deck’s own text, and none of imf/cmf/… would have any given deck left to override. If path is omitted (or empty), loads slug’s own bundled default deck (src/pybind/assets/PyDefaults.toml) instead, letting a caller build a usable SimControls for interactive work – e.g. sc = slug.SimControls() – without touching an input deck at all.

  • sim_type (str, optional) – Either “cluster” or “galaxy”; validated against the deck’s own sim_type key (which is what actually determines the simulation type) purely to give a clearer, earlier error for an unrecognized value. Defaults to “cluster”, matching the bundled default deck’s own sim_type.

  • imf (str, optional)

  • cmf (str, optional)

  • feH (str, optional)

  • clf (str, optional)

  • sfr (str, optional)

  • computeLbol (bool, optional)

  • specsyn (Specsyn, optional)

  • filters (FilterCollection, optional)

  • tracks (Tracks3D, optional)

  • minStochMass (float, optional)

  • intRelTol (float, optional)

  • intAbsTol (float, optional)

  • intMaxIter (int, optional) – Each, if given, is applied via the corresponding property’s own setter (setIMF(), setCMF(), …, setIntMaxIter()) after the SimControls described above (from path, or the bundled default deck) is otherwise fully built – e.g. SimControls(imf=”20.0”) is equivalent to SimControls() followed by sc.imf = “20.0” (except that if imf and tracks are both given, they are applied in whichever order lets each pass the other’s mass-range check, so that a valid pair is accepted regardless of the deck’s own IMF and tracks). specsyn/filters/tracks transfer ownership exactly as their own setter/property does, so the object passed in is no longer usable from Python afterward. specsyn, unlike filters/tracks, cannot usefully be passed here in practice: a Specsyn must have been constructed with controls=this same SimControls (see setSpecsyn()’s own docstring), which does not yet exist at the point a value for this keyword argument would need to be built – prefer setting it after construction instead (sc = SimControls(…); sc.specsyn = SpecsynBlackbody(…, controls=sc)). See each property’s own docstring for further details.

Raises:
  • RuntimeError – If the file cannot be parsed, sim_type is not “cluster” or “galaxy”, the deck is otherwise invalid, (only if path is empty) the bundled default deck cannot be found, or any of the property-setting keyword arguments above would itself raise a RuntimeError.

  • ValueError – If specsyn is given and was constructed against a different SimControls – see specsyn’s own description above.

property agbWindModel

The AGB star wind velocity model.

One of “none” or “slug2”, read from feedback.agb_winds in the input deck (“slug2” if that key was not given). Read live by Winds.vWindAGB() on every call – see its own docstring for what each model does – so assigning a new value (or calling setAGBWindModel()) takes effect immediately, with no need to rebuild winds.

Raises:

ValueError – On assignment (or setAGBWindModel()), if the value is not one of the two names above; the existing model is left unchanged in this case.

property avNebFac

The distribution of the ratio of nebular to stellar V-band extinction.

The factor f by which the V-band extinction applied to nebular emission exceeds that applied to the stellar light it accompanies (A_V,neb = f A_V), set by the input deck’s optional extinct.neb_factor key. It is a delta function at 1 (equal nebular and stellar extinction) if that key was not given, including when no extinction is applied at all, and is always finite and non-negative.

Reading returns a PDF; assigning a str sets a new one via setAVNebFac() – see its own docstring for the exact rules.

property checkpointInterval

The number of trials between checkpoints.

0 (the default) disables checkpointing. Only supported with HDF5 output (output_mode “h5” or “h5divided”), not ascii: assigning a non-zero value here does not itself check output_mode the way setting output.checkpoint_interval in an input deck does, so a SimControls built with ascii output that later has this set to a non-zero value here will raise a RuntimeError the first time a checkpoint is actually attempted, rather than immediately.

property clf

The cluster lifetime function.

Reading returns a PDF; assigning a str sets a new one via setCLF() – see its own docstring for the exact rules.

property cmf

The cluster mass function.

Reading returns a PDF; assigning a str sets a new one via setCMF() – see its own docstring for the exact rules.

property computeLbol

Whether the bolometric luminosity is computed as an output.

True if “Lbol” was included in phot.filters in the input deck, or this property (or setComputeLbol()) has since been set to True.

property extinct

The extinction curve, or None if none was requested.

Reading returns the Extinct requested via extinct.model (or None if neither extinct.AV nor extinct.AV_field was given in the input deck), built once, at construction, or later installed via setExtinct(); an Extinct read this way stays fully valid even after a later assignment replaces it. Assigning an Extinct (or None, to remove one already present) transfers its ownership to this SimControls, so it is no longer usable from Python after assignment – see setExtinct()’s own docstring, including the ValueError raised if it was built against a different SimControls.

property fCluster

The fraction of stellar mass formed in stochastically-treated clusters.

The fraction of a galaxy simulation’s stellar mass that forms in clusters treated stochastically (as individual Cluster objects); the remaining (1 - fCluster) is treated as a stellar population continuous in both mass and time. Defaults to 1.0 (every star forms in a stochastic cluster); only meaningful for, and only read from, a galaxy-type simulation’s own clusters.f_cluster.

property feH

The [Fe/H] distribution.

Reading returns a PDF; assigning a str sets a new one via setFeH() – see its own docstring for the exact rules, including the tracks2D() cache rebuild that happens if constFeH() is True afterward, and the RuntimeError raised if the new range is broader than the current one.

property filters

The photometric filter collection, or None if none was requested.

Reading returns the FilterCollection requested via phot.filters (or None if phot.filters was not given); a FilterCollection read this way stays fully valid even after a later assignment replaces it. Assigning a FilterCollection transfers its ownership to this SimControls, so it is no longer usable from Python after assignment – see setFilters()’s own docstring.

hasSN(*args, **kwargs)

Overloaded function.

  1. hasSN(self: slugpy._slug.SimControls, mass: typing.SupportsFloat | typing.SupportsIndex) -> bool

Check whether a star of a given mass ends its life as a supernova.

Parameters:
  • mass (float) – Stellar mass (Msun).

  • mass – Stellar mass (Msun).

  • feh (float) – [Fe/H] of the star.

Returns:

  • has_sn (bool) – If snMassLimits is non-empty, True if mass lies within any of its (lower, upper) intervals, inclusive of both ends. Otherwise, if yields is not None, whether mass lies within the mass range of any core-collapse supernova (ccsn) yield channel loaded. Otherwise, False.

  • 2. hasSN(self (slugpy._slug.SimControls, mass: typing.SupportsFloat | typing.SupportsIndex, feh: typing.SupportsFloat | typing.SupportsIndex) -> bool)

  • Check whether a star of a given mass and [Fe/H] ends its life as a supernova.

Returns:

has_sn – If snMassLimits is non-empty, True if mass lies within any of its (lower, upper) intervals, inclusive of both ends (feh is ignored). Otherwise, if yields is not None, yields.hasYield(mass, feh, YieldChannelType.ccsn) – which, unlike hasSN(mass), also catches failed supernovae within the ccsn yield channels’ own mass ranges. Otherwise, False.

Return type:

bool

property ignoredKeys

Input-deck keys that were valid but deliberately not read.

Read-only. Some keys are fine but have no effect for a particular simulation, e.g. nebular.log_U when nebular.compute_neb is false, or clusters.CLF in a cluster simulation. Unlike unusedKeys, these are not mistakes, so they produce no warning (only a note at verbosity 1 or higher).

Returns:

keys – One dict per key, in order of path, with entries ‘path’, ‘line’ and ‘column’ (as for unusedKeys) and ‘reason’ (str, why the key was not read, e.g. “nebular.compute_neb is false”).

Return type:

list of dict

property imf

The initial mass function.

Reading returns a PDF; assigning a str sets a new one via setIMF() (a numerical value is interpreted as a delta-function IMF at that mass, otherwise the value is interpreted as the name of an IMF PDF file – see setIMF()’s own docstring for the exact rules).

property inputDeckStr

The input deck’s own text.

The toml table this SimControls was constructed from, re-serialized back to text – not necessarily byte-identical to whatever text/file originally produced that table, but parses back to an equivalent table. Empty if this SimControls was built with no input deck at all. Read-only: there is no legitimate reason for a caller to override what deck actually built this SimControls.

property intAbsTol

The absolute tolerance for PDF integration.

See intRelTol’s own docstring on live (not snapshotted) effect.

property intMaxIter

The maximum number of bisection iterations for PDF integration.

Not a count of raw integrand evaluations, which each iteration costs several of. 0 means unlimited. See intRelTol’s own docstring on live (not snapshotted) effect.

property intRelTol

The relative tolerance for PDF integration.

Any spectral synthesizer built by this SimControls reads this value live, not a snapshot, so assigning a new value takes effect the next time it integrates – no need to rebuild the synthesizer.

property minIsotopeLifetime

Minimum isotope lifetime, in yr, below which isotopes decay instantly.

1e4 unless yields.min_isotope_lifetime was set in the input deck. Meaningful only if yields is not None. Every unstable isotope with a shorter lifetime is dropped from yields.isotopes and treated as decaying the instant it is produced: its tabulated yield goes to its first longer-lived descendants, and decays into it go straight on to those descendants too. This is accurate for yields at times long compared to this lifetime, and makes decay much cheaper to compute. 0 skips nothing; +inf makes every unstable isotope decay instantly.

Assigning any non-negative float rebuilds yields (if not None) at once, keeping its current isotope restriction (Yields.requestedIsotopes).

Raises:
  • ValueError – If the assigned value is negative or NaN. The old value is then kept.

  • RuntimeError – If the rebuild fails, e.g. because every requested isotope would be skipped. The old value is then restored.

property minStochMass

The minimum mass for fully stochastic treatment.

Assigning a value also recomputes the fraction of stellar mass being treated stochastically – see setMinStochMass()’s own docstring.

property modelName

The model name.

Base name of this simulation’s output file(s) – e.g. for HDF5 output, modelName + “.h5”. Defaults to “slug_sim” when no output.model_name was given in the input deck.

Like the write* flags, this is read by an OutputManager at its own construction, not live: assigning this only affects an OutputManager built from this SimControls afterward, not one already built from it.

property nTrial

The number of trials this simulation will run.

Defaults to 1 when no n_trial was given in the input deck. Assigning this before calling SimCluster.run() / SimGalaxy.run() takes effect immediately – no need to rebuild the simulation object.

property nebular

The nebular emission grid, or None if none was requested.

Reading returns the Nebular built from nebular.table/stars.tracks if nebular emission is being computed, and None otherwise. Nebular emission requires a spectral synthesizer, so nebular.compute_neb defaults to true if the input deck requested one (a deck that never mentions [nebular] at all still builds a Nebular), and to false if it did not; explicitly setting nebular.compute_neb = true without a spectral synthesizer is an error, and setting it false always leaves this None. Built once, at construction, or later installed via setNebular(); a Nebular read this way stays fully valid even after a later assignment replaces it. Assigning a Nebular (or None, to remove one already present) transfers its ownership to this SimControls, so it is no longer usable from Python after assignment – see setNebular()’s own docstring, including the ValueError raised if it was built against a different SimControls.

property noDecay

Whether radioactive decay should be excluded from computed yields.

False (the default) unless yields.no_decay was set to true in the input deck. Meaningful only if yields is not None. False means Yields.yield_()/yieldSum() report the amount of each isotope actually present at the requested output time, including whatever radioactive decay has occurred since it was produced; True means they instead report the cumulative amount of each isotope ever produced, regardless of whether some of it has since decayed into something else. Like yieldsChannelDecomposed, this is read live every time Yields.yield_()/yieldSum() runs, not cached once, so assigning this takes effect immediately.

property obWindModel

The O and B star wind velocity model.

One of “none”, “vink_01”, or “vink_sander_21”, read from feedback.ob_winds in the input deck (“vink_sander_21” if that key was not given). Read live by Winds.vWindOB() on every call – see its own docstring for what each model does – so assigning a new value (or calling setOBWindModel()) takes effect immediately, with no need to rebuild winds.

Raises:

ValueError – On assignment (or setOBWindModel()), if the value is not one of the three names above; the existing model is left unchanged in this case.

property otherWindModel

The wind velocity model for all stars not covered by wrWindModel, obWindModel, or agbWindModel.

One of “none” or “vesc”, read from feedback.other_winds in the input deck (“vesc” if that key was not given). Read live by Winds.vWindOther() on every call – see its own docstring for what each model does – so assigning a new value (or calling setOtherWindModel()) takes effect immediately, with no need to rebuild winds.

Raises:

ValueError – On assignment (or setOtherWindModel()), if the value is not one of the two names above; the existing model is left unchanged in this case.

property outDir

The output directory.

Directory into which output files are written. An empty string (the default when no output.out_dir was given in the input deck) means the current working directory.

Like the write* flags, this is read by an OutputManager at its own construction, not live: assigning this only affects an OutputManager built from this SimControls afterward, not one already built from it.

property outTimes

The output times, in years.

Reading returns the output times as a list of floats – either the explicit array from the input deck, or a single time drawn from the output time distribution if a distribution was specified instead. Assigning a list sets an explicit array and clears any distribution that was previously set: once assigned, outTimes always returns the assigned list, never a draw from a distribution.

property outputMode

The output mode.

One of SimControls.OutputMode.h5 (the default), .h5divided, or .ascii. Determines what kind of OutputManager is built from this SimControls, so like the write* flags, assigning this only affects an OutputManager built afterward, not one already built from it.

setAGBWindModel(self: slugpy._slug.SimControls, model: str) → None

Set the AGB star wind velocity model.

Equivalent to assigning the agbWindModel property – see its own docstring for what each model does.

Parameters:

model (str) – One of “none” or “slug2”.

Raises:

ValueError – If model is not one of the two names above; the existing model is left unchanged in this case.

setAVDist(self: slugpy._slug.SimControls, av_dist: str) → None

Set the distribution of V-band extinction for clustered stars.

Parameters:

av_dist (str) – A numerical value (interpreted as a delta-function A_V at that value) or the name of an A_V PDF file.

Raises:

RuntimeError – If av_dist is not numeric and does not name a file that can be found.

Notes

If this SimControls already has an extinction curve (its extinct property is not None), also rebuilds that Extinct’s own cached quantities (Extinct.rebuildCache()) – av_dist itself is never actually read by Extinct (only av_dist_field is), so this is harmless rather than strictly necessary, but kept for symmetry with set_av_dist_field()’s own identical behavior, where it is actually needed.

setAVDistField(self: slugpy._slug.SimControls, av_dist_field: str) → None

Set the distribution of V-band extinction for field stars.

Parameters:

av_dist_field (str) – A numerical value (interpreted as a delta-function A_V at that value) or the name of an A_V PDF file.

Raises:

RuntimeError – If av_dist_field is not numeric and does not name a file that can be found.

Notes

If this SimControls already has an extinction curve (its extinct property is not None), also rebuilds that Extinct’s own cached quantities (Extinct.rebuildCache()), so its cached expectation values (used by Extinct.applyExtinctionCts()/applyExtinctionCtsLines()) stay in sync with the new distribution.

setAVNebFac(self: slugpy._slug.SimControls, av_neb_fac: str) → None

Set the distribution of the ratio of nebular to stellar V-band extinction.

Parameters:

av_neb_fac (str) – A numerical value (interpreted as a delta-function factor at that value) or the name of a PDF file. See the avNebFac property for what this factor is.

Raises:

RuntimeError – If av_neb_fac is not numeric and does not name a file that can be found, or if the resulting distribution extends below 0 or is not finite (e.g. “nan” or “inf”); avNebFac is left unchanged in either case.

Notes

If this SimControls already has an extinction curve (its extinct property is not None), also rebuilds that Extinct’s own cached quantities (Extinct.rebuildCache()), so its cached nebular expectation values (used by Extinct.applyExtinctionCts() with nebular=True, and applyExtinctionCtsLines()) stay in sync with the new distribution.

setCLF(self: slugpy._slug.SimControls, clf: str) → None

Set the cluster lifetime function.

Parameters:

clf (str) – A numerical value (interpreted as a delta-function CLF at that lifetime) or the name of a CLF PDF file.

Raises:

RuntimeError – If clf is not numeric and does not name a file that can be found.

setCMF(self: slugpy._slug.SimControls, cmf: str) → None

Set the cluster mass function.

Parameters:

cmf (str) – A numerical value (interpreted as a delta-function CMF at that mass) or the name of a CMF PDF file.

Raises:

RuntimeError – If cmf is not numeric and does not name a file that can be found.

setCheckpointInterval(self: slugpy._slug.SimControls, interval: SupportsInt | SupportsIndex) → None

The number of trials between checkpoints.

0 (the default) disables checkpointing. Only supported with HDF5 output (output_mode “h5” or “h5divided”), not ascii: assigning a non-zero value here does not itself check output_mode the way setting output.checkpoint_interval in an input deck does, so a SimControls built with ascii output that later has this set to a non-zero value here will raise a RuntimeError the first time a checkpoint is actually attempted, rather than immediately.

setComputeLbol(self: slugpy._slug.SimControls, value: bool) → None

Set whether the bolometric luminosity should be computed as an output.

Lets a caller request or suppress Lbol output on an already-constructed SimControls – e.g. from Python, where there is no phot.filters input- deck entry to set “Lbol” through – so any Cluster built from this SimControls picks up the new setting the next time it advances.

Parameters:

value (bool) – New value for computeLbol().

setExtinct(self: slugpy._slug.SimControls, extinct: extinct::Extinct) → None

Set the extinction curve.

Parameters:

extinct (Extinct, optional) – The extinction curve to use; ownership is transferred to this SimControls, so extinct is no longer usable from Python after this call. May be None, to remove the current one.

Raises:

ValueError – If extinct is not None and was constructed with a controls argument other than this same SimControls.

Notes

Lets a caller build its own Extinct and install it on an already-constructed SimControls, without needing an input deck – including installing one for the first time on a SimControls whose extinct property was previously None, or passing None to remove one already present.

extinct must have been constructed with its own controls argument set to this same SimControls (e.g. extinct = slug.Extinct(name, controls=sc); sc.setExtinct(extinct)) – an Extinct stores a live reference to whichever SimControls it was built against, for the rest of its lifetime, and this method cannot re-bind it.

setFCluster(self: slugpy._slug.SimControls, f_cluster: SupportsFloat | SupportsIndex) → None

The fraction of stellar mass formed in stochastically-treated clusters.

The fraction of a galaxy simulation’s stellar mass that forms in clusters treated stochastically (as individual Cluster objects); the remaining (1 - fCluster) is treated as a stellar population continuous in both mass and time. Defaults to 1.0 (every star forms in a stochastic cluster); only meaningful for, and only read from, a galaxy-type simulation’s own clusters.f_cluster.

setFeH(self: slugpy._slug.SimControls, feh: str) → None

Set the [Fe/H] distribution.

Parameters:

feh (str) – A numerical value (interpreted as a fixed [Fe/H]) or the name of a [Fe/H] PDF file.

Raises:

RuntimeError – If feh is not numeric and does not name a file that can be found, or if its own [min, max] range is broader than the [Fe/H] range the current stellar tracks were loaded over – widening past it risks interpolating outside the range of data actually loaded – or extends beyond the requestedFehMin()/requestedFehMax() range of the installed spectral synthesizer or Yields, if any. Narrowing, or otherwise staying within, those ranges is always accepted. On rejection, this SimControls is left unchanged.

setFilters(self: slugpy._slug.SimControls, filters: phot::FilterCollection) → None

Set the photometric filter collection.

Parameters:

filters (FilterCollection) – The filter collection to use; ownership is transferred to this SimControls, so filters is no longer usable from Python after this call.

Notes

Lets a caller build its own FilterCollection (e.g. via addFilter()) and install it on an already-constructed SimControls, without needing an input deck.

setIMF(self: slugpy._slug.SimControls, imf: str) → None

Set the initial mass function.

Parameters:

imf (str) – A numerical value (interpreted as a delta-function IMF at that mass) or the name of an IMF PDF file, resolved relative to SLUG_DIR, SLUG_DATA_PATH, or REPO_DIR under data/imfs – the same way stars.IMF is resolved when parsing an input deck.

Raises:
  • RuntimeError – If imf is not numeric and does not name a file that can be found.

  • ValueError – If the new IMF’s maximum mass exceeds the current stellar tracks’ maximum mass. This SimControls is then left unchanged.

Notes

Like construction from an input deck, also prints a warning if the new IMF extends below the tracks’ minimum mass; stars in that range are treated as having zero luminosity.

setIntAbsTol(self: slugpy._slug.SimControls, abs_tol: SupportsFloat | SupportsIndex) → None

The absolute tolerance for PDF integration.

See intRelTol’s own docstring on live (not snapshotted) effect.

setIntMaxIter(self: slugpy._slug.SimControls, max_iter: SupportsInt | SupportsIndex) → None

The maximum number of bisection iterations for PDF integration.

Not a count of raw integrand evaluations, which each iteration costs several of. 0 means unlimited. See intRelTol’s own docstring on live (not snapshotted) effect.

setIntRelTol(self: slugpy._slug.SimControls, rel_tol: SupportsFloat | SupportsIndex) → None

The relative tolerance for PDF integration.

Any spectral synthesizer built by this SimControls reads this value live, not a snapshot, so assigning a new value takes effect the next time it integrates – no need to rebuild the synthesizer.

setMinIsotopeLifetime(self: slugpy._slug.SimControls, value: SupportsFloat | SupportsIndex) → None

Minimum isotope lifetime, in yr, below which isotopes decay instantly.

1e4 unless yields.min_isotope_lifetime was set in the input deck. Meaningful only if yields is not None. Every unstable isotope with a shorter lifetime is dropped from yields.isotopes and treated as decaying the instant it is produced: its tabulated yield goes to its first longer-lived descendants, and decays into it go straight on to those descendants too. This is accurate for yields at times long compared to this lifetime, and makes decay much cheaper to compute. 0 skips nothing; +inf makes every unstable isotope decay instantly.

Assigning any non-negative float rebuilds yields (if not None) at once, keeping its current isotope restriction (Yields.requestedIsotopes).

Raises:
  • ValueError – If the assigned value is negative or NaN. The old value is then kept.

  • RuntimeError – If the rebuild fails, e.g. because every requested isotope would be skipped. The old value is then restored.

setMinStochMass(self: slugpy._slug.SimControls, min_stoch_mass: SupportsFloat | SupportsIndex) → None

Set the minimum mass for fully stochastic treatment.

Parameters:

min_stoch_mass (float) – New minimum mass for fully stochastic treatment.

Notes

Also recomputes the fraction of stellar mass being treated stochastically, as imf().integral(min_stoch_mass, imf().getMax()), exactly as the constructor does when stars.min_stoch_mass is given.

setModelName(self: slugpy._slug.SimControls, name: str) → None

The model name.

Base name of this simulation’s output file(s) – e.g. for HDF5 output, modelName + “.h5”. Defaults to “slug_sim” when no output.model_name was given in the input deck.

Like the write* flags, this is read by an OutputManager at its own construction, not live: assigning this only affects an OutputManager built from this SimControls afterward, not one already built from it.

setNTrial(self: slugpy._slug.SimControls, n: SupportsInt | SupportsIndex) → None

The number of trials this simulation will run.

Defaults to 1 when no n_trial was given in the input deck. Assigning this before calling SimCluster.run() / SimGalaxy.run() takes effect immediately – no need to rebuild the simulation object.

setNebular(self: slugpy._slug.SimControls, nebular: nebular::Nebular) → None

Set the nebular emission grid.

Parameters:

nebular (Nebular, optional) – The nebular emission grid to use; ownership is transferred to this SimControls, so nebular is no longer usable from Python after this call. May be None, to remove the current one.

Raises:

ValueError – If nebular is not None and was constructed with a controls argument other than this same SimControls.

Notes

Lets a caller build its own Nebular and install it on an already-constructed SimControls, without needing an input deck – including installing one for the first time on a SimControls whose nebular property was previously None, or passing None to remove one already present. Does not touch nebControls().compute_neb either way, so that flag and the nebular property’s own None-ness can end up disagreeing if set independently – see setNebControls()’s own docstring.

nebular must have been constructed with its own controls argument set to this same SimControls, for the same reason described in setExtinct()’s own docstring – a Nebular stores an identical live reference to whichever SimControls it was built against.

setNoDecay(self: slugpy._slug.SimControls, value: bool) → None

Whether radioactive decay should be excluded from computed yields.

False (the default) unless yields.no_decay was set to true in the input deck. Meaningful only if yields is not None. False means Yields.yield_()/yieldSum() report the amount of each isotope actually present at the requested output time, including whatever radioactive decay has occurred since it was produced; True means they instead report the cumulative amount of each isotope ever produced, regardless of whether some of it has since decayed into something else. Like yieldsChannelDecomposed, this is read live every time Yields.yield_()/yieldSum() runs, not cached once, so assigning this takes effect immediately.

setOBWindModel(self: slugpy._slug.SimControls, model: str) → None

Set the O and B star wind velocity model.

Equivalent to assigning the obWindModel property – see its own docstring for what each model does.

Parameters:

model (str) – One of “none”, “vink_01”, or “vink_sander_21”.

Raises:

ValueError – If model is not one of the three names above; the existing model is left unchanged in this case.

setOtherWindModel(self: slugpy._slug.SimControls, model: str) → None

Set the wind velocity model for all other stars.

Equivalent to assigning the otherWindModel property – see its own docstring for what each model does.

Parameters:

model (str) – One of “none” or “vesc”.

Raises:

ValueError – If model is not one of the two names above; the existing model is left unchanged in this case.

setOutDir(self: slugpy._slug.SimControls, dir: str) → None

The output directory.

Directory into which output files are written. An empty string (the default when no output.out_dir was given in the input deck) means the current working directory.

Like the write* flags, this is read by an OutputManager at its own construction, not live: assigning this only affects an OutputManager built from this SimControls afterward, not one already built from it.

setOutTimes(self: slugpy._slug.SimControls, times: collections.abc.Sequence[SupportsFloat | SupportsIndex]) → None

The output times, in years.

Reading returns the output times as a list of floats – either the explicit array from the input deck, or a single time drawn from the output time distribution if a distribution was specified instead. Assigning a list sets an explicit array and clears any distribution that was previously set: once assigned, outTimes always returns the assigned list, never a draw from a distribution.

setOutputMode(self: slugpy._slug.SimControls, mode: slugpy._slug.SimControls.OutputMode) → None

The output mode.

One of SimControls.OutputMode.h5 (the default), .h5divided, or .ascii. Determines what kind of OutputManager is built from this SimControls, so like the write* flags, assigning this only affects an OutputManager built afterward, not one already built from it.

setSFR(self: slugpy._slug.SimControls, sfr: str) → None

Set the star formation rate.

Parameters:

sfr (str) – A numerical value (interpreted as a constant star formation rate, in Msun/yr) or the name of an SFR PDF file.

Raises:

RuntimeError – If sfr is neither numeric nor names a file that can be parsed as a PDF descriptor.

Notes

Unlike setIMF()/setCMF()/setFeH()/setCLF(), a numerical value is not interpreted as a delta function, but as the normalization of a non-normalized PDF that is constant in time – mirroring how galaxy.sfr itself is handled when parsing an input deck. Also unlike those four, a file name is not resolved relative to SLUG_DIR, SLUG_DATA_PATH, or REPO_DIR; it is used as given. Also clears sfrDist back to invalid/empty – see setSFRDist()’s own docstring for why.

setSFRDist(self: slugpy._slug.SimControls, sfr_dist: str) → None

Set the distribution from which a single, constant star formation rate is drawn.

Parameters:

sfr_dist (str) – A numerical value (interpreted as a delta function at that rate) or the name of an SFR-distribution PDF file.

Raises:

RuntimeError – If sfr_dist is neither numeric nor names a file that can be found.

Notes

Unlike setSFR(), this is a plain PDF-valued setter (a numerical value becomes a delta function, exactly as setCLF()/setCMF()/etc. already work): sfrDist() is a genuine distribution over a single, scalar rate value, not itself a rate as a function of time the way sfr is. Also clears sfr back to invalid/empty: only one of sfr/sfrDist is ever meant to be valid at a time (mirroring the exclusive-or rule the constructor enforces between galaxy.sfr/galaxy.sfr_dist when parsing a real input deck), so setting one via its own setter invalidates the other, regardless of which was set first. Each Galaxy built from a SimControls where sfrDist is the valid one draws its own, independent constant rate from it, once, at construction.

setSNMassLimits(self: slugpy._slug.SimControls, limits: collections.abc.Sequence[SupportsFloat | SupportsIndex]) → None

The stellar mass limits over which supernovae occur.

A list of masses in Msun, read from feedback.sn_mass_range in the input deck (empty if that key was not given). Consecutive pairs (lower, upper) each give one mass interval, inclusive of both ends, in which stars end their lives as supernovae; more than one pair describes disjoint intervals. If empty, hasSN() defers to the core-collapse supernova yield channels in yields instead.

Raises:

ValueError – On assignment (or setSNMassLimits()), if the list has an odd number of elements or its elements are not strictly increasing (which also rejects NaN); the existing limits are left unchanged in this case.

setSpecsyn(self: slugpy._slug.SimControls, specsyn: object) → None

Set the spectral synthesizer.

Parameters:

specsyn (Specsyn, optional) – The spectral synthesizer to use (e.g. a SpecsynBlackbody, SpecsynLibNoWind, SpecsynLibWR, or SpecsynLibChained); ownership is transferred to this SimControls, so specsyn is no longer usable from Python after this call. May be None, to remove the current one.

Raises:

ValueError – If specsyn is not None and was constructed with a controls argument other than this same SimControls – a Specsyn stores a live reference to whichever SimControls it was built against, for the rest of its lifetime, and this method cannot re-bind it, so specsyn must already have been constructed with controls=this SimControls (e.g. slug.SpecsynBlackbody(…, controls=sc); sc.setSpecsyn(specsyn)). This also means specsyn cannot usefully be passed as a constructor keyword argument (SimControls(…, specsyn=…)): the SimControls being constructed does not exist yet at the point specsyn would need to be built against it. Also raised if specsyn’s requestedFehMin()/requestedFehMax() range does not contain the currently installed synthesizer’s own (or, if there is none, the current [Fe/H] distribution): a synthesizer built for a narrower [Fe/H] range could not cover every [Fe/H] the simulation may ask about. Either way, this SimControls is left unchanged and specsyn stays usable from Python.

Notes

Lets a caller build its own spectral synthesizer and install it on an already-constructed SimControls, without needing an input deck.

setTracks(self: slugpy._slug.SimControls, tracks: object) → None

Set the stellar tracks.

Parameters:

tracks (Tracks3D) – The stellar tracks to use; ownership is transferred to this SimControls, so tracks is no longer usable from Python after this call. Must not be None.

Raises:

ValueError – If tracks is None, or if the [Fe/H] range tracks was loaded over does not cover the current [Fe/H] distribution (the feH property’s own [min, max]), or if the tracks’ maximum mass is below the current IMF’s maximum mass. This SimControls is then left unchanged, and tracks stays usable from Python.

Notes

Lets a caller build its own Tracks3D and install it on an already-constructed SimControls, without needing an input deck. If constFeH() is True, also recomputes tracks2D() (the [Fe/H]-sliced cache) from the new tracks, mirroring setFeH()’s own equivalent recomputation.

setVerbosity(self: slugpy._slug.SimControls, verbosity: SupportsInt | SupportsIndex) → None

The verbosity level.

Controls how much diagnostic output is printed during a simulation run. 0 (the default) means no extra output; higher values produce progressively more. Read live by every object that checks this SimControls’s verbosity() – no need to rebuild anything after assigning.

setWRWindModel(self: slugpy._slug.SimControls, model: str) → None

Set the Wolf-Rayet wind velocity model.

Equivalent to assigning the wrWindModel property – see its own docstring for what each model does.

Parameters:

model (str) – One of “none”, “l_over_c”, or “nugis_lamers_00”.

Raises:

ValueError – If model is not one of the three names above; the existing model is left unchanged in this case.

setWinds(self: slugpy._slug.SimControls, winds: object) → None

Set the stellar wind calculator.

Parameters:

winds (Winds, optional) – The Winds to use; ownership is transferred to this SimControls, so winds is no longer usable from Python after this call. May be None, to remove the one already present.

Raises:

ValueError – If winds is not None and was constructed with a controls argument other than this same SimControls – a Winds stores a live reference to whichever SimControls it was built against, and reads its wind models (wrWindModel, obWindModel, etc.) from there. The current winds is left unchanged, and winds stays usable from Python, in this case.

setWriteCluster(self: slugpy._slug.SimControls, value: bool) → None

Whether the clusters group/file is written.

True (the default) unless output.write_cluster was set to false in the input deck. Unlike intRelTol/z/etc., this is not read live by an already-built OutputManagerH5/OutputManagerAscii: each one decides once, at its own construction, which groups/files to create at all, so assigning this only affects an OutputManagerH5/OutputManagerAscii built from this SimControls afterward, not one already built from it.

setWriteClusterFeedback(self: slugpy._slug.SimControls, value: bool) → None

Whether the cluster_feedback group/file is written.

True (the default) unless output.write_cluster_feedback was set to false in the input deck. See writeCluster’s own docstring on when assigning this does (and does not) take effect.

setWriteClusterPhot(self: slugpy._slug.SimControls, value: bool) → None

Whether the cluster_phot group/file is written.

True (the default) unless output.write_cluster_phot was set to false in the input deck. See writeCluster’s own docstring on when assigning this does (and does not) take effect.

setWriteClusterSpec(self: slugpy._slug.SimControls, value: bool) → None

Whether the cluster_spectra group/file is written.

True (the default) unless output.write_cluster_spec was set to false in the input deck. See writeCluster’s own docstring on when assigning this does (and does not) take effect.

setWriteClusterYields(self: slugpy._slug.SimControls, value: bool) → None

Whether the cluster_yields group/file is written.

True (the default) unless output.write_cluster_yields was set to false in the input deck. See writeCluster’s own docstring on when assigning this does (and does not) take effect.

setWriteGalaxy(self: slugpy._slug.SimControls, value: bool) → None

Whether the galaxy group/file is written.

True (the default) unless output.write_galaxy was set to false in the input deck. Only meaningful for a galaxy-type simulation. See writeCluster’s own docstring on when assigning this does (and does not) take effect.

setWriteGalaxyFeedback(self: slugpy._slug.SimControls, value: bool) → None

Whether the galaxy_feedback group/file is written.

True (the default) unless output.write_galaxy_feedback was set to false in the input deck. Only meaningful for a galaxy-type simulation. See writeCluster’s own docstring on when assigning this does (and does not) take effect.

setWriteGalaxyPhot(self: slugpy._slug.SimControls, value: bool) → None

Whether the galaxy_phot group/file is written.

True (the default) unless output.write_galaxy_phot was set to false in the input deck. Only meaningful for a galaxy-type simulation. See writeCluster’s own docstring on when assigning this does (and does not) take effect.

setWriteGalaxySpec(self: slugpy._slug.SimControls, value: bool) → None

Whether the galaxy_spectra group/file is written.

True (the default) unless output.write_galaxy_spec was set to false in the input deck. Only meaningful for a galaxy-type simulation. See writeCluster’s own docstring on when assigning this does (and does not) take effect.

setWriteGalaxyYields(self: slugpy._slug.SimControls, value: bool) → None

Whether the galaxy_yields group/file is written.

True (the default) unless output.write_galaxy_yields was set to false in the input deck. Only meaningful for a galaxy-type simulation. See writeCluster’s own docstring on when assigning this does (and does not) take effect.

setYields(self: slugpy._slug.SimControls, yields: object) → None

Set the Yields built from yieldChannels.

Parameters:

yields (Yields, optional) – The Yields to use; ownership is transferred to this SimControls, so yields is no longer usable from Python after this call. May be None, to remove the current one.

Raises:

ValueError – If yields is not None and was constructed with a controls argument other than this same SimControls, or if its requestedFehMin()/requestedFehMax() range does not contain the currently installed Yields’ own (or, if there is none, the current [Fe/H] distribution). Either way, this SimControls is left unchanged and yields stays usable from Python.

Notes

Lets a caller build its own Yields and install it on an already-constructed SimControls, without needing an input deck – including installing one for the first time on a SimControls whose yields property was previously None, or passing None to remove one already present. Does not touch yieldChannels either way, so the two can end up disagreeing if set independently.

yields must have been constructed with its own controls argument set to this same SimControls (e.g. yields = slug.Yields(controls=sc); sc.setYields(yields)) – a Yields stores a live reference to whichever SimControls it was built against, for the rest of its lifetime, and this method cannot re-bind it.

A Yields object previously read back from the yields property stays fully valid even after this method replaces (or, with None, clears) this SimControls’s own copy – it’s simply no longer the one the yields property itself returns afterward.

setYieldsChannelDecomposed(self: slugpy._slug.SimControls, value: bool) → None

Whether yields should be reported decomposed by channel.

True (the default) unless yields.channel_decomposed was set to false in the input deck. Meaningful only if yields is not None. Unlike writeCluster/etc., this is read live by Cluster.computeYields()/ Galaxy.computeYields() and OutputManagerH5’s own cluster_yields/ galaxy_yields group creation every time each runs, not cached once – so assigning this takes effect immediately, the same as z/intRelTol, rather than only affecting an object built afterward.

setZ(self: slugpy._slug.SimControls, z: SupportsFloat | SupportsIndex) → None

The redshift.

Applied by every Specsyn’s and Extinct’s own wlObs(). Any such object built by this SimControls reads this value live, not a snapshot, so assigning a new value takes effect the next time wlObs() is called – no need to rebuild anything.

property sfr

The star formation rate.

Reading returns a PDF; assigning a str sets a new one via setSFR() – see its own docstring for the exact rules, which differ from imf/cmf/feH/clf’s.

property sfrDist

The distribution from which a single, constant star formation rate is drawn.

Reading returns a PDF; assigning a str sets a new one via setSFRDist() – see its own docstring for the exact rules.

simType(self: slugpy._slug.SimControls) → slugpy._slug.SimControls.SimType

Return the simulation type.

Returns:

sim_type

Return type:

SimControls.SimType

property snMassLimits

The stellar mass limits over which supernovae occur.

A list of masses in Msun, read from feedback.sn_mass_range in the input deck (empty if that key was not given). Consecutive pairs (lower, upper) each give one mass interval, inclusive of both ends, in which stars end their lives as supernovae; more than one pair describes disjoint intervals. If empty, hasSN() defers to the core-collapse supernova yield channels in yields instead.

Raises:

ValueError – On assignment (or setSNMassLimits()), if the list has an odd number of elements or its elements are not strictly increasing (which also rejects NaN); the existing limits are left unchanged in this case.

property specsyn

The spectral synthesizer, or None if none was requested.

Reading returns the Specsyn requested via spectra.model (or None if spectra.model was not given); a Specsyn read this way stays fully valid even after a later assignment replaces it, though it’s simply no longer the one this property itself returns. Assigning a Specsyn (or None, to remove one already present) transfers its ownership to this SimControls, so it is no longer usable from Python after assignment – see setSpecsyn()’s own docstring, including the ValueError raised if it was built against a different SimControls.

property strictInput

Whether an input-deck key that is never used is an error.

Read-only. This is the value of the optional top-level strict_input key of the deck this SimControls was built from, False by default. If False, a key that nothing reads (a typo, or a key in the wrong section) only produces a warning, and is listed in unusedKeys. If True, constructing the SimControls raises an error instead.

Returns:

strict_input

Return type:

bool

property tracks

The stellar tracks.

Reading returns the Tracks3D loaded via stars.tracks; a Tracks3D read this way stays fully valid even after a later assignment replaces it. Assigning a Tracks3D transfers its ownership to this SimControls, so it is no longer usable from Python after assignment – see setTracks()’s own docstring, including the tracks2D() cache rebuild that happens if constFeH() is True.

property unusedKeys

Input-deck keys that were never used.

Read-only. Filled in when the SimControls is constructed from a deck: every key the deck contains is recorded, and any that nothing read is listed here – typically a misspelled key, or one given in the wrong section (e.g. n_trial under [output] rather than at the top level). Each such key also produces a warning when the deck is read. Empty for a deck with no stray keys, and for a default-constructed SimControls.

Returns:

keys – One dict per key, in order of path, with entries ‘path’ (str, the dotted path of the key, e.g. “output.n_trial”), ‘line’ (int, its line in the deck, or 0 if the deck was not parsed from text), ‘column’ (int, likewise), and ‘hint’ (str, a suggestion of what the key was probably meant to be, e.g. “did you mean ‘n_trial’?”, or an empty string if there is none).

Return type:

list of dict

property verbosity

The verbosity level.

Controls how much diagnostic output is printed during a simulation run. 0 (the default) means no extra output; higher values produce progressively more. Read live by every object that checks this SimControls’s verbosity() – no need to rebuild anything after assigning.

property winds

The stellar wind calculator, or None if none is installed.

Reading returns the Winds built at construction, or later installed via setWinds(); None only for a SimControls that was never given one. Assigning a Winds (or None, to remove one already present) transfers ownership in exactly the same way as setWinds() – see its own docstring.

wl(self: slugpy._slug.SimControls) → list[float]

Return the rest-frame wavelength grid of the spectral synthesizer.

Returns:

wl – The wavelength grid, in Angstrom.

Return type:

list of float

Raises:

RuntimeError – If no spectral synthesizer was requested (spectra.model was not set in the input deck).

wlObs(self: slugpy._slug.SimControls) → list[float]

Return the observed-frame wavelength grid of the spectral synthesizer.

Returns:

wl_obs – The wavelength grid, in Angstrom, redshifted by (1 + z). This is the wavelength grid that a Cluster’s spec() is evaluated on.

Return type:

list of float

Raises:

RuntimeError – If no spectral synthesizer was requested (spectra.model was not set in the input deck).

property wrWindModel

The Wolf-Rayet wind velocity model.

One of “none”, “l_over_c”, or “nugis_lamers_00”, read from feedback.wr_winds in the input deck (“nugis_lamers_00” if that key was not given). Read live by Winds.vWindWR() on every call – see its own docstring for what each model does – so assigning a new value (or calling setWRWindModel()) takes effect immediately, with no need to rebuild winds.

Raises:

ValueError – On assignment (or setWRWindModel()), if the value is not one of the three names above; the existing model is left unchanged in this case.

property writeCluster

Whether the clusters group/file is written.

True (the default) unless output.write_cluster was set to false in the input deck. Unlike intRelTol/z/etc., this is not read live by an already-built OutputManagerH5/OutputManagerAscii: each one decides once, at its own construction, which groups/files to create at all, so assigning this only affects an OutputManagerH5/OutputManagerAscii built from this SimControls afterward, not one already built from it.

property writeClusterFeedback

Whether the cluster_feedback group/file is written.

True (the default) unless output.write_cluster_feedback was set to false in the input deck. See writeCluster’s own docstring on when assigning this does (and does not) take effect.

property writeClusterPhot

Whether the cluster_phot group/file is written.

True (the default) unless output.write_cluster_phot was set to false in the input deck. See writeCluster’s own docstring on when assigning this does (and does not) take effect.

property writeClusterSpec

Whether the cluster_spectra group/file is written.

True (the default) unless output.write_cluster_spec was set to false in the input deck. See writeCluster’s own docstring on when assigning this does (and does not) take effect.

property writeClusterYields

Whether the cluster_yields group/file is written.

True (the default) unless output.write_cluster_yields was set to false in the input deck. See writeCluster’s own docstring on when assigning this does (and does not) take effect.

property writeGalaxy

Whether the galaxy group/file is written.

True (the default) unless output.write_galaxy was set to false in the input deck. Only meaningful for a galaxy-type simulation. See writeCluster’s own docstring on when assigning this does (and does not) take effect.

property writeGalaxyFeedback

Whether the galaxy_feedback group/file is written.

True (the default) unless output.write_galaxy_feedback was set to false in the input deck. Only meaningful for a galaxy-type simulation. See writeCluster’s own docstring on when assigning this does (and does not) take effect.

property writeGalaxyPhot

Whether the galaxy_phot group/file is written.

True (the default) unless output.write_galaxy_phot was set to false in the input deck. Only meaningful for a galaxy-type simulation. See writeCluster’s own docstring on when assigning this does (and does not) take effect.

property writeGalaxySpec

Whether the galaxy_spectra group/file is written.

True (the default) unless output.write_galaxy_spec was set to false in the input deck. Only meaningful for a galaxy-type simulation. See writeCluster’s own docstring on when assigning this does (and does not) take effect.

property writeGalaxyYields

Whether the galaxy_yields group/file is written.

True (the default) unless output.write_galaxy_yields was set to false in the input deck. Only meaningful for a galaxy-type simulation. See writeCluster’s own docstring on when assigning this does (and does not) take effect.

property yieldChannels

The nucleosynthetic yield channels requested via yields.channel1, yields.channel2, etc.

Read-only; an empty list if no yields.channelN table was given at all.

property yields

The Yields built from yieldChannels, or None if none was requested.

Reading returns the Yields built once, at construction, or later installed via setYields() – see Yields’s own class docstring; a Yields read this way stays fully valid even after a later assignment replaces it. Assigning a Yields (or None, to remove one already present) transfers its ownership to this SimControls, so it is no longer usable from Python after assignment – see setYields()’s own docstring, including the ValueError raised if it was built against a different SimControls.

property yieldsChannelDecomposed

Whether yields should be reported decomposed by channel.

True (the default) unless yields.channel_decomposed was set to false in the input deck. Meaningful only if yields is not None. Unlike writeCluster/etc., this is read live by Cluster.computeYields()/ Galaxy.computeYields() and OutputManagerH5’s own cluster_yields/ galaxy_yields group creation every time each runs, not cached once – so assigning this takes effect immediately, the same as z/intRelTol, rather than only affecting an object built afterward.

property z

The redshift.

Applied by every Specsyn’s and Extinct’s own wlObs(). Any such object built by this SimControls reads this value live, not a snapshot, so assigning a new value takes effect the next time wlObs() is called – no need to rebuild anything.

class slugpy._slug.SimGalaxy

Drives a galaxy-type simulation end to end.

__init__(self: slugpy._slug.SimGalaxy, sim_controls: slugpy._slug.SimControls, output_manager: object, restart: bool = False) → None

Construct a SimGalaxy to drive a galaxy-type simulation end to end.

Parameters:
  • sim_controls (SimControls) – Simulation controls (physics settings and control-flow settings together); sim_controls must outlive this SimGalaxy.

  • output_manager (OutputManagerH5 or OutputManagerAscii) – Output manager to which simulation results should be written; ownership is transferred to this SimGalaxy, so output_manager is no longer usable from Python after this call.

  • restart (bool, default False) – Whether this run is resuming a previous, interrupted run from its most recent checkpoint; see run()’s own docstring. output_manager must itself have already been constructed with its own equivalent restart flag set (see OutputManagerH5’s own constructor); nothing here enforces that the two agree.

run(self: slugpy._slug.SimGalaxy) → int

Run the simulation.

Returns:

0 if every trial completed normally; 143 (128 + SIGTERM) if a SIGTERM was caught and this stopped early instead, with fewer than sim_controls.nTrial() trials completed – see trialsCompleted() to find out how many, and this SimGalaxy’s own C++ run() comment for the full detail on when and how that can happen.

Return type:

int

Notes

Runs sim_controls.nTrial() independent trials – each building a Galaxy and advancing it through every one of sim_controls’s own output times, writing its properties, spectrum, and photometry (and, for each currently-alive cluster, that cluster’s own) to output_manager as it goes (see SimGalaxy’s own C++ documentation for the full per-trial sequence) – exactly as the slug command-line executable does for a galaxy-type input deck. Blocks until every trial completes, which may take anywhere from seconds to hours depending on n_trial and the simulation’s own physics settings; releases the GIL for the duration, so this does not block other Python threads, and so the OpenMP parallelization this loop uses internally (if slug was built with OpenMP support) can actually make use of multiple cores. If this SimGalaxy was constructed with restart = True, starts from the trial number output_manager reports already completed (its own restartTrialsDone()) rather than from trial 0.

trialsCompleted(self: slugpy._slug.SimGalaxy) → int

Return the number of trials completed so far.

Returns:

Number of trials this simulation has finished running, out of sim_controls.nTrial() total.

Return type:

int

Notes

Safe to call from another thread while run() is still executing (e.g. to drive a progress bar), since run() releases the GIL for its own entire duration and this itself is a fast, non-blocking read.

class slugpy._slug.Specsyn

Abstract base class defining a common interface for spectral synthesis.

Takes a set of stellar parameters produced by interpolation on the tracks, and returns stellar spectra on a pre-defined wavelength grid. Python code encounters a Specsyn through one of its concrete subclasses – SpecsynBlackbody, SpecsynLibNoWind, SpecsynLibWR, or SpecsynLibChained – constructed directly.

__init__(*args, **kwargs)
intAbsTol(self: slugpy._slug.Specsyn) → float

Return the absolute tolerance for PDF integration.

See intRelTol()’s own docstring: read live from the SimControls this synthesizer was built from.

Returns:

abs_tol – Absolute convergence tolerance passed to the cubature integrator used by specCts().

Return type:

float

intMaxIter(self: slugpy._slug.Specsyn) → int

Return the maximum number of evaluations for PDF integration.

See intRelTol()’s own docstring: read live from the SimControls this synthesizer was built from.

Returns:

max_iter – Maximum number of integrand evaluations used by specCts(); 0 means unlimited.

Return type:

int

intRelTol(self: slugpy._slug.Specsyn) → float

Return the relative tolerance for PDF integration.

Read live from the SimControls this synthesizer was built from (see its own intRelTol property) – there is no setIntRelTol() here; changing the tolerance means setting it on that SimControls instead.

Returns:

rel_tol – Relative convergence tolerance passed to the cubature integrator used by specCts().

Return type:

float

requestedFehMax(self: slugpy._slug.Specsyn) → float

Return the maximum [Fe/H] this spectral synthesizer was constructed to cover.

Returns:

The maximum counterpart of requestedFehMin().

Return type:

float

requestedFehMin(self: slugpy._slug.Specsyn) → float

Return the minimum [Fe/H] this spectral synthesizer was constructed to cover.

Returns:

The feh_min its constructor was given, or -inf for a synthesizer with no [Fe/H] axis (SpecsynBlackbody, SpecsynLibWD). Unlike the data coverage a library actually holds, this is the range the caller asked for.

Return type:

float

Notes

SimControls.setSpecsyn()/setYields() compare this against the currently installed object’s own, to reject a replacement built for a narrower [Fe/H] range.

spec(self: slugpy._slug.Specsyn, props: collections.abc.Sequence[SupportsFloat | SupportsIndex], feh: SupportsFloat | SupportsIndex) → list[float]

Compute the spectrum of a single star.

Parameters:
  • props (list of float) – Stellar properties at this star’s mass, as returned by evaluating an Interpolator1D track segment. Must have exactly 9 elements, in the order: mass (Msun), mdot (Msun/yr), logL (Lsun), logTe (K), h_surf, he_surf, c_surf, n_surf, o_surf (all surface mass fractions).

  • feh (float) – [Fe/H] of the star.

Returns:

spec – Specific luminosity of the star, in erg/s/Angstrom, on the wavelength grid returned by wl().

Return type:

list of float

Raises:

RuntimeError – If props does not have exactly 9 elements, or if the star’s parameters fall outside this synthesizer’s domain and the out-of-bounds policy raises.

wl(self: slugpy._slug.Specsyn) → list[float]

Return the rest-frame wavelength grid.

Returns:

wl – Wavelength grid, in Angstrom, on which spec() is evaluated.

Return type:

list of float

wlObs(self: slugpy._slug.Specsyn) → list[float]

Return the observed-frame wavelength grid.

Returns:

wl_obs – Wavelength grid, in Angstrom, redshifted by (1 + z).

Return type:

list of float

class slugpy._slug.SpecsynBlackbody

An example Specsyn specialization, for testing and validation only.

Treats every star as a perfect blackbody radiating at its effective temperature, with a radius set by its luminosity and temperature via the Stefan-Boltzmann law. Not intended for production simulations.

__init__(self: slugpy._slug.SpecsynBlackbody, wl_min: SupportsFloat | SupportsIndex = 0.0, wl_max: SupportsFloat | SupportsIndex = 0.0, nwl: SupportsInt | SupportsIndex = 0, controls: object = None) → None

Construct a blackbody spectral synthesizer.

All arguments are optional; the wavelength range defaults to a logarithmically spaced grid from roughly 10 to 10,000 Angstrom (the range 10*Ry/hc to 0.01*Ry/hc), with 1000 points.

Parameters:
  • wl_min (float, optional) – Minimum wavelength of the output grid, in Angstrom. Ignored when nwl is 0 (falls back to the default range). Default is 0.

  • wl_max (float, optional) – Maximum wavelength of the output grid, in Angstrom. See wl_min. Default is 0.

  • nwl (int, optional) – Number of points in the output grid. 0 (the default) selects the built-in 1000-point default grid. If nonzero but wl_min is 0, uses nwl points spanning the default wavelength range.

  • controls (SimControls, optional) – Simulation controls; only the integrator tolerance settings (intRelTol, intAbsTol, intMaxIter) and z (redshift) are used. If None (the default), uses a minimal, all-C++-defaults SimControls – intRelTol = 1e-2, intAbsTol = 0, intMaxIter = unlimited, z = 0 – rather than slug’s bundled physics deck (unlike SimControls() itself, this never touches disk).

class slugpy._slug.SpecsynLibChained

A Specsyn specialization that chains together several atmosphere-model libraries.

Some parts of stellar parameter space are best covered by different model atmosphere libraries – e.g. an OB-star library for hot, massive stars and a cooler-star library for everything else. Each library in the chain is tried in turn, in priority order, and the first one able to produce a spectrum for a given star is used.

__init__(self: slugpy._slug.SpecsynLibChained, spectra_names: collections.abc.Sequence[str], feh_min: SupportsFloat | SupportsIndex, feh_max: SupportsFloat | SupportsIndex, afe: SupportsFloat | SupportsIndex = 0.0, cfe: SupportsFloat | SupportsIndex = 0.0, micro_turb: collections.abc.Sequence[SupportsFloat | SupportsIndex] = [], r: SupportsFloat | SupportsIndex = 500.0, registry_name: str = 'data/spectra/spectra.toml', wl_min: SupportsFloat | SupportsIndex = 0.0, wl_max: SupportsFloat | SupportsIndex = 0.0, nwl: SupportsInt | SupportsIndex = 0, t_clamp: bool = True, controls: object = None) → None

Construct a chained spectral synthesizer from several libraries.

Each star is assigned a spectrum by trying the chained libraries in priority order; the first library able to produce a spectrum for that star is used. This allows combining complementary libraries that cover different regions of stellar parameter space (e.g. TLUSTY for hot OB stars and BOSZ for cooler ones).

Parameters:
  • spectra_names (list of str) – Names of the spectral models to chain, in priority order.

  • feh_min (float) – Minimum [Fe/H] value spanned by the population.

  • feh_max (float) – Maximum [Fe/H] value spanned by the population.

  • afe (float, optional) – [alpha/Fe] value. Default is 0.0.

  • cfe (float, optional) – [C/Fe] value. Default is 0.0.

  • micro_turb (list of float, optional) – Microturbulent velocity in km/s, one value per library. An empty list (the default) uses each library’s own micro_default from the registry.

  • r (float, optional) – Spectral resolution. Default is 500.

  • registry_name (str, optional) – Path to the spectral library registry file. Default is the package’s default registry.

  • wl_min (float, optional) – Minimum output wavelength, in Angstrom. 0 (the default) falls back to each library’s own native wavelength coverage.

  • wl_max (float, optional) – Maximum output wavelength, in Angstrom. See wl_min.

  • nwl (int, optional) – Number of output wavelength points. 0 (the default) uses a common wavelength grid derived from all chained libraries.

  • t_clamp (bool, optional) – If True (the default), clamp each star’s log(Teff) to the range spanned by the chained libraries before calling spec(), so a star with a track-derived Teff outside any library’s coverage is handled by the nearest library grid point rather than raising an error.

  • controls (SimControls, optional) – Simulation controls; only integrator tolerance settings and z (redshift) are used. None (the default) uses a minimal, all-C++-defaults SimControls, not slug’s bundled physics deck – see SpecsynBlackbody’s own controls docstring for why.

Raises:

RuntimeError – If spectra_names is empty, micro_turb is non-empty and does not match spectra_names in length, or any library cannot be loaded.

class slugpy._slug.SpecsynLibNoWind

A spectral synthesizer for stars without optically thick winds.

Covers spectral libraries – like BOSZ and TLUSTY – whose spectra sit on a tensor grid of [Fe/H], log(g), and effective temperature, one HDF5 file per library. The counterpart to SpecsynLibWR, which instead covers Wolf-Rayet stars.

__init__(self: slugpy._slug.SpecsynLibNoWind, spectra_name: str, feh_min: SupportsFloat | SupportsIndex, feh_max: SupportsFloat | SupportsIndex, afe: SupportsFloat | SupportsIndex = 0.0, cfe: SupportsFloat | SupportsIndex = 0.0, micro_turb: SupportsFloat | SupportsIndex = nan, r: SupportsFloat | SupportsIndex = 500.0, registry_name: str = 'data/spectra/spectra.toml', wl_min: SupportsFloat | SupportsIndex = 0.0, wl_max: SupportsFloat | SupportsIndex = 0.0, nwl: SupportsInt | SupportsIndex = 0, controls: object = None) → None

Construct a no-wind spectral library synthesizer.

Covers libraries like BOSZ and TLUSTY, whose spectra sit on a (FeH, logg, Teff) tensor grid.

Parameters:
  • spectra_name (str) – Name of the spectral model in the registry (e.g. "BOSZ" or "TLUSTY_OB").

  • feh_min (float) – Minimum [Fe/H] value spanned by the population.

  • feh_max (float) – Maximum [Fe/H] value spanned by the population. May equal feh_min for a single-metallicity population.

  • afe (float, optional) – [alpha/Fe] value. Default is 0.0.

  • cfe (float, optional) – [C/Fe] value. Default is 0.0.

  • micro_turb (float, optional) – Microturbulent velocity in km/s. NaN (the default) uses each library’s own micro_default from the registry.

  • r (float, optional) – Spectral resolution. Default is 500.

  • registry_name (str, optional) – Path to the spectral library registry file. Default is the package’s default registry (data/spectra/spectra.toml).

  • wl_min (float, optional) – Minimum output wavelength, in Angstrom. 0 (the default) falls back to the library’s own native grid.

  • wl_max (float, optional) – Maximum output wavelength, in Angstrom. See wl_min.

  • nwl (int, optional) – Number of output wavelength points. 0 (the default) uses the library’s own native wavelength grid.

  • controls (SimControls, optional) – Simulation controls; only integrator tolerance settings and z (redshift) are used. None (the default) uses a minimal, all-C++-defaults SimControls, not slug’s bundled physics deck – see SpecsynBlackbody’s own controls docstring for why.

Raises:

RuntimeError – If spectra_name is not found in the registry, or the library file cannot be read.

class slugpy._slug.SpecsynLibWR

A spectral synthesizer for Wolf-Rayet stars.

Covers the Potsdam Wolf-Rayet (PoWR) model grids, whose atmospheres are parameterized by [Fe/H], stellar temperature, and “transformed radius” (a function of mass-loss rate and stellar radius that captures the optically thick wind ordinary stars don’t have) rather than the (log g, effective temperature) grid SpecsynLibNoWind uses.

__init__(self: slugpy._slug.SpecsynLibWR, spectra_name: str, feh_min: SupportsFloat | SupportsIndex, feh_max: SupportsFloat | SupportsIndex, registry_name: str = 'data/spectra/spectra.toml', wl_min: SupportsFloat | SupportsIndex = 0.0, wl_max: SupportsFloat | SupportsIndex = 0.0, nwl: SupportsInt | SupportsIndex = 0, controls: object = None) → None

Construct a Wolf-Rayet spectral library synthesizer.

Covers the Potsdam Wolf-Rayet (PoWR) model grids: spectra sit on a (FeH, log_Rt, log_Teff) tensor grid, where log_Rt is the log-transformed radius.

Parameters:
  • spectra_name (str) – Name of the spectral model in the registry. Must identify a WR library; currently "POWR_WNE", "POWR_WNL_H20", "POWR_WNL_H40", "POWR_WNL_H60", or "POWR_WC".

  • feh_min (float) – Minimum [Fe/H] value spanned by the population.

  • feh_max (float) – Maximum [Fe/H] value spanned by the population.

  • registry_name (str, optional) – Path to the spectral library registry file. Default is the package’s default registry (data/spectra/spectra.toml).

  • wl_min (float, optional) – Minimum output wavelength, in Angstrom. 0 (the default) falls back to the library’s own native wavelength coverage.

  • wl_max (float, optional) – Maximum output wavelength, in Angstrom. See wl_min.

  • nwl (int, optional) – Number of output wavelength points. 0 (the default) uses the library’s own common wavelength grid.

  • controls (SimControls, optional) – Simulation controls; only integrator tolerance settings and z (redshift) are used. None (the default) uses a minimal, all-C++-defaults SimControls, not slug’s bundled physics deck – see SpecsynBlackbody’s own controls docstring for why.

Raises:

RuntimeError – If spectra_name does not identify a recognized WR subtype, is not found in the registry, or the library file cannot be read.

class slugpy._slug.Tracks2D

A 2D set of stellar tracks, at a single ([Fe/H], v/vcrit, [alpha/Fe]) combination.

Interpolates stellar properties as a function of initial mass and age within one track set’s own (mass, age) grid at a fixed [Fe/H], rotation rate, and alpha-enhancement. See Tracks3D for a version that also interpolates across a range of [Fe/H].

__init__(self: slugpy._slug.Tracks2D, trackName: str, feh: SupportsFloat | SupportsIndex = 0, vvcrit: SupportsFloat | SupportsIndex = 0, afe: SupportsFloat | SupportsIndex = 0, registryName: str = 'data/tracks/tracks.toml') → None

Construct a Tracks2D object from tracks on disk.

Parameters:
  • trackName (str) – Name of the track set within the registry.

  • feh (float, optional) – [Fe/H] value of the desired track. Default is 0.0.

  • vvcrit (float, optional) – Rotation rate v/vcrit of the desired track. Default is 0.0.

  • afe (float, optional) – [alpha/Fe] value of the desired track. Default is 0.0.

  • registryName (str, optional) – Path to the track registry file. Default is the package’s default registry (data/tracks/tracks.toml).

Raises:

RuntimeError – If no track in trackName matches feh, vvcrit, and afe exactly.

aFe(self: slugpy._slug.Tracks2D) → float

Return the [alpha/Fe] value of this set of tracks.

Returns:

afe – [alpha/Fe] value of this set of tracks, or NaN if not available.

Return type:

float

feH(self: slugpy._slug.Tracks2D) → float

Return the [Fe/H] value of this set of tracks.

Returns:

feh – [Fe/H] value of this set of tracks.

Return type:

float

getIsochrone(self: slugpy._slug.Tracks2D, logT: SupportsFloat | SupportsIndex) → list

Return the isochrone at a given log time.

Parameters:

logT (float) – log10(time / yr) of the isochrone.

Returns:

isochrone – A list of Interpolator1D objects, each parameterized by mass, giving the isochrone. More than one entry indicates disjoint segments, which can occur for non-monotonic tracks; an empty list indicates that logT lies outside the tracks’ time range, or that it touches the tracks at only a single mass (too few points to interpolate).

Return type:

list of Interpolator1D

getTrack(self: slugpy._slug.Tracks2D, m: SupportsFloat | SupportsIndex) → slugpy._slug.Interpolator1D

Return the track for a star of a given mass.

Parameters:

m (float) – Stellar mass, in Msun.

Returns:

interp – An Interpolator1D object containing the interpolating track, parameterized by log10(time / yr).

Return type:

Interpolator1D

Raises:

RuntimeError – If m is less than mMin() or greater than mMax().

liveMassRange(self: slugpy._slug.Tracks2D, t: SupportsFloat | SupportsIndex) → list[tuple[float, float]]

Return the range(s) of stellar mass alive at a given time.

Parameters:

logT (float) – log10(time / yr) at which to evaluate.

Returns:

ranges – A list of (mMin, mMax) pairs giving the mass ranges alive at time t. Usually contains a single pair, but may contain more than one for non-monotonic tracks.

Return type:

list of tuple of float

logTMax(self: slugpy._slug.Tracks2D) → float

Return the maximum log10(time) spanned by this set of tracks.

Returns:

logtmax – Maximum log10(time / yr).

Return type:

float

logTMin(self: slugpy._slug.Tracks2D) → float

Return the minimum log10(time) spanned by this set of tracks.

Returns:

logtmin – Minimum log10(time / yr).

Return type:

float

mMax(self: slugpy._slug.Tracks2D) → float

Return the maximum mass spanned by this set of tracks.

Returns:

mmax – Maximum mass, in Msun.

Return type:

float

mMin(self: slugpy._slug.Tracks2D) → float

Return the minimum mass spanned by this set of tracks.

Returns:

mmin – Minimum mass, in Msun.

Return type:

float

massAndDerivFromLifetime(self: slugpy._slug.Tracks2D, logT: SupportsFloat | SupportsIndex) → list[tuple[float, float]]

Return the mass(es) and dm/d(logT) of the star(s) whose lifetime is a given value.

Parameters:

logT (float) – log10(lifetime / yr).

Returns:

pairs – A list of (mass, dm/d(logT)) pairs, one per star whose own lifetime (see starLifetime()) equals 10**logT yr. Usually a single pair, but may contain more than one for a non-monotonic mass-lifetime relation. The derivative is with respect to logT itself (not the un-logged lifetime).

Return type:

list of tuple of float

starLifetime(self: slugpy._slug.Tracks2D, m: Annotated[numpy.typing.ArrayLike, numpy.float64]) → object

Return the lifetime of a star of a given mass.

Parameters:

m (float or array_like of float) – Stellar mass, in Msun.

Returns:

lifetime – Time, in yr, at which a star of mass m ends this track.

Return type:

float or numpy.ndarray of float

vVcrit(self: slugpy._slug.Tracks2D) → float

Return the v/vcrit value of this set of tracks.

Returns:

vvcrit – v/vcrit value of this set of tracks, or NaN if not available.

Return type:

float

class slugpy._slug.Tracks3D

A 3D set of stellar tracks, spanning a range of [Fe/H] at a fixed v/vcrit and [alpha/Fe].

Interpolates stellar properties as a function of initial mass, age, and [Fe/H], by combining several Tracks2D grids (one per available [Fe/H] value within the requested range) and interpolating across them.

__init__(self: slugpy._slug.Tracks3D, trackName: str, fehMin: SupportsFloat | SupportsIndex, fehMax: SupportsFloat | SupportsIndex, vvcrit: SupportsFloat | SupportsIndex = 0, afe: SupportsFloat | SupportsIndex = 0, registryName: str = 'data/tracks/tracks.toml') → None

Construct a Tracks3D object from tracks on disk.

Parameters:
  • trackName (str) – Name of the track set within the registry.

  • fehMin (float) – Minimum [Fe/H] value to include.

  • fehMax (float) – Maximum [Fe/H] value to include.

  • vvcrit (float, optional) – Rotation rate v/vcrit of the desired tracks. Default is 0.0.

  • afe (float, optional) – [alpha/Fe] value of the desired tracks. Default is 0.0.

  • registryName (str, optional) – Path to the track registry file. Default is the package’s default registry (data/tracks/tracks.toml).

Raises:

RuntimeError – If no tracks in trackName match vvcrit and afe within the requested [Fe/H] range.

aFe(self: slugpy._slug.Tracks3D) → float

Return the [alpha/Fe] value of this set of tracks.

Returns:

afe – [alpha/Fe] value of this set of tracks, or NaN if not available.

Return type:

float

feH(self: slugpy._slug.Tracks3D) → list[float]

Return the [Fe/H] values spanned by this set of tracks.

Returns:

feh – [Fe/H] values spanned by this set of tracks.

Return type:

list of float

getIsochrone(self: slugpy._slug.Tracks3D, logT: SupportsFloat | SupportsIndex, feh: SupportsFloat | SupportsIndex) → list

Return the isochrone at a given log time and [Fe/H].

Parameters:
  • logT (float) – log10(time / yr) of the isochrone.

  • feh (float) – [Fe/H] value of the tracks to use.

Returns:

isochrone – A list of Interpolator1D objects, each parameterized by mass, giving the isochrone. More than one entry indicates disjoint segments, which can occur for non-monotonic tracks; an empty list indicates that logT lies outside the tracks’ time range, or that it touches the tracks at only a single mass (too few points to interpolate).

Return type:

list of Interpolator1D

getTrack(self: slugpy._slug.Tracks3D, m: SupportsFloat | SupportsIndex, feh: SupportsFloat | SupportsIndex) → slugpy._slug.Interpolator1D

Return the track for a star of a given mass and [Fe/H].

Parameters:
  • m (float) – Stellar mass, in Msun.

  • feh (float) – [Fe/H] value of the tracks to use.

Returns:

interp – An Interpolator1D object containing the interpolating track, parameterized by log10(time / yr).

Return type:

Interpolator1D

Raises:

RuntimeError – If m is less than mMin() or greater than mMax().

liveMassRange(self: slugpy._slug.Tracks3D, t: SupportsFloat | SupportsIndex, feh: SupportsFloat | SupportsIndex) → list[tuple[float, float]]

Return the range(s) of stellar mass alive at a given time and [Fe/H].

Parameters:
  • t (float) – log10(time / yr) at which to evaluate.

  • feh (float) – [Fe/H] value of the tracks to use.

Returns:

ranges – A list of (mMin, mMax) pairs giving the mass ranges alive at time t. Usually contains a single pair, but may contain more than one for non-monotonic tracks.

Return type:

list of tuple of float

logTMax(self: slugpy._slug.Tracks3D) → float

Return the maximum log10(time) spanned by this set of tracks.

Returns:

logtmax – Maximum log10(time / yr).

Return type:

float

logTMin(self: slugpy._slug.Tracks3D) → float

Return the minimum log10(time) spanned by this set of tracks.

Returns:

logtmin – Minimum log10(time / yr).

Return type:

float

mMax(self: slugpy._slug.Tracks3D) → float

Return the maximum mass spanned by this set of tracks.

Returns:

mmax – Maximum mass, in Msun.

Return type:

float

mMin(self: slugpy._slug.Tracks3D) → float

Return the minimum mass spanned by this set of tracks.

Returns:

mmin – Minimum mass, in Msun.

Return type:

float

massAndDerivFromLifetime(self: slugpy._slug.Tracks3D, logT: SupportsFloat | SupportsIndex, feh: SupportsFloat | SupportsIndex) → list[tuple[float, float]]

Return the mass(es) and dm/d(logT) of the star(s) whose lifetime is a given value, at a given [Fe/H].

Parameters:
  • logT (float) – log10(lifetime / yr).

  • feh (float) – [Fe/H] value of the tracks to use.

Returns:

pairs – A list of (mass, dm/d(logT)) pairs, one per star whose own lifetime (see starLifetime()) equals 10**logT yr. Usually a single pair, but may contain more than one for a non-monotonic mass-lifetime relation. The derivative is with respect to logT itself (not the un-logged lifetime).

Return type:

list of tuple of float

starLifetime(self: slugpy._slug.Tracks3D, m: Annotated[numpy.typing.ArrayLike, numpy.float64], feh: Annotated[numpy.typing.ArrayLike, numpy.float64]) → object

Return the lifetime of a star of a given mass and [Fe/H].

Parameters:
  • m (float or array_like of float) – Stellar mass, in Msun.

  • feh (float or array_like of float) – [Fe/H] value of the tracks to use. Broadcast against m.

Returns:

lifetime – Time, in yr, at which a star of mass m ends this track.

Return type:

float or numpy.ndarray of float

vVcrit(self: slugpy._slug.Tracks3D) → float

Return the v/vcrit value of this set of tracks.

Returns:

vvcrit – v/vcrit value of this set of tracks, or NaN if not available.

Return type:

float

class slugpy._slug.Winds

A calculator for stellar wind feedback quantities.

Reads the choice of wind model live from the SimControls it was built against (SimControls.wrWindModel, obWindModel, agbWindModel, and otherWindModel), on every call, so changing that choice takes effect immediately without rebuilding this object.

__init__(self: slugpy._slug.Winds, controls: slugpy._slug.SimControls) → None

Construct a Winds.

Parameters:

controls (SimControls) – Simulation controls this Winds reads its wind model choices from, live, for the rest of its lifetime. Kept alive at least as long as this Winds.

vWindAGB(self: slugpy._slug.Winds, props: collections.abc.Sequence[SupportsFloat | SupportsIndex], feh: SupportsFloat | SupportsIndex) → float

Compute the terminal wind velocity of an AGB star.

Parameters:
  • props (list of float) – Stellar properties, in the same 9-element layout vWindWR() takes. The star is assumed to already be an AGB star; this is not checked.

  • feh (float) – The star’s metallicity [Fe/H].

Returns:

vwind – Terminal wind velocity, in cm/s, from whichever model the SimControls this Winds was built against selects via its agbWindModel property: “none” gives exactly 0; “slug2” gives 9.4 km/s * (L / 1e4 Lsun)^(1/4) * (10^feh)^(1/2), the Elitzur & Ivezic (2001) scaling with the Goldman et al. (2017) normalization.

Return type:

float

Raises:

RuntimeError – If props does not have exactly 9 elements.

vWindOB(self: slugpy._slug.Winds, props: collections.abc.Sequence[SupportsFloat | SupportsIndex], feh: SupportsFloat | SupportsIndex) → float

Compute the terminal wind velocity of an O or B star.

Parameters:
  • props (list of float) – Stellar properties, in the same 9-element layout vWindWR() takes. The star is assumed to already be an O or B star; this is not checked.

  • feh (float) – The star’s metallicity [Fe/H], used as a proxy for log(Z/Zsun).

Returns:

vwind – Terminal wind velocity, in cm/s, from whichever model the SimControls this Winds was built against selects via its obWindModel property: “none” gives exactly 0; “vink_01” gives 1.3 or 2.6 times the effective escape speed sqrt(2 G M (1 - Gamma_e) / R) (below or above the Vink et al. 2001 bistability jump temperature, respectively), times (10^feh)^0.13, or exactly 0 if the electron-scattering Eddington factor Gamma_e >= 1; “vink_sander_21” gives the Vink & Sander (2021) fits, again switching at the same jump temperature.

Return type:

float

Raises:

RuntimeError – If props does not have exactly 9 elements.

vWindOther(self: slugpy._slug.Winds, props: collections.abc.Sequence[SupportsFloat | SupportsIndex]) → float

Compute the terminal wind velocity of any other star.

For stars not covered by vWindWR(), vWindOB(), or vWindAGB().

Parameters:

props (list of float) – Stellar properties, in the same 9-element layout vWindWR() takes.

Returns:

vwind – Terminal wind velocity, in cm/s, from whichever model the SimControls this Winds was built against selects via its otherWindModel property: “none” gives exactly 0; “vesc” gives the surface escape speed sqrt(2 G M / R), with R from L and Teff.

Return type:

float

Raises:

RuntimeError – If props does not have exactly 9 elements.

vWindWR(self: slugpy._slug.Winds, props: collections.abc.Sequence[SupportsFloat | SupportsIndex]) → float

Compute the terminal wind velocity of a Wolf-Rayet star.

Parameters:

props (list of float) – Stellar properties, in track order: mass (Msun), mdot (Msun/yr), logL (log10 Lsun), logTe (log10 K), h_surf, he_surf, c_surf, n_surf, o_surf – exactly 9 elements, the same layout Specsyn.spec() takes. The star is assumed to already be a Wolf-Rayet star; this is not checked.

Returns:

vwind – Terminal wind velocity, in cm/s, from whichever model the SimControls this Winds was built against selects via its wrWindModel property: “none” gives exactly 0; “l_over_c” gives L / (mdot c); “nugis_lamers_00” gives the Nugis & Lamers (2000) prescription, clamped to 740-5500 km/s.

Return type:

float

Raises:

RuntimeError – If props does not have exactly 9 elements.

class slugpy._slug.YieldChannel

Nucleosynthetic yield data for one channel (e.g. ccsn), one model (e.g. sukhbold16), over a range of [Fe/H].

__init__(self: slugpy._slug.YieldChannel, descriptor: slugpy._slug.YieldChannelDescriptor, feh_min: SupportsFloat | SupportsIndex, feh_max: SupportsFloat | SupportsIndex, registry_name: str = 'data/yields/yields.toml') → None

Construct a YieldChannel from a yield model on disk.

Parameters:
  • descriptor (YieldChannelDescriptor) – Which channel/model to load, and the mass range it should cover – descriptor.m_min/m_max mean exactly what rebuildYieldGrid()’s own m_min/m_max parameters do.

  • feh_min (float) – Minimum [Fe/H] value.

  • feh_max (float) – Maximum [Fe/H] value.

  • registry_name (str, optional) – Name of the yield registry file.

Raises:

RuntimeError – If descriptor.channel/model_name is not found in the registry, if feh_min or feh_max lies outside the [Fe/H] range actually available for that channel/model, or if the underlying HDF5 file cannot be read or is malformed.

Notes

Does not itself populate masses()/isotopes()/build a usable yield grid – rebuildYieldGrid() must be called at least once (with whatever m_min/m_max/isotopes are wanted) before yield_() can be called.

channel(self: slugpy._slug.YieldChannel) → slugpy._slug.YieldChannelType

Get which nucleosynthetic channel this object holds.

Returns:

channel – descriptor().channel – the channel named by the descriptor passed to the constructor.

Return type:

YieldChannelType

descriptor(self: slugpy._slug.YieldChannel) → slugpy._slug.YieldChannelDescriptor

Get a copy of the descriptor this channel was built from.

Returns:

descriptor – A copy of the descriptor passed to the constructor, except that m_min/m_max instead reflect whichever mass range was actually last requested – either still the constructor’s own descriptor.m_min/ m_max, if rebuildYieldGrid() has never been called with an explicit m_min/m_max of its own, or whatever it was called with most recently otherwise. A copy, not a live view: it does not update if this channel’s own descriptor changes on a later rebuildYieldGrid() call.

Return type:

YieldChannelDescriptor

feH(self: slugpy._slug.YieldChannel) → list[float]

Get the [Fe/H] values this channel’s yields are tabulated at.

Returns:

feh – The [Fe/H] values, ascending.

Return type:

list of float

hasYield(*args, **kwargs)

Overloaded function.

  1. hasYield(self: slugpy._slug.YieldChannel, mass: typing.SupportsFloat | typing.SupportsIndex) -> bool

Check whether a stellar mass falls within this channel’s mass grid.

Parameters:
  • mass (float) – Stellar mass to check (Msun).

  • mass – Stellar mass to check (Msun).

  • feh (float) – [Fe/H] to check; clamped to [feH()[0], feH()[-1]] first if outside it.

Returns:

  • has_yield (bool) – True if mass lies within [masses()[0], masses()[-1]]; always False before rebuildYieldGrid() has been called at least once.

  • 2. hasYield(self (slugpy._slug.YieldChannel, mass: typing.SupportsFloat | typing.SupportsIndex, feh: typing.SupportsFloat | typing.SupportsIndex) -> bool)

  • Check whether a star of a given mass and [Fe/H] has a non-zero yield.

Returns:

has_yield – False if hasYield(mass) is False. Otherwise True if any of the four (feH(), masses()) grid points at the corners of the grid cell containing (feh, mass) has a non-zero yield of any isotope, and False if all four have zero yields of every isotope. Unlike hasYield(mass), this catches gaps within the mass range where a model tabulates an all-zero yield, e.g. failed supernovae. Always False before rebuildYieldGrid() has been called at least once.

Return type:

bool

isotopes(self: slugpy._slug.YieldChannel) → list[slugpy._slug.IsotopeData]

Get the isotopes this channel’s yield grid is actually tabulated for.

Returns:

isotopes – The isotopes, in the same order as yield_()’s own return value – either isotopesOrig() itself, or whatever isotope list was last passed to rebuildYieldGrid(). Empty until rebuildYieldGrid() is called at least once.

Return type:

list of IsotopeData

isotopesOrig(self: slugpy._slug.YieldChannel) → list[slugpy._slug.IsotopeData]

Get the isotopes natively tabulated by the underlying model.

Returns:

isotopes_orig – The isotopes, exactly as read from the model’s own HDF5 file – unlike isotopes(), never affected by rebuildYieldGrid(), and already populated once the constructor returns.

Return type:

list of IsotopeData

masses(self: slugpy._slug.YieldChannel) → list[float]

Get the stellar masses this channel’s yields are tabulated at.

Returns:

masses – Stellar masses (Msun), ascending – this is the grid yield_()/ hasYield() actually use, which can extend below/above massesOrig()’s own range (extrapolated) or be a narrower sub-range of it. Empty until rebuildYieldGrid() is called at least once.

Return type:

list of float

massesOrig(self: slugpy._slug.YieldChannel) → list[float]

Get the stellar masses natively tabulated by the underlying model.

Returns:

masses_orig – Stellar masses (Msun), ascending, exactly as read from the model’s own HDF5 file – unlike masses(), never affected by rebuildYieldGrid()’s own m_min/m_max, and already populated once the constructor returns.

Return type:

list of float

rebuildYieldGrid(self: slugpy._slug.YieldChannel, m_min: SupportsFloat | SupportsIndex | None = None, m_max: SupportsFloat | SupportsIndex | None = None, isotopes: collections.abc.Sequence[slugpy._slug.IsotopeData] = []) → None

Rebuild masses()/isotopes() (and the underlying yield grid) from this channel’s own native data.

Parameters:
  • m_min (float, optional) – Minimum stellar mass this channel should cover; None (the default) means massesOrig()[0].

  • m_max (float, optional) – Maximum stellar mass this channel should cover; None (the default) means massesOrig()[-1].

  • isotopes (list of IsotopeData, optional) – The isotope list the yield grid’s own isotope axis should be built over; an empty list (the default) means “use isotopesOrig() itself, unchanged”. A non-empty list lets a caller reorder, subset, or extend the isotope list this channel’s own data is built over – e.g. to match another channel’s own isotopes, before chaining both together (see the Yields class).

Raises:

ValueError – If the resolved m_min or m_max is not finite and strictly positive, or if the resolved m_min is not strictly less than the resolved m_max.

Notes

Must be called at least once before yield_() can be called. Public so an already-constructed YieldChannel can be rebuilt (e.g. after changing which mass range it should cover) without building a new one.

requestedFehMax(self: slugpy._slug.YieldChannel) → float

Return the maximum [Fe/H] this channel was constructed to cover.

Returns:

The maximum counterpart of requestedFehMin().

Return type:

float

requestedFehMin(self: slugpy._slug.YieldChannel) → float

Return the minimum [Fe/H] this channel was constructed to cover.

Returns:

The feh_min the constructor was given. Unlike feH()[0], the lowest [Fe/H] actually loaded, this is the range the caller asked for.

Return type:

float

Notes

Yields.requestedFehMin() combines these across channels.

yield_(self: slugpy._slug.YieldChannel, mass: SupportsFloat | SupportsIndex, feh: SupportsFloat | SupportsIndex) → list[float]

Get the yield of every isotope for a star of given mass and [Fe/H].

Parameters:
  • mass (float) – Stellar mass (Msun); must satisfy hasYield(mass).

  • feh (float) – [Fe/H]; must lie within [feH()[0], feH()[-1]].

Returns:

yields – One yield (Msun) per entry of isotopes(), in the same order, bilinearly interpolated in (feh, mass).

Return type:

list of float

Raises:

RuntimeError – If rebuildYieldGrid() has never been called.

class slugpy._slug.YieldChannelDescriptor

Everything needed to select and size one YieldChannel.

Members have the same meaning as the like-named parameters of YieldChannel’s own constructor – see its own docstring for each.

__init__(self: slugpy._slug.YieldChannelDescriptor, channel: slugpy._slug.YieldChannelType, model_name: str, m_min: SupportsFloat | SupportsIndex | None = None, m_max: SupportsFloat | SupportsIndex | None = None) → None

Construct a YieldChannelDescriptor.

Parameters:
  • channel (YieldChannelType) – Which nucleosynthetic channel to load (e.g. YieldChannelType.ccsn).

  • model_name (str) – Name of the yield model (e.g. “sukhbold16”).

  • m_min (float, optional) – Minimum stellar mass this channel should cover; None (the default) means the model’s own native minimum.

  • m_max (float, optional) – Maximum stellar mass this channel should cover; None (the default) means the model’s own native maximum.

property channel
property m_max
property m_min
property model_name
class slugpy._slug.YieldChannelType

A known nucleosynthetic yield channel.

More channels will be added here as more yield sources are imported.

Members:

ccsn : Core-collapse supernova ejecta

massive_star_winds : Massive star winds (pre-supernova mass loss)

agb : Asymptotic giant branch stellar winds

__init__(self: slugpy._slug.YieldChannelType, value: SupportsInt | SupportsIndex) → None
agb = <YieldChannelType.agb: 2>
ccsn = <YieldChannelType.ccsn: 0>
massive_star_winds = <YieldChannelType.massive_star_winds: 1>
YieldChannelType.name -> str
property value
class slugpy._slug.Yields

Chains together the nucleosynthetic yield channels a SimControls requests.

Built from controls.yieldChannels(): one YieldChannel per descriptor, added via addChannel(). The constructor also calls rebuildYieldGrid() once, which collects every loaded channel’s own isotopesOrig(), and their decay products, into one deduplicated, sorted list, then splits off every unstable isotope shorter-lived than controls.minIsotopeLifetime into skippedIsotopes (treated as decaying instantly), leaving the rest as isotopes. It then pushes isotopes back down into every channel’s own rebuildYieldGrid() – so every YieldChannel this Yields owns ends up synchronized onto the same isotope list, in the same order.

__init__(self: slugpy._slug.Yields, controls: slugpy._slug.SimControls, registry_name: str = 'data/yields/yields.toml') → None

Construct a Yields from a SimControls’s own yieldChannels().

Parameters:
  • controls (SimControls) – Simulation controls this Yields reads its yield-channel descriptors (controls.yieldChannels()) and [Fe/H] range (controls.fehDist()) from, live, for the rest of its lifetime. Must outlive this Yields.

  • registry_name (str, optional) – Name of the yield registry file.

Raises:

RuntimeError – If any descriptor in controls.yieldChannels() names a channel/model not found in registry_name, or whose [Fe/H] range doesn’t cover controls.fehDist().

Notes

Prints a warning (to stdout, not thrown) if controls.yieldChannels() requests the same channel more than once – a suspicious pattern that’s easy to hit by accident, but not forbidden outright, since there are legitimate reasons for it too (e.g. comparing two different yield tables for the same channel).

addChannel(*args, **kwargs)

Overloaded function.

  1. addChannel(self: slugpy._slug.Yields, descriptor: slugpy._slug.YieldChannelDescriptor) -> None

Add one YieldChannel, built from a descriptor, to yieldChannels().

Parameters:

descriptor (YieldChannelDescriptor) – Which channel/model to load, and the mass range it should cover.

Raises:

RuntimeError – If descriptor.channel/model_name is not found in the registry named by registryName(), or if this Yields’s own SimControls’s [Fe/H] range lies outside the range actually available for that channel/model.

Notes

Also calls rebuildYieldGrid() afterward, so isotopes() (and every channel this Yields owns, including the new one) stays synchronized.

  1. addChannel(self: slugpy._slug.Yields, channel: object) -> None

Add one already-built YieldChannel to yieldChannels().

Parameters:

channel (YieldChannel) – The channel to add; ownership is transferred to this Yields, so channel is no longer usable from Python after this call. Must not be None.

Raises:

ValueError – If channel is None.

Notes

Unlike addChannel(), which builds a fresh YieldChannel from a descriptor, this overload moves an already-built channel into place. Also calls rebuildYieldGrid(), so isotopes() and every channel this Yields owns (including channel itself) stay synchronized afterward.

deleteChannel(self: slugpy._slug.Yields, index: SupportsInt | SupportsIndex) → None

Remove one entry from yieldChannels().

Parameters:

index (int) – Index, into yieldChannels(), of the channel to remove.

Raises:

IndexError – If index is out of range for yieldChannels().

Notes

Also calls rebuildYieldGrid() afterward, so isotopes() (and every remaining channel) stays synchronized once the removed channel’s own isotopes no longer count toward the union. A YieldChannel object previously read back from yieldChannels() stays fully valid even if it happens to be the entry index removes – it’s simply no longer one of the entries yieldChannels() itself returns afterward.

hasYield(*args, **kwargs)

Overloaded function.

  1. hasYield(self: slugpy._slug.Yields, mass: typing.SupportsFloat | typing.SupportsIndex, channel: slugpy._slug.YieldChannelType) -> bool

Check whether a star of a given mass returns a yield through a given channel.

Parameters:
  • mass (float) – Stellar mass (Msun).

  • channel (YieldChannelType) – The nucleosynthetic channel to check (e.g. YieldChannelType.ccsn).

  • mass – Stellar mass (Msun).

  • feh (float) – [Fe/H].

  • channel – The nucleosynthetic channel to check (e.g. YieldChannelType.ccsn).

Returns:

  • has_yield (bool) – True if any entry of yieldChannels() of type channel has its own hasYield(mass) True; False otherwise, including if no entry of yieldChannels() is of type channel at all. Entries of any other channel type are ignored; if more than one entry is of type channel (e.g. two models covering different sub-ranges of one channel’s mass range), mass need only lie within the mass grid of one of them.

  • 2. hasYield(self (slugpy._slug.Yields, mass: typing.SupportsFloat | typing.SupportsIndex, feh: typing.SupportsFloat | typing.SupportsIndex, channel: slugpy._slug.YieldChannelType) -> bool)

  • Check whether a star of a given mass and [Fe/H] has a non-zero yield through a given channel.

Returns:

has_yield – True if any entry of yieldChannels() of type channel has its own hasYield(mass, feh) True; False otherwise, including if no entry of yieldChannels() is of type channel at all. Unlike hasYield(mass, channel), this catches gaps within a channel’s mass range where the tabulated yield is zero for every isotope, e.g. failed supernovae – see YieldChannel.hasYield(mass, feh).

Return type:

bool

property isotopes

The isotopes this Yields’ yield grid is tabulated for.

Reading returns the isotopes tracked explicitly: by default, every isotope that appears in at least one of yieldChannels()’s own isotopesOrig() lists, or is a decay product of one, deduplicated and sorted, minus the unstable isotopes shorter-lived than controls().minIsotopeLifetime, which are listed in skippedIsotopes instead (e.g. Ni56 and Co56 at the default 1e4 yr) – see rebuildYieldGrid(). Once rebuildYieldGrid() has run (always true after the constructor itself returns), this is also exactly what every yieldChannels() entry’s own isotopes() equals, in the same order.

Assigning a list calls rebuildYieldGrid() with it, narrowing isotopes() down to the assigned isotopes plus their decay-chain context (or, for an empty list, resetting isotopes() back to the default above) – see rebuildYieldGrid()’s own docstring for exactly which isotopes that keeps, and for the RuntimeError raised if the assigned list is non-empty but matches nothing any loaded channel tabulates.

rebuildYieldGrid(self: slugpy._slug.Yields, isotopes: collections.abc.Sequence[slugpy._slug.IsotopeData] = []) → None

Rebuild isotopes() from yieldChannels(), then push it back into every channel.

Parameters:

isotopes (list of IsotopeData, optional) – The isotopes wanted; isotopes() is narrowed to these plus whatever decay-chain context they need (see Details). An empty list (the default) means “keep every isotope any loaded channel tabulates, and their decay products”, except those skipped (see Details). Saved as requestedIsotopes().

Raises:

RuntimeError – If isotopes is non-empty but matches nothing any loaded channel tabulates (or that is a decay product of something one tabulates), leaving isotopes() empty.

Notes

A non-empty isotopes list is expanded, not just intersected with what the loaded channels tabulate. isotopes() keeps every requested isotope that a channel tabulates or that is a decay product of one that is, plus every isotope that decays, directly or through intermediates, into one of those (so requesting Fe56 also keeps Ni56 and Co56, whose decay contributes to it), plus every decay product of anything kept (so requesting Ni56 also keeps Co56 and Fe56, and the decay network always stays complete). An emitted proton or alpha (H1 or He4) does not count as a link when looking for parents, so requesting H1 or He4 does not pull in every proton or alpha emitter; but a kept emitter does keep its own H1 or He4 decay product. Entries matching nothing are ignored.

Every unstable isotope shorter-lived than controls().minIsotopeLifetime is never kept, whether requested or not: it is listed in skippedIsotopes instead and treated as decaying instantly, its yield going to its first longer-lived descendants. Decay links are followed through such isotopes when applying the rules above. For example, with the default threshold (1e4 yr), Ni56 and Co56 are skipped, so requesting Fe56 keeps only Fe56, whose yield then includes the tabulated Ni56.

Called once by the constructor, right after every requested channel has been added; also callable directly, e.g. after addChannel() adds a further channel to an already-built Yields, to re-synchronize every channel – including ones added earlier – onto the new, larger union of isotopes, or to change which isotopes subset is kept.

registryName(self: slugpy._slug.Yields) → str

Get the name of the yield registry this Yields reads from.

Returns:

registry_name

Return type:

str

requestedFehMax(self: slugpy._slug.Yields) → float

Return the maximum [Fe/H] this Yields was constructed to cover.

Returns:

The maximum counterpart of requestedFehMin().

Return type:

float

requestedFehMin(self: slugpy._slug.Yields) → float

Return the minimum [Fe/H] this Yields was constructed to cover.

Returns:

The largest requestedFehMin() among yieldChannels, or -inf if there are none: channels can be added after construction, each with its own range, so this Yields covers only their intersection.

Return type:

float

Notes

SimControls.setSpecsyn()/setYields() compare this against the currently installed object’s own, to reject a replacement built for a narrower [Fe/H] range.

requestedIsotopes(self: slugpy._slug.Yields) → list[slugpy._slug.IsotopeData]

The isotope list the last rebuildYieldGrid() call was given.

Returns:

Empty if isotopes is unrestricted. SimControls.minIsotopeLifetime passes this back to rebuildYieldGrid() when it rebuilds, to keep the same restriction.

Return type:

list of IsotopeData

setChannels(*args, **kwargs)

Overloaded function.

  1. setChannels(self: slugpy._slug.Yields, descriptors: collections.abc.Sequence[slugpy._slug.YieldChannelDescriptor]) -> None

Replace yieldChannels() wholesale with channels built from a list of descriptors.

Parameters:

descriptors (list of YieldChannelDescriptor) – The descriptors to build fresh channels from, in order – see addChannel()’s own docstring for what each one means and how it’s loaded.

Raises:

RuntimeError – If any descriptor fails to load (e.g. an unknown channel/model, or a [Fe/H] range mismatch). yieldChannels() is left completely unchanged in this case – every replacement channel is built into a temporary list first, and yieldChannels() only ever gets replaced wholesale once every descriptor has succeeded.

Notes

Unlike the YieldChannel-list overload, this builds every channel fresh from disk rather than moving in already-built ones. Also calls rebuildYieldGrid() afterward. As with the YieldChannel-list overload, a YieldChannel object read back from yieldChannels() before this call stays fully valid afterward – see deleteChannel()’s own docstring.

  1. setChannels(self: slugpy._slug.Yields, channels: collections.abc.Sequence) -> None

Replace yieldChannels() wholesale with a list of already-built channels.

Parameters:

channels (list of YieldChannel) – The channels to install, in order; ownership of each is transferred to this Yields, so none of them are usable from Python after this call. None of the entries may be None.

Raises:

ValueError – If any entry of channels is None.

Notes

yieldChannels() is discarded and replaced by channels, then rebuildYieldGrid() is called, synchronizing isotopes() (and every installed channel) onto the union of their own isotopesOrig(). A YieldChannel object previously read back from yieldChannels() stays fully valid afterward, even though it’s no longer one of the entries yieldChannels() itself returns – see deleteChannel()’s own docstring for the same behavior.

property skippedIsotopes

The isotopes treated as decaying instantly.

Returns:

Every unstable isotope the loaded channels tabulate or decay into whose lifetime is below controls().minIsotopeLifetime, as of the last rebuildYieldGrid(). None of these appear in isotopes; their yields are credited to their first longer-lived descendants instead.

Return type:

list of IsotopeData

property yieldChannels

The yield channels loaded so far.

Reading returns the channels in the same order as controls().yieldChannels(); each one stays fully valid even after being removed/replaced by a later deleteChannel()/setChannels() call – see deleteChannel()’s own docstring. Assigning a list transfers ownership of each element to this Yields via setChannels() – see its own docstring for the two accepted element types (YieldChannel or YieldChannelDescriptor) – then calls rebuildYieldGrid(), so isotopes() (and every channel) stays synchronized onto the new list.

yieldSum(self: slugpy._slug.Yields, mass: SupportsFloat | SupportsIndex, feh: SupportsFloat | SupportsIndex, dt_decay: SupportsFloat | SupportsIndex = 0.0) → list[float]

Get the sum, over every channel, of yield_(mass, feh), decayed by dt_decay.

Parameters:
  • mass (float) – Stellar mass (Msun); see yield_()’s own mass parameter.

  • feh (float) – [Fe/H]; see yield_()’s own feh parameter.

  • dt_decay (float, optional) – Elapsed time, in years, over which to apply radioactive decay – see yield_()’s own dt_decay parameter for exactly what this means and when it’s ignored. Applied once, to the summed total, rather than once per channel – numerically identical either way, since decay is linear in each isotope’s own mass.

Returns:

yield_sum – One yield (Msun) per entry of isotopes(), in the same order: result[j] = sum over i of yield_(mass, feh, 0)[i][j], decayed by dt_decay.

Return type:

list of float

Raises:

RuntimeError – Under the same conditions as yield_().

yield_(self: slugpy._slug.Yields, mass: SupportsFloat | SupportsIndex, feh: SupportsFloat | SupportsIndex, dt_decay: SupportsFloat | SupportsIndex = 0.0) → list[list[float]]

Get every channel’s own yield, as one (n_channels, len(isotopes())) array.

Parameters:
  • mass (float) – Stellar mass (Msun); need not satisfy every yieldChannels() entry’s own hasYield(mass).

  • feh (float) – [Fe/H]; need not lie within every yieldChannels() entry’s own feH() range.

  • dt_decay (float, optional) – Elapsed time, in years (the same units as every isotope’s own lifetime()), over which to apply radioactive decay to the raw per-channel yields before returning them; 0 (the default) applies no decay at all. Ignored entirely if the SimControls this Yields was built from has noDecay set to True, in which case every returned value is the cumulative amount of each isotope ever produced, regardless of any radioactive decay since.

Returns:

yields – yields[i][j] is the yield (Msun) of isotopes()[j] from yieldChannels()[i], for a star of the given mass/feh, after dt_decay has elapsed. Row i is left all zero if yieldChannels()[i] doesn’t cover mass/feh.

Return type:

list of list of float

Raises:

RuntimeError – If any yieldChannels() entry’s own yield_() throws (e.g. rebuildYieldGrid() was never called on that particular channel).

slugpy._slug.isotopeTable(z: SupportsInt | SupportsIndex, a: SupportsInt | SupportsIndex) → slugpy._slug.IsotopeData

Look up a single isotope by (Z, A) in the global isotope table.

Parameters:
  • z (int) – Atomic number.

  • a (int) – Mass number.

Returns:

isotope – The requested isotope’s data.

Return type:

IsotopeData

Raises:

KeyError – If no isotope with this (Z, A) exists in the table.

Notes

The returned IsotopeData is a reference into the single, global isotope table, resolved once at program startup – see its own class docstring. The most common use for this function is building a list of isotopes to pass to YieldChannel.rebuildYieldGrid()/Yields.rebuildYieldGrid(), to restrict which isotopes end up tabulated.

slugpy._slug.parsePDFDescriptor(file_name: str) → slugpy._slug.PDF

Construct a PDF from a descriptor file.

Parameters:

file_name (str) – Name of the PDF descriptor file.

Returns:

pdf

Return type:

PDF

Raises:

RuntimeError – If the file cannot be found or parsed.