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_ll_inspiral_create_prior_diststats
20 # A program to create some prior likelihood data to seed an online analysis
22 # ### Command line interface
24 # --verbose, action = "store_true", help = "Be verbose."
25 # --num-templates, metavar = "N", default = 1000, type = "int", help = "Set the number of templates per bank. default 1000")
26 # --num-banks, metavar = "N", default = 1, type = "int", help = "Set the number of banks. default 1")
27 # --write-likelihood-basename, metavar = "string", default = "prior.xml.gz", help = "Write likelihood files to disk with this basename: default prior.xml.gz.")
28 # --write-likelihood-cache, metavar = "filename", help = "Write likelihood files to disk and include the names in this cachefile file.")
29 # --segment-and-horizon, action = "append", help = "Append to a list of segments and horizon distances for a given instrument. Argument specified as IFO:start:end:horizon, e.g., H1:1000000000:1000000100:120 ")
30 # --background-prefactors, metavar = "s,e", default = "1.0,20.", help = "Set the range of prefactors on the chi-squared distribution for the background model: default 1.0,20.")
31 # --injection-prefactors, metavar = "s,e", default = "0.01,0.25", help = "Set the range of prefactors on the chi-squared distribution for the signal model: default 0.01,0.25")
34 # =============================================================================
38 # =============================================================================
44 from gstlal
import far
45 from gstlal
import inspiral_pipe
46 from glue.ligolw
import utils as ligolw_utils
47 from glue.ligolw.utils
import process as ligolw_process
48 from glue.ligolw
import ligolw
49 from glue.text_progress_bar
import ProgressBar
50 from pylal
import rate, snglcoinc
51 from glue
import segments
52 from glue
import iterutils
53 from glue.lal
import LIGOTimeGPS, CacheEntry
55 from optparse
import OptionParser
58 def parse_command_line():
59 parser = OptionParser(
60 version =
"Name: %%prog\n%s" %
"" # FIXME
62 parser.add_option(
"-v",
"--verbose", action =
"store_true", help =
"Be verbose.")
63 parser.add_option(
"--num-templates", metavar =
"N", default = 1000, type =
"int", help =
"Set the number of templates per bank. default 1000")
64 parser.add_option(
"--num-banks", metavar =
"N", default = 1, type =
"int", help =
"Set the number of banks. default 1")
65 parser.add_option(
"--write-likelihood-basename", metavar =
"string", default =
"prior.xml.gz", help =
"Write likelihood files to disk with this basename: default prior.xml.gz.")
66 parser.add_option(
"--write-likelihood-cache", metavar =
"filename", help =
"Write likelihood files to disk and include the names in this cachefile file.")
67 parser.add_option(
"--segment-and-horizon", action =
"append", help =
"Append to a list of segments and horizon distances for a given instrument. Argument specified as IFO:start:end:horizon, e.g., H1:1000000000:1000000100:120 ")
68 parser.add_option(
"--background-prefactors", metavar =
"s,e", default =
"1.0,20.", help =
"Set the range of prefactors on the chi-squared distribution for the background model: default 1.0,20.")
69 parser.add_option(
"--injection-prefactors", metavar =
"s,e", default =
"0.01,0.25", help =
"Set the range of prefactors on the chi-squared distribution for the signal model: default 0.01,0.25")
70 options, filenames = parser.parse_args()
72 process_params = dict(options.__dict__)
74 def parse_segment_and_horizon(options = options):
75 seglistdict = segments.segmentlistdict()
77 for x in options.segment_and_horizon:
78 ifo, start, stop, horizon = x.split(
":")
79 seglistdict.setdefault(ifo, segments.segmentlist()).append(segments.segment([LIGOTimeGPS(
float(start)), LIGOTimeGPS(
float(stop))]))
80 horizon_history.setdefault(ifo, far.NearestLeafTree())[LIGOTimeGPS(
float(start))] =
float(horizon)
81 horizon_history.setdefault(ifo, far.NearestLeafTree())[LIGOTimeGPS(
float(stop))] =
float(horizon)
82 return seglistdict, horizon_history
84 seglistdict, horizon_history = parse_segment_and_horizon(options)
86 instruments = frozenset(seglistdict)
87 if len(instruments) < 2:
88 raise ValueError("must specify at least two distinct instrument")
90 bankcachedict = None
#inspiral_pipe.parse_cache_str(options.bank_cache)
92 return options, process_params, instruments, seglistdict, horizon_history, bankcachedict
95 options, process_params, instruments, segs, horizon_history, bankcachedict = parse_command_line()
98 print "Livetime: ", abs(segs)
99 print "Extent: ", segs.extent_all()
102 # quantities derived from input
106 # Number of background events in each detector
108 # This is calculated assuming the following
109 # 1) There are options.num_templates in the analysis
110 # 2) Each template produces exactly 1 trigger for every second that a given
111 # detector is on according to the user provided segments
114 n_background = dict(((ifo,
float(abs(seg)) * options.num_templates)
for ifo, seg in segs.items()))
117 # Number of zero lag events in each detector
119 # This is calculated assuming the following
120 # 1) Only coincident events go into the zero_lag histograms
121 # 2) The coincidence rate is 100 times lower than background rate for each detector
124 n_zerolag = dict(((ifo,
float(abs(seg)) * options.num_templates / 100.)
for ifo, seg in segs.items()))
127 # Initialize an empty ThincaCoincParamsDistributions class
130 diststats = far.ThincaCoincParamsDistributions()
133 # Add background, zero_lag and injection prior distributions in the SNR and chi-squared plane
136 diststats.add_background_prior(n = n_background, ba =
"background_rates", prefactors_range = tuple(
float(x)
for x in options.background_prefactors.split(
",")), verbose = options.verbose)
137 diststats.add_background_prior(n = n_zerolag, ba =
"zero_lag_rates", prefactors_range = tuple(
float(x)
for x in options.background_prefactors.split(
",")), verbose = options.verbose)
138 diststats.add_foreground_snrchi_prior(n = dict(((ifo, 1e6)
for ifo, seg in segs.items())), prefactors_range = tuple(
float(x)
for x in options.injection_prefactors.split(
",")), verbose = options.verbose)
141 # Update the horizon distance history with our fake, user provided horizon history
144 diststats.horizon_history.update(horizon_history)
147 # Fake a set of coincident triggers for all possible combinations
148 # FIXME Derive these from the segment lists!!! Use Kipp's code??
151 for i in range(2, len(instruments) + 1):
152 for ifos in [frozenset(x) for x in iterutils.choices(tuple(instruments), i)]:
153 diststats.zero_lag_rates[
"instruments"][diststats.instrument_categories.category(ifos),] = min(n_background[ifo] for ifo in ifos) / 100.**(i-1)
155 diststats.add_instrument_combination_counts(segs = segs,
verbose = options.
verbose)
161 horizon_distances = dict(((ifo, numpy.mean(h.values())) for ifo, h in horizon_history.items()))
162 for n in range(2, len(horizon_distances) + 1):
163 for instruments in iterutils.choices(horizon_distances.keys(), n):
164 # Force the SNR pdf to be generated to be at the actual horizon distance values not the quantized ones
165 key = frozenset(instruments), frozenset(diststats.quantize_horizon_distances(horizon_distances).items())
167 print >>sys.stderr,
"For horizon distances %s" %
", ".join(
"%s = %.4g Mpc" % item for item in sorted(horizon_distances.items()))
168 progressbar = ProgressBar(text =
"%s SNR PDF" %
", ".join(sorted(key[0])))
171 binnedarray = diststats.joint_pdf_of_snrs(key[0], horizon_distances, progressbar = progressbar)
174 lnbinnedarray = binnedarray.copy()
175 with numpy.errstate(divide =
"ignore"):
176 lnbinnedarray.array = numpy.log(lnbinnedarray.array)
177 pdf = rate.InterpBinnedArray(lnbinnedarray, fill_value = float(
"-inf"))
178 diststats.snr_joint_pdf_cache[key] = pdf, binnedarray, 0
180 diststats.populate_prob_of_instruments_given_signal(segs)
183 # Finished with this class
189 # Prep an output XML file
192 xmldoc = ligolw.Document()
193 xmldoc.appendChild(ligolw.LIGO_LW())
194 process = ligolw_process.register_to_xmldoc(xmldoc, u
"gstlal_ll_inspiral_create_prior_diststats", ifos = instruments, paramdict = process_params)
197 # Instantiate a new RankingData class from our distribution stats
200 ranking_data = far.RankingData(diststats, instruments = instruments, process_id = process.process_id, nsamples = 100000,
verbose = options.
verbose)
203 # Simulate a measured coincident trigger likelihood histogram by just using the background one with a lower normalized count
206 for instruments in ranking_data.background_likelihood_rates:
207 if instruments is None:
210 ranking_data.zero_lag_likelihood_rates[instruments].array[:] = ranking_data.background_likelihood_rates[instruments].array[:] / ranking_data.background_likelihood_rates[instruments].array.sum() * diststats.zero_lag_rates[
"instruments"][diststats.instrument_categories.category(ifos),]
212 ranking_data._compute_combined_rates()
213 ranking_data.finish()
216 # record results in output file
219 far.gen_likelihood_control_doc(xmldoc, process, diststats, ranking_data, segs, comment = u
"background and signal priors (no real data)")
225 ligolw_process.set_process_end_time(process)
227 cachefile = open(options.write_likelihood_cache,
"w")
229 for n in range(options.num_banks):
230 this_name =
"%04d_%s" % (n, options.write_likelihood_basename)
231 c = CacheEntry(
"".join(sorted(segs.keys())),
"PRIORS", segs.extent_all(), this_name)
233 ligolw_utils.write_filename(xmldoc, this_name, gz = this_name.endswith(
".gz"),
verbose = options.
verbose)
236 shutil.copyfile(original, this_name)
237 print >> cachefile, str(c)