Forked from
lscsoft / GstLAL
2560 commits behind the upstream repository.
-
Chad Hanna authoredChad Hanna authored
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
gstlal_inspiral_mass_model 4.84 KiB
#!/usr/bin/env python
#
# Copyright (C) 2017,2018 Heather Fong and Chad Hanna
#
# 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.
import h5py
import argparse
import numpy
from glue.ligolw import ligolw
from glue.ligolw import lsctables, param as ligolw_param, array as ligolw_array
from glue.ligolw import utils as ligolw_utils
from glue.ligolw.utils import process as ligolw_process
import lal.series
from lal import rate
@ligolw_array.use_in
@ligolw_param.use_in
@lsctables.use_in
class LIGOLWContentHandler(ligolw.LIGOLWContentHandler):
pass
def chirpmass(m1, m2):
return (m1 * m2)**.6 / (m1 + m2)**.2
def schechter_norm(lower, upper, maxM, alpha):
norm_masses = numpy.linspace(lower, upper, 10000)
return numpy.sum(schechter(norm_masses, maxM, alpha)) * (norm_masses[1] - norm_masses[0])
def schechter(mass, maxM, alpha):
return (mass / maxM)**alpha * numpy.exp(-mass / maxM) / maxM
parser = argparse.ArgumentParser(description = "Create analytic mass models for prior weighting of templates")
parser.add_argument("--template-bank", metavar='name', type=str, help='The input template bank file name.', required = True)
parser.add_argument("--output", metavar='name', type=str, help='The output file name', default = "inspiral_mass_model.h5")
parser.add_argument("--model", metavar='name', type=str, help='Mass model. Options are: ligo. If you want another one, submit a patch.')
parser.add_argument("--verbose", help='Be verbose', action="store_true")
options = parser.parse_args()
# Read the template bank file
xmldoc = ligolw_utils.load_filename(options.template_bank, verbose = options.verbose, contenthandler = LIGOLWContentHandler)
sngl_inspiral_table = lsctables.SnglInspiralTable.get_table(xmldoc)
mchirps_of_tmps = chirpmass(sngl_inspiral_table.get_column("mass1"), sngl_inspiral_table.get_column("mass2"))
num_templates = len(mchirps_of_tmps)
num_bins = num_templates / 500
massBA = rate.BinnedDensity(rate.NDBins((rate.LogarithmicBins(min(mchirps_of_tmps)-1e-6, max(mchirps_of_tmps)+1e-6, num_bins),)))
for m in mchirps_of_tmps:
massBA.count[(m,)] += 1
rate.filter_array(massBA.array, rate.gaussian_window(num_bins / 50., sigma = 5))
# Assign the proper mass probabilities
ids = {}
tmplt_ids = []
mchirps = []
probs = []
bbhnorm = schechter_norm(5., 45, 45., -1.6)
othernorm = schechter_norm(1, 200, 200., -2.35)
for row in sngl_inspiral_table:
assert row.template_id not in ids
tmplt_ids.append(int(row.template_id))
if options.model == "ligo":
#
# BNS portion
#
# assume a 0.15 solar mass std deviation, this should capture both population distribution and snr effects
mchirp = chirpmass(row.mass1, row.mass2)
sigma = 0.15
mean = 1.2
bnsprob = 1. / (2 * numpy.pi * sigma**2)**.5 * numpy.exp(-(mchirp - mean)**2 / 2. / sigma**2)
#
# BBH portion
#
# normalised over 5 -- 45 Msun
# From: https://www.lsc-group.phys.uwm.edu/ligovirgo/cbcnote/RatesAndSignificance/O1O2CatalogRates
bbhprob = schechter(mchirp, 45., -1.6) / bbhnorm
#
# Other: made up
#
otherprob = schechter(mchirp, 200., -2.35) / othernorm
#
# Combined
#
bns_rate = 916.
bbh_rate = 56.
other_rate = 20. # made up
# FIXME if the noise is ever normalized over mass then we would need the following, but it isn't
#ids[row.template_id] = (bns_rate * bnsprob + bbh_rate * bbhprob + other_rate * otherprob) / massBA[(mchirp,)] / (bns_rate + bbh_rate + other_rate)
ids[row.template_id] = (bns_rate * bnsprob + bbh_rate * bbhprob + other_rate * otherprob) / (bns_rate + bbh_rate + other_rate)
mchirps.append(mchirp)
probs.append(ids[row.template_id])
else:
raise ValueError("Invalid mass model")
coefficients = numpy.zeros((1, 1, max(ids)+1), dtype=float)
for tid in ids:
coefficients[0,0,tid] = numpy.log(ids[tid] / len(sngl_inspiral_table))
#print coefficients.max()
#import matplotlib
#matplotlib.use('agg')
#from matplotlib import pyplot
#pyplot.loglog(mchirps, probs, "*")
#pyplot.savefig("blah.png")
#
# Write it out
f = h5py.File(options.output, "w")
# put in a dummy interval for the piecewise polynomials in SNR
f.create_dataset("SNR", data = numpy.array([0., 100.]))
f.create_dataset("coefficients", data = coefficients, compression="gzip")
f.create_dataset("event_id", data = numpy.array(tmplt_ids).astype(int))
f.close()