gstlal-inspiral  0.4.2
 All Classes Namespaces Files Functions Variables Pages
gstlal_inspiral_create_prior_diststats
1 #!/usr/bin/env python
2 #
3 # Copyright (C) 2010--2014 Kipp Cannon, Chad Hanna
4 #
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.
9 #
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.
14 #
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.
18 #
19 ## @file gstlal_inspiral_create_prior_diststats
20 # A program to create some prior likelihood data to seed an online analysis
21 #
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).
29 
30 #
31 # =============================================================================
32 #
33 # Preamble
34 #
35 # =============================================================================
36 #
37 
38 
39 import sys
40 from optparse import OptionParser
41 import numpy
42 
43 
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
49 
50 
51 from pylal import series as lalseries
52 from pylal import rate
53 
54 
55 from gstlal import far
56 from gstlal import reference_psd
57 
58 
59 __author__ = "Chad Hanna <chad.hanna@ligo.org>"
60 __version__ = "git id %s" % "" # FIXME
61 __date__ = "" # FIXME
62 
63 
64 #
65 # =============================================================================
66 #
67 # Command Line
68 #
69 # =============================================================================
70 #
71 
72 
73 def parse_command_line():
74  parser = OptionParser(
75  version = "Name: %%prog\n%s" % "" # FIXME
76  )
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()
86 
87  process_params = dict(options.__dict__)
88 
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")
92 
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))
100 
101  if len(filenames) > 1:
102  raise ValueError("At this point only one PSD file is supported on the command line")
103 
104  options.horizon_distance_masses = [map(float, s.split(",")) for s in options.horizon_distance_masses]
105 
106  return options, process_params, filenames
107 
108 
109 
110 #
111 # =============================================================================
112 #
113 # Main
114 #
115 # =============================================================================
116 #
117 
118 
119 #
120 # command line
121 #
122 
123 
124 options, process_params, filenames = parse_command_line()
125 
126 
127 #
128 # initialize output document (records process start time)
129 #
130 
131 
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)
135 
136 
137 #
138 # create parameter distribution priors
139 #
140 
141 
142 coincparamsdistributions = far.ThincaCoincParamsDistributions()
143 
144 if options.background_prior > 0:
145  coincparamsdistributions.add_background_prior(n = options.background_prior, instruments = options.instrument, verbose = options.verbose)
146 
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)
149 
150 
151 #
152 # seed SNR PDF cache
153 #
154 
155 
156 for n, filename in enumerate(filenames, 1):
157  if options.verbose:
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)
162  if options.verbose:
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)
165 
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)
173 
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())
176  if options.verbose:
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])))
179  else:
180  progressbar = None
181  binnedarray = coincparamsdistributions.joint_pdf_of_snrs(key[0], horizon_distances, progressbar = progressbar)
182  del progressbar
183  coincparamsdistributions.snr_joint_pdf_cache[key] = None, binnedarray, 0
184 
185 
186 #
187 # record results in output file
188 #
189 
190 
191 far.gen_likelihood_control_doc(xmldoc, process, coincparamsdistributions, None, {}, comment = u"background and signal priors (no real data)")
192 
193 
194 #
195 # done
196 #
197 
198 
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)