Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added milky way height and radius distributions #4920

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions examples/distributions/example.ini
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ q =
;xi2 =
;phi_a =
;phi_s =
r =

[prior-v0]
name = uniform
Expand Down Expand Up @@ -114,3 +115,12 @@ max-q = 8
;max-chi_eff = 1
;min-xi_bounds = 0.
;max-xi_bounds = 1

[prior-r]
name = sym_gamma_dist
min-r = -10
max-r = 10
scales = 1,2
weights = 0.5,0.5
power = 1
interp_points = 1000
6 changes: 5 additions & 1 deletion pycbc/distributions/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@
from pycbc.distributions.fixedsamples import FixedSamples
from pycbc.distributions.mass import MchirpfromUniformMass1Mass2, \
QfromUniformMass1Mass2
from pycbc.distributions.sym_gamma_dist import SymGammaDist



# a dict of all available distributions
distribs = {
Expand All @@ -61,7 +64,8 @@
FixedSamples.name: FixedSamples,
MchirpfromUniformMass1Mass2.name: MchirpfromUniformMass1Mass2,
QfromUniformMass1Mass2.name: QfromUniformMass1Mass2,
FisherSky.name: FisherSky
FisherSky.name: FisherSky,
SymGammaDist.name: SymGammaDist
}

def read_distributions_from_config(cp, section="prior"):
Expand Down
121 changes: 121 additions & 0 deletions pycbc/distributions/sym_gamma_dist.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import logging
import numpy
import scipy
from pycbc.distributions import bounded

logger = logging.getLogger('pycbc.distributions.sym_gamma_dist')

class SymGammaDist(bounded.BoundedDist):
name = 'sym_gamma_dist'
"""
Samples from a weighted sum of one dimensional symmetric gamma distributions charecterised by a power $n$,
scale factors $s_{i}$, and weights $w_{i}$
\[
p(x) = \sum_{i} w_{i} |x|^{n} exp(-|x|/s_{i})
\]
The inverse cdf is calculated by interpolating the cdf over the range of the variable
The cdf is calculated using regularised lower incomplete gamma function as defined in scipy.special

Parameters
-----------
Example config file

[prior-x]
name = sym_gamma_dist
min-x = -10
max-x = 10
scales = 1,2
weights = 0.5,0.5
power = 2
interp_points = 500

"""



def __init__(self, scales = None, weights = None,
power = None, interp_points = None, **params):
super(SymGammaDist, self).__init__(**params)
self._scales = {}
self._weights = {}
self._power = {}
self._interp_points = {}
self._norms = {}
for p, bounds in self._bounds.items():
if type(scales) == str:
self._scales[p] = [float(s) for s in scales.split(",")]
else:
self._scales[p] = [float(scales)]
if type(weights) == str:
self._weights[p] = [float(w) for w in weights.split(",")]
else:
self._weights[p] = [float(weights)]
self._power[p] = float(power)
self._interp_points[p] = int(interp_points)
if len(self._scales[p]) != len(self._weights[p]):
raise ValueError(f'Unequal number of scales and weights'
+ f'provided for parameter {p}')
if numpy.sum(self._weights[p]) != float(1):
raise ValueError('Weights should add to 1.0')
self._norms[p] = [0]*len(self._scales[p])
if numpy.sign(bounds[0]) == numpy.sign(bounds[1]):
for i in range(len(self._norms[p])):
self._norms[p][i] = numpy.abs(scipy.special.factorial(self._power[p])
*self._scales[p][i]**(self._power[p]+1)
*(scipy.special.gammainc(self._power[p]+1, numpy.abs(bounds[0]/self._scales[p][i]))
-scipy.special.gammainc(self._power[p]+1, numpy.abs(bounds[1]/self._scales[p][i]))))
if numpy.sign(bounds[0]) != numpy.sign(bounds[1]):
for i in range(len(self._norms[p])):
self._norms[p][i] = numpy.abs(scipy.special.factorial(self._power[p])
*self._scales[p][i]**(self._power[p]+1)
*(scipy.special.gammainc(self._power[p]+1, numpy.abs(bounds[0]/self._scales[p][i]))
+scipy.special.gammainc(self._power[p]+1, numpy.abs(bounds[1]/self._scales[p][i]))))

def c0(self, x, power, scale):
return scipy.special.gammainc(power+1,numpy.abs(x/scale))*\
scipy.special.factorial(power)*scale**(power+1)

def _logpdf(self, **kwargs):
if kwargs in self:
lpdf_p = 0
for p in self._params:
pdf_i = 0
for i in range(len(self._scales[p])):
pdf_i += (self._weights[p][i]/self._norms[p][i])* \
numpy.abs(kwargs[p])**(self._power[p])* \
numpy.e**(-numpy.abs(kwargs[p])/self._scales[p][i])
lpdf_p += numpy.log(pdf_i)
return lpdf_p
else:
return -numpy.inf
def _pdf(self, **kwargs):
return numpy.e**(self._logpdf(**kwargs))

def _cdfinv_param(self, param, value):
param_min, param_max = self._bounds[param][0], self._bounds[param][1]
param_array = numpy.linspace(param_min,
param_max,
self._interp_points[param])

if numpy.sign(param_min) != numpy.sign(param_max):
cdf_array = numpy.zeros(self._interp_points[param])
for i in range(len(self._scales[param])):
mask = param_array <= 0
cdf_array[mask] = cdf_array[mask] + (self._weights[param][i]/self._norms[param][i])* \
(self.c0(numpy.abs(param_min), self._power[param], self._scales[param][i])
-self.c0(numpy.abs(param_array[mask]), self._power[param], self._scales[param][i]))
cdf_array[~mask] = cdf_array[~mask] + (self._weights[param][i]/self._norms[param][i])* \
(self.c0(param_min, self._power[param], self._scales[param][i])
+self.c0(param_array[~mask], self._power[param], self._scales[param][i]))
inv_cdf_interpolate = scipy.interpolate.interp1d(cdf_array, param_array)

return inv_cdf_interpolate(value)
if numpy.sign(param_min) == numpy.sign(param_max):
cdf_array = numpy.zeros(self._interp_points[param])
for i in range(len(self._scales[param])):
cdf_array += (self._weights[param][i]/self._norms[param][i])* \
numpy.abs(self.c0(param_min, self._power[param], self._scales[param][i])
-self.c0(param_array, self._power[param], self._scales[param][i]))
inv_cdf_interpolate = scipy.interpolate.interp1d(cdf_array, param_array)
return inv_cdf_interpolate(value)
__all__ = ['SymGammaDist']
Loading