-
ChiWai Chan authoredChiWai Chan authored
gstlal_inspiral_create_prior_diststats 8.04 KiB
#!/usr/bin/env python3
#
# Copyright (C) 2010--2014 Kipp Cannon, 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.
#
### A program to create some prior likelihood data to seed an offline analysis
#
# =============================================================================
#
# Preamble
#
# =============================================================================
#
from optparse import OptionParser
import numpy
import scipy
from lal import series
from ligo.lw import ligolw
from ligo.lw import lsctables
from ligo.lw import array as ligolw_array
from ligo.lw import param as ligolw_param
from ligo.lw import utils as ligolw_utils
from ligo.lw.utils import process as ligolw_process
from gstlal import far
from gstlal import svd_bank
from gstlal import templates
@ligolw_array.use_in
@ligolw_param.use_in
@lsctables.use_in
class LIGOLWContentHandler(ligolw.LIGOLWContentHandler):
pass
__author__ = "Chad Hanna <chad.hanna@ligo.org>"
__version__ = "git id %s" % "" # FIXME
__date__ = "" # FIXME
#
# =============================================================================
#
# Command Line
#
# =============================================================================
#
def parse_command_line():
parser = OptionParser(
version = "Name: %%prog\n%s" % "" # FIXME
)
parser.add_option("-v", "--verbose", action = "store_true", help = "Be verbose.")
# FIXME: default must be identical to gstlal_inspiral's default
parser.add_option("--coincidence-threshold", metavar = "value", type = "float", default = 0.005, help = "Set the coincidence window in seconds (default = 0.005). The light-travel time between instruments will be added automatically in the coincidence test.")
# FIXME: default must be identical to gstlal_inspiral's default
parser.add_option("--min-instruments", metavar = "count", type = "int", default = 2, help = "Set the minimum number of instruments that must contribute triggers to form a candidate (default = 2).")
parser.add_option("--write-likelihood", metavar = "filename", help = "Write merged raw likelihood data to this file.")
parser.add_option("--instrument", action = "append", help = "Append to a list of instruments to create dist stats for. List must be whatever instruments you intend to analyze.")
parser.add_option("-p", "--background-prior", metavar = "N", default = 1, type = "float", help = "Include an exponential background prior with the maximum bin count = N, default 1")
parser.add_option("--df", metavar = "N", default = 40, help = "set the degrees of freedom for the background chisq prior: default 40. You can also use template bandwidth to set this by setting it to 'bandwidth'")
parser.add_option("--svd-file", metavar = "filename", help = "The SVD file to read the template ids from")
parser.add_option("--svd-bin", metavar = "%04d", help = "The bin that this is, required if giving json manifest for --svd-file")
parser.add_option("--mass-model-file", metavar = "filename", help = "The mass model file to read from (hdf5 format)")
parser.add_option("--dtdphi-file", metavar = "filename", help = "dtdphi snr ratio pdfs to read from (hdf5 format). Default passed by gstlal_inspiral_pipe, but not when run as a standalone program.")
parser.add_option("--idq-file", metavar = "filename", help = "idq glitch file (hdf5 format)")
parser.add_option("--psd-xml", type = "string", help = "Specify a PSD to use for computing template bandwidth. Required if df is bandwidth")
options, filenames = parser.parse_args()
process_params = dict(options.__dict__)
if not options.instrument:
raise ValueError("must specify at least one --instrument")
options.instrument = set(options.instrument)
if options.min_instruments < 1:
raise ValueError("--min-instruments must be >= 1")
if options.min_instruments > len(options.instrument):
raise ValueError("--min-instruments is greater than the number of unique --instrument's")
if filenames:
raise ValueError("unrecognized arguments after options: %s" % " ".join(filenames))
if options.df == "bandwidth" and options.psd_xml is None:
raise ValueError("Must specify psd xml file if using bandwidth to set degrees of freedom")
psd = {}
if options.psd_xml:
for ifo, p in series.read_psd_xmldoc(ligolw_utils.load_filename(options.psd_xml, verbose = options.verbose, contenthandler = series.PSDContentHandler)).items():
f = numpy.arange(len(p.data.data)) * p.deltaF
# remove the last 10% of the PSD to remove anti-aliasing artifacts and replace with +inf
psd[ifo] = scipy.interpolate.interp1d(f[:int(0.9*len(f))], p.data.data[:int(0.9*len(f))], fill_value = numpy.inf, bounds_error = False)
template_ids = []
horizon_factors = {}
bandwidths = []
if options.svd_file.endswith(".xml") or options.svd_file.endswith(".xml.gz"):
for n, bank in enumerate(svd_bank.read_banks(options.svd_file, contenthandler = LIGOLWContentHandler, verbose = options.verbose)):
if bank.bank_type != "signal_model":
continue
template_ids += [row.template_id for row in bank.sngl_inspiral_table]
# FIXME don't hard code
if options.df == "bandwidth":
for ifo in psd:
bandwidths += [templates.bandwidth(row.mass1, row.mass2, row.spin1z, row.spin2z, f_min = 10.0, f_max = row.f_final, delta_f = 0.25, psd = psd[ifo]) for row in bank.sngl_inspiral_table]
horizon_factors.update(bank.horizon_factors)
elif options.svd_file.endswith(".json"):
assert options.svd_bin is not None
import json
with open(options.svd_file) as f:
manifest = json.loads(f.read())
bandwidths = [manifest[options.svd_bin]["min_bw"], manifest[options.svd_bin]["max_bw"]]
horizon_factors.update(manifest[options.svd_bin]["horizon_factors"])
template_ids = [int(template_id) for template_id in list(manifest[options.svd_bin]["horizon_factors"].keys())]
else:
raise ValueError("svd file cannot be read")
if options.df == "bandwidth":
# don't let the bandwidth get too small
options.df = max(int(min(bandwidths)) + 1, 10) * 3
return options, process_params, filenames, template_ids, horizon_factors
#
# =============================================================================
#
# Main
#
# =============================================================================
#
#
# command line
#
options, process_params, filenames, template_ids, horizon_factors = parse_command_line()
#
# initialize output document (records process start time)
#
xmldoc = ligolw.Document()
xmldoc.appendChild(ligolw.LIGO_LW())
process = ligolw_process.register_to_xmldoc(xmldoc, u"gstlal_inspiral_create_prior_diststats", instruments = options.instrument, paramdict = process_params)
#
# create parameter distribution priors
#
rankingstat = far.RankingStat(template_ids = template_ids, instruments = options.instrument, delta_t = options.coincidence_threshold, min_instruments = options.min_instruments, population_model_file = options.mass_model_file, dtdphi_file = options.dtdphi_file, horizon_factors = horizon_factors, idq_file = options.idq_file)
if options.background_prior > 0:
rankingstat.denominator.add_noise_model(number_of_events = options.background_prior)
# Add the numerator
rankingstat.numerator.add_signal_model(df = int(options.df), verbose = options.verbose)
#
# record results in output file
#
far.gen_likelihood_control_doc(xmldoc, rankingstat, None)
#
# done
#
process.set_end_time_now()
ligolw_utils.write_filename(xmldoc, options.write_likelihood, verbose = options.verbose)