Class Extinct

Class Documentation

class Extinct

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

An Extinct is built from a named curve in an extinction curve registry (see data/extinct/extinct.toml/extinct.h5 and data/tools/extinct/add_extinction_curve.py/fetch_draine_extinction.py for how these are populated): the curve’s own native (wavelength, kappa) tabulation is read from the registry, then interpolated onto controls.specsyn()->wl(), clipped to the native curve’s own coverage. kappa is in arbitrary units – only the curve’s shape matters, since a caller scales it by a separately supplied A_V.

Loading the curve from disk (loadCurve()) and rebuilding the cached quantities derived from it and from controls_ (rebuildCache()) are each exposed as their own public method, rather than folded entirely into the constructor, so that a caller who has already built an Extinct can cheaply refresh it after some part of controls_ changes – rebuildCache() alone if only controls_.specsyn()’s wavelength grid, controls_.nebular(), or controls_.avDistField() changed, or loadCurve() if the curve itself (extinct.model) changed and the underlying data must be re-read from disk. Both are failure-atomic: each performs its actual work (loadCurveImpl()/rebuildCacheImpl()) on a disposable copy of *this, committing the result back (via commitFrom()) only once that work has fully succeeded, so a caller who catches an exception from either always finds this object exactly as it was beforehand, never a partially-updated mix of old and new state.

Public Functions

inline Extinct(const std::string &extinctName, const io::SimControls &controls, const std::string &registryName = defaultRegistry)

Construct an Extinct from a named registry entry.

Calls loadCurveImpl(extinctName, registryName) – see its own comment, and rebuildCacheImpl()’s, for what actually happens. Calls the *Impl variant directly, not loadCurve() itself (which additionally wraps this same work for atomicity – see its own comment): a constructor that throws leaves no object behind to roll back to, so that extra copy- and-commit dance would be pure overhead here.

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

  • controls – Simulation controls this Extinct reads its wavelength grid (controls.specsyn()->wl()), redshift (see wlObs()), nebular emission grid, and field-star A_V distribution from, live, for the rest of its lifetime – see controls_’s own comment. controls.specsyn() may be null (e.g. before Python installs one via SimControls::setSpecsyn(), or after removing one already installed) – see rebuildCacheImpl()’s own comment for what that leaves this Extinct able to do. Must outlive this Extinct. Has no default of its own (unlike registryName below): a reference bound to a temporary default-constructed SimControls would dangle the moment this constructor returned, since this class stores it live rather than copying out of it.

  • registryName – Name of the extinction curve registry file

Throws:

std::runtime_error – if extinctName is not found in the registry, or the registry/HDF5 file cannot be read

Extinct(const Extinct&) = default
Extinct(Extinct&&) = default
auto operator=(const Extinct&) -> Extinct& = delete
auto operator=(Extinct&&) -> Extinct& = delete
~Extinct() = default
inline void loadCurve(const std::string &extinctName, const std::string &registryName = defaultRegistry)

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

Locates and parses registryName, validates that it lists extinctName, opens the HDF5 file it names, reads that curve’s own native (wavelength, kappa) tabulation, and rebuilds every cached quantity derived from it – the actual work is loadCurveImpl()’s, see its own comment.

Performed on a disposable copy of *this, committed back (see commitFrom()) only once that copy’s loadCurveImpl() call has fully succeeded – see this class’s own top-level comment for why. Called once, by the constructor (via loadCurveImpl() directly there, not this wrapper – see the constructor’s own comment for why). Also public so a caller (e.g. from Python, after SimControls’s own extinct.model changes) can reload a different curve into an already- constructed Extinct, without building a new one.

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

  • registryName – Name of the extinction curve registry file

Throws:

std::runtime_error – if extinctName is not found in the registry, or the registry/HDF5 file cannot be read

void rebuildCache()

Recompute every cached quantity derived from wlDat_/extinctDat_ and controls_.

