28 from fpconst
import NegInf
30 NegInf = float(
"-inf")
38from igwn_ligolw
import ligolw
39from igwn_ligolw
import lsctables
40from igwn_ligolw
import utils
as ligolw_utils
41from igwn_ligolw.utils
import process
as ligolw_process
44from igwn_segments
import utils
as segmentsUtils
45from .offsetvector
import offsetvector
46from .
import snglcoinc
49__author__ =
"Kipp Cannon <kipp.cannon@ligo.org>"
50from .git_version
import date
as __date__
51from .git_version
import version
as __version__
70 Return a dictionary of snglcoinc.TOATriangulator objects
71 initialized for a variety of instrument combinations.
72 timing_uncertainties is a dictionary of instrument->$\\Delta t$
73 pairs. The return value
is a dictionary of (instrument
74 tuple)->TOATrangulator mappings. The instrument names
in each
75 tuple are sorted
in alphabetical order,
and the triangulators are
76 constructed
with the instruments
in that order (the the
81 >>> x =
triangulators({
"H1": 0.005,
"L1": 0.005,
"V1": 0.005})
83 constructs a dictionary of triangulators
for every combination of
84 two
or more instruments that can be constructed
from those three.
86 The program lalapps_string_plot_binj can be used to measure the
87 timing uncertainties
for the instruments
in a search.
89 allinstruments = sorted(timing_uncertainties.keys())
92 for n in range(2, len(allinstruments) + 1):
93 for instruments
in itertools.combinations(allinstruments, n):
94 triangulators[instruments] =
snglcoinc.TOATriangulator([lal.cached_detector_by_prefix[instrument].location
for instrument
in instruments], [timing_uncertainties[instrument]
for instrument
in instruments])
120 >>> x = InstrumentBins()
121 >>> x[frozenset(("H1", "L1"))]
124 frozenset(['H1', 'L1'])
127 names = (
"E0",
"E1",
"E2",
"E3",
"G1",
"H1",
"H2",
"H1H2+",
"H1H2-",
"L1",
"V1")
130 super(InstrumentBins, self).
__init__(frozenset(combo)
for n
in range(len(names) + 1)
for combo
in itertools.combinations(names, n))
138 return numpy.arange(0, len(self), dtype =
"double")
140 return numpy.arange(1, len(self) + 1, dtype =
"double")
142 xml_bins_name =
u"instrumentbins"
145rate.NDBins.xml_bins_name_mapping.update({
146 InstrumentBins.xml_bins_name: InstrumentBins,
147 InstrumentBins: InstrumentBins.xml_bins_name
163 for instrument
in instruments:
164 self.
densities[
"%s_snr2_chi2" % instrument] = rate.BinnedLnPDF(rate.NDBins((rate.ATanLogarithmicBins(10, 1e7, 801), rate.ATanLogarithmicBins(.1, 1e4, 801))))
165 for pair
in itertools.combinations(sorted(instruments), 2):
166 dt = 0.005 + snglcoinc.light_travel_time(*pair)
167 self.
densities[
"%s_%s_dt" % pair] = rate.BinnedLnPDF(rate.NDBins((rate.ATanBins(-dt, +dt, 801),)))
168 self.
densities[
"%s_%s_dA" % pair] = rate.BinnedLnPDF(rate.NDBins((rate.ATanBins(-0.5, +0.5, 801),)))
169 self.
densities[
"%s_%s_df" % pair] = rate.BinnedLnPDF(rate.NDBins((rate.ATanBins(-0.2, +0.2, 501),)))
174 self.
densities[
"instrumentgroup,rss_timing_residual"] = rate.BinnedLnPDF(rate.NDBins((
InstrumentBins(instruments), rate.ATanBins(-0.02, +0.02, 1001))))
179 except AttributeError:
182 return sum(interps[param](*value)
for param, value
in params.items())
if params
else NegInf
185 if type(self) != type(other)
or set(self.
densities) != set(other.densities):
186 raise TypeError(
"cannot add %s and %s" % (type(self), type(other)))
188 pdf += other.densities[key]
191 except AttributeError:
196 for param, value
in params.items():
197 self.
densities[param].count[value] += weight
202 new.densities[key] = pdf.copy()
206 self.
interps =
dict((key, pdf.mkinterp())
for key, pdf
in self.
densities.items()
if "rss_timing_residual" not in key)
210 if key.endswith(
"_snr2_chi2"):
211 rate.filter_array(pdf.array, rate.gaussian_window(11, 11, sigma = 20))
212 elif key.endswith(
"_dt")
or key.endswith(
"_dA")
or key.endswith(
"_df"):
213 rate.filter_array(pdf.array, rate.gaussian_window(11, sigma = 20))
214 elif key.startswith(
"instrumentgroup"):
224 xml = super(LnLRDensity, self).
to_xml(name)
225 instruments = set(key.split(
"_", 1)[0]
for key
in self.
densities if key.endswith(
"_snr2_chi2"))
226 xml.appendChild(ligolw.Param.from_pyvalue(
"instruments", lsctables.instrumentsproperty.set(instruments)))
228 xml.appendChild(pdf.to_xml(key))
234 self = cls(lsctables.instrumentsproperty.get(ligolw.Param.get_param(xml,
"instruments").value))
236 self.
densities[key] = rate.BinnedLnPDF.from_xml(xml, key)
241 ligo_lw_name_suffix =
u"stringcusp_coincparamsdistributions"
250 if type(self) != type(other):
251 raise TypeError(other)
252 if set(self.
triangulators.keys()) != set(other.triangulators.keys()):
253 raise ValueError(
"incompatible instruments")
262 instruments = set(param[:2]
for param
in kwargs
if param.endswith(
"_snr2_chi2"))
265 if instruments == set((
"H1",
"H2")):
269 return super(StringCoincParamsDistributions, self).
__call__(**kwargs)
297 events = tuple(sorted(events, key =
lambda event: event.ifo))
298 instruments = tuple(event.ifo
for event
in events)
304 ignored, ignored, ignored, rss_timing_residual = self.
triangulators[instruments](tuple(event.peak + offsetvector[event.ifo]
for event
in events))
314 rss_timing_residual = 0.0
323 params[
"%s_snr2_chi2" % event.ifo] = (event.snr**2.0, event.chisq / event.chisq_dof)
330 for event1, event2
in itertools.combinations(events, 2):
331 assert event1.ifo != event2.ifo
333 prefix =
"%s_%s_" % (event1.ifo, event2.ifo)
335 dt = float((event1.peak + offsetvector[event1.ifo]) - (event2.peak + offsetvector[event2.ifo]))
336 params[
"%sdt" % prefix] = (dt,)
338 dA = math.log10(abs(event1.amplitude / event2.amplitude))
339 params[
"%sdA" % prefix] = (dA,)
342 f_cut1 = event1.central_freq + event1.bandwidth / 2
343 f_cut2 = event2.central_freq + event2.bandwidth / 2
344 df = float((math.log10(f_cut1) - math.log10(f_cut2)) / (math.log10(f_cut1) + math.log10(f_cut2)))
345 params[
"%sdf" % prefix] = (df,)
365 xml = [elem
for elem
in xml.getElementsByTagName(ligolw.LIGO_LW.tagName)
if elem.hasAttribute(
u"Name")
and elem.Name == name]
367 raise ValueError(
"XML tree must contain exactly one %s element named %s" % (ligolw.LIGO_LW.tagName, name))
374 self.
numerator = LnLRDensity.from_xml(xml,
"numerator")
375 self.
denominator = LnLRDensity.from_xml(xml,
"denominator")
376 self.
candidates = LnLRDensity.from_xml(xml,
"candidates")
379 instruments = [key.replace(
"_snr2_chi2",
"")
for key
in self.
numerator.densities.keys()
if "_snr2_chi2" in key]
399 for n, filename
in enumerate(filenames, 1):
401 print(
"%d/%d:" % (n, len(filenames)), end=
' ', file=sys.stderr)
402 xmldoc = ligolw_utils.load_filename(filename, verbose = verbose)
403 this_coinc_params = StringCoincParamsDistributions.from_xml(xmldoc,
u"string_cusp_likelihood")
404 this_seglists = lsctables.SearchSummaryTable.get_table(xmldoc).get_out_segmentlistdict(lsctables.ProcessTable.get_table(xmldoc).get_ids_by_program(
u"lalapps_string_meas_likelihood")).coalesce()
406 if coinc_params
is None:
407 coinc_params = this_coinc_params
409 coinc_params += this_coinc_params
411 seglists = this_seglists
413 seglists |= this_seglists
414 return coinc_params, seglists
428 seglists is a segmentlistdict of times when each of a set of
429 instruments were on, time_slides is a sequence of
430 instrument-->offset dictionaries, each vector of offsets in the
431 sequence is applied to the segmentlists and the total time during
432 which at least min_instruments were on is summed and returned. If
433 clip is not None, after each offset vector
is applied to seglists
434 the result
is intersected
with clip before computing the livetime.
435 If verbose
is True then progress reports are printed to stderr.
438 seglists = seglists.copy() # don't modify original
441 print("computing the live time for %d time slides:" % N, file=sys.stderr)
442 for n, time_slide
in enumerate(time_slides):
444 print(
"\t%.1f%%\r" % (100.0 * n / N), end=
' ', file=sys.stderr)
445 seglists.offsets.update(time_slide)
447 livetime += float(abs(segmentsUtils.vote(seglists.values(), min_instruments)))
449 livetime += float(abs(segmentsUtils.vote((seglists & clip).values(), min_instruments)))
451 print(
"\t100.0%", file=sys.stderr)
457 like time_slides_livetime() except computes the time for which
458 exactly the instruments given by the sequence instruments were on
463 onseglists = seglists.copy(keys = instruments)
465 offseglists = seglists.copy(keys = set(seglists) - set(instruments))
468 print(
"computing the live time for %s in %d time slides:" % (
", ".join(instruments), N), file=sys.stderr)
469 for n, time_slide
in enumerate(time_slides):
471 print(
"\t%.1f%%\r" % (100.0 * n / N), end=
' ', file=sys.stderr)
472 onseglists.offsets.update(time_slide)
473 offseglists.offsets.update(time_slide)
475 livetime += float(abs(onseglists.intersection(onseglists.keys()) - offseglists.union(offseglists.keys())))
477 livetime += float(abs((onseglists & clip).intersection(onseglists.keys()) - offseglists.union(offseglists.keys())))
479 print(
"\t100.0%", file=sys.stderr)
494 Create a temporary table named "recovered_ln_likelihood_ratio"
495 containing two columns: "simulation_id", the simulation_id of an
496 injection,
and "ln_likelihood_ratio", the highest log likelihood
497 ratio at which that injection was recovered by a coincidence of
500 cursor = connection.cursor()
502CREATE TEMPORARY TABLE recovered_ln_likelihood_ratio (simulation_id TEXT PRIMARY KEY, ln_likelihood_ratio REAL)
505INSERT OR REPLACE INTO
506 recovered_ln_likelihood_ratio
508 sim_burst.simulation_id AS simulation_id,
509 MAX(coinc_event.likelihood) AS ln_likelihood_ratio
512 JOIN coinc_event_map AS a ON (
513 a.table_name ==
"sim_burst"
514 AND a.event_id == sim_burst.simulation_id
516 JOIN coinc_event_map AS b ON (
517 b.coinc_event_id == a.coinc_event_id
519 JOIN coinc_event ON (
520 b.table_name ==
"coinc_event"
521 AND b.event_id == coinc_event.coinc_event_id
524 coinc_event.coinc_def_id == ?
526 sim_burst.simulation_id
527 """, (coinc_def_id,))
531def create_sim_burst_best_string_sngl_map(connection, coinc_def_id):
533 Construct a sim_burst --> best matching coinc_event mapping.
535 connection.cursor().execute("""
536CREATE TEMPORARY TABLE
537 sim_burst_best_string_sngl_map
540 sim_burst.simulation_id AS simulation_id,
546 JOIN coinc_event_map AS b ON (
547 b.coinc_event_id == a.coinc_event_id
549 JOIN coinc_event ON (
550 coinc_event.coinc_event_id == a.coinc_event_id
553 b.table_name ==
'sngl_burst'
554 AND b.event_id == sngl_burst.event_id
557 a.table_name ==
'sim_burst'
558 AND a.event_id == sim_burst.simulation_id
559 AND coinc_event.coinc_def_id == ?
561 (sngl_burst.chisq / sngl_burst.chisq_dof) / (sngl_burst.snr * sngl_burst.snr)
568 """, (coinc_def_id,))
571def create_sim_burst_best_string_coinc_map(connection, coinc_def_id):
573 Construct a sim_burst --> best matching coinc_event mapping
for
574 string cusp injections
and coincs.
576 # FIXME: this hasn't finished being ported from the inspiral code
577 connection.cursor().execute("""
578CREATE TEMPORARY TABLE
579 sim_burst_best_string_coinc_map
582 sim_burst.simulation_id AS simulation_id,
585 coinc_inspiral.coinc_event_id
588 JOIN coinc_event_map AS b ON (
589 b.coinc_event_id == a.coinc_event_id
591 JOIN coinc_inspiral ON (
592 b.table_name == 'coinc_event'
593 AND b.event_id == coinc_inspiral.coinc_event_id
596 a.table_name ==
'sim_burst'
597 AND a.event_id == sim_burst.simulation_id
598 AND coinc_event.coinc_def_id == ?
600 (sngl_burst.chisq / sngl_burst.chisq_dof) / (sngl_burst.snr * sngl_burst.snr)
606 coinc_event_id IS NOT NULL
607 """, (coinc_def_id,))
Base class for parameter distribution densities for use in log likelihood ratio ranking statistics.
def get_xml_root(cls, xml, name)
Sub-classes can use this in their overrides of the .from_xml() method to find the root element of the...
Mixin to assist in implementing a log likelihood ratio ranking statistic class.
Time-of-arrival triangulator.
def __init__(self, names)
def __init__(self, instruments)
def copy(self)
Return a duplicate copy of this object.
def __iadd__(self, other)
Marginalize the two densities.
def increment(self, weight=1.0, **params)
Increment the counts defining this density at the given parameters.
def finish(self)
Ensure all internal densities are normalized, and initialize interpolator objects as needed for smoot...
def from_xml(cls, xml, name)
In the XML document tree rooted at xml, search for the serialized LnLRDensity object named name,...
def __call__(self, **params)
Evaluate.
def to_xml(self, name)
Serialize to an XML fragment and return the root element of the resulting XML tree.
def __init__(self, instruments)
def from_xml(cls, xml, name)
def __iadd__(self, other)
def ln_lr_from_triggers(self, events, offsetvector)
def __call__(self, **kwargs)
Return the natural logarithm of the likelihood ratio for the given parameters,.
string ligo_lw_name_suffix
def coinc_params(self, events, offsetvector)
def get_xml_root(cls, xml, name)
def time_slides_livetime(seglists, time_slides, min_instruments, verbose=False, clip=None)
seglists is a segmentlistdict of times when each of a set of instruments were on, time_slides is a se...
def create_recovered_ln_likelihood_ratio_table(connection, coinc_def_id)
Create a temporary table named "recovered_ln_likelihood_ratio" containing two columns: "simulation_id...
def time_slides_livetime_for_instrument_combo(seglists, time_slides, instruments, verbose=False, clip=None)
like time_slides_livetime() except computes the time for which exactly the instruments given by the s...
def load_likelihood_data(filenames, verbose=False)
def triangulators(timing_uncertainties)
Return a dictionary of snglcoinc.TOATriangulator objects initialized for a variety of instrument comb...