# Source code for beast.physicsmodel.grid_weights_stars

```"""
Grid Weights
============
The use of a non-uniformly spaced grid complicates the marginalization
step as the trick of summation instead of integration is used.  But this
trick only works when the grid is uniformly spaced in all dimensions.

If the grid is not uniformly spaced, weights can be used to correct
for the non-uniform spacing.
"""
import numpy as np

__all__ = [
"compute_distance_grid_weights",
"compute_age_grid_weights",
"compute_mass_grid_weights",
"compute_metallicity_grid_weights",
"compute_bin_boundaries",
]

[docs]
def compute_bin_boundaries(tab):
"""
Computes the boundaries of bins

The bin boundaries are defined as the midpoint between each value in tab.
At the two edges, 1/2 of the bin width is subtractted/added to the
min/max of tab.

Parameters
----------
tab : numpy array
centers of each bin

Returns
-------
tab2 : numpy array
boundaries of the bins
"""
temp = tab[1:] - np.diff(tab) / 2.0
tab2 = np.zeros(len(tab) + 1)
tab2[0] = tab[0] - np.diff(tab)[0] / 2.0
tab2[-1] = tab[-1] + np.diff(tab)[-1] / 2.0
tab2[1:-1] = temp
return tab2

[docs]
def compute_age_grid_weights(logages):
"""
Computes the age weights to set a uniform prior on linear SFR

Parameters
----------
logages : numpy vector
log(ages)

Returns
-------
age_weights : numpy vector
total masses at each age for a constant SFR in linear age
"""
# ages need to be monotonically increasing
aindxs = np.argsort(logages)

# Computes the bin boundaries in log
logages_bounds = compute_bin_boundaries(logages[aindxs])

# initialize the age weights
age_weights = np.full(len(aindxs), 0.0)

# Returns the age weight as a numpy array
age_weights[aindxs] = np.diff(10 ** (logages_bounds))

# normalize to avoid numerical issues (too small or too large)
age_weights /= np.average(age_weights)

# return in the order that logages was passed
return age_weights

[docs]
def compute_mass_grid_weights(masses):
"""
Computes the mass weights to set a uniform prior on linear mass

Parameters
----------
masses : numpy vector
masses

Returns
-------
mass_weights : numpy vector
weights to provide a constant SFR in linear age
"""
# sort the initial mass along this isochrone
sindxs = np.argsort(masses)

# Compute the mass bin boundaries
masses_bounds = compute_bin_boundaries(masses[sindxs])

# compute the weights = bin widths
mass_weights = np.zeros(len(masses))
mass_weights[sindxs] = np.diff(masses_bounds)

# normalize to avoid numerical issues (too small or too large)
mass_weights /= np.average(mass_weights)

return mass_weights

[docs]
def compute_metallicity_grid_weights(mets):
"""
Computes the metallicity weights to set a uniform prior on linear metallicity

Parameters
----------
mets : numpy vector
metallicities

Returns
-------
metallicity_weights : numpy vector
weights to provide a flat metallicity
"""
# sort the initial mass along this isochrone
sindxs = np.argsort(mets)

# Compute the mass bin boundaries
mets_bounds = compute_bin_boundaries(mets[sindxs])

# compute the weights = bin widths
mets_weights = np.zeros(len(mets))
mets_weights[sindxs] = np.diff(mets_bounds)

# normalize to avoid numerical issues (too small or too large)
mets_weights /= np.average(mets_weights)

return mets_weights

[docs]
def compute_distance_grid_weights(dists):
"""
Computes the distance weights to set a uniform prior on linear distance

Parameters
----------
dists : numpy vector
distances

Returns
-------
dist_weights : numpy vector
weights to provide a flat distance
"""
# sort
tdists = np.array(dists)
sindxs = np.argsort(tdists)

# Compute the bin boundaries
dists_bounds = compute_bin_boundaries(tdists[sindxs])

# compute the weights = bin widths
dists_weights = np.zeros(len(tdists))
dists_weights[sindxs] = np.diff(dists_bounds)

# normalize to avoid numerical issues (too small or too large)
dists_weights /= np.average(dists_weights)

return dists_weights

```