If controls_.specsyn() is null, clears every cached quantity (wl_/extinct_/wlOffset_/extinctLines_/extinctionFacCts_/ extinctionFacCtsNeb_/extinctionFacCtsLines_) instead of computing anything – see rebuildCacheImpl()’s own comment for why every one of them, not just wl_/extinct_, ends up equally unusable in that state. Every method that reads these quantities (wlObs(), applyExtinction(), applyExtinctionCts(), applyExtinctionLines(), applyExtinctionCtsLines()) throws rather than silently returning an empty or wrongly-shaped result while this Extinct is in that state – see their own comments.

Otherwise, builds an interpolator from the native curve data (wlDat_, extinctDat_) and:

  • interpolates it onto controls_.specsyn()->wl(), clipped to the native curve’s own coverage, into wl_/extinct_ (see wl()’s own comment for wlOffset_);

  • interpolates it onto every nebular emission line’s own wavelength too, if a nebular emission grid was requested (see initExtinctLines());

  • normalizes both of the above to a V-band extinction of 1 mag (see normalize());

  • precomputes extinctionFacCts_/extinctionFacCtsNeb_/extinctionFacCtsLines_ (see their own comments). The actual computation is rebuildCacheImpl()’s – this method itself only performs it on a disposable copy of *this and commits the result back on success (see commitFrom(), and this class’s own top-level comment for why), so a failure partway through (e.g. a degenerate avDistField – see computeExtinctionFacCts()) leaves every cached quantity exactly as it was before the call.

Called once, by loadCurveImpl(), immediately after it finishes reading wlDat_/extinctDat_ from disk (via rebuildCacheImpl() directly there, not this wrapper – see loadCurveImpl()’s own comment for why). Also public so a caller (e.g. from Python, after SimControls’s own spectral synthesizer, nebular emission grid, or field-star A_V distribution changes) can recompute these cached quantities from the curve already loaded, without re-reading it from disk. Safe to call more than once, for the same reason rebuildCacheImpl() is – see its own comment.

Defined out-of-line, in Extinct.cpp, next to rebuildCacheImpl() (which needs io::SimControls’s complete type to call controls_.specsyn()/nebular()/avDistField() – see that file’s own comment), even though this wrapper itself does not.

inline auto controls() const -> const io::SimControls&

Get the SimControls this Extinct was constructed against.

Returns:

A const reference to controls_ – see its own comment. Exposed so a caller replacing a SimControls’s own extinction curve (see SimControls::setExtinct()) can verify it is installing an Extinct actually built against that same SimControls, rather than one whose controls_ points somewhere else entirely.

inline auto wlDat() const -> const std::vector<double>&

Get the native extinction curve wavelength grid.

Returns:

A const reference to the wavelength grid, in Angstrom, as read directly from the registry entry

inline auto extinctDat() const -> const std::vector<double>&

Get the native extinction curve.

Returns:

A const reference to the extinction curve, in arbitrary units, at each wavelength in wlDat()

inline auto wl() const -> const std::vector<double>&

Get the interpolated wavelength grid.

Returns:

A const reference to controls_.specsyn()->wl(), clipped to wlDat()’s own [min, max] coverage – empty if controls_.specsyn() was null the last time rebuildCache() ran (see its own comment)

inline auto extinct() const -> const std::vector<double>&

Get the interpolated extinction curve.

Returns:

A const reference to the extinction curve, in arbitrary units, interpolated onto wl() – empty exactly when wl() is, and for the same reason

auto wlObs() const -> std::vector<double>

Get the observed-frame interpolated wavelength grid.

Defined out-of-line, in Extinct.cpp – see that file’s own comment for why (controls_.z() needs io::SimControls’s complete type, which this header can only forward-declare; mirrors Specsyn::wlObs()’s identical situation).

Throws:

std::runtime_error – if wl() is empty (controls_.specsyn() was null the last time rebuildCache() ran – see its own comment)

Returns:

wl(), redshifted by (1 + z), with z read live from controls_

inline auto wlOffset() const

Get the number of leading elements chopped off controls_.specsyn()->wl()

Returns:

wlOffset_ – the number of leading elements of controls_.specsyn()->wl() that fell below the native curve’s own coverage and so are absent from wl()/extinct() (see rebuildCache()’s own comment). Lets a caller line up a spectrum tabulated on that same wavelength grid with wl()’s own, narrower grid, exactly as applyExtinction() does internally. 0 (not otherwise meaningful) whenever wl() is empty.

