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.
19 ## @file gstlal_inspiral_create_prior_diststats
20 # A program to create some prior likelihood data to seed an online analysis
22 # ### Command line interface
23 # + `--verbose`: Be verbose.
24 # + `--synthesize-injection-count` [N] (int): Synthesize an injection distribution with N injections (default is 1000000).
25 # + `--write-likelihood` [filename]: Write merged raw likelihood data to this file.
26 # + `--instrument`: Append to a list of instruments to create dist stats for. Must be whatever instruments you intend to analyze.
27 # + `--trials-far-thresh` (float): Set the far threshold for the thresh parameter in the trials table.
28 # + `--background-prior` [N] (float): Include an exponential background prior with the maximum bin count = N (default is 1).
31 # =============================================================================
35 # =============================================================================
40 from optparse
import OptionParser
44 from glue
import iterutils
45 from glue.ligolw
import ligolw
46 from glue.ligolw
import utils as ligolw_utils
47 from glue.ligolw.utils
import process as ligolw_process
48 from glue.text_progress_bar
import ProgressBar
51 from pylal
import series as lalseries
52 from pylal
import rate
55 from gstlal
import far
56 from gstlal
import reference_psd
59 __author__ =
"Chad Hanna <chad.hanna@ligo.org>"
65 # =============================================================================
69 # =============================================================================
73 def parse_command_line():
74 parser = OptionParser(
75 version =
"Name: %%prog\n%s" %
"" # FIXME
77 parser.add_option(
"-v",
"--verbose", action =
"store_true", help =
"Be verbose.")
78 parser.add_option(
"-s",
"--synthesize-injection-count", metavar =
"N", default = 100000, type =
"int", help =
"Synthesize an injection distribution with N injections. default 1000000")
79 parser.add_option(
"--write-likelihood", metavar =
"filename", help =
"Write merged raw likelihood data to this file.")
80 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.")
81 parser.add_option(
"--horizon-distances", action =
"append", help =
"Cache SNR PDFs for these instruments and horizon distances. Format is \"instrument=distance,instrument=distance,...\", e.g., H1=120,L1=120,V1=48. Units for distance are irrelevant (PDFs depend only on their ratios). A PDF will be constructed for every combination of two or more instruments from the set. It is an error for an instrument to be named here and not in a --instrument option.")
82 parser.add_option(
"--horizon-distance-masses", metavar =
"m1,m2", action =
"append", default = [
"1.4,1.4"], help =
"When computing pre-cached SNR PDFs from a collection of PSD files, compute horizon distances for these masses in solar mass units (default = 1.4,1.4). Can be given multiple times.")
83 parser.add_option(
"--horizon-distance-flow", metavar =
"Hz", default = 10., type =
"float", help =
"When computing pre-cached SNR PDFs from a collection PSD files, start horizon distance integral at this frequency in Hertz (default = 10 Hz).")
84 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")
85 options, filenames = parser.parse_args()
87 process_params = dict(options.__dict__)
89 options.instrument = set(options.instrument)
90 if not options.instrument or len(options.instrument) < 2:
91 raise ValueError(
"must specify at least two distinct --instrument's")
93 if options.horizon_distances is None:
94 options.horizon_distances = []
95 options.horizon_distances = [dict((name, float(dist)) for name, dist in [name_dist.split(
"=") for name_dist in horizon_distances.strip().split(
",")]) for horizon_distances in options.horizon_distances]
96 if options.horizon_distances:
97 all_horizon_instruments = reduce(lambda a, b: a | b, (set(horizon_distances) for horizon_distances in options.horizon_distances))
98 if all_horizon_instruments > options.instrument:
99 raise ValueError(
"missing %s for instruments named in --horizon-distances options" %
", ".join(
"--instrument %s" % inst for inst in all_horizon_instruments - options.instrument))
101 if len(filenames) > 1:
102 raise ValueError(
"At this point only one PSD file is supported on the command line")
104 options.horizon_distance_masses = [map(float, s.split(
",")) for s in options.horizon_distance_masses]
106 return options, process_params, filenames
111 # =============================================================================
115 # =============================================================================
124 options, process_params, filenames = parse_command_line()
128 # initialize output document (records process start time)
132 xmldoc = ligolw.Document()
133 xmldoc.appendChild(ligolw.LIGO_LW())
134 process = ligolw_process.register_to_xmldoc(xmldoc, u
"gstlal_inspiral_create_prior_diststats", ifos = options.instrument, paramdict = process_params)
138 # create parameter distribution priors
142 coincparamsdistributions = far.ThincaCoincParamsDistributions()
144 if options.background_prior > 0:
145 coincparamsdistributions.add_background_prior(n = options.background_prior, instruments = options.instrument,
verbose = options.
verbose)
147 if options.synthesize_injection_count > 0:
148 coincparamsdistributions.add_foreground_snrchi_prior(instruments = options.instrument, n = options.synthesize_injection_count, prefactors_range = (0.0, 0.10), df = 40,
verbose = options.
verbose)
156 for n, filename in enumerate(filenames, 1):
158 print >>sys.stderr,
"%d/%d:" % (n, len(filenames)),
159 psd = lalseries.
read_psd_xmldoc(ligolw_utils.load_filename(filename, contenthandler = lalseries.LIGOLWContentHandler,
verbose = options.
verbose))
160 for m1, m2 in options.horizon_distance_masses:
161 horizon_distances = dict((instrument, (0. if instrument not in psd else reference_psd.
horizon_distance(psd[instrument], m1, m2, 8., options.horizon_distance_flow))) for instrument in options.instrument)
163 print >>sys.stderr,
"\t%s" %
", ".join(
"%s = %.4g Mpc" % x for x in sorted(horizon_distances.items()))
164 options.horizon_distances.append(horizon_distances)
166 for horizon_distances in options.horizon_distances:
167 for n in range(2, len(horizon_distances) + 1):
168 for instruments in iterutils.choices(horizon_distances.keys(), n):
169 # FIXME get_snr_joint_pdf() should be called in the
170 # future, but for now we just make pdfs for the actual
171 # horizon distances requested not the quantized ones.
172 # coincparamsdistributions.get_snr_joint_pdf(instruments, horizon_distances,
verbose = options.
verbose)
174 # Force the SNR pdf to be generated to be at the actual horizon distance values not the quantized ones
175 key = frozenset(instruments), frozenset(coincparamsdistributions.quantize_horizon_distances(horizon_distances).items())
177 print >>sys.stderr,
"For horizon distances %s" %
", ".join(
"%s = %.4g Mpc" % item for item in sorted(horizon_distances.items()))
178 progressbar = ProgressBar(text =
"%s SNR PDF" %
", ".join(sorted(key[0])))
181 binnedarray = coincparamsdistributions.joint_pdf_of_snrs(key[0], horizon_distances, progressbar = progressbar)
183 coincparamsdistributions.snr_joint_pdf_cache[key] = None, binnedarray, 0
187 # record results in output file
191 far.gen_likelihood_control_doc(xmldoc, process, coincparamsdistributions, None, {}, comment = u
"background and signal priors (no real data)")
199 ligolw_process.set_process_end_time(process)
200 ligolw_utils.write_filename(xmldoc, options.write_likelihood, gz = options.write_likelihood.endswith(
".gz"),
verbose = options.verbose)