Package glue :: Package ligolw :: Module lsctables
[hide private]
[frames] | no frames]

Source Code for Module glue.ligolw.lsctables

   1  # Copyright (C) 2006--2016  Kipp Cannon 
   2  # 
   3  # This program is free software; you can redistribute it and/or modify it 
   4  # under the terms of the GNU General Public License as published by the 
   5  # Free Software Foundation; either version 3 of the License, or (at your 
   6  # option) any later version. 
   7  # 
   8  # This program is distributed in the hope that it will be useful, but 
   9  # WITHOUT ANY WARRANTY; without even the implied warranty of 
  10  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General 
  11  # Public License for more details. 
  12  # 
  13  # You should have received a copy of the GNU General Public License along 
  14  # with this program; if not, write to the Free Software Foundation, Inc., 
  15  # 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. 
  16   
  17   
  18  # 
  19  # ============================================================================= 
  20  # 
  21  #                                   Preamble 
  22  # 
  23  # ============================================================================= 
  24  # 
  25   
  26   
  27  """ 
  28  LSC Table definitions.  These must be kept synchronized with the official 
  29  definitions in the LDAS CVS repository at 
  30  http://www.ldas-sw.ligo.caltech.edu/cgi-bin/cvsweb.cgi/ldas/dbms/db2/sql. 
  31  Maintenance of the table definitions is left to the conscience of 
  32  interested users. 
  33  """ 
  34   
  35   
  36  import math 
  37  import numpy 
  38  import warnings 
  39  from xml import sax 
  40   
  41   
  42  from glue import git_version 
  43  from glue import iterutils 
  44  from glue import offsetvector 
  45  from glue import segments 
  46  import lal 
  47  from lal import LIGOTimeGPS 
  48  from . import ligolw 
  49  from . import table 
  50  from . import types as ligolwtypes 
  51  from . import ilwd 
  52   
  53   
  54  __author__ = "Kipp Cannon <kipp.cannon@ligo.org>" 
  55  __version__ = "git id %s" % git_version.id 
  56  __date__ = git_version.date 
