def snr_series_to_xml(snr_series, document, sngl_inspiral_id): """Save an SNR time series into an XML document, in a format compatible with BAYESTAR. """ snr_lal = snr_series.lal() snr_lal.name = 'snr' snr_lal.sampleUnits = '' snr_xml = _build_series(snr_lal, ('Time', 'Time,Real,Imaginary'), None, 'deltaT', 's') snr_node = document.childNodes[-1].appendChild(snr_xml) eid_param = LIGOLWParam.from_pyvalue('event_id', sngl_inspiral_id) snr_node.appendChild(eid_param)
def make_psd_xmldoc(psddict, xmldoc=None): """Add a set of PSDs to a LIGOLW XML document. If the document is not given, a new one is created first. """ xmldoc = ligolw.Document() if xmldoc is None else xmldoc.childNodes[0] # the PSDs must be children of a LIGO_LW with name "psd" root_name = 'psd' Attributes = ligolw.sax.xmlreader.AttributesImpl lw = xmldoc.appendChild(ligolw.LIGO_LW(Attributes({'Name': root_name}))) for instrument, psd in psddict.items(): xmlseries = _build_series(psd, ('Frequency,Real', 'Frequency'), None, 'deltaF', 's^-1') fs = lw.appendChild(xmlseries) fs.appendChild(LIGOLWParam.from_pyvalue('instrument', instrument)) return xmldoc
def _build_series(series, dim_names, comment, delta_name, delta_unit): Attributes = ligolw.sax.xmlreader.AttributesImpl elem = ligolw.LIGO_LW(Attributes({'Name': str(series.__class__.__name__)})) if comment is not None: elem.appendChild(ligolw.Comment()).pcdata = comment elem.appendChild(ligolw.Time.from_gps(series.epoch, 'epoch')) elem.appendChild(LIGOLWParam.from_pyvalue('f0', series.f0, unit='s^-1')) delta = getattr(series, delta_name) if numpy.iscomplexobj(series.data.data): data = numpy.row_stack((numpy.arange(len(series.data.data)) * delta, series.data.data.real, series.data.data.imag)) else: data = numpy.row_stack( (numpy.arange(len(series.data.data)) * delta, series.data.data)) a = LIGOLWArray.build(series.name, data, dim_names=dim_names) a.Unit = str(series.sampleUnits) dim0 = a.getElementsByTagName(ligolw.Dim.tagName)[0] dim0.Unit = delta_unit dim0.Start = series.f0 dim0.Scale = delta elem.appendChild(a) return elem
def do_it_to(xmldoc): """ NOTE: this performs an in-place transcription of the contents of the XML document tree. This should be assumed to be a destructive operation on the contents of the tree. If you wish to hold references to any of the Table elements or other structures in the tree and wish them to remain intact so they can be used afterwards, make copies first """ # # walk the tree finding Table elements # for table in list(xmldoc.getElementsByTagName(ligolw.Table.tagName)): # # this is not the table we're looking for # if table.Name not in ilwdchar_tables: continue # # make a copy of the table with glue.ligolw's lsctables and # replace the old table with the new table in the XML tree # newtable = table.parentNode.replaceChild( lsctables.New(lsctables.TableByName[table.Name], table.columnnames), table) # # build a row transcription function for this table # if table.Name != "coinc_event_map": ilwdclsmap = ilwdchar_tables[table.Name] newrowtype = newtable.RowType def newrow(row, nonilwdcharattrs=tuple(colname for colname in table.columnnames if colname not in ilwdclsmap), ilwdcharattrs=tuple(colname for colname in table.columnnames if colname in ilwdclsmap)): kwargs = dict( (attr, getattr(row, attr)) for attr in nonilwdcharattrs) kwargs.update((attr, ilwdclsmap[attr](getattr(row, attr))) for attr in ilwdcharattrs) return newrowtype(**kwargs) else: # event_id IDs obtain their table name prefix from # the table_name column newrowtype = newtable.RowType def newrow(row, coinc_id_ilwdcls=ilwdchar_tables["coinc_event"] ["coinc_event_id"]): # FIXME this is probably a dumb way to do this, # but it shouldn't matter once we have no # reason to convert back to ilwdchar if "event_id" in ilwdchar_tables[row.table_name]: event_id = ilwdchar_tables[row.table_name]["event_id"]( row.event_id) elif "simulation_id" in ilwdchar_tables[row.table_name]: event_id = ilwdchar_tables[ row.table_name]["simulation_id"](row.event_id) elif "coinc_event_id" in ilwdchar_tables[row.table_name]: event_id = ilwdchar_tables[ row.table_name]["coinc_event_id"](row.event_id) else: raise KeyError( "event_id, simulation_id or coinc_event_id not in " + ilwdchar_tables[row.table_name]) return newrowtype(table_name=row.table_name, event_id=event_id, coinc_event_id=coinc_id_ilwdcls( row.coinc_event_id)) # # transcribe rows from the old table into the new table # newtable.extend(newrow(row) for row in table) # # dispose of the old table # table.unlink() # # walk the tree looking for Param elements containing sngl_inspiral # IDs and convert to ilwd:char # ilwdcls = ilwdchar_tables["sngl_inspiral"]["event_id"] for param in list(ligo_lw_Param.getParamsByName(xmldoc, "event_id")): param.Type = u"ilwd:char" param.pcdata = ilwdcls(param.pcdata) # # done # return xmldoc
def main(args=None): p = parser() opts = p.parse_args(args) # LIGO-LW XML imports. from ligo.lw import ligolw from ligo.lw.param import Param from ligo.lw.utils.search_summary import append_search_summary from ligo.lw import utils as ligolw_utils from ligo.lw.lsctables import ( New, CoincDefTable, CoincID, CoincInspiralTable, CoincMapTable, CoincTable, ProcessParamsTable, ProcessTable, SimInspiralTable, SnglInspiralTable, TimeSlideTable) # glue, LAL and pylal imports. from ligo import segments import lal import lal.series import lalsimulation from lalinspiral.inspinjfind import InspiralSCExactCoincDef from lalinspiral.thinca import InspiralCoincDef from tqdm import tqdm # BAYESTAR imports. from ..io.events.ligolw import ContentHandler from ..bayestar import filter from ..util.progress import progress_map # Read PSDs. xmldoc = ligolw_utils.load_fileobj( opts.reference_psd, contenthandler=lal.series.PSDContentHandler) psds = lal.series.read_psd_xmldoc(xmldoc, root_name=None) psds = { key: filter.InterpolatedPSD(filter.abscissa(psd), psd.data.data) for key, psd in psds.items() if psd is not None} psds = [psds[ifo] for ifo in opts.detector] # Extract simulation table from injection file. inj_xmldoc = ligolw_utils.load_fileobj( opts.input, contenthandler=ContentHandler) orig_sim_inspiral_table = SimInspiralTable.get_table(inj_xmldoc) # Prune injections that are outside distance limits. orig_sim_inspiral_table[:] = [ row for row in orig_sim_inspiral_table if opts.min_distance <= row.distance <= opts.max_distance] # Open output file. xmldoc = ligolw.Document() xmlroot = xmldoc.appendChild(ligolw.LIGO_LW()) # Create tables. Process and ProcessParams tables are copied from the # injection file. coinc_def_table = xmlroot.appendChild(New(CoincDefTable)) coinc_inspiral_table = xmlroot.appendChild(New(CoincInspiralTable)) coinc_map_table = xmlroot.appendChild(New(CoincMapTable)) coinc_table = xmlroot.appendChild(New(CoincTable)) xmlroot.appendChild(ProcessParamsTable.get_table(inj_xmldoc)) xmlroot.appendChild(ProcessTable.get_table(inj_xmldoc)) sim_inspiral_table = xmlroot.appendChild(New(SimInspiralTable)) sngl_inspiral_table = xmlroot.appendChild(New(SnglInspiralTable)) time_slide_table = xmlroot.appendChild(New(TimeSlideTable)) # Write process metadata to output file. process = register_to_xmldoc( xmldoc, p, opts, instruments=opts.detector, comment="Simulated coincidences") # Add search summary to output file. all_time = segments.segment([lal.LIGOTimeGPS(0), lal.LIGOTimeGPS(2e9)]) append_search_summary(xmldoc, process, inseg=all_time, outseg=all_time) # Create a time slide entry. Needed for coinc_event rows. time_slide_id = time_slide_table.get_time_slide_id( {ifo: 0 for ifo in opts.detector}, create_new=process) # Populate CoincDef table. inspiral_coinc_def = copy.copy(InspiralCoincDef) inspiral_coinc_def.coinc_def_id = coinc_def_table.get_next_id() coinc_def_table.append(inspiral_coinc_def) found_coinc_def = copy.copy(InspiralSCExactCoincDef) found_coinc_def.coinc_def_id = coinc_def_table.get_next_id() coinc_def_table.append(found_coinc_def) # Precompute values that are common to all simulations. detectors = [lalsimulation.DetectorPrefixToLALDetector(ifo) for ifo in opts.detector] responses = [det.response for det in detectors] locations = [det.location for det in detectors] if opts.jobs != 1: from .. import omp omp.num_threads = 1 # disable OpenMP parallelism func = functools.partial(simulate, psds=psds, responses=responses, locations=locations, measurement_error=opts.measurement_error, f_low=opts.f_low, f_high=opts.f_high, waveform=opts.waveform) # Make sure that each thread gets a different random number state. # We start by drawing a random integer s in the main thread, and # then the i'th subprocess will seed itself with the integer i + s. # # The seed must be an unsigned 32-bit integer, so if there are n # threads, then s must be drawn from the interval [0, 2**32 - n). # # Note that *we* are thread 0, so there are a total of # n=1+len(sim_inspiral_table) threads. seed = np.random.randint(0, 2 ** 32 - len(sim_inspiral_table) - 1) np.random.seed(seed) with tqdm(desc='accepted') as progress: for sim_inspiral, simulation in zip( orig_sim_inspiral_table, progress_map( func, np.arange(len(orig_sim_inspiral_table)) + seed + 1, orig_sim_inspiral_table, jobs=opts.jobs)): sngl_inspirals = [] used_snr_series = [] net_snr = 0.0 count_triggers = 0 # Loop over individual detectors and create SnglInspiral entries. for ifo, (horizon, abs_snr, arg_snr, toa, series) \ in zip(opts.detector, simulation): if np.random.uniform() > opts.duty_cycle: continue elif abs_snr >= opts.snr_threshold: # If SNR < threshold, then the injection is not found. # Skip it. count_triggers += 1 net_snr += np.square(abs_snr) elif not opts.keep_subthreshold: continue # Create SnglInspiral entry. used_snr_series.append(series) sngl_inspirals.append( sngl_inspiral_table.RowType(**dict( dict.fromkeys(sngl_inspiral_table.validcolumns, None), process_id=process.process_id, ifo=ifo, mass1=sim_inspiral.mass1, mass2=sim_inspiral.mass2, spin1x=sim_inspiral.spin1x, spin1y=sim_inspiral.spin1y, spin1z=sim_inspiral.spin1z, spin2x=sim_inspiral.spin2x, spin2y=sim_inspiral.spin2y, spin2z=sim_inspiral.spin2z, end=toa, snr=abs_snr, coa_phase=arg_snr, f_final=opts.f_high, eff_distance=horizon / abs_snr))) net_snr = np.sqrt(net_snr) # If too few triggers were found, then skip this event. if count_triggers < opts.min_triggers: continue # If network SNR < threshold, then the injection is not found. # Skip it. if net_snr < opts.net_snr_threshold: continue # Add Coinc table entry. coinc = coinc_table.appendRow( coinc_event_id=coinc_table.get_next_id(), process_id=process.process_id, coinc_def_id=inspiral_coinc_def.coinc_def_id, time_slide_id=time_slide_id, insts=opts.detector, nevents=len(opts.detector), likelihood=None) # Add CoincInspiral table entry. coinc_inspiral_table.appendRow( coinc_event_id=coinc.coinc_event_id, instruments=[ sngl_inspiral.ifo for sngl_inspiral in sngl_inspirals], end=lal.LIGOTimeGPS(1e-9 * np.mean([ sngl_inspiral.end.ns() for sngl_inspiral in sngl_inspirals if sngl_inspiral.end is not None])), mass=sim_inspiral.mass1 + sim_inspiral.mass2, mchirp=sim_inspiral.mchirp, combined_far=0.0, # Not provided false_alarm_rate=0.0, # Not provided minimum_duration=None, # Not provided snr=net_snr) # Record all sngl_inspiral records and associate them with coincs. for sngl_inspiral, series in zip(sngl_inspirals, used_snr_series): # Give this sngl_inspiral record an id and add it to the table. sngl_inspiral.event_id = sngl_inspiral_table.get_next_id() sngl_inspiral_table.append(sngl_inspiral) if opts.enable_snr_series: elem = lal.series.build_COMPLEX8TimeSeries(series) elem.appendChild( Param.from_pyvalue('event_id', sngl_inspiral.event_id)) xmlroot.appendChild(elem) # Add CoincMap entry. coinc_map_table.appendRow( coinc_event_id=coinc.coinc_event_id, table_name=sngl_inspiral_table.tableName, event_id=sngl_inspiral.event_id) # Record injection if not opts.preserve_ids: sim_inspiral.simulation_id = sim_inspiral_table.get_next_id() sim_inspiral_table.append(sim_inspiral) progress.update() # Record coincidence associating injections with events. for i, sim_inspiral in enumerate(sim_inspiral_table): coinc = coinc_table.appendRow( coinc_event_id=coinc_table.get_next_id(), process_id=process.process_id, coinc_def_id=found_coinc_def.coinc_def_id, time_slide_id=time_slide_id, instruments=None, nevents=None, likelihood=None) coinc_map_table.appendRow( coinc_event_id=coinc.coinc_event_id, table_name=sim_inspiral_table.tableName, event_id=sim_inspiral.simulation_id) coinc_map_table.appendRow( coinc_event_id=coinc.coinc_event_id, table_name=coinc_table.tableName, event_id=CoincID(i)) # Record process end time. process.set_end_time_now() # Write output file. write_fileobj(xmldoc, opts.output)