# Copyright (C) 2017,2018 Heather Fong
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2 of the License, or (at your
# option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# =============================================================================
#
# Preamble
#
# =============================================================================
#
import h5py
import math
import numpy
import os
try:
from scipy.interpolate import PPoly
except ImportError:
# argh, scipy too old
# FIXME: delete this when we can rely on LDG sites having a
# new-enough scipy
from lal.rate import IrregularBins
class PPoly(object):
def __init__(self, c, x):
self.intervals = IrregularBins(x)
self.coeffs = c
self.x0 = x
def __call__(self, x):
i = self.intervals[x]
return numpy.poly1d(self.coeffs[:,i].squeeze())(x - self.x0[i]),
from gstlal import stats as gstlalstats
# FIXME: caution, this information might get organized differently later.
# for now we just need to figure out where the gstlal-inspiral directory in
# share/ is. don't write anything that assumes that this module will
# continue to define any of these symbols
from gstlal import paths as gstlal_config_paths
__all__ = [
"UniformInTemplatePopulationModel",
"SourcePopulationModel"
]
#
# =============================================================================
#
# Population Model
#
# =============================================================================
#
[docs]class SourcePopulationModel(object):
#
# NOTE: This is no longer the default file used in the population
# model. Various tools including the dag have been modified to allow
# the user to specify the mass model file at run time. If you want to
# use this file, you should point the dag script to wherever it is on
# your filesystem.
#
# NOTE: future code will have this comment and these next two lines deleted.
#
#POPULATION_MODELS_PATH = os.path.join(gstlal_config_paths["pkgdatadir"], "population_models")
#DEFAULT_FILENAME = os.path.join(POPULATION_MODELS_PATH, "O2/lnP_template_signal_BBH_logm_reweighted_mchirp.hdf5")
def __init__(self, template_ids, filename = None):
"""
Sets the polynomial coefficients, given the template ID and
SNR for a source population model, from which lnP is then
computed using PPoly.
"""
if filename is not None:
with h5py.File(filename, 'r') as model:
snr_bp = model['SNR'][()]
template_ids = numpy.array([x for x in template_ids])
try:
template_id_to_index_map = {x:n for n, x in enumerate(numpy.array(model['template_id']))}
except KeyError:
# FIXME: assume sequential order if model['event_id'] doesn't exist
template_id_to_index_map = {x:n for n, x in enumerate(numpy.array(model['event_id']))}
# PPoly can construct an array of polynomials by just
# feeding it the coefficients array all in one go, but then
# it insists on evaluating all of them at once. we don't
# want to suffer that cost, so we have to make an array of
# PPoly objects ourselves, and index into it to evaluate
# just one. since we have to do this anyway, we use a
# dictionary to also solve the problem of mapping
# template_id to a specific polynomial
try:
these_template_id_indices = numpy.array([template_id_to_index_map[t] for t in template_ids], dtype=numpy.int32)
these_template_id_indices_sort_index = numpy.argsort(these_template_id_indices)
except KeyError:
raise KeyError("One or more template IDs are not in this model")
coefficients = model['coefficients'][:,:,these_template_id_indices[these_template_id_indices_sort_index]]
self.polys = {template_ids[these_template_id_indices_sort_index[n]]:PPoly(coefficients[:,:, n], snr_bp) for n in range(len(these_template_id_indices_sort_index))}
self.max_snr = snr_bp.max()
else:
self.polys = None
self.max_snr = None
@gstlalstats.assert_ln_probability
def lnP_template_signal(self, template_id, snr):
assert snr >= 0.
try:
lnP_vs_snr = self.polys[template_id]
except KeyError:
raise KeyError("template ID %d is not in this model" % template_id)
# PPoly's .__call__() returns an array, so we need the .item()
return lnP_vs_snr(min(snr, self.max_snr)).item()