Class Cluster

Class Documentation

class Cluster

A class to represent a mono-age stellar cluster.

Public Types

using Segment = interp::Interpolator1D<static_cast<size_t>(tracks::FieldIdx::nTrackQty)>
using Interp1dPtr = std::vector<std::unique_ptr<Segment>>
using Track2DVar = std::variant<tracks::Tracks2D, std::shared_ptr<const tracks::Tracks2D>>

Public Functions

Cluster(unsigned long uid, double mass, double time, const io::SimControls &controls)

Initialize a cluster.

Parameters:
  • uid – Unique ID of cluster

  • mass – Target cluster mass

  • time – Cluster formation time

  • controls – Simulation controls (physics settings and control-flow/integrator-tolerance settings together); stored by reference, so it must outlive this Cluster – see controls_’s own comment

Cluster(unsigned long uid, double mass, double time, const io::SimControls &controls, const utils::RngState &rngState)

Reconstruct a cluster’s stellar masses from a previously recorded rng state.

Sets every member the same way the primary constructor does, except for feH_, aV_, avNeb_, m_, and birthMass_: rngState_ is set to rngState directly, since that is this cluster’s own birth state by construction, rather than one captured live. feH_, aV_ and avNeb_ (if SimControls::avDist() is valid), and m_ are then all drawn together, in the same order the primary constructor draws them, from rngState rather than the live rng stream – saving the live state first and restoring it immediately afterward, so this constructor has no lasting effect on the ambient rng stream. All of these draws, not just m_’s, must be replayed from rngState for the result to come out bitwise identical to the original cluster’s: PDF::draw() generally consumes rng state (to pick a segment, via a utils::DiscreteDist, if there is more than one, and within most segment types’ own draw), so drawing feH_ (and aV_) live first would already have advanced the stream before m_’s draw ever saw rngState, decoupling the draws from the sequence that originally produced them. birthMass_ (which starts at 0.0, overwritten once m_ is drawn) is then reduced from m_ before m_ is sorted, matching the primary constructor’s own order (there, forced by computing birthMass_ in the member initializer list, which runs before the constructor body’s own sort) – reducing in a different order would reproduce the same set of masses but not necessarily the same birthMass_ bit-for-bit, since floating-point addition is not associative.

Parameters:
  • uid – Unique ID of cluster

  • mass – Target cluster mass

  • time – Cluster formation time

  • controls – Simulation controls; see the primary constructor’s own comment

  • rngState – The rng state to draw star masses from – typically one previously returned by rngState() (e.g. read back from an output file), so that the resulting starMasses()/birthMass() come out bitwise identical to the original cluster’s

inline auto rngState() const -> const utils::RngState&

Return the state of the rng at this cluster’s birth.

Returns:

A const reference to the serialized rng state (see utils::RngThread::getState()) in effect immediately before this cluster’s own stochastic draws, sufficient to exactly reproduce its starMasses()/birthMass() later via the rngState-accepting constructor overload

inline auto uid() const

Return the cluster’s unique identifier.

Returns:

Unique ID of cluster

inline auto targetMass() const

Return the cluster’s target mass.

Returns:

Target cluster mass in Msun

inline auto birthMass() const

Return the cluster’s actual mass at birth.

Returns:

Actual cluster mass at birth in Msun

inline auto formTime() const

Return the cluster’s formation time.

Returns:

Cluster formation time

inline auto feH() const

Return the cluster’s [Fe/H].

Returns:

[Fe/H] of cluster

inline auto aV() const

Return the cluster’s V-band extinction.

Returns:

A_V, in magnitudes, drawn from SimControls::avDist() at construction, or 0 if SimControls::avDist() is not valid (extinct.AV was not given in the input deck)

inline auto avNeb() const

Return the V-band extinction applied to the cluster’s nebular emission.

Returns:

A_V,neb, in magnitudes: aV() times a factor drawn from SimControls::avNebFac() at construction (see that method’s own comment), or 0 if SimControls::avDist() is not valid (no extinction requested)

inline auto starMasses() const -> const auto&

Return the current list of living stellar masses.

Returns:

Masses of currently alive stars in Msun

inline auto deadStarMasses() const -> const auto&

Return the list of dead stellar masses.

Returns:

Masses of dead stars in Msun

inline auto starDeathTimes() const -> const auto&

Return the death time of every currently-alive star.

Returns:

Death time (formTime() + the star’s own lifetime at this cluster’s [Fe/H]) of every entry of starMasses(), in the same order – see the constructor’s own comment for why that order is not, in general, starMasses()’s own ascending-mass order

inline auto deadStarDeathTimes() const -> const auto&

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

Returns:

Death time of every entry of deadStarMasses(), in the same order – both are cleared and repopulated together every advance() call, see updateLivingStars()’s own comment

auto tracks() const -> const tracks::Tracks2D&

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