inline auto applyExtinction(const double A_V, const std::vector<double> &spec) const -> std::vector<double>

Apply this extinction curve to a spectrum.

spec’s first wlOffset_ elements (those falling outside this curve’s own wavelength coverage) are discarded; each of the remaining wl().size() elements is multiplied by exp(-A_V * extinct()) at the corresponding wavelength.

Parameters:
  • A_V – V-band extinction to apply, in magnitudes

  • spec – Spectrum to extinguish, tabulated on exactly controls_.specsyn()->wl()

Throws:

std::runtime_error – if wl() is empty (controls_.specsyn() was null the last time rebuildCache() ran – see its own comment)

Returns:

The extinguished spectrum, on the wavelength grid returned by wl()

inline auto applyExtinctionCts(const std::vector<double> &spec, const bool nebular = false) const -> std::vector<double>

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 of spec’s remaining wl().size() elements is multiplied by extinctionFacCts_ at the corresponding wavelength: the expectation value of exp(-A_V * extinct()) over the field-star A_V distribution (io::SimControls::avDistField()), precomputed by rebuildCache() – see extinctionFacCts_’s own comment; or, if nebular is true, by extinctionFacCtsNeb_ instead – see its own comment.

Parameters:
  • spec – Spectrum to extinguish, tabulated on exactly controls_.specsyn()->wl() – see applyExtinction()’s own spec parameter

  • nebular – If true, spec is nebular emission, and is attenuated by extinctionFacCtsNeb_ (which also integrates over the nebular-to-stellar extinction ratio, io::SimControls::avNebFac()) instead of extinctionFacCts_

Throws:

std::runtime_error – if wl() is empty (controls_.specsyn() was null the last time rebuildCache() ran – see its own comment)

Returns:

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

inline auto applyExtinctionLines(const double A_V, const std::vector<double> &lineLum) const -> std::vector<double>

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

below – this method already returns an empty result for.

Line-luminosity analog of applyExtinction(): each element of lineLum is multiplied by exp(-A_V * extinctLines_) at the corresponding line. Unlike applyExtinction(), no elements are dropped – extinctLines_ already reads 0 (rather than being absent) for any line outside the native curve’s own coverage – so lineLum and the result share the same size and indexing as extinctLines_/controls_.nebular()->lineWl(), with no analog of wlOffset_.

Parameters:
  • A_V – V-band extinction to apply, in magnitudes

  • lineLum – Luminosity of each of controls_.nebular()->lineWl()’s own lines, in erg/s

Throws:

std::runtime_error – if wl() is empty (controls_.specsyn() was null the last time rebuildCache() ran – see its own comment). Does NOT throw merely because extinctLines_ itself is empty (controls_.nebular() is null): that is a separate, valid state – see

Returns:

The extinguished line luminosities, in the same order as lineLum/controls_.nebular()->lineWl()

inline auto applyExtinctionCtsLines(const std::vector<double> &lineLum) const -> std::vector<double>

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

Line-luminosity analog of applyExtinctionCts(): each element of lineLum is multiplied by extinctionFacCtsLines_ at the corresponding line – the expectation value of exp(-A_V f * extinctLines_) over the field-star A_V distribution (io::SimControls::avDistField()) and the nebular-to-stellar extinction ratio f (io::SimControls::avNebFac()), since lines are always nebular emission, precomputed by rebuildCache() – see extinctionFacCtsLines_’s own comment. See applyExtinctionLines()’s own comment for why there is no analog of wlOffset_ here.

Parameters:

lineLum – Luminosity of each of controls_.nebular()->lineWl()’s own lines, in erg/s – see applyExtinctionLines()’s own lineLum parameter

Throws:

std::runtime_error – if wl() is empty (controls_.specsyn() was null the last time rebuildCache() ran). Does NOT throw merely because extinctLines_ itself is empty – see applyExtinctionLines()’s own identical comment.

Returns:

The expected extinguished line luminosities, in the same order as lineLum/controls_.nebular()->lineWl()