Source code for beast.fitting.pdf1d
# class to generate 1D PDFs for many objects all with
# spare or full nD likelihoods on the same grid of models
from __future__ import (absolute_import, division, print_function,
unicode_literals)
import math
import numpy as np
[docs]class pdf1d():
def __init__(self, gridvals, nbins, logspacing=False, minval=None, maxval=None):
"""
Create an object which can be used to efficiently generate a 1D pdf for an observed object
Parameters
----------
gridvals: array-like
values of the quantity for all the grid points
nbins: int
number of bins to use for the 1D pdf
logspacing: bool
whether to use logarithmic spacing for the bins
minval, maxval: float (optional)
override the range for the bins. this can be useful to make
sure that the pdfs for different runs have the same bins
"""
self.nbins = nbins
self.n_gridvals = len(gridvals)
self.logspacing = logspacing
indxs = np.arange(self.n_gridvals)
self.n_indxs = len(indxs)
# storage of the grid values to consider
tgridvals = np.array(gridvals[indxs])
if len(tgridvals) <= 0:
# this is a hack to just get the code to work when
# all the possible values are negative and the requested
# pdf is for log x values
self.bad = True
self.bin_vals = np.linspace(0.0,1.0, num=self.nbins)
else:
self.bad = False
self.min_val = tgridvals.min() if minval is None else minval
self.max_val = tgridvals.max() if maxval is None else maxval
# if log spacing requested, make the transformation
if logspacing:
self.min_val = math.log10(self.min_val)
self.max_val = math.log10(self.max_val)
tgridvals = np.log10(tgridvals)
self.bin_delta = (self.max_val - self.min_val)/(self.nbins-1)
self.bin_vals = self.min_val + np.arange(self.nbins)*self.bin_delta
self.bin_edges = self.min_val + \
(np.arange(self.nbins+1) - 0.5)*self.bin_delta
# get in indices of the grid for each bin in the PDF
_tpdf_indxs = np.digitize(tgridvals, self.bin_edges)
# generate the reverse indices
# (like the IDL version returned by the histogram function)
_tgrid_indxs = np.arange(self.n_indxs)
self.bin_edges_indxs = np.zeros((self.nbins+1), dtype=np.uint64)
for i in range(nbins):
# find the indicies for the current bin
_cur_indxs, = np.where(_tpdf_indxs == (i+1))
_cur_indxs = indxs[_cur_indxs]
self.bin_edges_indxs[i+1] = self.bin_edges_indxs[i] + \
len(_cur_indxs)
if len(_cur_indxs) > 0:
_tgrid_indxs[self.bin_edges_indxs[i]
:self.bin_edges_indxs[i+1]] = _cur_indxs
# transform the bin edges back to linear spacing if log spacing
# was asked for
if logspacing:
self.bin_vals = np.power(10.0,self.bin_vals)
self.bin_edges = np.power(10.0,self.bin_edges)
self.tpdf_indxs = _tgrid_indxs
[docs] def gen1d(self, gindxs, weights):
if self.bad:
return (self.bin_vals, np.zeros((self.nbins)))
else:
_tgrid = np.zeros(self.n_gridvals)
_tgrid[gindxs] = weights
_vals_1d = np.zeros(self.nbins)
for i in range(self.nbins):
if self.bin_edges_indxs[i] < self.bin_edges_indxs[i+1]:
_vals_1d[i] = np.sum(_tgrid[self.tpdf_indxs[
self.bin_edges_indxs[i]:self.bin_edges_indxs[i+1]]])
return (self.bin_vals, _vals_1d)
[docs] def gen1d_full(self, weights):
if self.bad:
return (self.bin_vals, np.zeros((self.nbins)))
else:
_vals_1d = np.zeros(self.nbins)
for i in range(self.nbins):
if self.bin_edges_indxs[i] < self.bin_edges_indxs[i+1]:
_vals_1d[i] = np.sum(weights[self.tpdf_indxs[
self.bin_edges_indxs[i]:self.bin_edges_indxs[i+1]]])
return (self.bin_vals, _vals_1d)