3 # Copyright (C) 2010--2014 Kipp Cannon, Chad Hanna
5 # This program is free software; you can redistribute it and/or modify it
6 # under the terms of the GNU General Public License as published by the
7 # Free Software Foundation; either version 2 of the License, or (at your
8 # option) any later version.
10 # This program is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
13 # Public License for more details.
15 # You should have received a copy of the GNU General Public License along
16 # with this program; if not, write to the Free Software Foundation, Inc.,
17 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 # A program to compute the noise probability distributions of likehood ratios for inspiral triggers
22 # ### Command line interface
24 # + `--likelihood-cache` [filename]: Also load the likelihood ratio data files listsed in this LAL cache. See lalapps_path2cache for information on how to produce a LAL cache file.
25 # + `--verbose`: Be verbose.
26 # + `--ranking-stat-samples` [N] (int): Construct ranking statistic histograms by drawing this many samples from the ranking statistic generator (default = 1000000).
27 # + `--output` [filename]: Write merged raw likelihood data and likelihood ratio histograms to this LIGO Light-Weight XML file.
30 # =============================================================================
34 # =============================================================================
38 from optparse
import OptionParser
42 from glue
import iterutils
43 from glue.lal
import CacheEntry
44 from glue.ligolw
import ligolw
45 from glue.ligolw
import utils as ligolw_utils
46 from glue.ligolw.utils
import process as ligolw_process
47 from glue.ligolw.utils
import search_summary as ligolw_search_summary
48 from glue
import segments
49 from gstlal
import far
52 __author__ =
"Kipp Cannon <kipp.cannon@ligo.org>"
58 # =============================================================================
62 # =============================================================================
66 def parse_command_line():
67 parser = OptionParser(
68 version =
"Name: %%prog\n%s" %
"" # FIXME
70 parser.add_option(
"--likelihood-cache", metavar =
"filename", help =
"Also load the likelihood ratio data files listsed in this LAL cache. See lalapps_path2cache for information on how to produce a LAL cache file.")
71 parser.add_option(
"-v",
"--verbose", action =
"store_true", help =
"Be verbose.")
72 parser.add_option(
"--ranking-stat-samples", metavar =
"N", default = 10000000, type =
"int", help =
"Construct ranking statistic histograms by drawing this many samples from the ranking statistic generator (default = 10000000).")
73 parser.add_option(
"--samples-file", metavar =
"filename", action =
"append", help =
"Load the results of previous sampler runs from this file, and add the samples we generate to it. Can be given multiple times.")
74 parser.add_option(
"--samples-cache", metavar =
"filename", help =
"Load the results of previous sampler runs from the files listed in this LAL cache. See lalapps_path2cache for information on how to produce a LAL cache file.")
75 parser.add_option(
"--output", metavar =
"filename", help =
"Write merged raw likelihood data and likelihood ratio histograms to this LIGO Light-Weight XML file.")
76 options, urls = parser.parse_args()
78 paramdict = options.__dict__.copy()
80 if options.likelihood_cache is not None:
81 urls += [CacheEntry(line).url for line in open(options.likelihood_cache)]
83 raise ValueError(
"must provide some likelihood files")
85 if options.samples_file is None:
86 options.samples_file = []
87 if options.samples_cache is not None:
88 options.samples_file += [CacheEntry(line).url for line in open(options.samples_cache)]
90 if options.output is None:
91 raise ValueError(
"must set --output")
93 return options, urls, paramdict
97 # =============================================================================
101 # =============================================================================
110 options, urls, paramdict = parse_command_line()
114 # load parameter distribution data and, optionally, samples from previous
119 old_ranking_data = None
120 for n, filename in enumerate(options.samples_file, start = 1):
122 print >>sys.stderr,
"%d/%d:" % (n, len(options.samples_file)),
123 xmldoc = ligolw_utils.load_url(filename, contenthandler = far.ThincaCoincParamsDistributions.LIGOLWContentHandler,
verbose = options.
verbose)
124 ignored, this_ranking_data, ignored = far.parse_likelihood_control_doc(xmldoc)
126 if this_ranking_data is None:
127 raise ValueError(
"%s does not contain ranking statistic distribution data" % filename)
128 if old_ranking_data is None:
129 old_ranking_data = this_ranking_data
131 old_ranking_data += this_ranking_data
133 coincparamsdistributions = None
134 seglists = segments.segmentlistdict()
135 for n, likelihood_url in enumerate(urls, start = 1):
137 print >>sys.stderr,
"%d/%d:" % (n, len(urls)),
138 xmldoc = ligolw_utils.load_url(likelihood_url, contenthandler = far.ThincaCoincParamsDistributions.LIGOLWContentHandler,
verbose = options.
verbose)
139 this_coincparamsdistributions, ignored, this_seglists = far.parse_likelihood_control_doc(xmldoc)
141 if this_coincparamsdistributions is None:
142 raise ValueError(
"%s does not contain parameter distribution data" % likelihood_url)
143 if coincparamsdistributions is None:
144 coincparamsdistributions = this_coincparamsdistributions
146 coincparamsdistributions += this_coincparamsdistributions
147 seglists |= this_seglists
150 print >>sys.stderr,
"total livetime:\n\t%s" %
",\n\t".join(
"%s = %s s" % (instrument, str(abs(segs))) for instrument, segs in seglists.items())
152 # Compute the probability of instruments given signal
153 coincparamsdistributions.populate_prob_of_instruments_given_signal(segs = seglists, n = 1.0,
verbose = options.
verbose)
155 # Compute the intrument combination counts
156 coincparamsdistributions.add_instrument_combination_counts(segs = seglists,
verbose = options.
verbose)
160 # rebuild event parameter PDFs (+= method has not constructed these
166 if old_ranking_data is not None:
171 # take a moment to make sure we have SNR PDFs for all instrument
172 # combinations so that we don
't end up doing this inside the sampling
177 all_instrument_combos = [instruments for n in range(2, len(seglists) + 1) for instruments in iterutils.choices(seglists.keys(), n)]
178 for horizon_distances in coincparamsdistributions.horizon_history.all():
179 for instruments in all_instrument_combos:
180 coincparamsdistributions.get_snr_joint_pdf(instruments, horizon_distances, verbose = options.verbose)
184 # generate likelihood ratio histograms
188 ranking_data = far.RankingData(coincparamsdistributions, instruments = seglists.keys(), nsamples = options.ranking_stat_samples, verbose = options.verbose)
189 if old_ranking_data is not None:
190 ranking_data += old_ranking_data
194 # Write the parameter and ranking statistic distribution data to a file
198 xmldoc = ligolw.Document()
199 xmldoc.appendChild(ligolw.LIGO_LW())
200 process = ligolw_process.register_to_xmldoc(xmldoc, u"gstlal_inspiral_calc_rank_pdfs", paramdict = paramdict)
201 search_summary = ligolw_search_summary.append_search_summary(xmldoc, process, ifos = seglists.keys(), inseg = seglists.extent_all(), outseg = seglists.extent_all())
202 far.gen_likelihood_control_doc(xmldoc, process, coincparamsdistributions, ranking_data, seglists)
203 ligolw_process.set_process_end_time(process)
204 ligolw_utils.write_filename(xmldoc, options.output, gz = (options.output or "stdout").endswith(".gz"), verbose = options.verbose)