Loading [MathJax]/extensions/TeX/AMSsymbols.js
LALBurst 2.0.7.1-b246709
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Macros Modules Pages
lalburst_power_plot_binj.py
Go to the documentation of this file.
1##python
2#
3# Copyright (C) 2006 Kipp Cannon
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
20#
21# =============================================================================
22#
23# Preamble
24#
25# =============================================================================
26#
27
28
29import math
30import numpy
31from optparse import OptionParser
32import sqlite3
33import sys
34
35
36from igwn_ligolw import dbtables
37from igwn_ligolw import utils
38from lal import rate
39from lal.utils import CacheEntry
40from lalburst import git_version
41from lalburst import SimBurstUtils
42from lalburst import SnglBurstUtils
43import igwn_segments as segments
44
45
46__author__ = "Kipp Cannon <kipp.cannon@ligo.org>"
47__version__ = "git id %s" % git_version.id
48__date__ = git_version.date
49
50
51#
52# =============================================================================
53#
54# Command Line
55#
56# =============================================================================
57#
58
59
61 parser = OptionParser(
62 version = "Name: %%prog\n%s" % git_version.verbose_msg
63 )
64 parser.add_option("--made-only", action = "store_true", default = False, help = "Plot only injections that were made.")
65 parser.add_option("-b", "--base", metavar = "base", default = "plotbinj_", help = "Set the prefix for output filenames (default = \"plotbinj_\")")
66 parser.add_option("-f", "--format", metavar = "format", default = "png", help = "Set the output image format (default = \"png\")")
67 parser.add_option("--amplitude-func", metavar = "hrsswave|hrssdet|E", default = "hrsswave", help = "Select the amplitude to show on the plots. \"hrsswave\" = the h_rss of the wave, \"hrssdet\" = the h_rss in the detector, \"E\" = the radiated energy over r^2.")
68 parser.add_option("--input-cache", metavar = "filename", action = "append", default = [], help = "Get list of trigger files from this LAL cache file.")
69 parser.add_option("-l", "--live-time-program", metavar = "program", default = "lalapps_power", help = "Set the name, as it appears in the process table, of the program whose search summary entries define the search live time (default = \"lalapps_power\").")
70 parser.add_option("--plot", metavar = "number", action = "append", default = None, help = "Generate the given plot number (default = make all plots). Use \"none\" to disable plots.")
71 parser.add_option("--coinc-plot", metavar = "number", action = "append", default = None, help = "Generate the given coinc plot number (default = make all coinc plots). Use \"none\" to disable coinc plots.")
72 parser.add_option("-t", "--tmp-space", metavar = "path", help = "Path to a directory suitable for use as a work area while manipulating the database file. The database file will be worked on in this directory, and then moved to the final location when complete. This option is intended to improve performance when running in a networked environment, where there might be a local disk with higher bandwidth than is available to the filesystem on which the final output will reside.")
73 parser.add_option("-v", "--verbose", action = "store_true", help = "Be verbose.")
74 options, filenames = parser.parse_args()
75
76 if options.amplitude_func == "hrsswave":
77 options.amplitude_func = lambda sim, instrument, offsetvector: sim.hrss
78 options.amplitude_lbl = r"$h_{\mathrm{rss}}$"
79 elif options.amplitude_func == "hrssdet":
80 options.amplitude_func = SimBurstUtils.hrss_in_instrument
81 options.amplitude_lbl = r"$h_{\mathrm{rss}}^{\mathrm{det}}$"
82 elif options.amplitude_func == "E":
83 options.amplitude_func = lambda sim, instrument, offsetvector: sim.egw_over_rsquared
84 options.amplitude_lbl = r"$M_{\odot} / \mathrm{pc}^{2}$"
85 else:
86 raise ValueError("unrecognized --amplitude-func %s" % options.amplitude_func)
87
88 if options.plot is None:
89 options.plot = range(10)
90 elif "none" in options.plot:
91 options.plot = []
92 else:
93 options.plot = map(int, options.plot)
94 if options.coinc_plot is None:
95 options.coinc_plot = range(2)
96 elif "none" in options.coinc_plot:
97 options.coinc_plot = []
98 else:
99 options.coinc_plot = map(int, options.coinc_plot)
100
101 filenames = filenames or []
102 for cache in options.input_cache:
103 if options.verbose:
104 print("reading '%s' ..." % cache, file=sys.stderr)
105 filenames += [CacheEntry(line).path for line in file(cache)]
106
107 return options, filenames
108
109
110#
111# =============================================================================
112#
113# Frequency vs. Time
114#
115# =============================================================================
116#
117
118
119class FreqVsTime(object):
120 def __init__(self, instrument):
121 self.fig, self.axes = SnglBurstUtils.make_burst_plot("GPS Time (s)", "Frequency (Hz)")
122 self.axes.semilogy()
123 self.instrument = instrument
125 self.injected_x = []
126 self.injected_y = []
127 self.missed_x = []
128 self.missed_y = []
129 self.seglist = segments.segmentlist()
130
131 def add_contents(self, contents):
132 self.seglist |= contents.seglists[self.instrument]
133 for values in contents.connection.cursor().execute("""
134SELECT
135 *,
136 EXISTS (
137 SELECT
138 *
139 FROM
140 sim_burst_map
141 JOIN sngl_burst ON (
142 sngl_burst.event_id == sim_burst_map.event_id
143 )
144 WHERE
145 sim_burst_map.simulation_id == sim_burst.simulation_id
146 AND sngl_burst.ifo == ?
147 )
148FROM
149 sim_burst
150 """, (self.instrument,)):
151 sim = contents.sim_burst_table.row_from_cols(values)
152 found = values[-1]
153 if SimBurstUtils.injection_was_made(sim, contents.seglists, (self.instrument,)):
154 self.num_injections += 1
155 peak = float(sim.time_at_instrument(self.instrument))
156 self.injected_x.append(peak)
157 self.injected_y.append(sim.frequency)
158 if not found:
159 self.missed_x.append(peak)
160 self.missed_y.append(sim.frequency)
161
162 def finish(self):
163 self.axes.plot(self.injected_x, self.injected_y, "k+")
164 if not options.made_only:
165 self.axes.plot(self.missed_x, self.missed_y, "rx")
166 for seg in ~self.seglist & segments.segmentlist([segments.segment(self.axes.get_xlim())]):
167 self.axes.axvspan(float(seg[0]), float(seg[1]), facecolor = "k", alpha = 0.2)
168 self.axes.set_ylim([min(self.injected_y), max(self.injected_y)])
169 self.axes.set_title("Injection Locations\n(%d Injections)" % self.num_injections)
170
171
172#
173# =============================================================================
174#
175# Amplitude vs. Frequency
176#
177# =============================================================================
178#
179
180
181class HrssVsFreqScatter(object):
182 def __init__(self, instrument, amplitude_func, amplitude_lbl):
183 self.fig, self.axes = SnglBurstUtils.make_burst_plot("Frequency (Hz)", amplitude_lbl)
184 self.axes.loglog()
185 self.instrument = instrument
186 self.amplitude_func = amplitude_func
187 self.amplitude_lbl = amplitude_lbl
189 self.injected_x = []
190 self.injected_y = []
191 self.missed_x = []
192 self.missed_y = []
193
194 def add_contents(self, contents):
195 offsetvectors = contents.time_slide_table.as_dict()
196 for values in contents.connection.cursor().execute("""
197SELECT
198 *,
199 EXISTS (
200 SELECT
201 *
202 FROM
203 sim_burst_map
204 JOIN sngl_burst ON (
205 sngl_burst.event_id == sim_burst_map.event_id
206 )
207 WHERE
208 sim_burst_map.simulation_id == sim_burst.simulation_id
209 AND sngl_burst.ifo == ?
210 )
211FROM
212 sim_burst
213 """, (self.instrument,)):
214 sim = contents.sim_burst_table.row_from_cols(values)
215 found = values[-1]
216 if SimBurstUtils.injection_was_made(sim, contents.seglists, (self.instrument,)):
217 self.num_injections += 1
218 amplitude = self.amplitude_func(sim, self.instrument, offsetvectors[sim.time_slide_id])
219 self.injected_x.append(sim.frequency)
220 self.injected_y.append(amplitude)
221 if not found:
222 self.missed_x.append(sim.frequency)
223 self.missed_y.append(amplitude)
224
225 def finish(self):
226 self.axes.plot(self.injected_x, self.injected_y, "k+")
227 if not options.made_only:
228 self.axes.plot(self.missed_x, self.missed_y, "rx")
229 self.axes.set_xlim([min(self.injected_x), max(self.injected_x)])
230 self.axes.set_ylim([min(self.injected_y), max(self.injected_y)])
231 self.axes.set_title("Injection " + self.amplitude_lbl + " vs. Frequency\n(%d Injections)" % self.num_injections)
232
233
234#
235# =============================================================================
236#
237# Trigger Count Histogram
238#
239# =============================================================================
240#
241
242
244 def __init__(self, instrument):
245 self.fig, self.axes = SnglBurstUtils.make_burst_plot("Number of Triggers Coincident with Injection", "Count")
246 self.axes.semilogy()
247 self.instrument = instrument
248 self.found = 0
249 self.bins = []
250
251 def add_contents(self, contents):
252 for nevents, in contents.connection.cursor().execute("""
253SELECT
254 nevents
255FROM
256 coinc_event
257WHERE
258 coinc_def_id == ?
259 """, (contents.sb_definer_id,)):
260 self.found += 1
261 while nevents + 1 >= len(self.bins):
262 self.bins.append(0)
263 self.bins[nevents] += 1
264
265 def finish(self):
266 self.axes.plot(range(len(self.bins)), self.bins, "ko-")
267 self.axes.set_title("Triggers per Found Injection\n(%d Found Injections)" % self.found)
268
269
270#
271# =============================================================================
272#
273# Recovered vs. Injected h_rss
274#
275# =============================================================================
276#
277
278
280 def __init__(self, instrument, amplitude_func, amplitude_lbl):
281 self.fig, self.axes = SnglBurstUtils.make_burst_plot(r"Injected " + amplitude_lbl, r"Recovered $h_{\mathrm{rss}}$")
282 self.axes.loglog()
283 self.fig.set_size_inches(8, 8)
284 self.instrument = instrument
285 self.amplitude_func = amplitude_func
286 self.amplitude_lbl = amplitude_lbl
287 self.matches = 0
288 self.x = []
289 self.y = []
290 self.c = []
291
292 def add_contents(self, contents):
293 offsetvectors = contents.time_slide_table.as_dict()
294 for values in contents.connection.cursor().execute("""
295SELECT
296 sim_burst.*,
297 sngl_burst.peak_frequency,
298 sngl_burst.ms_hrss
299FROM
300 sim_burst
301 JOIN sim_burst_map ON (
302 sim_burst_map.simulation_id == sim_burst.simulation_id
303 )
304 JOIN sngl_burst ON (
305 sngl_burst.event_id == sim_burst_map.event_id
306 )
307WHERE
308 sngl_burst.ifo == ?
309 """, (self.instrument,)):
310 sim = contents.sim_burst_table.row_from_cols(values)
311 freq_rec, hrss_rec = values[-2:]
312 self.matches += 1
313 self.x.append(self.amplitude_func(sim, self.instrument, offsetvectors[sim.time_slide_id]))
314 self.y.append(hrss_rec)
315 self.c.append(math.log(freq_rec))
316
317 def finish(self):
318 self.axes.scatter(self.x, self.y, c = self.c, s = 16)
319 #xmin, xmax = self.axes.get_xlim()
320 #ymin, ymax = self.axes.get_ylim()
321 xmin, xmax = min(self.x), max(self.x)
322 ymin, ymax = min(self.y), max(self.y)
323 xmin = ymin = min(xmin, ymin)
324 xmax = ymax = max(xmax, ymax)
325 self.axes.plot([xmin, xmax], [ymin, ymax], "k-")
326 self.axes.set_xlim([xmin, xmax])
327 self.axes.set_ylim([ymin, ymax])
328 self.axes.set_title(r"Recovered $h_{\mathrm{rss}}$ vs.\ Injected " + self.amplitude_lbl + " (%d Events Matching Injections)" % self.matches)
329
330
332 def __init__(self, instrument, amplitude_func, amplitude_lbl):
333 self.fig, self.axes = SnglBurstUtils.make_burst_plot(r"$f_{\mathrm{injected}}$ (Hz)", r"Recovered $h_{\mathrm{rss}}$ / Injected "+ amplitude_lbl)
334 self.axes.loglog()
335 self.fig.set_size_inches(8, 8)
336 self.instrument = instrument
337 self.amplitude_func = amplitude_func
338 self.amplitude_lbl = amplitude_lbl
339 self.matches = 0
340 self.x = []
341 self.y = []
342 self.c = []
343
344 def add_contents(self, contents):
345 offsetvectors = contents.time_slide_table.as_dict()
346 for values in contents.connection.cursor().execute("""
347SELECT
348 sim_burst.*,
349 sngl_burst.peak_frequency,
350 sngl_burst.ms_hrss
351FROM
352 sim_burst
353 JOIN sim_burst_map ON (
354 sim_burst_map.simulation_id == sim_burst.simulation_id
355 )
356 JOIN sngl_burst ON (
357 sngl_burst.event_id == sim_burst_map.event_id
358 )
359WHERE
360 sngl_burst.ifo == ?
361 """, (self.instrument,)):
362 sim = contents.sim_burst_table.row_from_cols(values)
363 freq_rec, hrss_rec = values[-2:]
364 self.matches += 1
365 self.x.append(sim.frequency)
366 self.y.append(hrss_rec / self.amplitude_func(sim, self.instrument, offsetvectors[sim.time_slide_id]))
367 self.c.append(math.log(freq_rec))
368
369 def finish(self):
370 self.axes.scatter(self.x, self.y, c = self.c, s = 16)
371 self.axes.set_xlim([min(self.x), max(self.x)])
372 self.axes.set_ylim([min(self.y), max(self.y)])
373 self.axes.set_title(r"Ratio of Recovered $h_{\mathrm{rss}}$ to Injected " + self.amplitude_lbl + r" vs.\ Frequency (%d Events Matching Injections)" % self.matches)
374
375
377 def __init__(self, instrument, amplitude_func, amplitude_lbl):
378 self.fig, self.axes = SnglBurstUtils.make_burst_plot(r"$\Delta f_{\mathrm{recovered}}$ (Hz)", r"Recovered $h_{\mathrm{rss}}$ / Injected " + amplitude_lbl)
379 self.axes.loglog()
380 self.fig.set_size_inches(8, 8)
381 self.instrument = instrument
382 self.amplitude_func = amplitude_func
383 self.amplitude_lbl = amplitude_lbl
384 self.matches = 0
385 self.x = []
386 self.y = []
387 self.c = []
388
389 def add_contents(self, contents):
390 offsetvectors = contents.time_slide_table.as_dict()
391 for values in contents.connection.cursor().execute("""
392SELECT
393 sim_burst.*,
394 sngl_burst.bandwidth,
395 sngl_burst.peak_frequency,
396 sngl_burst.ms_hrss
397FROM
398 sim_burst
399 JOIN sim_burst_map ON (
400 sim_burst_map.simulation_id == sim_burst.simulation_id
401 )
402 JOIN sngl_burst ON (
403 sngl_burst.event_id == sim_burst_map.event_id
404 )
405WHERE
406 sngl_burst.ifo == ?
407 """, (self.instrument,)):
408 sim = contents.sim_burst_table.row_from_cols(values)
409 bandwidth, freq_rec, hrss_rec = values[-3:]
410 self.matches += 1
411 self.x.append(bandwidth)
412 self.y.append(hrss_rec / self.amplitude_func(sim, self.instrument, offsetvectors[sim.time_slide_id]))
413 self.c.append(math.log(freq_rec))
414
415 def finish(self):
416 self.axes.scatter(self.x, self.y, c = self.c, s = 16)
417 self.axes.set_xlim([min(self.x), max(self.x)])
418 self.axes.set_ylim([min(self.y), max(self.y)])
419 self.axes.set_title(r"Ratio of Recovered $h_{\mathrm{rss}}$ to Injected " + self.amplitude_lbl + r" vs.\ Recovered Bandwidth (%d Events Matching Injections)" % self.matches)
420
421
422#
423# =============================================================================
424#
425# Recovered Time Offset
426#
427# =============================================================================
428#
429
430
432 def __init__(self, instrument, interval, width):
433 self.fig, self.axes = SnglBurstUtils.make_burst_plot(r"$t_{\mathrm{recovered}} - t_{\mathrm{injected}}$ (s)", "Triggers per Unit Offset")
434 self.axes.semilogy()
435 self.instrument = instrument
436 self.found = 0
437 # 21 bins per filter width
438 bins = int(float(abs(interval)) / width) * 21
439 binning = rate.NDBins((rate.LinearBins(interval[0], interval[1], bins),))
440 self.offsets = rate.BinnedDensity(binning)
441 self.coinc_offsets = rate.BinnedDensity(binning)
442
443 def add_contents(self, contents):
444 # this outer loop assumes each injection can only be found
445 # in at most one coinc, otherwise the "found" count is
446 # wrong.
447 for values in contents.connection.cursor().execute("""
448SELECT
449 sim_burst.*,
450 coinc_event.coinc_event_id
451FROM
452 coinc_event
453 JOIN coinc_event_map ON (
454 coinc_event_map.coinc_event_id == coinc_event.coinc_event_id
455 )
456 JOIN sim_burst ON (
457 coinc_event_map.table_name == 'sim_burst'
458 AND coinc_event_map.event_id == sim_burst.simulation_id
459 )
460WHERE
461 coinc_def_id == ?
462 """, (contents.sb_definer_id,)):
463 sim = contents.sim_burst_table.row_from_cols(values)
464 coinc_event_id = values[-1]
465 sim_peak = sim.time_at_instrument(self.instrument)
466 self.found += 1
467 bursts = tuple(SnglBurstUtils.coinc_sngl_bursts(contents, coinc_event_id))
468 coinc_dt = 0
469 for burst in bursts:
470 dt = float(burst.peak - sim_peak)
471 if burst.ifo == self.instrument:
472 try:
473 self.offsets.count[dt,] += 1.0
474 except IndexError:
475 # outside plot range
476 pass
477 coinc_dt += dt * burst.ms_snr
478 coinc_dt /= sum(burst.ms_snr for burst in bursts)
479 try:
480 self.coinc_offsets.count[coinc_dt,] += 1.0
481 except IndexError:
482 # outside plot range
483 pass
484
485 def finish(self):
486 self.axes.set_title("Trigger Peak Time - Injection Peak Time\n(%d Found Injections)" % self.found)
487 # 21 bins per filter width
488 filter = rate.gaussian_window(21)
489 rate.filter_array(self.offsets.array, filter)
490 rate.filter_array(self.coinc_offsets.array, filter)
491 self.axes.plot(self.offsets.centres()[0], self.offsets.at_centres(), "k")
492 self.axes.plot(self.coinc_offsets.centres()[0], self.coinc_offsets.at_centres(), "r")
493 self.axes.legend(["%s residuals" % self.instrument, "SNR-weighted mean of residuals in all instruments"], loc = "lower right")
494
495
496#
497# =============================================================================
498#
499# Recovered Frequency Offset
500#
501# =============================================================================
502#
503
504
506 def __init__(self, instrument, interval, width):
507 self.fig, self.axes = SnglBurstUtils.make_burst_plot(r"$f_{\mathrm{recovered}} / f_{\mathrm{injected}}$", "Event Number Density")
508 self.axes.loglog()
509 self.instrument = instrument
510 self.found = 0
511 # 21 bins per filter width
512 bins = int(float(abs(interval)) / width) * 21
513 binning = rate.NDBins((rate.LinearBins(interval[0], interval[1], bins),))
514 self.offsets = rate.BinnedDensity(binning)
515 self.coinc_offsets = rate.BinnedDensity(binning)
516
517 def add_contents(self, contents):
518 # this outer loop assumes each injection can only be found
519 # in at most one coinc, otherwise the "found" count is
520 # wrong.
521 for coinc_event_id, sim_frequency in contents.connection.cursor().execute("""
522SELECT
523 coinc_event.coinc_event_id,
524 sim_burst.frequency
525FROM
526 coinc_event
527 JOIN coinc_event_map ON (
528 coinc_event_map.coinc_event_id == coinc_event.coinc_event_id
529 )
530 JOIN sim_burst ON (
531 coinc_event_map.table_name == 'sim_burst'
532 AND sim_burst.simulation_id == coinc_event_map.event_id
533 )
534WHERE
535 coinc_event.coinc_def_id == ?
536 """, (contents.sb_definer_id,)):
537 self.found += 1
538 bursts = tuple(SnglBurstUtils.coinc_sngl_bursts(contents, coinc_event_id))
539 for burst in bursts:
540 if burst.ifo == self.instrument:
541 df = math.log(burst.peak_frequency / sim_frequency, 10)
542 try:
543 self.offsets.count[df,] += 1.0
544 except IndexError:
545 # outside plot range
546 pass
547 # snr-weighted mean of peak frequencies
548 coinc_freq = sum(burst.peak_frequency * burst.ms_snr for burst in bursts) / sum(burst.ms_snr for burst in bursts)
549 df = math.log(coinc_freq / sim_frequency, 10)
550 try:
551 self.coinc_offsets.count[df,] += 1.0
552 except IndexError:
553 # outside plot range
554 pass
555
556 def finish(self):
557 self.axes.set_title("Trigger Peak Frequency / Injection Centre Frequency\n(%d Found Injections)" % self.found)
558 # 21 bins per filter width
559 filter = rate.gaussian_window(21)
560 rate.filter_array(self.offsets.array, filter)
561 rate.filter_array(self.coinc_offsets.array, filter)
562 self.axes.plot(10**self.offsets.centres()[0], self.offsets.at_centres(), "k")
563 self.axes.plot(10**self.coinc_offsets.centres()[0], self.coinc_offsets.at_centres(), "r")
564 self.axes.legend(["%s triggers" % self.instrument, "SNR-weighted mean of all matching triggers"], loc = "lower right")
565 ymin, ymax = self.axes.get_ylim()
566 if ymax / ymin > 1e6:
567 ymin = ymax / 1e6
568 self.axes.set_ylim((ymin, ymax))
569
570
571#
572# =============================================================================
573#
574# Recovered vs. Injected Frequency
575#
576# =============================================================================
577#
578
579
581 def __init__(self, instrument, amplitude_func):
582 self.fig, self.axes = SnglBurstUtils.make_burst_plot(r"$f_{\mathrm{injected}}$ (Hz)", r"$f_{\mathrm{recovered}}$ (Hz)")
583 self.axes.loglog()
584 self.fig.set_size_inches(8, 8)
585 self.instrument = instrument
586 self.amplitude_func = amplitude_func
587 self.matches = 0
588 self.x = []
589 self.y = []
590 self.c = []
591
592 def add_contents(self, contents):
593 offsetvectors = contents.time_slide_table.as_dict()
594 for values in contents.connection.cursor().execute("""
595SELECT
596 sim_burst.*,
597 sngl_burst.peak_frequency,
598 sngl_burst.ms_hrss
599FROM
600 sim_burst
601 JOIN sim_burst_map ON (
602 sim_burst_map.simulation_id == sim_burst.simulation_id
603 )
604 JOIN sngl_burst ON (
605 sngl_burst.event_id == sim_burst_map.event_id
606 )
607WHERE
608 sngl_burst.ifo == ?
609 """, (self.instrument,)):
610 sim = contents.sim_burst_table.row_from_cols(values)
611 freq_rec, hrss_rec = values[-2:]
612 self.matches += 1
613 self.x.append(sim.frequency)
614 self.y.append(freq_rec)
615 self.c.append(math.log(hrss_rec / self.amplitude_func(sim, self.instrument, offsetvectors[sim.time_slide_id])))
616
617 def finish(self):
618 self.axes.scatter(self.x, self.y, c = self.c, s = 16)
619 xmin, xmax = min(self.x), max(self.x)
620 ymin, ymax = min(self.y), max(self.y)
621 xmin = ymin = min(xmin, ymin)
622 xmax = ymax = max(xmax, ymax)
623 self.axes.plot([xmin, xmax], [ymin, ymax], "k-")
624 self.axes.set_xlim([xmin, xmax])
625 self.axes.set_ylim([ymin, ymax])
626 self.axes.set_title(r"Recovered Frequency vs.\ Injected Frequency (%d Events Matching Injections)" % self.matches)
627
628
630 def __init__(self, instruments):
631 self.fig, self.axes = SnglBurstUtils.make_burst_plot(r"$f_{\mathrm{injected}}$ (Hz)", r"$f_{\mathrm{recovered}}$ (Hz)")
632 self.axes.loglog()
633 self.fig.set_size_inches(8, 8)
634 self.instruments = set(instruments)
635 self.matches = 0
636 self.x = []
637 self.y = []
638 self.c = []
639
640 def add_contents(self, contents):
641 # FIXME: this query doesn't check for the correct
642 # instruments (should be done via coinc_def_id)
643 for values in contents.connection.cursor().execute("""
644SELECT
645 sim_burst.*,
646 multi_burst.central_freq,
647 multi_burst.amplitude
648FROM
649 sim_burst
650 JOIN sim_coinc_map ON (
651 sim_coinc_map.simulation_id == sim_burst.simulation_id
652 )
653 JOIN coinc_event AS sim_coinc_event ON (
654 sim_coinc_event.coinc_event_id == sim_coinc_map.coinc_event_id
655 )
656 JOIN multi_burst ON (
657 multi_burst.coinc_event_id == sim_coinc_map.event_id
658 )
659WHERE
660 sim_coinc_event.coinc_def_id == ?
661 """, (contents.sce_definer_id,)):
662 sim = contents.sim_burst_table.row_from_cols(values)
663 freq_rec, hrss_rec = values[-2:]
664 self.matches += 1
665 self.x.append(sim.frequency)
666 self.y.append(freq_rec)
667 self.c.append(math.log(hrss_rec / sim.hrss))
668
669 def finish(self):
670 self.axes.scatter(self.x, self.y, c = self.c, s = 16)
671 xmin, xmax = min(self.x), max(self.x)
672 ymin, ymax = min(self.y), max(self.y)
673 xmin = ymin = min(xmin, ymin)
674 xmax = ymax = max(xmax, ymax)
675 self.axes.plot([xmin, xmax], [ymin, ymax], "k-")
676 self.axes.set_xlim([xmin, xmax])
677 self.axes.set_ylim([ymin, ymax])
678 self.axes.set_title(r"Recovered Frequency vs.\ Injected Frequency (%d Events Matching Injections)" % self.matches)
679
680
681#
682# =============================================================================
683#
684# Plot
685#
686# =============================================================================
687#
688
689
690#
691# How to create new plots
692#
693
694
695def new_plots(instrument, amplitude_func, amplitude_lbl, plots):
696 l = (
697 FreqVsTime(instrument),
698 HrssVsFreqScatter(instrument, amplitude_func, amplitude_lbl),
699 SimBurstUtils.Efficiency_hrss_vs_freq((instrument,), amplitude_func, amplitude_lbl, 0.1),
700 TriggerCountHistogram(instrument),
701 RecoveredVsInjectedhrss(instrument, amplitude_func, amplitude_lbl),
702 RecoveredPerInjectedhrssVsFreq(instrument, amplitude_func, amplitude_lbl),
703 RecoveredPerInjectedhrssVsBandwidth(instrument, amplitude_func, amplitude_lbl),
704 RecoveredTimeOffset(instrument, segments.segment(-0.03, +0.03), 0.00015),
705 RecoveredFrequencyOffset(instrument, segments.segment(-1.0, +1.0), .002),
706 RecoveredVsInjectedFreq(instrument, amplitude_func)
707 )
708 return [l[i] for i in plots]
709
710
711def new_coinc_plots(instruments, amplitude_func, amplitude_lbl, plots):
712 l = (
713 SimBurstUtils.Efficiency_hrss_vs_freq(instruments, amplitude_func, amplitude_lbl, 0.1),
715 )
716 return [l[i] for i in plots]
717
718
719#
720# Parse command line
721#
722
723
724options, filenames = parse_command_line()
725if not options.plot and not options.coinc_plot or not filenames:
726 print("Nothing to do!", file=sys.stderr)
727 sys.exit(0)
728
729
730#
731# Process files
732#
733
734
735plots = {}
736coincplots = new_coinc_plots(("H1", "H2", "L1"), options.amplitude_func, options.amplitude_lbl, options.coinc_plot)
737
738for n, filename in enumerate(utils.sort_files_by_size(filenames, options.verbose, reverse = True)):
739 if options.verbose:
740 print("%d/%d: %s" % (n + 1, len(filenames), filename), file=sys.stderr)
741 working_filename = dbtables.get_connection_filename(filename, tmp_path = options.tmp_space, verbose = options.verbose)
742 database = SnglBurstUtils.CoincDatabase(sqlite3.connect(str(working_filename)), options.live_time_program)
743 if options.verbose:
744 SnglBurstUtils.summarize_coinc_database(database)
745 if options.plot:
746 if database.coinc_table is not None:
747 database.connection.cursor().execute("""
748CREATE TEMPORARY VIEW
749 sim_burst_map
750AS
751 SELECT
752 a.event_id AS simulation_id,
753 a.coinc_event_id AS coinc_event_id,
754 b.event_id AS event_id
755 FROM
756 coinc_event_map AS a
757 JOIN coinc_event_map AS b ON (
758 a.table_name == 'sim_burst'
759 AND b.table_name == 'sngl_burst'
760 AND b.coinc_event_id == a.coinc_event_id
761 )
762 """)
763 for instrument in database.instruments:
764 if instrument not in plots:
765 plots[instrument] = new_plots(instrument, options.amplitude_func, options.amplitude_lbl, options.plot)
766 for n, plot in zip(options.plot, plots[instrument]):
767 if options.verbose:
768 print("adding to %s plot %d ..." % (instrument, n), file=sys.stderr)
769 plot.add_contents(database)
770 if options.coinc_plot:
771 database.connection.cursor().execute("""
772CREATE TEMPORARY VIEW
773 sim_coinc_map
774AS
775 SELECT
776 a.event_id AS simulation_id,
777 a.coinc_event_id AS coinc_event_id,
778 b.event_id AS event_id
779 FROM
780 coinc_event_map AS a
781 JOIN coinc_event_map AS b ON (
782 a.table_name == 'sim_burst'
783 AND b.table_name == 'coinc_event'
784 AND b.coinc_event_id == a.coinc_event_id
785 )
786 """)
787 for n, plot in enumerate(coincplots):
788 if options.verbose:
789 print("adding to coinc plot %d ..." % options.coinc_plot[n], file=sys.stderr)
790 plot.add_contents(database)
791 database.connection.close()
792 dbtables.discard_connection_filename(filename, working_filename, verbose = options.verbose)
793
794
795#
796# compute the binning for the efficiency contour plots
797#
798
799
800def make_binning(plots):
801 plots = [plot for instrument in plots.keys() for plot in plots[instrument] if isinstance(plot, SimBurstUtils.Efficiency_hrss_vs_freq)]
802 if not plots:
803 return None
804 minx = min([min(plot.injected_x) for plot in plots])
805 maxx = max([max(plot.injected_x) for plot in plots])
806 miny = min([min(plot.injected_y) for plot in plots])
807 maxy = max([max(plot.injected_y) for plot in plots])
808 return rate.NDBins((rate.LogarithmicBins(minx, maxx, 512), rate.LogarithmicBins(miny, maxy, 512)))
809
810
811binning = make_binning(plots)
812
813
814#
815# finish and write regular plots, deleting them as we go to save memory
816#
817
818
819efficiencies = []
820for instrument in plots:
821 n = 0
822 format = "%%s%s_%%0%dd.%%s" % (instrument, int(math.log10(max(options.plot) or 1)) + 1)
823 while len(plots[instrument]):
824 plot = plots[instrument].pop(0)
825 filename = format % (options.base, options.plot[n], options.format)
826 if options.verbose:
827 print("finishing %s plot %d ..." % (instrument, options.plot[n]), file=sys.stderr)
828 try:
829 if isinstance(plot, SimBurstUtils.Efficiency_hrss_vs_freq):
830 plot.finish(binning = binning)
831 efficiencies.append(plot)
832 fig = SimBurstUtils.plot_Efficiency_hrss_vs_freq(plot)
833 else:
834 plot.finish()
835 fig = plot.fig
836 except ValueError as e:
837 print("can't finish %s plot %d: %s" % (instrument, options.plot[n], str(e)), file=sys.stderr)
838 else:
839 if options.verbose:
840 print("writing %s ..." % filename, file=sys.stderr)
841 fig.savefig(filename)
842 n += 1
843
844
845#
846# finish and write coinc plots, deleting them as we go to save memory
847#
848
849
850for n, plot in enumerate(coincplots):
851 format = "%%s%s_%%0%dd.%%s" % ("coinc", int(math.log10(max(options.coinc_plot) or 1)) + 1)
852 filename = format % (options.base, options.coinc_plot[n], options.format)
853 if options.verbose:
854 print("finishing coinc plot %d ..." % options.coinc_plot[n], file=sys.stderr)
855 try:
856 if isinstance(plot, SimBurstUtils.Efficiency_hrss_vs_freq):
857 plot.finish(binning = binning)
858 fig = SimBurstUtils.plot_Efficiency_hrss_vs_freq(plot)
859 else:
860 plot.finish()
861 fig = plot.fig
862 except ValueError as e:
863 print("can't finish coinc plot %d: %s" % (options.coinc_plot[n], str(e)), file=sys.stderr)
864 else:
865 if options.verbose:
866 print("writing %s ..." % filename, file=sys.stderr)
867 fig.savefig(filename)
868
869
870#
871# generate and write theoretical coincident detection efficiency
872#
873
874
876 fig, axes = SnglBurstUtils.make_burst_plot("Frequency (Hz)", r"$h_{\mathrm{rss}}$")
877 axes.loglog()
878
879 e = efficiencies[0]
880 xcoords, ycoords = e.efficiency.centres()
881 zvals = e.efficiency.ratio()
882 error = e.error
883 for n, e in enumerate(efficiencies[1:]):
884 error += e.error
885 other_xcoords, other_ycoords = e.efficiency.centres()
886 if (xcoords != other_xcoords).any() or (ycoords != other_ycoords).any():
887 # binnings don't match, can't compute product of
888 # efficiencies
889 raise ValueError("binning mismatch")
890 zvals *= e.efficiency.ratio()
891 error /= len(efficiencies)
892
893 nfound = numpy.array([len(e.found_x) for e in efficiencies], dtype = "double")
894 ninjected = numpy.array([len(e.injected_x) for e in efficiencies], dtype = "double")
895
896 # the model for guessing the ninjected in the coincidence case is
897 # to assume that the injections done in the instrument with the
898 # most injections were done into all three with a probability given
899 # by the ratio of the number actually injected into each instrument
900 # to the number injected into the instrument with the most
901 # injected, and then to assume that these are independent random
902 # occurances and that to be done in coincidence an injection must
903 # be done in all three instruments.
904
905 ninjected_guess = (ninjected / ninjected.max()).prod() * ninjected.min()
906
907 # the model for guessing the nfound in the coincidence case is to
908 # assume that each injection is found or missed in each instrument
909 # at random, and to be found in the coincidence case it must be
910 # found in all three.
911
912 nfound_guess = (nfound / ninjected).prod() * ninjected_guess
913
914 ninjected_guess = int(round(ninjected_guess))
915 nfound_guess = int(round(nfound_guess))
916
917 instruments = r" \& ".join(sorted("+".join(sorted(e.instruments)) for e in efficiencies))
918
919 cset = axes.contour(xcoords, ycoords, numpy.transpose(zvals), (.1, .2, .3, .4, .5, .6, .7, .8, .9))
920 cset.clabel(inline = True, fontsize = 5, fmt = r"$%%g \pm %g$" % error, colors = "k")
921
922 axes.set_title(r"%s Estimated Injection Detection Efficiency ($\sim$%d of $\sim$%d Found)" % (instruments, nfound_guess, ninjected_guess))
923
924 return fig
925
926
927if efficiencies:
928 if options.verbose:
929 print("computing theoretical coincident detection efficiency ...", file=sys.stderr)
930 fig = plot_multi_Efficiency_hrss_vs_freq(efficiencies)
931 filename = "%scoincidence.png" % options.base
932 if options.verbose:
933 print("writing %s ..." % filename, file=sys.stderr)
934 fig.savefig(filename)
static double max(double a, double b)
Definition: EPFilters.c:43
static double min(double a, double b)
Definition: EPFilters.c:42
def __init__(self, instrument, amplitude_func, amplitude_lbl)
def __init__(self, instrument, amplitude_func, amplitude_lbl)
def __init__(self, instrument, amplitude_func, amplitude_lbl)
def __init__(self, instrument, interval, width)
def __init__(self, instrument, amplitude_func, amplitude_lbl)
def new_plots(instrument, amplitude_func, amplitude_lbl, plots)
def plot_multi_Efficiency_hrss_vs_freq(efficiencies)
def new_coinc_plots(instruments, amplitude_func, amplitude_lbl, plots)