3 # Copyright (C) 2009-2013 Kipp Cannon, Chad Hanna, Drew Keppel
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.
19 ##@file gstlal_inspiral_marginalize_likelihood
20 # A program to marginalize the likelihood pdfs in noise across mass bins for a gstlal inspiral analysis.
22 # ### Command line interface
24 # + `--ignore-missing`: Ignore and skip missing input documents.
25 # + `--output` [filename]: Set the output file name (default = write to stdout).
26 # + `--likelihood-cache` [filename]: Set the cache file name from which to read likelihood files
27 # + `--verbose`: Be verbose.
31 # | Names | Hash | Date |
32 # | ------------------------------------------- | ------------------------------------------- | ---------- |
33 # | Florent, Jolien, Kipp, Chad | ca54624dac65388bc8dfd0d8f5ed5d187fbcb99a | 2015-05-14 |
38 # =============================================================================
42 # =============================================================================
46 from optparse
import OptionParser
50 from glue.ligolw
import ligolw
51 from glue.ligolw
import utils as ligolw_utils
52 from glue.ligolw.utils
import process as ligolw_process
53 from glue.ligolw.utils
import search_summary as ligolw_search_summary
54 from glue
import segments
58 from gstlal
import far
62 # =============================================================================
66 # =============================================================================
70 def parse_command_line():
71 parser = OptionParser(
73 parser.add_option(
"--ignore-missing", action =
"store_true", help =
"Ignore and skip missing input documents.")
74 parser.add_option(
"-o",
"--output", metavar =
"filename", help =
"Set the output file name (default = write to stdout).")
75 parser.add_option(
"--likelihood-cache", metavar =
"filename", help =
"Set the cache file name from which to read likelihood files.")
76 parser.add_option(
"--verbose", action =
"store_true", help =
"Be verbose.")
78 options, urls = parser.parse_args()
80 if options.likelihood_cache:
81 urls += [lal.CacheEntry(line).url for line in open(options.likelihood_cache)]
82 if not urls and not options.ignore_missing:
83 raise ValueError(
"no input documents")
89 # =============================================================================
93 # =============================================================================
102 options, urls = parse_command_line()
106 # initialize output document
110 xmldoc = ligolw.Document()
111 xmldoc.appendChild(ligolw.LIGO_LW())
112 process = ligolw_process.register_to_xmldoc(xmldoc, u
"gstlal_inspiral_marginalize_likelihood", options.__dict__)
113 search_summary = ligolw_search_summary.append_search_summary(xmldoc, process)
117 # loop over input documents
123 seglists = segments.segmentlistdict()
124 for n, url in enumerate(urls, start = 1):
126 # load input document
130 print >>sys.stderr,
"%d/%d:" % (n, len(urls)),
132 in_xmldoc = ligolw_utils.load_url(url,
verbose = options.
verbose, contenthandler = far.ThincaCoincParamsDistributions.LIGOLWContentHandler)
134 # IOError is raised when an on-disk file is missing.
135 # urllib2.URLError is raised when a URL cannot be loaded,
136 # but this is subclassed from IOError so IOError will catch
138 if not options.ignore_missing:
141 print >>sys.stderr,
"Could not load \"%s\" ... skipping as requested" % url
145 # compute weighted sum of ranking data PDFs
148 this_distributions, this_ranking_data, this_seglists = far.parse_likelihood_control_doc(in_xmldoc)
151 if this_distributions is None:
152 raise ValueError(
"\"%s\" contains no parameter PDF data" % url)
153 if this_ranking_data is None:
154 raise ValueError(
"\"%s\" contains no ranking statistic PDF data" % url)
156 if distributions is None:
157 distributions = this_distributions
159 distributions += this_distributions
160 if ranking_data is None:
161 ranking_data = this_ranking_data
163 ranking_data += this_ranking_data
164 seglists |= this_seglists
168 # regenerate event parameter PDFs. += method doesn
't compute these
171 # NOTE: the FAP/FAR code doesn't actually use any of the information in
172 # the parameter PDF file. that code does need to know the
"count above
173 # threshold" but in the offline case that count isn
't known until after the
174 # coincs are ranked (the files loaded here have the count of all coincs,
175 # not just coincs above the ranking stat FAP/FAR normalization threshold).
176 # the compute_far_from_snr_chisq_histograms program will count the
177 # above-threshold events itself and replace the coinc counts in the
178 # parameter PDF file with its counts and write a new file. we wouldn't
179 # need to load the parameter PDF files here at all except that the Farr et
180 # al. rate estimation code needs the marginalized numerator and denominator
183 # also re-generate likelihood ratio (ranking data) PDFs from the combined
184 # bin counts. this shouldn
't be needed but it's fast and maybe more
185 # accurate than relying on the weighted sum of the PDFs to have been
195 # write output document
199 distributions.process_id = ranking_data.process_id = process.process_id
200 far.gen_likelihood_control_doc(xmldoc, process, distributions, ranking_data, seglists)
201 search_summary.instruments = seglists.keys()
202 search_summary.in_segment = search_summary.out_segment = seglists.extent_all()
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)