Composable distributions for STROOPWAFEL parameter sampling.
A Distribution bundles the four things STROOPWAFEL needs to know
about a parameter’s prior, which used to be spread across samplers.py,
priors.py and transforms.py:
how to draw samples (in sampling space),
the prior pdf (in sampling space),
the adaptive-sampling sigma (Gaussian kernel width), and
the transform between physical and sampling space.
Each distribution is a base distribution (Uniform,
PowerLaw, BrokenPowerLaw, TruncatedNormal) composed
with a transform (Identity, Log10, Ln,
Sin, CosShift). The base operates entirely in sampling
space; the
transform maps to and from the physical space the user specifies bounds in
and the simulation consumes. For example flat_in_log is
Uniform(transform=Log10()) and sana is
PowerLaw(-0.55, transform=Log10()).
To add a distribution, build an instance and either pass it straight to a
Parameter or register it
under a name:
from cosmic.sample.stroopwafel.distributions import PowerLaw, register
register('my_imf', PowerLaw(-2.7))
All array-valued methods take and return (N,) ndarrays.
- class cosmic.sample.stroopwafel.distributions.BrokenPowerLaw(breaks, alphas, transform=None)[source]¶
Bases:
DistributionContinuous broken power law:
p(x) \propto x^alphawithalphachanging at fixed breakpoints.The density is continuous across every breakpoint. With the default
Identitytransform this gives the Kroupa IMF (breaks=[0.5],alphas=[-1.3, -2.3]): shallower below 0.5 Msun, steeper above. Over any window that contains no breakpoint it reduces exactly toPowerLaw, so sampling masses above 0.5 Msun behaves identically to a single power law.Sampling and
sigmause a piecewise inverse CDF; the normalisation, sampling, and density are all computed over the requested[lo, hi]window only (segments outside it are ignored).- Parameters:
- breakssequence of float
Internal breakpoints in sampling space, strictly increasing. The distribution has
len(breaks) + 1segments.- alphassequence of float
Power-law exponent for each segment (
len(breaks) + 1of them);alphas[i]applies belowbreaks[i]andalphas[-1]above the final break. None may equal exactly -1.- transformTransform, optional
Map between physical and sampling space, by default
Identity.
- pdf(values, lo, hi)[source]¶
Prior probability density at
values(sampling space).- Parameters:
- valuesnumpy.ndarray
(N,) array of values in sampling space.
- lofloat
Lower bound in sampling space.
- hifloat
Upper bound in sampling space.
- Returns:
- numpy.ndarray
(N,) array of prior densities, normalised over
[lo, hi].
- sample(n, lo, hi, rng=None)[source]¶
Draw
nsamples in sampling space within[lo, hi].- Parameters:
- nint
Number of samples to draw.
- lofloat
Lower bound in sampling space.
- hifloat
Upper bound in sampling space.
- rngnumpy.random.Generator, optional
Random number generator, by default None.
- Returns:
- numpy.ndarray
(N,) array of samples in sampling space.
- sigma(values, lo, hi, avg_density)[source]¶
CDF-space step, identical in spirit to
PowerLaw.sigma().
- class cosmic.sample.stroopwafel.distributions.CosShift[source]¶
Bases:
TransformSampling space is
cos(angle + pi/2) = -sin(angle).Suitable for declination-like coordinates measured from
-pi/2topi/2. The map is monotonically decreasing, soTransform.bounds()swaps the endpoints to keeplo <= hi.
- class cosmic.sample.stroopwafel.distributions.Distribution(transform=None)[source]¶
Bases:
objectA prior distribution, sampled and evaluated in sampling space.
Subclasses implement
sample()andpdf().sigma()has a default implementation (avg_density / pdf) that power laws override. Alllo/hiarguments are bounds in sampling space (i.e. already passed throughself.transform);ParameterSpacehandles that conversion viaTransform.bounds().- Parameters:
- transformTransform, optional
Map between physical and sampling space, by default
Identity.
- pdf(values, lo, hi)[source]¶
Prior probability density at
values(sampling space).- Parameters:
- valuesnumpy.ndarray
(N,) array of values in sampling space.
- lofloat
Lower bound in sampling space.
- hifloat
Upper bound in sampling space.
- Returns:
- numpy.ndarray
(N,) array of prior densities, normalised over
[lo, hi].
- sample(n, lo, hi, rng=None)[source]¶
Draw
nsamples in sampling space within[lo, hi].- Parameters:
- nint
Number of samples to draw.
- lofloat
Lower bound in sampling space.
- hifloat
Upper bound in sampling space.
- rngnumpy.random.Generator, optional
Random number generator, by default None.
- Returns:
- numpy.ndarray
(N,) array of samples in sampling space.
- sigma(values, lo, hi, avg_density)[source]¶
Per-sample Gaussian kernel width for adaptive refinement.
The default places a kernel whose width is the local inter-sample spacing,
avg_density / pdf. Distributions with closed-form CDFs (e.g.PowerLaw) override this with an exact CDF-space step.- Parameters:
- valuesnumpy.ndarray
(K,) array of hit values in sampling space.
- lofloat
Lower bound in sampling space.
- hifloat
Upper bound in sampling space.
- avg_densityfloat
Characteristic inter-sample spacing.
- Returns:
- numpy.ndarray
(K,) array of sigma values.
- class cosmic.sample.stroopwafel.distributions.Identity[source]¶
Bases:
TransformIdentity transform: sampling space is physical space.
- class cosmic.sample.stroopwafel.distributions.Ln[source]¶
Bases:
TransformSampling space is
ln(physical)(physical must be positive).
- class cosmic.sample.stroopwafel.distributions.Log10[source]¶
Bases:
TransformSampling space is
log10(physical)(physical must be positive).
- class cosmic.sample.stroopwafel.distributions.PowerLaw(alpha, transform=None)[source]¶
Bases:
DistributionPower-law distribution
p(x) \propto x^alphaon[lo, hi].Sampling uses the inverse CDF and the prior is the normalised power law, both in sampling space. Combined with a transform this covers
kroupaandsana_ecc(identity) andsana(Log10).- Parameters:
- alphafloat
Power-law exponent.
- transformTransform, optional
Map between physical and sampling space, by default
Identity.
- pdf(values, lo, hi)[source]¶
Prior probability density at
values(sampling space).- Parameters:
- valuesnumpy.ndarray
(N,) array of values in sampling space.
- lofloat
Lower bound in sampling space.
- hifloat
Upper bound in sampling space.
- Returns:
- numpy.ndarray
(N,) array of prior densities, normalised over
[lo, hi].
- sample(n, lo, hi, rng=None)[source]¶
Draw
nsamples in sampling space within[lo, hi].- Parameters:
- nint
Number of samples to draw.
- lofloat
Lower bound in sampling space.
- hifloat
Upper bound in sampling space.
- rngnumpy.random.Generator, optional
Random number generator, by default None.
- Returns:
- numpy.ndarray
(N,) array of samples in sampling space.
- sigma(values, lo, hi, avg_density)[source]¶
Exact CDF-space step for the power-law sigma.
Maps each hit to its CDF position, steps by
avg_densityin CDF space, maps back, and returns the larger of the two distances. The CDF ofp(x) \propto x^alphaon[lo, hi]isF(x) = (x^a - lo^a) / (hi^a - lo^a)witha = alpha + 1, so the inverse isF^{-1}(u) = (u*(hi^a - lo^a) + lo^a)^{1/a}. Keeping every intermediate in[lo^a, hi^a]avoids the catastrophic cancellation seen with very smalllo.- Raises:
- ValueError
If
lo <= 0(the power-law variable must be positive over the whole range).
- class cosmic.sample.stroopwafel.distributions.Sin[source]¶
Bases:
TransformSampling space is
sin(angle)for an angle in[-pi/2, pi/2].
- class cosmic.sample.stroopwafel.distributions.Transform[source]¶
Bases:
objectMap between physical space and sampling space.
The base class is the identity transform; subclasses override
to_sampling()andto_physical().boundsis derived automatically and handles non-monotonic-increasing maps (e.g.CosShift) by sorting the endpoints.- bounds(lo, hi)[source]¶
Map a physical-space bound pair into sampling space.
- Parameters:
- lofloat
Lower bound in physical space.
- hifloat
Upper bound in physical space.
- Returns:
- lo_samplingfloat
Lower bound in sampling space.
- hi_samplingfloat
Upper bound in sampling space.
- class cosmic.sample.stroopwafel.distributions.TruncatedNormal(mu, scale, transform=None)[source]¶
Bases:
DistributionNormal distribution truncated to
[lo, hi]in sampling space.Combined with
Lnthis gives the'disberg'natal-kick prior: the kick magnitudevfollowsLogNormal(mu, scale)soln(v)is normally distributed, and sampling space isln(v).- Parameters:
- mufloat
Mean of the underlying normal (in sampling space).
- scalefloat
Standard deviation of the underlying normal (in sampling space).
- transformTransform, optional
Map between physical and sampling space, by default
Identity.
- pdf(values, lo, hi)[source]¶
Prior probability density at
values(sampling space).- Parameters:
- valuesnumpy.ndarray
(N,) array of values in sampling space.
- lofloat
Lower bound in sampling space.
- hifloat
Upper bound in sampling space.
- Returns:
- numpy.ndarray
(N,) array of prior densities, normalised over
[lo, hi].
- sample(n, lo, hi, rng=None)[source]¶
Draw
nsamples in sampling space within[lo, hi].- Parameters:
- nint
Number of samples to draw.
- lofloat
Lower bound in sampling space.
- hifloat
Upper bound in sampling space.
- rngnumpy.random.Generator, optional
Random number generator, by default None.
- Returns:
- numpy.ndarray
(N,) array of samples in sampling space.
- class cosmic.sample.stroopwafel.distributions.Uniform(transform=None)[source]¶
Bases:
DistributionUniform distribution on
[lo, hi]in sampling space.Combined with a transform this covers
uniform(identity),flat_in_log(Log10),uniform_in_sine(Sin) anduniform_in_cosine(CosShift).- pdf(values, lo, hi)[source]¶
Prior probability density at
values(sampling space).- Parameters:
- valuesnumpy.ndarray
(N,) array of values in sampling space.
- lofloat
Lower bound in sampling space.
- hifloat
Upper bound in sampling space.
- Returns:
- numpy.ndarray
(N,) array of prior densities, normalised over
[lo, hi].
- sample(n, lo, hi, rng=None)[source]¶
Draw
nsamples in sampling space within[lo, hi].- Parameters:
- nint
Number of samples to draw.
- lofloat
Lower bound in sampling space.
- hifloat
Upper bound in sampling space.
- rngnumpy.random.Generator, optional
Random number generator, by default None.
- Returns:
- numpy.ndarray
(N,) array of samples in sampling space.
- cosmic.sample.stroopwafel.distributions.get_distribution(dist)[source]¶
Resolve a name or instance to a
Distribution.- Parameters:
- diststr or Distribution
Either a key in
DISTRIBUTIONSor a distribution instance (returned unchanged).
- Returns:
- Distribution
The resolved distribution instance.