If the simulation has a fixed [Fe/H], this returns a reference to the slice shared by SimControls (and thus by every Cluster in the simulation). Otherwise it returns a reference to the slice computed for, and owned by, this Cluster alone. Either way, callers can use the returned Tracks2D uniformly without needing to know which case applies.

Returns:

A const reference to a Tracks2D object at this cluster’s [Fe/H]

inline auto spec() -> const auto&

Return the cluster’s continuously-sampled spectrum.

Computed lazily: if advance() has run since spec_/specExtinct_ were last computed, this triggers computeSpec() (which computes spec_/specExtinct_/specNeb_/specNebExtinct_/lineLum_/lineLumExtinct_ together) before returning, so the result is always current as of the last advance() – see specCurrent_’s own comment. Not const, since it may need to run that computation.

Returns:

A const reference to the spectrum of the non-stochastically-sampled part of the population, on the wavelength grid of the simulation’s spectral synthesizer, or an empty vector if no spectral synthesizer was requested (SimControls::specsyn() is null)

inline auto specExtinct() -> const auto&

Return the cluster’s extincted spectrum.

Computed lazily – see spec()’s own comment; all share the same specCurrent_ flag, since a single computeSpec() call computes them together.

Returns:

A const reference to spec(), attenuated by aV() through SimControls::extinct(), on the wavelength grid returned by SimControls::extinct()’s own wl(); an empty vector if no extinction curve was requested (SimControls::extinct() is null) or spec() itself is empty (no spectral synthesizer was requested)

inline auto phot() -> const auto&

Return the cluster’s photometry.

Computed lazily – see spec()’s own comment; computePhot() itself calls spec()/specExtinct() (rather than reading spec_/specExtinct_ directly), so calling phot() alone, with no prior call to spec(), still computes a spectrum current as of the last advance() first.

Returns:

A const reference to the photometric value computed from spec() by each filter in SimControls::filters(), in the same order as FilterCollection::filterNames()/ filterUnits(), or an empty vector if no filter collection was requested (SimControls::filters() is null)

inline auto photExtinct() -> const auto&

Return the cluster’s extincted photometry.

Computed lazily – see phot()’s own comment; all share the same photCurrent_ flag, since a single computePhot() call computes them together. A filter whose passband extends past the edge of the extinction curve’s wavelength coverage is NaN – see FilterCollection::phot()’s three-argument overload.

Returns:

A const reference to the photometric value computed from specExtinct() by each filter in SimControls::filters(), in the same order as phot(); an empty vector if no extinction curve was requested (SimControls::extinct() is null) or no filter collection was requested (SimControls::filters() is null)

inline auto specNeb() -> const auto&

Return the cluster’s stellar + nebular spectrum.

Computed lazily – see spec()’s own comment; shares the same specCurrent_ flag, since a single computeSpec() call computes spec_/specExtinct_/specNeb_/specNebExtinct_/lineLum_/lineLumExtinct_ together.

Returns:

A const reference to spec(), with nebular continuum and line emission added via SimControls::nebular()’s own getCluster(), on the same wavelength grid as spec(); an empty vector if no nebular emission grid was requested (SimControls::nebular() is null) or spec() itself is empty (no spectral synthesizer was requested)

inline auto specNebExtinct() -> const auto&

Return the cluster’s extincted stellar + nebular spectrum.

Computed lazily – see specNeb()’s own comment.

Returns:

A const reference to specNeb(), attenuated by aV() through SimControls::extinct(), on the wavelength grid returned by SimControls::extinct()’s own wl(); an empty vector if no extinction curve was requested (SimControls::extinct() is null) or specNeb() itself is empty (no nebular emission grid or no spectral synthesizer was requested)

inline auto lineLum() -> const auto&

Return the cluster’s nebular emission line luminosities.

Computed lazily – see specNeb()’s own comment.

Returns:

A const reference to the luminosity of each of SimControls::nebular()’s own lineWl() lines, in erg/s, in the same order; an empty vector if no nebular emission grid was requested (SimControls::nebular() is null) or spec() itself is empty (no spectral synthesizer was requested)

inline auto lineLumExtinct() -> const auto&

Return the cluster’s extincted nebular emission line luminosities.

Computed lazily – see lineLum()’s own comment.

Returns:

A const reference to lineLum(), attenuated by aV() through SimControls::extinct(); an empty vector if no extinction curve was requested (SimControls::extinct() is null) or lineLum() itself is empty (no nebular emission grid or no spectral synthesizer was requested)

inline auto photNeb() -> const auto&

Return the cluster’s stellar + nebular photometry.

Computed lazily – see phot()’s own comment; shares the same photCurrent_ flag, since a single computePhot() call computes phot_/photExtinct_/photNeb_/photNebExtinct_ together.

Returns:

A const reference to the photometric value computed from specNeb() by each filter in SimControls::filters(), in the same order as phot(); an empty vector if no nebular emission grid was requested (SimControls::nebular() is null) or no filter collection was requested (SimControls::filters() is null)

inline auto photNebExtinct() -> const auto&

Return the cluster’s extincted stellar + nebular photometry.

Computed lazily – see photNeb()’s own comment. A filter whose passband extends past the edge of the extinction curve’s wavelength coverage is NaN – see FilterCollection::phot()’s three-argument overload.

Returns:

A const reference to the photometric value computed from specNebExtinct() by each filter in SimControls::filters(), in the same order as phot(); an empty vector if no extinction curve was requested (SimControls::extinct() is null), no nebular emission grid was requested (SimControls::nebular() is null), or no filter collection was requested (SimControls::filters() is null)

inline auto lbol()

Return the cluster’s bolometric luminosity.

Computed lazily – see spec()’s own comment. computeLbol() itself is a no-op (leaving lbol_ at 0) unless SimControls::computeLbol() is true, mirroring computeSpec()/ computePhot()’s own null-guards.

Returns:

The population’s total bolometric luminosity, in Lsun, at the current time, or 0 if SimControls::computeLbol() is false (Lbol was never requested)

inline auto yields() const -> const auto&

Return this cluster’s total nucleosynthetic yield of each isotope.

Unlike spec()/phot()/lbol() (see spec()’s own comment), not computed lazily here: advance() itself calls computeYields() eagerly at the end of every call (see its own comment for why), so yields_ is already current by the time this is called – rather than being recomputed from scratch, yields_ accumulates the contribution of every star that has died over this cluster’s whole lifetime so far, and stays at the all-zero vector it was sized to at construction (see its own comment) until advance() has run at least once.

Returns:

A const reference to yields_: intended to be the total yield (Msun) of each isotope in controls().yields()’s own isotopes(), summed over this cluster’s stars – laid out as one channel-major row (of isotopes().size() entries each) per entry in controls().yields()->yieldChannels() if controls().yieldsChannelDecomposed() is true, or just isotopes().size() combined totals (summed over every channel) if false; an empty vector if no yield channels were requested (controls().yields() is null)

inline auto cumSNe() const -> double

Return the cumulative number of supernovae up to the current time.

The result is the sum of the supernovae from the stochastically-sampled part of the population (stochSN_), which is always an integer, and from the non-stochastic part (nonStochSN_), which in general is not – hence the return type is double rather than an integer type.

Like yields(), not computed lazily here: advance() itself calls computeFeedback() eagerly at the end of every call (see lastFeedbackTime_’s own comment for why), so both counts are already current by the time this is called. Zero until advance() has run at least once. Which stars count as supernovae is decided by SimControls::hasSN(mass, feH), at this cluster’s own feH() – see its own comment.

Returns:

Number of supernovae that have occurred in this cluster from its formation up to the current time

inline auto mDotWind() -> double

Return the population’s total stellar wind mass flux.

Computed lazily, like lbol() (see spec()’s own comment): advance() only marks the wind fluxes stale (windsCurrent_), and the first of mDotWind()/pDotWind()/eDotWind() called afterward recomputes all three via computeWinds() – see its own comment for how. Unlike cumSNe(), nothing here depends on which stars died during a particular advance() call, so there is no need to pay for this on every step.

Returns:

The summed mass loss rate of every living star, in Msun/yr, at the current time; 0 until advance() has run at least once

inline auto pDotWind() -> double

Return the population’s total stellar wind momentum flux.

See mDotWind()’s own comment.

Returns:

The summed wind momentum flux, mdot * v_wind, of every living star, in g cm s^-2 (dyn), at the current time; 0 until advance() has run at least once

inline auto eDotWind() -> double

Return the population’s total stellar wind energy flux.

See mDotWind()’s own comment.

Returns:

The summed wind kinetic energy flux, (1/2) mdot * v_wind^2, of every living star, in erg s^-1, at the current time; 0 until advance() has run at least once

inline auto isDisrupted() const

Return whether the cluster has disrupted.

Returns:

True if the cluster has disrupted

void advance(double t)

Advance the cluster in time.

Updates the living/dead star lists and the isochrone for the new time, then marks spec_/specExtinct_/specNeb_/ specNebExtinct_/lineLum_/lineLumExtinct_/phot_/photExtinct_/photNeb_/ photNebExtinct_/lbol_ as stale (see specCurrent_/ photCurrent_/lbolCurrent_’s own comments) rather than recomputing them itself – they are instead recomputed lazily, on demand, the next time spec()/specExtinct()/ specNeb()/specNebExtinct()/lineLum()/lineLumExtinct()/phot()/ photExtinct()/photNeb()/photNebExtinct()/lbol() is actually called.

Parameters:

t – Time to which to advance, in yr