57 58 59 # 60 # ============================================================================= 61 # 62 # Convenience Functions 63 # 64 # ============================================================================= 65 # 66 67 68 -def New(cls, columns = None, **kwargs):
69 """ 70 Construct a pre-defined LSC table. The optional columns argument 71 is a sequence of the names of the columns the table should be 72 constructed with. If columns = None, then the table is constructed 73 with all valid columns (use columns = [] to create a table with no 74 columns). 75 76 Example: 77 78 >>> import sys 79 >>> tbl = New(ProcessTable, [u"process_id", u"start_time", u"end_time", u"comment"]) 80 >>> tbl.write(sys.stdout) # doctest: +NORMALIZE_WHITESPACE 81 <Table Name="process:table"> 82 <Column Type="ilwd:char" Name="process:process_id"/> 83 <Column Type="int_4s" Name="process:start_time"/> 84 <Column Type="int_4s" Name="process:end_time"/> 85 <Column Type="lstring" Name="process:comment"/> 86 <Stream Delimiter="," Type="Local" Name="process:table"> 87 </Stream> 88 </Table> 89 """ 90 new = cls(sax.xmlreader.AttributesImpl({u"Name": cls.TableName.enc(cls.tableName)}), **kwargs) 91 colnamefmt = new.Name + u":%s" 92 if columns is not None: 93 for key in sorted(columns): 94 if key not in new.validcolumns: 95 raise ligolw.ElementError("invalid Column '%s' for Table '%s'" % (key, new.Name)) 96 new.appendChild(table.Column(sax.xmlreader.AttributesImpl({u"Name": colnamefmt % key, u"Type": new.validcolumns[key]}))) 97 else: 98 for key, value in sorted(new.validcolumns.items()): 99 new.appendChild(table.Column(sax.xmlreader.AttributesImpl({u"Name": colnamefmt % key, u"Type": value}))) 100 new._end_of_columns() 101 new.appendChild(table.TableStream(sax.xmlreader.AttributesImpl({u"Name": new.getAttribute(u"Name"), u"Delimiter": table.TableStream.Delimiter.default, u"Type": table.TableStream.Type.default}))) 102 return new
103
104 105 -def HasNonLSCTables(elem):
106 """ 107 Return True if the document tree below elem contains non-LSC 108 tables, otherwise return False. 109 """ 110 return any(t.Name not in TableByName for t in elem.getElementsByTagName(ligolw.Table.tagName))
111
112 113 -class instrumentsproperty(object):
114 - def __init__(self, name):
115 self.name = name
116 117 @staticmethod
118 - def get(ifos):
119 """ 120 Parse the values stored in the "ifos" and "instruments" 121 columns found in many tables. This function is mostly for 122 internal use by the .instruments properties of the 123 corresponding row classes. The mapping from input to 124 output is as follows (rules are applied in order): 125 126 input is None --> output is None 127 128 input contains "," --> output is set of strings split on 129 "," with leading and trailing whitespace stripped from each 130 piece and empty strings removed from the set 131 132 input contains "+" --> output is set of strings split on 133 "+" with leading and trailing whitespace stripped from each 134 piece and empty strings removed from the set 135 136 else, after stripping input of leading and trailing 137 whitespace, 138 139 input has an even length greater than two --> output is set 140 of two-character pieces 141 142 input is a non-empty string --> output is a set containing 143 input as single value 144 145 else output is an empty set. 146 147 NOTE: the complexity of this algorithm is a consequence of 148 there being several conventions in use for encoding a set 149 of instruments into one of these columns; it has been 150 proposed that L.L.W. documents standardize on the 151 comma-delimited variant of the encodings recognized by this 152 function, and for this reason the inverse function, 153 instrumentsproperty.set(), implements that encoding only. 154 155 NOTE: to force a string containing an even number of 156 characters to be interpreted as a single instrument name 157 and not to be be split into two-character pieces, add a "," 158 character to the end to force the comma-delimited decoding 159 to be used. instrumentsproperty.set() does this for you. 160 161 Example: 162 163 >>> print(instrumentsproperty.get(None)) 164 None 165 >>> instrumentsproperty.get(u"") 166 set([]) 167 >>> instrumentsproperty.get(u" , ,,") 168 set([]) 169 >>> instrumentsproperty.get(u"H1") 170 set([u'H1']) 171 >>> instrumentsproperty.get(u"SWIFT") 172 set([u'SWIFT']) 173 >>> instrumentsproperty.get(u"H1L1") 174 set([u'H1', u'L1']) 175 >>> instrumentsproperty.get(u"H1L1,") 176 set([u'H1L1']) 177 >>> instrumentsproperty.get(u"H1,L1") 178 set([u'H1', u'L1']) 179 >>> instrumentsproperty.get(u"H1+L1") 180 set([u'H1', u'L1']) 181 """ 182 if ifos is None: 183 return None 184 if u"," in ifos: 185 result = set(ifo.strip() for ifo in ifos.split(u",")) 186 result.discard(u"") 187 return result 188 if u"+" in ifos: 189 result = set(ifo.strip() for ifo in ifos.split(u"+")) 190 result.discard(u"") 191 return result 192 ifos = ifos.strip() 193 if len(ifos) > 2 and not len(ifos) % 2: 194 # if ifos is a string with an even number of 195 # characters greater than two, split it into 196 # two-character pieces. FIXME: remove this when 197 # the inspiral codes don't write ifos strings like 198 # this anymore 199 return set(ifos[n:n+2] for n in range(0, len(ifos), 2)) 200 if ifos: 201 return set([ifos]) 202 return set()
203 204 @staticmethod
205 - def set(instruments):
206 """ 207 Convert an iterable of instrument names into a value 208 suitable for storage in the "ifos" column found in many 209 tables. This function is mostly for internal use by the 210 .instruments properties of the corresponding row classes. 211 The input can be None or an iterable of zero or more 212 instrument names, none of which may be zero-length, consist 213 exclusively of spaces, or contain "," or "+" characters. 214 The output is a single string containing the unique 215 instrument names concatenated using "," as a delimiter. 216 instruments will only be iterated over once and so can be a 217 generator expression. Whitespace is allowed in instrument 218 names but might not be preserved. Repeated names will not 219 be preserved. 220 221 NOTE: in the special case that there is 1 instrument name 222 in the iterable and it has an even number of characters > 2 223 in it, the output will have a "," appended in order to 224 force instrumentsproperty.get() to parse the string back 225 into a single instrument name. This is a special case 226 included temporarily to disambiguate the encoding until all 227 codes have been ported to the comma-delimited encoding. 228 This behaviour will be discontinued at that time. DO NOT 229 WRITE CODE THAT RELIES ON THIS! You have been warned. 230 231 Example: 232 233 >>> print(instrumentsproperty.set(None)) 234 None 235 >>> instrumentsproperty.set(()) 236 u'' 237 >>> instrumentsproperty.set((u"H1",)) 238 u'H1' 239 >>> instrumentsproperty.set((u"H1",u"H1",u"H1")) 240 u'H1' 241 >>> instrumentsproperty.set((u"H1",u"L1")) 242 u'H1,L1' 243 >>> instrumentsproperty.set((u"SWIFT",)) 244 u'SWIFT' 245 >>> instrumentsproperty.set((u"H1L1",)) 246 u'H1L1,' 247 """ 248 if instruments is None: 249 return None 250 _instruments = sorted(set(instrument.strip() for instrument in instruments)) 251 # safety check: refuse to accept blank names, or names 252 # with commas or pluses in them as they cannot survive the 253 # encode/decode process 254 if not all(_instruments) or any(u"," in instrument or u"+" in instrument for instrument in _instruments): 255 raise ValueError(instruments) 256 if len(_instruments) == 1 and len(_instruments[0]) > 2 and not len(_instruments[0]) % 2: 257 # special case disambiguation. FIXME: remove when 258 # everything uses the comma-delimited encoding 259 return u"%s," % _instruments[0] 260 return u",".join(_instruments)
261
262 - def __get__(self, obj, type = None):
263 return self.get(getattr(obj, self.name))
264
265 - def __set__(self, obj, instruments):
266 setattr(obj, self.name, self.set(instruments))
267 268 269 instrument_set_from_ifos = instrumentsproperty.get 270 ifos_from_instrument_set = instrumentsproperty.set
271 272 273 -class gpsproperty(object):
274 """ 275 Descriptor used internally to implement LIGOTimeGPS-valued 276 properties. 277 """
278 - def __init__(self, s_name, ns_name):
279 self.s_name = s_name 280 self.ns_name = ns_name
281 282 posinf = 0x7FFFFFFF, 0xFFFFFFFF 283 neginf = 0xFFFFFFFF, 0xFFFFFFFF 284
285 - def __get__(self, obj, type = None):
286 s = getattr(obj, self.s_name) 287 ns = getattr(obj, self.ns_name) 288 if s is None and ns is None: 289 return None 290 if (s, ns) == self.posinf: 291 return segments.PosInfinity 292 if (s, ns) == self.neginf: 293 return segments.NegInfinity 294 return LIGOTimeGPS(s, ns)
295
296 - def __set__(self, obj, gps):
297 if gps is None: 298 s = ns = None 299 elif isinstance(gps, segments.infinity) or math.isinf(gps): 300 if gps > 0: 301 s, ns = self.posinf 302 elif gps < 0: 303 s, ns = self.neginf 304 else: 305 raise ValueError(gps) 306 else: 307 try: 308 s = gps.gpsSeconds 309 ns = gps.gpsNanoSeconds 310 except AttributeError: 311 # try converting and going again 312 return self.__set__(obj, LIGOTimeGPS(gps)) 313 if abs(ns) > 999999999: 314 raise ValueError("denormalized LIGOTimeGPS not allowed") 315 setattr(obj, self.s_name, s) 316 setattr(obj, self.ns_name, ns)
317
318 319 -class gpsproperty_with_gmst(gpsproperty):
320 - def __init__(self, s_name, ns_name, gmst_name):
321 super(gpsproperty_with_gmst, self).__init__(s_name, ns_name) 322 self.gmst_name = gmst_name
323
324 - def __set__(self, obj, gps):
325 super(gpsproperty_with_gmst, self).__set__(obj, gps) 326 if gps is None: 327 setattr(obj, self.gmst_name, None) 328 else: 329 # re-retrieve the value in case it required type 330 # conversion 331 gps = self.__get__(obj) 332 setattr(obj, self.gmst_name, lal.GreenwichMeanSiderealTime(gps))
333
334 335 -class segmentproperty(object):
336 """ 337 Descriptor used internally to expose pairs of GPS-valued properties 338 as segment-valued properties. 339 """
340 - def __init__(self, start_name, stop_name):
341 self.start = start_name 342 self.stop = stop_name
343
344 - def __get__(self, obj, type = None):
345 start = getattr(obj, self.start) 346 stop = getattr(obj, self.stop) 347 if start is None and stop is None: 348 return None 349 return segments.segment(start, stop)
350
351 - def __set__(self, obj, seg):
352 if seg is None: 353 start = stop = None 354 else: 355 start, stop = seg 356 setattr(obj, self.start, start) 357 setattr(obj, self.stop, stop)
358 359 360 # 361 # ============================================================================= 362 # 363 # process:table 364 # 365 # ============================================================================= 366 # 367 368 369 ProcessID = ilwd.get_ilwdchar_class(u"process", u"process_id")
370 371 372 -class ProcessTable(table.Table):
373 tableName = "process" 374 validcolumns = { 375 "program": "lstring", 376 "version": "lstring", 377 "cvs_repository": "lstring", 378 "cvs_entry_time": "int_4s", 379 "comment": "lstring", 380 "is_online": "int_4s", 381 "node": "lstring", 382 "username": "lstring", 383 "unix_procid": "int_4s", 384 "start_time": "int_4s", 385 "end_time": "int_4s", 386 "jobid": "int_4s", 387 "domain": "lstring", 388 "ifos": "lstring", 389 "process_id": "ilwd:char" 390 } 391 constraints = "PRIMARY KEY (process_id)" 392 next_id = ProcessID(0) 393
394 - def get_ids_by_program(self, program):
395 """ 396 Return a set containing the process IDs from rows whose 397 program string equals the given program. 398 """ 399 return set(row.process_id for row in self if row.program == program)
400
401 402 -class Process(table.Table.RowType):
403 """ 404 Example: 405 406 >>> x = Process() 407 >>> x.instruments = (u"H1", u"L1") 408 >>> x.ifos 409 u'H1,L1' 410 >>> x.instruments 411 set([u'H1', u'L1']) 412 """ 413 __slots__ = tuple(ProcessTable.validcolumns.keys()) 414 415 instruments = instrumentsproperty("ifos") 416
417 - def get_ifos(self):
418 """ 419 Return a set of the instruments for this row. 420 """ 421 return self.instruments
422
423 - def set_ifos(self, instruments):
424 """ 425 Serialize a sequence of instruments into the ifos 426 attribute. The instrument names must not contain the "," 427 character. 428 """ 429 self.instruments = instruments
430 431 432 ProcessTable.RowType = Process 433 434 435 # 436 # ============================================================================= 437 # 438 # lfn:table 439 # 440 # ============================================================================= 441 # 442 443 444 LfnID = ilwd.get_ilwdchar_class(u"lfn", u"lfn_id")
445 446 447 -class LfnTable(table.Table):
448 tableName = "lfn" 449 validcolumns = { 450 "process_id": "ilwd:char", 451 "lfn_id": "ilwd:char", 452 "name": "lstring", 453 "comment": "lstring", 454 "start_time": "int_4s", 455 "end_time": "int_4s" 456 } 457 constraints = "PRIMARY KEY (lfn_id)" 458 next_id = LfnID(0)
459
460 461 -class Lfn(table.Table.RowType):
462 __slots__ = tuple(LfnTable.validcolumns.keys())
463 464 465 LfnTable.RowType = Lfn
466 467 468 # 469 # ============================================================================= 470 # 471 # process_params:table 472 # 473 # ============================================================================= 474 # 475 476 477 -class ProcessParamsTable(table.Table):
478 tableName = "process_params" 479 validcolumns = { 480 "program": "lstring", 481 "process_id": "ilwd:char", 482 "param": "lstring", 483 "type": "lstring", 484 "value": "lstring" 485 } 486 # FIXME: these constraints break ID remapping in the DB backend. 487 # an index is used instead. switch back to the constraints when I 488 # can figure out how not to break remapping. 489 #constraints = "PRIMARY KEY (process_id, param)" 490 how_to_index = { 491 "pp_pip_index": ("process_id", "param"), 492 } 493
494 - def append(self, row):
495 if row.type is not None and row.type not in ligolwtypes.Types: 496 raise ligolw.ElementError("unrecognized type '%s'" % row.type) 497 table.Table.append(self, row)
498
499 500 -class ProcessParams(table.Table.RowType):
501 """ 502 Example: 503 504 >>> x = ProcessParams() 505 >>> x.pyvalue = u"test" 506 >>> x.type 507 u'lstring' 508 >>> x.value 509 u'test' 510 >>> x.pyvalue 511 u'test' 512 >>> x.pyvalue = 6. 513 >>> x.type 514 u'real_8' 515 >>> x.value 516 u'6' 517 >>> x.pyvalue 518 6.0 519 >>> x.pyvalue = None 520 >>> print(x.type) 521 None 522 >>> print(x.value) 523 None 524 >>> print(x.pyvalue) 525 None 526 >>> x.pyvalue = True 527 >>> x.type 528 u'int_4s' 529 >>> x.value 530 u'1' 531 >>> x.pyvalue 532 1 533 """ 534 __slots__ = tuple(ProcessParamsTable.validcolumns.keys()) 535 536 @property
537 - def pyvalue(self):
538 if self.value is None: 539 return None 540 try: 541 parsefunc = ligolwtypes.ToPyType[self.type] 542 except KeyError: 543 raise ValueError("invalid type '%s'" % self.type) 544 return parsefunc(self.value)
545 546 @pyvalue.setter
547 - def pyvalue(self, value):
548 if value is None: 549 self.type = self.value = None 550 else: 551 try: 552 self.type = ligolwtypes.FromPyType[type(value)] 553 except KeyError: 554 raise ValueError("type not supported: %s" % repr(type(value))) 555 self.value = value if self.type in ligolwtypes.StringTypes else ligolwtypes.FormatFunc[self.type](value)
556 557 558 ProcessParamsTable.RowType = ProcessParams
559 560 561 # 562 # ============================================================================= 563 # 564 # search_summary:table 565 # 566 # ============================================================================= 567 # 568 569 570 -class SearchSummaryTable(table.Table):
571 tableName = "search_summary" 572 validcolumns = { 573 "process_id": "ilwd:char", 574 "shared_object": "lstring", 575 "lalwrapper_cvs_tag": "lstring", 576 "lal_cvs_tag": "lstring", 577 "comment": "lstring", 578 "ifos": "lstring", 579 "in_start_time": "int_4s", 580 "in_start_time_ns": "int_4s", 581 "in_end_time": "int_4s", 582 "in_end_time_ns": "int_4s", 583 "out_start_time": "int_4s", 584 "out_start_time_ns": "int_4s", 585 "out_end_time": "int_4s", 586 "out_end_time_ns": "int_4s", 587 "nevents": "int_4s", 588 "nnodes": "int_4s" 589 } 590 how_to_index = { 591 "ss_pi_index": ("process_id",), 592 } 593
594 - def get_inlist(self):
595 """ 596 Return a segmentlist object describing the times spanned by 597 the input segments of all rows in the table. 598 599 Note: the result is not coalesced, the segmentlist 600 contains the segments as they appear in the table. 601 """ 602 return segments.segmentlist(row.in_segment for row in self)
603
604 - def get_outlist(self):
605 """ 606 Return a segmentlist object describing the times spanned by 607 the output segments of all rows in the table. 608 609 Note: the result is not coalesced, the segmentlist 610 contains the segments as they appear in the table. 611 """ 612 return segments.segmentlist(row.out_segment for row in self)
613
614 - def get_in_segmentlistdict(self, process_ids = None):
615 """ 616 Return a segmentlistdict mapping instrument to in segment 617 list. If process_ids is a sequence of process IDs, then 618 only rows with matching IDs are included otherwise all rows 619 are included. 620 621 Note: the result is not coalesced, each segmentlist 622 contains the segments listed for that instrument as they 623 appeared in the table. 624 """ 625 seglists = segments.segmentlistdict() 626 for row in self: 627 ifos = row.instruments or (None,) 628 if process_ids is None or row.process_id in process_ids: 629 seglists.extend(dict((ifo, segments.segmentlist([row.in_segment])) for ifo in ifos)) 630 return seglists
631
632 - def get_out_segmentlistdict(self, process_ids = None):
633 """ 634 Return a segmentlistdict mapping instrument to out segment 635 list. If process_ids is a sequence of process IDs, then 636 only rows with matching IDs are included otherwise all rows 637 are included. 638 639 Note: the result is not coalesced, each segmentlist 640 contains the segments listed for that instrument as they 641 appeared in the table. 642 """ 643 seglists = segments.segmentlistdict() 644 for row in self: 645 ifos = row.instruments or (None,) 646 if process_ids is None or row.process_id in process_ids: 647 seglists.extend(dict((ifo, segments.segmentlist([row.out_segment])) for ifo in ifos)) 648 return seglists
649
650 651 -class SearchSummary(table.Table.RowType):
652 """ 653 Example: 654 655 >>> x = SearchSummary() 656 >>> x.instruments = (u"H1", u"L1") 657 >>> x.ifos 658 u'H1,L1' 659 >>> x.instruments 660 set([u'H1', u'L1']) 661 >>> x.in_start = x.out_start = LIGOTimeGPS(0) 662 >>> x.in_end = x.out_end = LIGOTimeGPS(10) 663 >>> x.in_segment 664 segment(LIGOTimeGPS(0, 0), LIGOTimeGPS(10, 0)) 665 >>> x.out_segment 666 segment(LIGOTimeGPS(0, 0), LIGOTimeGPS(10, 0)) 667 >>> x.in_segment = x.out_segment = None 668 >>> print(x.in_segment) 669 None 670 >>> print(x.out_segment) 671 None 672 """ 673 __slots__ = tuple(SearchSummaryTable.validcolumns.keys()) 674 675 instruments = instrumentsproperty("ifos") 676 677 in_start = gpsproperty("in_start_time", "in_start_time_ns") 678 in_end = gpsproperty("in_end_time", "in_end_time_ns") 679 out_start = gpsproperty("out_start_time", "out_start_time_ns") 680 out_end = gpsproperty("out_end_time", "out_end_time_ns") 681 682 in_segment = segmentproperty("in_start", "in_end") 683 out_segment = segmentproperty("out_start", "out_end") 684
685 - def get_ifos(self):
686 """ 687 Return a set of the instruments for this row. 688 """ 689 return self.instruments
690
691 - def set_ifos(self, instruments):
692 """ 693 Serialize a sequence of instruments into the ifos 694 attribute. The instrument names must not contain the "," 695 character. 696 """ 697 self.instruments = instruments
698
699 - def get_in(self):
700 """ 701 Get the input segment. 702 """ 703 return self.in_segment
704
705 - def set_in(self, seg):
706 """ 707 Set the input segment. 708 """ 709 self.in_segment = seg
710
711 - def get_out(self):
712 """ 713 Get the output segment. 714 """ 715 return self.out_segment
716
717 - def set_out(self, seg):
718 """ 719 Set the output segment. 720 """ 721 self.out_segment = seg
722 723 724 SearchSummaryTable.RowType = SearchSummary 725 726 727 # 728 # ============================================================================= 729 # 730 # search_summvars:table 731 # 732 # ============================================================================= 733 # 734 735 736 SearchSummVarsID = ilwd.get_ilwdchar_class(u"search_summvars", u"search_summvar_id")
737 738 739 -class SearchSummVarsTable(table.Table):
740 tableName = "search_summvars" 741 validcolumns = { 742 "process_id": "ilwd:char", 743 "search_summvar_id": "ilwd:char", 744 "name": "lstring", 745 "string": "lstring", 746 "value": "real_8" 747 } 748 constraints = "PRIMARY KEY (search_summvar_id)" 749 next_id = SearchSummVarsID(0)
750
751 752 -class SearchSummVars(table.Table.RowType):
753 __slots__ = tuple(SearchSummVarsTable.validcolumns.keys())
754 755 756 SearchSummVarsTable.RowType = SearchSummVars 757 758 759 # 760 # ============================================================================= 761 # 762 # experiment:table 763 # 764 # ============================================================================= 765 # 766 767 768 ExpDefID = ilwd.get_ilwdchar_class(u"experiment", u"experiment_id")
769 770 771 -class ExperimentTable(table.Table):
772 tableName = "experiment" 773 validcolumns = { 774 "experiment_id": "ilwd:char", 775 "search_group": "lstring", 776 "search": "lstring", 777 "lars_id": "lstring", 778 "instruments": "lstring", 779 "gps_start_time": "int_4s", 780 "gps_end_time": "int_4s", 781 "comments": "lstring" 782 } 783 constraints = "PRIMARY KEY (experiment_id)" 784 next_id = ExpDefID(0) 785
786 - def get_expr_id(self, search_group, search, lars_id, instruments, gps_start_time, gps_end_time, comments = None):
787 """ 788 Return the expr_def_id for the row in the table whose 789 values match the givens. 790 If a matching row is not found, returns None. 791 792 @search_group: string representing the search group (e.g., cbc) 793 @serach: string representing search (e.g., inspiral) 794 @lars_id: string representing lars_id 795 @instruments: the instruments; must be a python set 796 @gps_start_time: string or int representing the gps_start_time of the experiment 797 @gps_end_time: string or int representing the gps_end_time of the experiment 798 """ 799 # create string from instrument set 800 instruments = ifos_from_instrument_set(instruments) 801 802 # look for the ID 803 for row in self: 804 if (row.search_group, row.search, row.lars_id, row.instruments, row.gps_start_time, row.gps_end_time, row.comments) == (search_group, search, lars_id, instruments, gps_start_time, gps_end_time, comments): 805 # found it 806 return row.experiment_id 807 808 # experiment not found in table 809 return None
810
811 - def write_new_expr_id(self, search_group, search, lars_id, instruments, gps_start_time, gps_end_time, comments = None):
812 """ 813 Creates a new def_id for the given arguments and returns it. 814 If an entry already exists with these, will just return that id. 815 816 @search_group: string representing the search group (e.g., cbc) 817 @serach: string representing search (e.g., inspiral) 818 @lars_id: string representing lars_id 819 @instruments: the instruments; must be a python set 820 @gps_start_time: string or int representing the gps_start_time of the experiment 821 @gps_end_time: string or int representing the gps_end_time of the experiment 822 """ 823 824 # check if id already exists 825 check_id = self.get_expr_id( search_group, search, lars_id, instruments, gps_start_time, gps_end_time, comments = comments ) 826 if check_id: 827 return check_id 828 829 # experiment not found in table 830 row = self.RowType() 831 row.experiment_id = self.get_next_id() 832 row.search_group = search_group 833 row.search = search 834 row.lars_id = lars_id 835 row.instruments = ifos_from_instrument_set(instruments) 836 row.gps_start_time = gps_start_time 837 row.gps_end_time = gps_end_time 838 row.comments = comments 839 self.append(row) 840 841 # return new ID 842 return row.experiment_id
843
844 - def get_row_from_id(self, experiment_id):
845 """ 846 Returns row in matching the given experiment_id. 847 """ 848 row = [row for row in self if row.experiment_id == experiment_id] 849 if len(row) > 1: 850 raise ValueError("duplicate ids in experiment table") 851 if len(row) == 0: 852 raise ValueError("id '%s' not found in table" % experiment_id) 853 854 return row[0]
855
856 857 -class Experiment(table.Table.RowType):
858 __slots__ = tuple(ExperimentTable.validcolumns.keys()) 859
860 - def get_instruments(self):
861 """ 862 Return a set of the instruments for this row. 863 """ 864 return instrument_set_from_ifos(self.instruments)
865
866 - def set_instruments(self, instruments):
867 """ 868 Serialize a sequence of instruments into the ifos 869 attribute. The instrument names must not contain the "," 870 character. 871 """ 872 self.instruments = ifos_from_instrument_set(instruments)
873 874 875 ExperimentTable.RowType = Experiment 876 877 878 # 879 # ============================================================================= 880 # 881 # experiment_summary:table 882 # 883 # ============================================================================= 884 # 885 886 887 ExpSummID = ilwd.get_ilwdchar_class(u"experiment_summary", u"experiment_summ_id")
888 889 890 -class ExperimentSummaryTable(table.Table):
891 tableName = "experiment_summary" 892 validcolumns = { 893 "experiment_summ_id": "ilwd:char", 894 "experiment_id": "ilwd:char", 895 "time_slide_id": "ilwd:char", 896 "veto_def_name": "lstring", 897 "datatype": "lstring", 898 "sim_proc_id": "ilwd:char", 899 "duration": "int_4s", 900 "nevents": "int_4u" 901 } 902 constraints = "PRIMARY KEY (experiment_summ_id)" 903 how_to_index = { 904 "es_ei_index": ("experiment_id",), 905 "es_dt_index": ("datatype",) 906 } 907 next_id = ExpSummID(0) 908 909 datatypes = ['slide', 'all_data', 'playground', 'exclude_play', 'simulation'] 910 911
912 - def as_id_dict(self):
913 """ 914 Return table as a dictionary mapping experiment_id, time_slide_id, 915 veto_def_name, and sim_proc_id (if it exists) to the expr_summ_id. 916 """ 917 d = {} 918 for row in self: 919 if row.experiment_id not in d: 920 d[row.experiment_id] = {} 921 if (row.time_slide_id, row.veto_def_name, row.datatype, row.sim_proc_id) in d[row.experiment_id]: 922 # entry already exists, raise error 923 raise KeyError("duplicate entries in experiment_summary table") 924 d[row.experiment_id][(row.time_slide_id, row.veto_def_name, row.datatype, row.sim_proc_id)] = row.experiment_summ_id 925 926 return d
927
928 - def get_expr_summ_id(self, experiment_id, time_slide_id, veto_def_name, datatype, sim_proc_id = None):
929 """ 930 Return the expr_summ_id for the row in the table whose experiment_id, 931 time_slide_id, veto_def_name, and datatype match the given. If sim_proc_id, 932 will retrieve the injection run matching that sim_proc_id. 933 If a matching row is not found, returns None. 934 """ 935 936 # look for the ID 937 for row in self: 938 if (row.experiment_id, row.time_slide_id, row.veto_def_name, row.datatype, row.sim_proc_id) == (experiment_id, time_slide_id, veto_def_name, datatype, sim_proc_id): 939 # found it 940 return row.experiment_summ_id 941 942 # if get to here, experiment not found in table 943 return None
944
945 - def write_experiment_summ(self, experiment_id, time_slide_id, veto_def_name, datatype, sim_proc_id = None ):
946 """ 947 Writes a single entry to the experiment_summ table. This can be used 948 for either injections or non-injection experiments. However, it is 949 recommended that this only be used for injection experiments; for 950 non-injection experiments write_experiment_summ_set should be used to 951 ensure that an entry gets written for every time-slide performed. 952 """ 953 # check if entry alredy exists; if so, return value 954 check_id = self.get_expr_summ_id(experiment_id, time_slide_id, veto_def_name, datatype, sim_proc_id = sim_proc_id) 955 if check_id: 956 return check_id 957 958 row = self.RowType() 959 row.experiment_summ_id = self.get_next_id() 960 row.experiment_id = experiment_id 961 row.time_slide_id = time_slide_id 962 row.veto_def_name = veto_def_name 963 row.datatype = datatype 964 row.sim_proc_id = sim_proc_id 965 row.nevents = None 966 row.duration = None 967 self.append(row) 968 969 return row.experiment_summ_id
970
971 - def write_non_injection_summary(self, experiment_id, time_slide_dict, veto_def_name, write_all_data = True, write_playground = True, write_exclude_play = True, return_dict = False):
972 """ 973 Method for writing a new set of non-injection experiments to the experiment 974 summary table. This ensures that for every entry in the 975 experiment table, an entry for every slide is added to 976 the experiment_summ table, rather than just an entry for slides that 977 have events in them. Default is to write a 3 rows for zero-lag: one for 978 all_data, playground, and exclude_play. (If all of these are set to false, 979 will only slide rows.) 980 981 Note: sim_proc_id is hard-coded to None because time-slides 982 are not performed with injections. 983 984 @experiment_id: the experiment_id for this experiment_summary set 985 @time_slide_dict: the time_slide table as a dictionary; used to figure out 986 what is zero-lag and what is slide 987 @veto_def_name: the name of the vetoes applied 988 @write_all_data: if set to True, writes a zero-lag row who's datatype column 989 is set to 'all_data' 990 @write_playground: same, but datatype is 'playground' 991 @write_exclude_play: same, but datatype is 'exclude_play' 992 @return_dict: if set to true, returns an id_dict of the table 993 """ 994 for slide_id in time_slide_dict: 995 # check if it's zero_lag or not 996 if not any( time_slide_dict[slide_id].values() ): 997 if write_all_data: 998 self.write_experiment_summ( experiment_id, slide_id, veto_def_name, 'all_data', sim_proc_id = None ) 999 if write_playground: 1000 self.write_experiment_summ( experiment_id, slide_id, veto_def_name, 'playground', sim_proc_id = None ) 1001 if write_exclude_play: 1002 self.write_experiment_summ( experiment_id, slide_id, veto_def_name, 'exclude_play', sim_proc_id = None ) 1003 else: 1004 self.write_experiment_summ( experiment_id, slide_id, veto_def_name, 'slide', sim_proc_id = None ) 1005 1006 if return_dict: 1007 return self.as_id_dict()
1008 1009
1010 - def add_nevents(self, experiment_summ_id, num_events, add_to_current = True):
1011 """ 1012 Add num_events to the nevents column in a specific entry in the table. If 1013 add_to_current is set to False, will overwrite the current nevents entry in 1014 the row with num_events. Otherwise, default is to add num_events to 1015 the current value. 1016 1017 Note: Can subtract events by passing a negative number to num_events. 1018 """ 1019 for row in self: 1020 if row.experiment_summ_id != experiment_summ_id: 1021 continue 1022 if row.nevents is None: 1023 row.nevents = 0 1024 if add_to_current: 1025 row.nevents += num_events 1026 return row.nevents 1027 else: 1028 row.nevents = num_events 1029 return row.nevents 1030 1031 # if get to here, couldn't find experiment_summ_id in the table 1032 raise ValueError("'%s' could not be found in the table" % (str(experiment_summ_id)))
1033
1034 1035 -class ExperimentSummary(table.Table.RowType):
1036 __slots__ = tuple(ExperimentSummaryTable.validcolumns.keys())
1037 1038 1039 ExperimentSummaryTable.RowType = ExperimentSummary
1040 1041 1042 # 1043 # ============================================================================= 1044 # 1045 # experiment_map:table 1046 # 1047 # ============================================================================= 1048 # 1049 1050 1051 -class ExperimentMapTable(table.Table):
1052 tableName = "experiment_map" 1053 validcolumns = { 1054 "experiment_summ_id": "ilwd:char", 1055 "coinc_event_id": "ilwd:char", 1056 } 1057 how_to_index = { 1058 "em_esi_index": ("experiment_summ_id",), 1059 "em_cei_index": ("coinc_event_id",) 1060 } 1061
1062 - def get_experiment_summ_ids( self, coinc_event_id ):
1063 """ 1064 Gets all the experiment_summ_ids that map to a given coinc_event_id. 1065 """ 1066 experiment_summ_ids = [] 1067 for row in self: 1068 if row.coinc_event_id == coinc_event_id: 1069 experiment_summ_ids.append(row.experiment_summ_id) 1070 if len(experiment_summ_ids) == 0: 1071 raise ValueError("'%s' could not be found in the experiment_map table" % coinc_event_id) 1072 return experiment_summ_ids
1073
1074 1075 -class ExperimentMap(table.Table.RowType):
1076 __slots__ = tuple(ExperimentMapTable.validcolumns.keys())
1077 1078 1079 ExperimentMapTable.RowType = ExperimentMap 1080 1081 1082 # 1083 # ============================================================================= 1084 # 1085 # gds_trigger:table 1086 # 1087 # ============================================================================= 1088 # 1089 1090 1091 GDSTriggerID = ilwd.get_ilwdchar_class(u"gds_trigger", u"event_id")
1092 1093 -class GDSTriggerTable(table.Table):
1094 tableName = "gds_trigger" 1095 validcolumns = { 1096 "creator_db": "int_4s", 1097 "process_id": "ilwd:char_u", 1098 "filter_id": "ilwd:char", 1099 "name": "lstring", 1100 "subtype": "lstring", 1101 "ifo": "lstring", 1102 "start_time": "int_4s", 1103 "start_time_ns": "int_4s", 1104 "duration": "real_4", 1105 "priority": "int_4s", 1106 "disposition": "int_4s", 1107 "size": "real_4", 1108 "significance": "real_4", 1109 "frequency": "real_4", 1110 "bandwidth": "real_4", 1111 "time_peak": "real_4", 1112 "time_average": "real_4", 1113 "time_sigma": "real_4", 1114 "freq_peak": "real_4", 1115 "freq_average": "real_4", 1116 "freq_sigma": "real_4", 1117 "noise_power": "real_4", 1118 "signal_power": "real_4", 1119 "pixel_count": "int_4s", 1120 "confidence": "real_4", 1121 "binarydata": "ilwd:char_u", 1122 "binarydata_length": "int_4s", 1123 "event_id": "ilwd:char" 1124 } 1125 constraints = "PRIMARY KEY (event_id)" 1126 next_id = GDSTriggerID(0) 1127 interncolumns = ("process_id", "ifo", "subtype")
1128
1129 1130 -class GDSTrigger(table.Table.RowType):
1131 __slots__ = tuple(GDSTriggerTable.validcolumns.keys()) 1132 1133 # 1134 # Tile properties 1135 # 1136
1137 - def get_start(self):
1138 return LIGOTimeGPS(self.start_time, self.start_time_ns)
1139
1140 - def set_start(self, gps):
1141 self.start_time, self.start_time_ns = gps.seconds, gps.nanoseconds
1142
1143 - def get_stop(self):
1144 return LIGOTimeGPS(self.start_time, self.start_time_ns) + self.duration
1145
1146 - def get_peak(self):
1147 return LIGOTimeGPS(self.time_peak, self.time_peak)
1148
1149 - def set_peak(self, gps):
1150 self.time_peak, self.peak_time_ns = gps.seconds, gps.nanoseconds
1151
1152 - def get_period(self):
1153 start = LIGOTimeGPS(self.start_time, self.start_time_ns) 1154 return segments.segment(start, start + self.duration)
1155
1156 - def set_period(self, period):
1157 self.start_time, self.start_time_ns = period[0].seconds, period[0].nanoseconds 1158 self.duration = float(abs(period))
1159
1160 - def get_band(self):
1161 low = self.frequency 1162 return segments.segment(low, low + self.bandwidth)
1163
1164 - def set_band(self, band):
1165 self.frequency = band[0] 1166 self.bandwidth = abs(band)
1167 1168 GDSTriggerTable.RowType = GDSTrigger 1169 1170 1171 # 1172 # ============================================================================= 1173 # 1174 # sngl_burst:table 1175 # 1176 # ============================================================================= 1177 # 1178 1179 1180 SnglBurstID = ilwd.get_ilwdchar_class(u"sngl_burst", u"event_id")
1181 1182 1183 -class SnglBurstTable(table.Table):
1184 tableName = "sngl_burst" 1185 validcolumns = { 1186 "creator_db": "int_4s", 1187 "process_id": "ilwd:char", 1188 "filter_id": "ilwd:char", 1189 "ifo": "lstring", 1190 "search": "lstring", 1191 "channel": "lstring", 1192 "start_time": "int_4s", 1193 "start_time_ns": "int_4s", 1194 "stop_time": "int_4s", 1195 "stop_time_ns": "int_4s", 1196 "duration": "real_4", 1197 "flow": "real_4", 1198 "fhigh": "real_4", 1199 "central_freq": "real_4", 1200 "bandwidth": "real_4", 1201 "amplitude": "real_4", 1202 "snr": "real_4", 1203 "confidence": "real_4", 1204 "chisq": "real_8", 1205 "chisq_dof": "real_8", 1206 "tfvolume": "real_4", 1207 "hrss": "real_4", 1208 "time_lag": "real_4", 1209 "peak_time": "int_4s", 1210 "peak_time_ns": "int_4s", 1211 "peak_frequency": "real_4", 1212 "peak_strain": "real_4", 1213 "peak_time_error": "real_4", 1214 "peak_frequency_error": "real_4", 1215 "peak_strain_error": "real_4", 1216 "ms_start_time": "int_4s", 1217 "ms_start_time_ns": "int_4s", 1218 "ms_stop_time": "int_4s", 1219 "ms_stop_time_ns": "int_4s", 1220 "ms_duration": "real_4", 1221 "ms_flow": "real_4", 1222 "ms_fhigh": "real_4", 1223 "ms_bandwidth": "real_4", 1224 "ms_hrss": "real_4", 1225 "ms_snr": "real_4", 1226 "ms_confidence": "real_4", 1227 "param_one_name": "lstring", 1228 "param_one_value": "real_8", 1229 "param_two_name": "lstring", 1230 "param_two_value": "real_8", 1231 "param_three_name": "lstring", 1232 "param_three_value": "real_8", 1233 "event_id": "ilwd:char" 1234 } 1235 constraints = "PRIMARY KEY (event_id)" 1236 next_id = SnglBurstID(0) 1237 interncolumns = ("process_id", "ifo", "search", "channel") 1238
1239 - def get_column(self, column):
1240 """@returns: an array of column values for each row in the table 1241 1242 @param column: 1243 name of column to return 1244 @returntype: 1245 numpy.ndarray 1246 """ 1247 if column.lower() == 'q': 1248 return self.get_q 1249 else: 1250 return self.getColumnByName(column).asarray()
1251
1252 - def get_peak(self):
1253 """@returns: the peak time of each row in the table 1254 @returntype: numpy.ndarray 1255 """ 1256 return numpy.asarray([row.get_peak() for row in self])
1257
1258 - def get_start(self):
1259 """@returns: the start time of each row in the table 1260 @returntype: numpy.ndarray 1261 """ 1262 return numpy.asarray([row.get_start() for row in self])
1263
1264 - def get_ms_start(self):
1265 """@returns: the start time of the most significant tile for 1266 each row in the table 1267 @returntype: numpy.ndarray 1268 """ 1269 return numpy.asarray([row.get_ms_start() for row in self])
1270
1271 - def get_stop(self):
1272 """@returns: the stop time of each row in the table 1273 @returntype: numpy.ndarray 1274 """ 1275 return numpy.asarray([row.get_stop() for row in self])
1276
1277 - def get_ms_stop(self):
1278 """@returns: the stop time of the most significant tile for 1279 each row in the table 1280 @returntype: numpy.ndarray 1281 """ 1282 return numpy.asarray([row.get_ms_stop() for row in self])
1283
1284 - def get_q(self):
1285 """@returns: the Q of each row in the table 1286 @returntype: numpy.ndarray 1287 """ 1288 return numpy.asarray([row.get_q() for row in self])
1289
1290 - def get_z(self):
1291 """@returns: the Z (Omega-Pipeline energy) of each row in the 1292 table 1293 @returntype: numpy.ndarray 1294 """ 1295 return numpy.asarray([row.get_z() for row in self])
1296
1297 - def get_period(self):
1298 """@returns: the period segment of each row in the table 1299 @returntype: glue.segments.segmentlist 1300 """ 1301 return segments.segmentlist([row.get_period() for row in self])
1302
1303 - def get_ms_period(self):
1304 """@returns: the period segment for the most significant tile 1305 of each row in the table 1306 @returntype: glue.segments.segmentlist 1307 """ 1308 return segments.segmentlist([row.get_ms_period() for row in self])
1309
1310 - def get_band(self):
1311 """@returns: the frequency band of each row in the table 1312 @returntype: glue.segments.segmentlist 1313 """ 1314 return segments.segmentlist([row.get_band() for row in self])
1315
1316 - def get_ms_band(self):
1317 """@returns: the frequency band of the most significant tile 1318 for each row in the table 1319 """ 1320 return segments.segmentlist([row.get_ms_band() for row in self])
1321
1322 - def veto(self, seglist):
1323 """@returns: those rows of the table that don't lie within a 1324 given seglist 1325 """ 1326 keep = self.copy() 1327 for row in self: 1328 time = row.get_peak() 1329 if time not in seglist: 1330 keep.append(row) 1331 return keep
1332
1333 - def vetoed(self, seglist):
1334 """@returns: those rows of the table that lie within a given 1335 seglist 1336 """ 1337 vetoed = self.copy() 1338 for row in self: 1339 time = row.get_peak() 1340 if time in seglist: 1341 vetoed.append(row) 1342 return vetoed
1343
1344 - def veto_seglistdict(self, seglistdict):
1345 keep = self.copy() 1346 for row in self: 1347 time = row.get_peak() 1348 if time not in seglistdict[row.ifo]: 1349 keep.append(row) 1350 return keep
1351
1352 - def vetoed_seglistdict(self, seglistdict):
1353 vetoed = self.copy() 1354 for row in self: 1355 time = row.get_peak() 1356 if time in seglistdict[row.ifo]: 1357 vetoed.append(row) 1358 return vetoed
1359
1360 1361 -class SnglBurst(table.Table.RowType):
1362 __slots__ = tuple(SnglBurstTable.validcolumns.keys()) 1363 1364 # 1365 # Tile properties 1366 # 1367 1368 start = gpsproperty("start_time", "start_time_ns") 1369 stop = gpsproperty("stop_time", "stop_time_ns") 1370 peak = gpsproperty("peak_time", "peak_time_ns") 1371 1372 @property
1373 - def period(self):
1374 start = self.start 1375 try: 1376 stop = self.stop 1377 except AttributeError: 1378 stop = None 1379 # special case: use duration if stop is not recorded 1380 if start is not None and stop is None and self.duration is not None: 1381 stop = start + self.duration 1382 if start is None and stop is None: 1383 return None 1384 return segments.segment(start, stop)
1385 1386 @period.setter
1387 - def period(self, seg):
1388 if seg is None: 1389 self.start = self.stop = self.duration = None 1390 else: 1391 self.start, self.stop = seg 1392 self.duration = float(abs(seg))
1393 1394 @property
1395 - def band(self):
1396 if self.central_freq is None and self.bandwidth is None: 1397 return None 1398 return segments.segment(self.central_freq - self.bandwidth / 2., self.central_freq + self.bandwidth / 2.)
1399 1400 @band.setter
1401 - def band(self, seg):
1402 if seg is None: 1403 try: 1404 self.flow = self.fhigh = None 1405 except AttributeError: 1406 # not in LAL C version 1407 pass 1408 self.central_freq = self.bandwidth = None 1409 else: 1410 try: 1411 self.flow, self.fhigh = seg 1412 except AttributeError: 1413 # not in LAL C version 1414 pass 1415 self.central_freq = sum(seg) / 2. 1416 self.bandwidth = abs(seg)
1417 1418 # 1419 # "Most significant pixel" properties 1420 # 1421 1422 ms_start = gpsproperty("ms_start_time", "ms_start_time_ns") 1423 ms_stop = gpsproperty("ms_stop_time", "ms_stop_time_ns") 1424 ms_peak = gpsproperty("ms_peak_time", "ms_peak_time_ns") 1425 1426 @property
1427 - def ms_period(self):
1428 start = self.ms_start 1429 stop = self.ms_stop 1430 # special case: use duration if stop is not recorded 1431 if start is not None and stop is None and self.ms-duration is not None: 1432 stop = start + self.ms_duration 1433 if start is None and stop is None: 1434 return None 1435 return segments.segment(start, stop)
1436 1437 @ms_period.setter
1438 - def ms_period(self, seg):
1439 if seg is None: 1440 self.ms_start = self.ms_stop = self.ms_duration = None 1441 else: 1442 self.ms_start, self.ms_stop = seg 1443 self.ms_duration = float(abs(seg))
1444 1445 @property
1446 - def ms_band(self):
1447 if self.ms_flow is None and self.ms_bandwidth is None: 1448 return None 1449 return segments.segment(self.ms_flow, self.ms_flow + self.ms_bandwidth)
1450 1451 @ms_band.setter
1452 - def ms_band(self, seg):
1453 if seg is None: 1454 self.ms_bandwidth = self.ms_flow = self.ms_fhigh = None 1455 else: 1456 self.ms_flow, self.ms_fhigh = seg 1457 self.ms_bandwidth = abs(seg)
1458 1459 # legacy compatibility. DO NOT USE 1460
1461 - def get_start(self):
1462 return self.start
1463
1464 - def set_start(self, gps):
1465 self.start = gps
1466
1467 - def get_stop(self):
1468 return self.stop
1469
1470 - def set_stop(self, gps):
1471 self.stop = gps
1472
1473 - def get_peak(self):
1474 return self.peak
1475
1476 - def set_peak(self, gps):
1477 self.peak = gps
1478
1479 - def get_period(self):
1480 return self.period
1481
1482 - def set_period(self, period):
1483 self.period = period
1484
1485 - def get_band(self):
1486 return self.band
1487
1488 - def set_band(self, band):
1489 self.band = band
1490
1491 - def get_ms_start(self):
1492 return self.ms_start
1493
1494 - def set_ms_start(self, gps):
1495 self.ms_start = gps
1496
1497 - def get_ms_stop(self):
1498 return self.ms_stop
1499
1500 - def set_ms_stop(self, gps):
1501 self.ms_stop = gps
1502
1503 - def get_ms_period(self):
1504 return self.ms_period
1505
1506 - def set_ms_period(self, period):
1507 self.ms_period = period
1508
1509 - def get_ms_band(self):
1510 return self.ms_band
1511
1512 - def set_ms_band(self, band):
1513 self.ms_band = band
1514 1515 # 1516 # Omega-Pipeline properties 1517 # 1518
1519 - def get_q(self):
1520 return self.duration * 2 * numpy.pi**(1/2.) * self.central_freq
1521
1522 - def get_z(self):
1523 return self.snr ** 2 / 2.
1524 1525 1526 SnglBurstTable.RowType = SnglBurst
1527 1528 1529 # 1530 # ============================================================================= 1531 # 1532 # multi_burst:table 1533 # 1534 # ============================================================================= 1535 # 1536 1537 1538 # 1539 # FIXME: I think extra columns have been added here that aren't in other 1540 # places where this table is defined. 1541 # 1542 1543 1544 -class MultiBurstTable(table.Table):
1545 tableName = "multi_burst" 1546 validcolumns = { 1547 "creator_db": "int_4s", 1548 "process_id": "ilwd:char", 1549 "filter_id": "ilwd:char", 1550 "ifos": "lstring", 1551 "start_time": "int_4s", 1552 "start_time_ns": "int_4s", 1553 "duration": "real_4", 1554 "peak_time": "int_4s", 1555 "peak_time_ns": "int_4s", 1556 "central_freq": "real_4", 1557 "bandwidth": "real_4", 1558 "amplitude": "real_4", 1559 "snr": "real_4", 1560 "confidence": "real_4", 1561 "false_alarm_rate": "real_4", 1562 "ligo_axis_ra": "real_4", 1563 "ligo_axis_dec": "real_4", 1564 "ligo_angle": "real_4", 1565 "ligo_angle_sig": "real_4", 1566 "coinc_event_id": "ilwd:char" 1567 } 1568 # FIXME: like some other tables here, this table should have the 1569 # constraint that the coinc_event_id column is a primary key. this 1570 # breaks ID reassignment in ligolw_sqlite, so until that is fixed 1571 # the constraint is being replaced with an index. 1572 #constraints = "PRIMARY KEY (coinc_event_id)" 1573 how_to_index = { 1574 "mb_cei_index": ("coinc_event_id",) 1575 }
1576
1577 1578 -class MultiBurst(table.Table.RowType):
1579 __slots__ = tuple(MultiBurstTable.validcolumns.keys()) 1580 1581 instruments = instrumentsproperty("ifos") 1582 1583 start = gpsproperty("start_time", "start_time_ns") 1584 peak = gpsproperty("peak_time", "peak_time_ns") 1585 1586 @property
1587 - def period(self):
1588 start = self.start 1589 if start is None and self.duration is None: 1590 return None 1591 return segments.segment(start, start + self.duration)
1592 1593 @period.setter
1594 - def period(self, seg):
1595 if seg is None: 1596 self.start = self.duration = None 1597 else: 1598 self.start = seg[0] 1599 self.duration = float(abs(seg))
1600 1601 @property
1602 - def band(self):
1603 if self.central_freq is None and self.bandwidth is None: 1604 return None 1605 return segments.segment(self.central_freq - self.bandwidth / 2., self.central_freq + self.bandwidth / 2.)
1606 1607 @band.setter
1608 - def band(self, seg):
1609 if seg is None: 1610 self.central_freq = self.bandwidth = None 1611 else: 1612 self.central_freq = sum(seg) / 2. 1613 self.bandwidth = abs(seg)
1614 1615 # legacy compatibility. DO NOT USE 1616
1617 - def get_ifos(self):
1618 return self.instruments
1619
1620 - def set_ifos(self, instruments):
1622
1623 - def get_peak(self):
1624 return self.peak
1625
1626 - def set_peak(self, gps):
1627 self.peak = gps
1628 1629 1630 MultiBurstTable.RowType = MultiBurst 1631 1632 1633 # 1634 # ============================================================================= 1635 # 1636 # sngl_inspiral:table 1637 # 1638 # ============================================================================= 1639 # 1640 1641 1642 SnglInspiralID = ilwd.get_ilwdchar_class(u"sngl_inspiral", u"event_id")
1643 1644 1645 -class SnglInspiralTable(table.Table):
1646 tableName = "sngl_inspiral" 1647 validcolumns = { 1648 "process_id": "ilwd:char", 1649 "ifo": "lstring", 1650 "search": "lstring", 1651 "channel": "lstring", 1652 "end_time": "int_4s", 1653 "end_time_ns": "int_4s", 1654 "end_time_gmst": "real_8", 1655 "impulse_time": "int_4s", 1656 "impulse_time_ns": "int_4s", 1657 "template_duration": "real_8", 1658 "event_duration": "real_8", 1659 "amplitude": "real_4", 1660 "eff_distance": "real_4", 1661 "coa_phase": "real_4", 1662 "mass1": "real_4", 1663 "mass2": "real_4", 1664 "mchirp": "real_4", 1665 "mtotal": "real_4", 1666 "eta": "real_4", 1667 "kappa": "real_4", 1668 "chi": "real_4", 1669 "tau0": "real_4", 1670 "tau2": "real_4", 1671 "tau3": "real_4", 1672 "tau4": "real_4", 1673 "tau5": "real_4", 1674 "ttotal": "real_4", 1675 "psi0": "real_4", 1676 "psi3": "real_4", 1677 "alpha": "real_4", 1678 "alpha1": "real_4", 1679 "alpha2": "real_4", 1680 "alpha3": "real_4", 1681 "alpha4": "real_4", 1682 "alpha5": "real_4", 1683 "alpha6": "real_4", 1684 "beta": "real_4", 1685 "f_final": "real_4", 1686 "snr": "real_4", 1687 "chisq": "real_4", 1688 "chisq_dof": "int_4s", 1689 "bank_chisq": "real_4", 1690 "bank_chisq_dof": "int_4s", 1691 "cont_chisq": "real_4", 1692 "cont_chisq_dof": "int_4s", 1693 "sigmasq": "real_8", 1694 "rsqveto_duration": "real_4", 1695 "Gamma0": "real_4", 1696 "Gamma1": "real_4", 1697 "Gamma2": "real_4", 1698 "Gamma3": "real_4", 1699 "Gamma4": "real_4", 1700 "Gamma5": "real_4", 1701 "Gamma6": "real_4", 1702 "Gamma7": "real_4", 1703 "Gamma8": "real_4", 1704 "Gamma9": "real_4", 1705 "spin1x": "real_4", 1706 "spin1y": "real_4", 1707 "spin1z": "real_4", 1708 "spin2x": "real_4", 1709 "spin2y": "real_4", 1710 "spin2z": "real_4", 1711 "event_id": "ilwd:char" 1712 } 1713 constraints = "PRIMARY KEY (event_id)" 1714 # FIXME: lal uses an ID of 0 to indicate "no valid ID has been 1715 # set", so we start at 1 for safety, but eventually that should be 1716 # fixed in LAL and then this can be put back to 0 for cleanliness. 1717 next_id = SnglInspiralID(1) 1718 interncolumns = ("process_id", "ifo", "search", "channel") 1719
1720 - def get_column(self,column,fac=250.,index=6.):
1721 if column == 'reduced_chisq': 1722 return self.get_reduced_chisq() 1723 if column == 'reduced_bank_chisq': 1724 return self.get_reduced_bank_chisq() 1725 if column == 'reduced_cont_chisq': 1726 return self.get_reduced_cont_chisq() 1727 if column == 'snr_over_chi': 1728 return self.get_snr_over_chi() 1729 if column == 'effective_snr': 1730 return self.get_effective_snr(fac=fac) 1731 if column == 'new_snr': 1732 return self.get_new_snr(index=index) 1733 if column == 'lvS5stat': 1734 return self.get_lvS5stat() 1735 elif column == 'chirp_eff_distance': 1736 return self.get_chirp_eff_dist() 1737 else: 1738 return self.getColumnByName(column).asarray()
1739
1740 - def get_end(self):
1741 return [row.get_end() for row in self]
1742
1743 - def get_reduced_chisq(self):
1744 return self.get_column('chisq') / (2*self.get_column('chisq_dof') - 2)
1745
1746 - def get_reduced_bank_chisq(self):
1747 return self.get_column('bank_chisq') / self.get_column('bank_chisq_dof')
1748
1749 - def get_reduced_cont_chisq(self):
1750 return self.get_column('cont_chisq') / self.get_column('cont_chisq_dof')
1751
1752 - def get_effective_snr(self, fac=250.0):
1753 snr = self.get_column('snr') 1754 rchisq = self.get_column('reduced_chisq') 1755 return snr/ (1 + snr**2/fac)**(0.25) / rchisq**(0.25)
1756
1757 - def get_bank_effective_snr(self, fac=250.0):
1758 snr = self.get_column('snr') 1759 rchisq = self.get_column('reduced_bank_chisq') 1760 return snr/ (1 + snr**2/fac)**(0.25) / rchisq**(0.25)
1761
1762 - def get_cont_effective_snr(self, fac=250.0):
1763 snr = self.get_column('snr') 1764 rchisq = self.get_column('reduced_cont_chisq') 1765 return snr/ (1 + snr**2/fac)**(0.25) / rchisq**(0.25)
1766
1767 - def get_new_snr(self, index=6.0):
1768 # kwarg 'index' is assigned to the parameter chisq_index 1769 # nhigh gives the asymptotic large rho behaviour of d (ln chisq) / d (ln rho) 1770 # for fixed new_snr eg nhigh = 2 -> chisq ~ rho^2 at large rho 1771 snr = self.get_column('snr') 1772 rchisq = self.get_column('reduced_chisq') 1773 nhigh = 2. 1774 newsnr = snr/ (0.5*(1+rchisq**(index/nhigh)))**(1./index) 1775 numpy.putmask(newsnr, rchisq < 1, snr) 1776 return newsnr
1777
1778 - def get_bank_new_snr(self, index=6.0):
1779 snr = self.get_column('snr') 1780 rchisq = self.get_column('reduced_bank_chisq') 1781 nhigh = 2. 1782 banknewsnr = snr/ (0.5*(1+rchisq**(index/nhigh)))**(1./index) 1783 numpy.putmask(banknewsnr, rchisq < 1, snr) 1784 return banknewsnr
1785
1786 - def get_cont_new_snr(self, index=6.0):
1787 snr = self.get_column('snr') 1788 rchisq = self.get_column('reduced_cont_chisq') 1789 nhigh = 2. 1790 contnewsnr = snr/ (0.5*(1+rchisq**(index/nhigh)))**(1./index) 1791 numpy.putmask(contnewsnr, rchisq < 1, snr) 1792 return contnewsnr
1793
1794 - def get_chirp_eff_dist(self, ref_mass=1.4):
1795 mchirp = self.get_column('mchirp') 1796 eff_dist = self.get_column('eff_distance') 1797 return SnglInspiral.chirp_distance(eff_dist, mchirp, ref_mass)
1798
1799 - def get_snr_over_chi(self):
1800 return self.get_column('snr')/self.get_column('chisq')**(1./2)
1801
1802 - def get_lvS5stat(self):
1803 return self.get_column('beta')
1804
1805 - def ifocut(self, ifo, inplace=False):
1806 """ 1807 Return a SnglInspiralTable with rows from self having IFO equal 1808 to the given ifo. If inplace, modify self directly, else create 1809 a new table and fill it. 1810 """ 1811 if inplace: 1812 iterutils.inplace_filter(lambda row: row.ifo == ifo, self) 1813 return self 1814 else: 1815 ifoTrigs = self.copy() 1816 ifoTrigs.extend([row for row in self if row.ifo == ifo]) 1817 return ifoTrigs
1818
1819 - def veto(self,seglist):
1820 vetoed = self.copy() 1821 keep = self.copy() 1822 for row in self: 1823 time = row.get_end() 1824 if time in seglist: 1825 vetoed.append(row) 1826 else: 1827 keep.append(row) 1828 return keep
1829
1830 - def vetoed(self, seglist):
1831 """ 1832 Return the inverse of what veto returns, i.e., return the triggers 1833 that lie within a given seglist. 1834 """ 1835 vetoed = self.copy() 1836 keep = self.copy() 1837 for row in self: 1838 time = row.get_end() 1839 if time in seglist: 1840 vetoed.append(row) 1841 else: 1842 keep.append(row) 1843 return vetoed
1844
1845 - def veto_seglistdict(self, seglistdict):
1846 vetoed = self.copy() 1847 keep = self.copy() 1848 for row in self: 1849 time = row.get_end() 1850 if time in seglistdict[row.ifo]: 1851 vetoed.append(row) 1852 else: 1853 keep.append(row) 1854 return keep
1855
1856 - def vetoed_seglistdict(self, seglistdict):
1857 vetoed = self.copy() 1858 keep = self.copy() 1859 for row in self: 1860 time = row.get_end() 1861 if time in seglistdict[row.ifo]: 1862 vetoed.append(row) 1863 else: 1864 keep.append(row) 1865 return vetoed
1866
1867 - def getslide(self,slide_num):
1868 """ 1869 Return the triggers with a specific slide number. 1870 @param slide_num: the slide number to recover (contained in the event_id) 1871 """ 1872 slideTrigs = self.copy() 1873 slideTrigs.extend(row for row in self if row.get_slide_number() == slide_num) 1874 return slideTrigs
1875
1876 1877 -class SnglInspiral(table.Table.RowType):
1878 __slots__ = tuple(SnglInspiralTable.validcolumns.keys()) 1879 1880 @staticmethod
1881 - def chirp_distance(dist, mchirp, ref_mass=1.4):
1882 return dist * (2.**(-1./5) * ref_mass / mchirp)**(5./6)
1883 1884 # 1885 # Properties 1886 # 1887 1888 end = gpsproperty("end_time", "end_time_ns") 1889 1890 @property
1891 - def spin1(self):
1892 if self.spin1x is None and self.spin1y is None and self.spin1z is None: 1893 return None 1894 return numpy.array((self.spin1x, self.spin1y, self.spin1z), dtype = "double")
1895 1896 @spin1.setter
1897 - def spin1(self, spin):
1898 if spin is None: 1899 self.spin1x, self.spin1y, self.spin1z = None, None, None 1900 else: 1901 self.spin1x, self.spin1y, self.spin1z = spin
1902 1903 @property
1904 - def spin2(self):
1905 if self.spin2x is None and self.spin2y is None and self.spin2z is None: 1906 return None 1907 return numpy.array((self.spin2x, self.spin2y, self.spin2z), dtype = "double")
1908 1909 @spin2.setter
1910 - def spin2(self, spin):
1911 if spin is None: 1912 self.spin2x, self.spin2y, self.spin2z = None, None, None 1913 else: 1914 self.spin2x, self.spin2y, self.spin2z = spin
1915 1916 # 1917 # Methods 1918 # 1919
1920 - def get_reduced_chisq(self):
1921 return float(self.chisq)/ (2*self.chisq_dof - 2)
1922
1923 - def get_reduced_bank_chisq(self):
1924 return float(self.bank_chisq)/ self.bank_chisq_dof
1925
1926 - def get_reduced_cont_chisq(self):
1927 return float(self.cont_chisq)/ self.cont_chisq_dof
1928
1929 - def get_effective_snr(self,fac=250.0):
1930 return self.snr/ (1 + self.snr**2/fac)**(0.25)/ self.get_reduced_chisq()**0.25
1931
1932 - def get_bank_effective_snr(self,fac=250.0):
1933 return self.snr/ (1 + self.snr**2/fac)**(0.25)/ self.get_reduced_bank_chisq()**0.25
1934
1935 - def get_cont_effective_snr(self,fac=250.0):
1936 return self.snr/ (1 + self.snr**2/fac)**(0.25)/ self.get_reduced_cont_chisq()**0.25
1937
1938 - def get_new_snr(self,index=6.0):
1939 rchisq = self.get_reduced_chisq() 1940 nhigh = 2. 1941 if rchisq > 1.: 1942 return self.snr/ ((1+rchisq**(index/nhigh))/2)**(1./index) 1943 else: 1944 return self.snr
1945
1946 - def get_bank_new_snr(self,index=6.0):
1947 rchisq = self.get_reduced_bank_chisq() 1948 nhigh = 2. 1949 if rchisq > 1.: 1950 return self.snr/ ((1+rchisq**(index/nhigh))/2)**(1./index) 1951 else: 1952 return self.snr
1953
1954 - def get_cont_new_snr(self,index=6.0):
1955 rchisq = self.get_reduced_cont_chisq() 1956 nhigh = 2. 1957 if rchisq > 1.: 1958 return self.snr/ ((1+rchisq**(index/nhigh))/2)**(1./index) 1959 else: 1960 return self.snr
1961
1962 - def get_far(self):
1963 return self.alpha
1964
1965 - def get_ifar(self):
1966 if self.alpha < 0.000000001: 1967 self.alpha = 0.000000001 1968 return 1./self.alpha
1969
1970 - def get_lvS5stat(self):
1971 return self.beta
1972 1973 # FIXME: how are two inspiral events defined to be the same?
1974 - def __eq__(self, other):
1975 return not ( 1976 cmp(self.ifo, other.ifo) or 1977 cmp(self.end, other.end) or 1978 cmp(self.mass1, other.mass1) or 1979 cmp(self.mass2, other.mass2) or 1980 cmp(self.spin1, other.spin1) or 1981 cmp(self.spin2, other.spin2) or 1982 cmp(self.search, other.search) 1983 )
1984 1985 # 1986 # Legacy 1987 # 1988
1989 - def get_end(self):
1990 return self.end
1991
1992 - def set_end(self, gps):
1993 self.end = gps
1994 1995 1996 SnglInspiralTable.RowType = SnglInspiral
1997 1998 1999 # 2000 # ============================================================================= 2001 # 2002 # coinc_inspiral:table 2003 # 2004 # ============================================================================= 2005 # 2006 2007 2008 -class CoincInspiralTable(table.Table):
2009 tableName = "coinc_inspiral" 2010 validcolumns = { 2011 "coinc_event_id": "ilwd:char", 2012 "ifos": "lstring", 2013 "end_time": "int_4s", 2014 "end_time_ns": "int_4s", 2015 "mass": "real_8", 2016 "mchirp": "real_8", 2017 "minimum_duration": "real_8", 2018 "snr": "real_8", 2019 "false_alarm_rate": "real_8", 2020 "combined_far": "real_8" 2021 } 2022 # FIXME: like some other tables here, this table should have the 2023 # constraint that the coinc_event_id column is a primary key. this 2024 # breaks ID reassignment in ligolw_sqlite, so until that is fixed 2025 # the constraint is being replaced with an index. 2026 #constraints = "PRIMARY KEY (coinc_event_id)" 2027 how_to_index = { 2028 "ci_cei_index": ("coinc_event_id",) 2029 } 2030 interncolumns = ("coinc_event_id", "ifos")
2031
2032 2033 -class CoincInspiral(table.Table.RowType):
2034 """ 2035 Example: 2036 2037 >>> x = CoincInspiral() 2038 >>> x.instruments = (u"H1", u"L1") 2039 >>> x.ifos 2040 u'H1,L1' 2041 >>> x.instruments 2042 set([u'H1', u'L1']) 2043 >>> x.end = LIGOTimeGPS(10) 2044 >>> x.end 2045 LIGOTimeGPS(10, 0) 2046 >>> x.end = None 2047 >>> print(x.end) 2048 None 2049 """ 2050 __slots__ = tuple(CoincInspiralTable.validcolumns.keys()) 2051 2052 instruments = instrumentsproperty("ifos") 2053 2054 end = gpsproperty("end_time", "end_time_ns") 2055
2056 - def get_end(self):
2057 return self.end
2058
2059 - def set_end(self, gps):
2060 self.end = gps
2061
2062 - def get_ifos(self):
2063 return self.instruments
2064
2065 - def set_ifos(self, ifos):
2066 self.instruments = ifos
2067 2068 2069 CoincInspiralTable.RowType = CoincInspiral 2070 2071 2072 # 2073 # ============================================================================= 2074 # 2075 # sngl_ringdown:table 2076 # 2077 # ============================================================================= 2078 # 2079 2080 2081 SnglRingdownID = ilwd.get_ilwdchar_class(u"sngl_ringdown", u"event_id")
2082 2083 2084 -class SnglRingdownTable(table.Table):
2085 tableName = "sngl_ringdown" 2086 validcolumns = { 2087 "process_id": "ilwd:char", 2088 "ifo": "lstring", 2089 "channel": "lstring", 2090 "start_time": "int_4s", 2091 "start_time_ns": "int_4s", 2092 "start_time_gmst": "real_8", 2093 "frequency": "real_4", 2094 "quality": "real_4", 2095 "phase": "real_4", 2096 "mass": "real_4", 2097 "spin": "real_4", 2098 "epsilon": "real_4", 2099 "num_clust_trigs": "int_4s", 2100 "ds2_H1H2": "real_4", 2101 "ds2_H1L1": "real_4", 2102 "ds2_H1V1": "real_4", 2103 "ds2_H2L1": "real_4", 2104 "ds2_H2V1": "real_4", 2105 "ds2_L1V1": "real_4", 2106 "amplitude": "real_4", 2107 "snr": "real_4", 2108 "eff_dist": "real_4", 2109 "sigma_sq": "real_8", 2110 "event_id": "ilwd:char" 2111 } 2112 constraints = "PRIMARY KEY (event_id)" 2113 next_id = SnglRingdownID(0) 2114 interncolumns = ("process_id", "ifo", "channel") 2115
2116 - def get_start(self):
2117 return [row.get_start() for row in self]
2118
2119 2120 -class SnglRingdown(table.Table.RowType):
2121 __slots__ = tuple(SnglRingdownTable.validcolumns.keys()) 2122
2123 - def get_start(self):
2124 return LIGOTimeGPS(self.start_time, self.start_time_ns)
2125
2126 - def set_start(self, gps):
2127 self.start_time, self.start_time_ns = gps.seconds, gps.nanoseconds
2128
2129 - def get_id_parts(self):
2130 """ 2131 Return the three pieces of the int_8s-style event_id. 2132 """ 2133 int_event_id = int(self.event_id) 2134 a = int_event_id // 1000000000 2135 slidenum = (int_event_id % 1000000000) // 100000 2136 b = int_event_id % 100000 2137 return int(a), int(slidenum), int(b)
2138 2139 2140 SnglRingdownTable.RowType = SnglRingdown
2141 2142 2143 # 2144 # ============================================================================= 2145 # 2146 # coinc_ringdown:table 2147 # 2148 # ============================================================================= 2149 # 2150 2151 2152 -class CoincRingdownTable(table.Table):
2153 tableName = "coinc_ringdown" 2154 validcolumns = { 2155 "coinc_event_id": "ilwd:char", 2156 "ifos": "lstring", 2157 "start_time": "int_4s", 2158 "start_time_ns": "int_4s", 2159 "frequency": "real_8", 2160 "quality": "real_8", 2161 "mass": "real_8", 2162 "spin": "real_8", 2163 "snr": "real_8", 2164 "choppedl_snr": "real_8", 2165 "snr_sq": "real_8", 2166 "eff_coh_snr": "real_8", 2167 "null_stat": "real_8", 2168 "kappa": "real_8", 2169 "snr_ratio": "real_8", 2170 "false_alarm_rate": "real_8", 2171 "combined_far": "real_8" 2172 } 2173 # constraints = "PRIMARY KEY (coinc_event_id)" 2174 how_to_index = { 2175 "cr_cei_index": ("coinc_event_id",) 2176 } 2177 interncolumns = ("coinc_event_id", "ifos")
2178
2179 2180 -class CoincRingdown(table.Table.RowType):
2181 __slots__ = tuple(CoincRingdownTable.validcolumns.keys()) 2182
2183 - def get_start(self):
2184 return LIGOTimeGPS(self.start_time, self.start_time_ns)
2185
2186 - def set_start(self, gps):
2187 self.start_time, self.start_time_ns = gps.seconds, gps.nanoseconds
2188
2189 - def set_ifos(self, ifos):
2191
2192 - def get_ifos(self):
2193 return instrument_set_from_ifos(self.ifos)
2194 2195 2196 CoincRingdownTable.RowType = CoincRingdown 2197 2198 2199 # 2200 # ============================================================================= 2201 # 2202 # multi_inspiral:table 2203 # 2204 # ============================================================================= 2205 # 2206 2207 2208 MultiInspiralID = ilwd.get_ilwdchar_class(u"multi_inspiral", u"event_id")
2209 2210 2211 -class MultiInspiralTable(table.Table):
2212 tableName = "multi_inspiral" 2213 validcolumns = { 2214 "process_id": "ilwd:char", 2215 "ifos": "lstring", 2216 "search": "lstring", 2217 "end_time": "int_4s", 2218 "end_time_ns": "int_4s", 2219 "end_time_gmst": "real_8", 2220 "impulse_time": "int_4s", 2221 "impulse_time_ns": "int_4s", 2222 "amplitude": "real_4", 2223 "distance": "real_4", 2224 "eff_dist_h1": "real_4", 2225 "eff_dist_h2": "real_4", 2226 "eff_dist_l": "real_4", 2227 "eff_dist_g": "real_4", 2228 "eff_dist_t": "real_4", 2229 "eff_dist_v": "real_4", 2230 "eff_dist_h1h2": "real_4", 2231 "coa_phase": "real_4", 2232 "mass1": "real_4", 2233 "mass2": "real_4", 2234 "mchirp": "real_4", 2235 "eta": "real_4", 2236 "chi": "real_4", 2237 "kappa": "real_4", 2238 "tau0": "real_4", 2239 "tau2": "real_4", 2240 "tau3": "real_4", 2241 "tau4": "real_4", 2242 "tau5": "real_4", 2243 "ttotal": "real_4", 2244 "snr": "real_4", 2245 "snr_dof": "int_4s", 2246 "chisq": "real_4", 2247 "chisq_dof": "int_4s", 2248 "bank_chisq": "real_4", 2249 "bank_chisq_dof": "int_4s", 2250 "cont_chisq": "real_4", 2251 "cont_chisq_dof": "int_4s", 2252 "trace_snr": "real_4", 2253 "snr_h1": "real_4", 2254 "snr_h2": "real_4",