1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 import copy
26
27 from pylal import SearchSummaryUtils
28 from glue.ligolw import ligolw
29 from glue.ligolw import table
30 from glue.ligolw import lsctables
31 from glue.ligolw import utils
32 from glue.ligolw.utils import ligolw_add
33 from glue import iterutils
34 from glue import segments
35
36
37
38
39
40
41
42
43
44
45 -class ExtractSnglInspiralTableLIGOLWContentHandler(ligolw.PartialLIGOLWContentHandler):
46 """
47 LIGOLWContentHandler that will extract only the SnglInspiralTable from a document.
48 See glue.ligolw.LIGOLWContentHandler help for more info.
49 """
50 - def __init__(self,document):
51 def filterfunc(name,attrs):
52 return name==ligolw.Table.tagName and attrs.has_key('Name') and table.Table.TableName(attrs.get('Name'))==lsctables.SnglInspiralTable.tableName
53 ligolw.PartialLIGOLWContentHandler.__init__(self,document,filterfunc)
54
55
57 """
58 Custom row ID thing for sngl_inspiral tables with int_8s event IDs.
59 """
60 column_name = "event_id"
61
64
66 self.n += 1
67 a = self.n // 100000
68 b = self.n % 100000
69 return lsctables.SnglInspiralID(a * 1000000000 + row.get_id_parts()[1] * 100000 + b)
70
71
73 """
74 Read the SnglInspiralTables from a list of files.
75 If filterFunc is not None, only keep triggers for which filterFunc
76 evaluates to True. Ex.: filterFunc=lambda sng: sng.snr >= 6.0
77
78 @param fileList: list of input files
79 @param verbose: print progress
80 """
81
82
83
84
85
86
87
88
89
90
91
92 sngls = lsctables.New(lsctables.SnglInspiralTable, \
93 columns=lsctables.SnglInspiralTable.loadcolumns)
94
95 lsctables.use_in(ExtractSnglInspiralTableLIGOLWContentHandler)
96 for i,file in enumerate(fileList):
97 if verbose: print str(i+1)+"/"+str(len(fileList))+": "
98 xmldoc = utils.load_filename(file, verbose=verbose, contenthandler=ExtractSnglInspiralTableLIGOLWContentHandler)
99 try:
100 sngl_table = lsctables.SnglInspiralTable.get_table(xmldoc)
101 if filterFunc is not None:
102 iterutils.inplace_filter(filterFunc, sngl_table)
103 except ValueError:
104 sngl_table = None
105 if sngl_table: sngls.extend(sngl_table)
106 xmldoc.unlink()
107
108 return sngls
109
110
113 """
114 Function for reading time-slided single inspiral triggers
115 with automatic resliding the times, given a list of input files.
116
117 @param fileList: List of files containing single inspiral time-slided
118 triggers
119 @param shiftVector: Dictionary of time shifts to apply to triggers
120 keyed by IFO
121 @param vetoFile: segwizard formatted file used to veto all triggers
122 @param verbose: print progress
123 """
124
125
126
127
128
129 inspTriggers = ReadSnglInspiralFromFiles(fileList, verbose=verbose)
130 if inspTriggers:
131
132 segDict = SearchSummaryUtils.GetSegListFromSearchSummaries(fileList)
133 rings = segments.segmentlist(iterutils.flatten(segDict.values()))
134 rings.sort()
135
136
137 if vetoFile is not None:
138 segList = segmentsUtils.fromsegwizard(open(vetoFile))
139 inspTriggers = inspTriggers.veto(segList)
140
141
142 slideTriggersOnRingWithVector(inspTriggers, shiftVector, rings)
143
144
145 return inspTriggers
146
147
149 """
150 Collect the sngl_inspiral rows from a desired stage in the pipeline.
151 -- For the INSPIRAL and zerolag THINCA stages, the entire sngl_inspiral table is returned.
152 -- For the slide THINCA stages, return only the rows in the sngl_inspiral that
153 compose a coincident event from the desired time-slide
154 @param xmldoc: ligolw_xml doc
155 @param slideDict: dictionary of the desired time-slide (eg. {u'H1': 0.0, u'L1': 100.0})
156 @param stage: the name of the stage (INSPIRAL_FIRST, THINCA_0_CAT_2, etc)
157 """
158
159 sngls_tbl = lsctables.SnglInspiralTable.get_table(xmldoc)
160 if 'THINCA' in stage and slideDict:
161
162 time_slide_tbl = lsctables.TimeSlideTable.get_table(xmldoc)
163 time_slide_dict = time_slide_tbl.as_dict()
164
165 coinc_event_tbl = lsctables.CoincTable.get_table(xmldoc)
166 coinc_map_tbl = lsctables.CoincMapTable.get_table(xmldoc)
167
168
169 time_slide_ids = set()
170 for tsid, offsets in time_slide_dict.items():
171 if offsets.values() == slideDict.values():
172 time_slide_ids.add( tsid )
173
174 coinc_event_ids = set()
175 for coinc in coinc_event_tbl:
176 if coinc.time_slide_id in time_slide_ids:
177 coinc_event_ids.add( coinc.coinc_event_id )
178
179 event_ids = set()
180 for row in coinc_map_tbl:
181 if row.coinc_event_id in coinc_event_ids:
182 event_ids.add( row.event_id )
183
184 sngls_tbl_eid = sngls_tbl.getColumnByName("event_id")
185 coinc_sngls_tbl = xmldoc.childNodes[0].insertBefore( lsctables.New(lsctables.SnglInspiralTable), sngls_tbl)
186 for idx, event_id in enumerate(event_ids):
187 coinc_sngls_tbl.insert( idx, sngls_tbl[sngls_tbl_eid.index(event_id)] )
188
189 return coinc_sngls_tbl
190 else:
191 return sngls_tbl
192
193
194
195
196
197
198
199
200
201
203 """
204 Orders a and b by peak time.
205 """
206 return cmp(a.get_end(), b.get_end())
207
208
210 """
211 Orders a and b by peak time.
212 """
213 return cmp(a.snr, b.snr)
214
215
217 """
218 Returns 0 if a and b are less than twindow appart.
219 """
220 tdiff = abs(a.get_end() - b.get_end())
221 if tdiff < twindow:
222 return 0
223 else:
224 return cmp(a.get_end(), b.get_end())
225
226
227
228
229
230
231
232
233
235 """
236 In-place modify trigger_list so that triggers are slid by appropriate value
237 of shifts.
238
239 @param triggerList: a SnglInspiralTable
240 @param shifts: a dictionary of the time-shifts keyed by IFO
241 """
242 for trigger in triggerList:
243 end_time = trigger.get_end()
244 trigger.set_end( end_time + shifts[trigger.ifo] )
245
247 """
248 Return time after adding shift, but constrained to lie along the ring
249 """
250 assert time in ring
251
252 return ring[0] + (float(time - ring[0]) + shift) % float(abs(ring))
253
254
256 """
257 In-place modify trigger_list so that triggers are slid by appropriate value
258 of shifts along their enclosing ring segment by the algorithm given in XXX.
259 This function calls the function slideTimeOnRing
260
261 @param triggerList: a SnglInspiralTable
262 @param rings: sorted segment list of possible rings
263 @param shifts: a dictionary of the time-shifts keyed by IFO
264 """
265 for trigger in triggerList:
266 end_time = trigger.get_end()
267 trigger.set_end(slideTimeOnRing(end_time, shifts[trigger.ifo], rings[rings.find(end_time)]))
268
270 """
271 In-place modify trigger_list so that triggers are unslid by appropriate
272 value of shifts along their enclosing ring segment by the algorithm given in
273 XXX.
274 This function calls the function slideTriggersOnRing
275
276 @param triggerList: a SnglInspiralTable
277 @param rings: sorted segment list of possible rings
278 @param shifts: a dictionary of the time-shifts keyed by IFO
279 """
280 slideTriggersOnRings(triggerList, rings, dict((ifo, -shift) for ifo, shift in shifts.items()))
281
283 """
284 In-place modify trigger_list so that triggers are slid by
285 along their enclosing ring segment by the algorithm given in XXX.
286 Slide numbers are extracted from the event_id of each trigger,
287 and multiplied by the corresponding (ifo-keyed) entry in shift_vector
288 to get the total slide amount.
289 This function is called by ReadSnglInspiralSlidesFromFiles and
290 calls the function slideTimeOnRing
291
292 @param triggerList: a SnglInspiralTable
293 @param shiftVector: a dictionary of the unit time-shift vector,
294 keyed by IFO
295 @param rings: sorted segment list of possible rings
296 """
297 for trigger in triggerList:
298 end_time = trigger.get_end()
299 trigger.set_end(slideTimeOnRing(end_time, trigger.get_slide_number() * shiftVector[trigger.ifo], rings[rings.find(end_time)]))
300
302 """
303 Return seglistdict with segments that are slid by appropriate values of
304 shifts along the ring segment by the algorithm given in XXX.
305
306 @param ring: segment on which to cyclicly slide segments in
307 seglistdict
308 @param seglistdict: segments to be slid on ring
309 @param shifts: a dictionary of the time-shifts keyed by IFO
310 """
311
312 ring_duration = float(abs(ring))
313
314
315 ring = segments.segmentlistdict.fromkeys(seglistdict.keys(), segments.segmentlist([ring]))
316
317
318 seglistdict = seglistdict & ring
319
320
321
322 seglistdict.offsets.update(dict((instrument, shift % ring_duration) for instrument, shift in shifts.items()))
323
324
325
326
327 extra = seglistdict - ring
328 seglistdict &= ring
329
330
331 for instrument in extra.keys():
332 extra.offsets[instrument] -= ring_duration
333
334
335
336 return seglistdict | extra
337
338
340 """
341 @on_instruments is an iterable of the instruments that must be on.
342
343 @off_instruments is an iterable of the instruments that must be off.
344
345 on_instruments and off_instruments must be disjoint.
346
347 @rings is a list of segments defining the analysis ring boundaries. They
348 can overlap, and do not need to be ordered.
349
350 @vetoseglistdict is a coalesced glue.segments.segmentlistdict object
351 providing the veto segments for whatever instruments have vetoes defined
352 for them. This can include veto lists for instruments other than those
353 listed in on_ and off_instruments (extra veto lists will be ignored), and
354 it need not provide lists for all instruments (instruments for which
355 there are no veto segment lists are assumed to be on at all times).
356
357 @offsetvectors is an iterable of dictionaries of instrument-offset pairs.
358 Each dictionary must contain entries for all instruments in the union of
359 on_instruments and off_instruments (it is allowed to name others as well,
360 but they will be ignored). An example of one dictionary of
361 instrument-offset pairs: {"H1": 0.0, "H2": 5.0, "L1": 10.0}.
362
363 The return value is a float giving the livetime in seconds.
364 """
365
366
367 on_instruments = set(on_instruments)
368 off_instruments = set(off_instruments)
369
370
371 if on_instruments & off_instruments:
372 raise ValueError, "on_instruments and off_instruments not disjoint"
373
374
375 on_instruments &= set(vetoseglistdict.keys())
376
377
378
379 all_instruments = on_instruments | off_instruments
380 offsetvectors = tuple(dict((key, value) for key, value in offsetvector.items() if key in all_instruments) for offsetvector in offsetvectors)
381
382
383
384 if not offsetvectors:
385 return []
386
387
388
389 for offsetvector in offsetvectors:
390 if not set(offsetvector.keys()).issuperset(all_instruments):
391 raise ValueError, "incomplete offset vector %s; missing instrument(s) %s" % (repr(offsetvector), ", ".join(all_instruments - set(offsetvector.keys())))
392
393
394 live_time = [0.0] * len(offsetvectors)
395
396
397
398 if not set(vetoseglistdict.keys()).issuperset(off_instruments):
399 return live_time
400
401
402
403 coalesced_rings = segments.segmentlist(rings).coalesce()
404 vetoseglistdict = segments.segmentlistdict((key, segments.segmentlist(seg for seg in seglist if coalesced_rings.intersects_segment(seg))) for key, seglist in vetoseglistdict.items() if key in all_instruments)
405
406
407 for ring in rings:
408
409 ring = segments.segmentlist([ring])
410
411
412
413
414 clipped_vetoseglistdict = segments.segmentlistdict((key, seglist & ring) for key, seglist in vetoseglistdict.items())
415
416
417
418 if not all(clipped_vetoseglistdict[key] for key in off_instruments):
419 continue
420
421
422 for n, offsetvector in enumerate(offsetvectors):
423
424 slidvetoes = slideSegListDictOnRing(ring[0], clipped_vetoseglistdict, offsetvector)
425
426
427
428
429
430
431
432
433 live_time[n] += float(abs(ring - slidvetoes.union(on_instruments) - (~slidvetoes).union(off_instruments)))
434
435
436 return live_time
437