def generate_template(mass1, mass2, S, f_low, sample_rate, template_duration, approximant, amplitude_order, phase_order): template_length = sample_rate * template_duration if approximant == lalsimulation.TaylorF2: zf, _ = lalsimulation.SimInspiralChooseFDWaveform( 0, 1 / template_duration, mass1 * lal.LAL_MSUN_SI, mass2 * lal.LAL_MSUN_SI, 0, 0, 0, 0, 0, 0, f_low, 0, 1e6 * lal.LAL_PC_SI, 0, 0, 0, None, None, amplitude_order, phase_order, approximant) lal.ResizeCOMPLEX16FrequencySeries(zf, 0, template_length // 2 + 1) # Generate over-whitened template psd = lal.CreateREAL8FrequencySeries(None, zf.epoch, zf.f0, zf.deltaF, lal.lalDimensionlessUnit, len(zf.data.data)) psd.data.data = S(abscissa(psd)) zW = matched_filter_spa(zf, psd) elif approximant == lalsimulation.TaylorT4: hplus, hcross = lalsimulation.SimInspiralChooseTDWaveform( 0, 1 / sample_rate, mass1 * lal.LAL_MSUN_SI, mass2 * lal.LAL_MSUN_SI, 0, 0, 0, 0, 0, 0, f_low, f_low, 1e6 * lal.LAL_PC_SI, 0, 0, 0, None, None, amplitude_order, phase_order, approximant) ht = lal.CreateREAL8TimeSeries(None, lal.LIGOTimeGPS(-template_duration), hplus.f0, hplus.deltaT, hplus.sampleUnits, template_length) hf = lal.CreateCOMPLEX16FrequencySeries(None, lal.LIGOTimeGPS(0), 0, 0, lal.lalDimensionlessUnit, template_length // 2 + 1) plan = CreateForwardREAL8FFTPlan(template_length, 0) ht.data.data[:-len(hplus.data.data)] = 0 ht.data.data[-len(hplus.data.data):] = hplus.data.data lal.REAL8TimeFreqFFT(hf, ht, plan) psd = lal.CreateREAL8FrequencySeries(None, hf.epoch, hf.f0, hf.deltaF, lal.lalDimensionlessUnit, len(hf.data.data)) psd.data.data = S(abscissa(psd)) zWreal = matched_filter_real(hf, psd) ht.data.data[:-len(hcross.data.data)] = 0 ht.data.data[-len(hcross.data.data):] = hcross.data.data lal.REAL8TimeFreqFFT(hf, ht, plan) zWimag = matched_filter_real(hf, psd) zW = lal.CreateCOMPLEX16TimeSeries(None, zWreal.epoch, zWreal.f0, zWreal.deltaT, zWreal.sampleUnits, len(zWreal.data.data)) zW.data.data = zWreal.data.data + zWimag.data.data * 1j else: raise ValueError("unrecognized approximant") return zW.data.data[::-1].conj() * np.sqrt( 2) * template_duration / sample_rate / 2
def lal(self): """ Returns a LAL Object that contains this data """ lal_data = None if type(self._data) is not _numpy.ndarray: raise TypeError("Cannot return lal type from the GPU") elif self._data.dtype == _numpy.float32: lal_data = _lal.CreateREAL4FrequencySeries("", self._epoch, 0, self.delta_f, _lal.lalSecondUnit, len(self)) elif self._data.dtype == _numpy.float64: lal_data = _lal.CreateREAL8FrequencySeries("", self._epoch, 0, self.delta_f, _lal.lalSecondUnit, len(self)) elif self._data.dtype == _numpy.complex64: lal_data = _lal.CreateCOMPLEX8FrequencySeries( "", self._epoch, 0, self.delta_f, _lal.lalSecondUnit, len(self)) elif self._data.dtype == _numpy.complex128: lal_data = _lal.CreateCOMPLEX16FrequencySeries( "", self._epoch, 0, self.delta_f, _lal.lalSecondUnit, len(self)) lal_data.data.data[:] = self._data return lal_data
def lal(self): """Produces a LAL frequency series object equivalent to self. Returns ------- lal_data : {lal.*FrequencySeries} LAL frequency series object containing the same data as self. The actual type depends on the sample's dtype. If the epoch of self was 'None', the epoch of the returned LAL object will be LIGOTimeGPS(0,0); otherwise, the same as that of self. Raises ------ TypeError If frequency series is stored in GPU memory. """ lal_data = None if self._epoch is None: ep = _lal.LIGOTimeGPS(0,0) else: ep = self._epoch if self._data.dtype == _numpy.float32: lal_data = _lal.CreateREAL4FrequencySeries("",ep,0,self.delta_f,_lal.SecondUnit,len(self)) elif self._data.dtype == _numpy.float64: lal_data = _lal.CreateREAL8FrequencySeries("",ep,0,self.delta_f,_lal.SecondUnit,len(self)) elif self._data.dtype == _numpy.complex64: lal_data = _lal.CreateCOMPLEX8FrequencySeries("",ep,0,self.delta_f,_lal.SecondUnit,len(self)) elif self._data.dtype == _numpy.complex128: lal_data = _lal.CreateCOMPLEX16FrequencySeries("",ep,0,self.delta_f,_lal.SecondUnit,len(self)) lal_data.data.data[:] = self.numpy() return lal_data
def gen_psd(fs,T_obs,op='AdvDesign',det='H1'): """ generates noise for a variety of different detectors """ N = T_obs * fs # the total number of time samples dt = 1 / fs # the sampling time (sec) df = 1 / T_obs # the frequency resolution psd = lal.CreateREAL8FrequencySeries(None, lal.LIGOTimeGPS(0), 0.0, df,lal.HertzUnit, N // 2 + 1) if det=='H1' or det=='L1': if op == 'AdvDesign': lalsimulation.SimNoisePSDAdVDesignSensitivityP1200087(psd, 10.0) elif op == 'AdvEarlyLow': lalsimulation.SimNoisePSDAdVEarlyLowSensitivityP1200087(psd, 10.0) elif op == 'AdvEarlyHigh': lalsimulation.SimNoisePSDAdVEarlyHighSensitivityP1200087(psd, 10.0) elif op == 'AdvMidLow': lalsimulation.SimNoisePSDAdVMidLowSensitivityP1200087(psd, 10.0) elif op == 'AdvMidHigh': lalsimulation.SimNoisePSDAdVMidHighSensitivityP1200087(psd, 10.0) elif op == 'AdvLateLow': lalsimulation.SimNoisePSDAdVLateLowSensitivityP1200087(psd, 10.0) elif op == 'AdvLateHigh': lalsimulation.SimNoisePSDAdVLateHighSensitivityP1200087(psd, 10.0) else: print 'unknown noise option' exit(1) else: print 'unknown detector - will add Virgo soon' exit(1) return psd
def optimal_snr(m1_intrinsic, m2_intrinsic, chi1, chi2, z, psd_fn=ls.SimNoisePSDaLIGOEarlyHighSensitivityP1200087): """Return the optimal SNR of a signal. :param m1_intrinsic: The source-frame mass 1. :param m2_intrinsic: The source-frame mass 2. :param chi1: The aligned spin component for mass 1. :param chi2: The aligned spin component for mass 2. :param z: The redshift. :param psd_fn: A function that returns the detector PSD at a given frequency (default is early aLIGO high sensitivity, defined in [P1200087](https://dcc.ligo.org/LIGO-P1200087/public). :return: The SNR of a face-on, overhead source. """ # Get dL, Gpc dL = cosmo.Planck15.luminosity_distance(z).to(u.Gpc).value # Basic setup: min frequency for w.f., PSD start freq, etc. fmin = 19.0 fref = 40.0 psdstart = 20.0 # This is a conservative estimate of the chirp time + MR time (2 seconds) tmax = ls.SimInspiralChirpTimeBound(fmin, m1_intrinsic * (1 + z) * lal.MSUN_SI, m2_intrinsic * (1 + z) * lal.MSUN_SI, abs(chi1), abs(chi2)) + 2 df = 1.0 / next_pow_two(tmax) fmax = 2048.0 # Hz --- based on max freq of 5-5 inspiral # Generate the waveform, redshifted as we would see it in the detector, but with zero angles (i.e. phase = 0, inclination = 0) hp, hc = ls.SimInspiralChooseFDWaveform( (1 + z) * m1_intrinsic * lal.MSUN_SI, (1 + z) * m2_intrinsic * lal.MSUN_SI, 0.0, 0.0, chi1, 0.0, 0.0, chi2, dL * 1e9 * lal.PC_SI, 0.0, 0.0, 0.0, 0.0, 0.0, df, fmin, fmax, fref, None, ls.IMRPhenomPv2) Nf = int(round(fmax / df)) + 1 fs = linspace(0, fmax, Nf) sel = fs > psdstart # PSD sffs = lal.CreateREAL8FrequencySeries("psds", 0, 0.0, df, lal.DimensionlessUnit, fs.shape[0]) psd_fn(sffs, psdstart) return ls.MeasureSNRFD(hp, sffs, psdstart, -1.0)
def generate_psd(S): psd = lal.CreateREAL8FrequencySeries(None, lal.LIGOTimeGPS(0), 0, 1 / data_duration, filter.unitInverseHertz, data_length // 2 + 1) psd.data.data = S(filter.abscissa(psd)) return psd
def test_get_max_z(): gwcosmo = GWCosmo(default_cosmology.get_cosmology_from_string('Planck15')) f_low = 10 f_high = 4096 df = 0.1 waveform = 'IMRPhenomPv2' snr = 8 m1 = np.asarray([50.0]) m2 = np.asarray([30.0, 50.0]) x1 = np.asarray([-1.0, 0.0, 1.0]) x2 = np.asarray([-1.0, -0.5, 0.5, 1.0]) psd = lal.CreateREAL8FrequencySeries('', 0, f_low, df, lal.DimensionlessUnit, int((f_high - f_low) // df)) lalsimulation.SimNoisePSDaLIGODesignSensitivityP1200087(psd, f_low) result = gwcosmo.get_max_z([psd], waveform, f_low, snr, m1, m2, x1, x2) # Check that shape matches assert result.shape == (1, 2, 3, 4) # Spot check some individual cells for im1, m1_ in enumerate(m1): for im2, m2_ in enumerate(m2): for ix1, x1_ in enumerate(x1): for ix2, x2_ in enumerate(x2): expected = gwcosmo.z_at_snr([psd], waveform, f_low, snr, m1_, m2_, x1_, x2_) assert result[im1, im2, ix1, ix2] == expected
def signal_psd_series(H, S): n = H.data.data.size f = H.f0 + np.arange(1, n) * H.deltaF ret = lal.CreateREAL8FrequencySeries( 'signal PSD / noise PSD', 0, H.f0, H.deltaF, lal.DimensionlessUnit, n) ret.data.data[0] = 0 ret.data.data[1:] = H.data.data[1:] / S(f) return ret
def from_string(psd_name, length, delta_f, low_freq_cutoff): """Generate a frequency series containing a LALSimulation PSD specified by name. Parameters ---------- psd_name : string PSD name as found in LALSimulation, minus the SimNoisePSD prefix. length : int Length of the frequency series in samples. delta_f : float Frequency resolution of the frequency series. low_freq_cutoff : float Frequencies below this value are set to zero. Returns ------- psd : FrequencySeries The generated frequency series. """ # check if valid PSD model if psd_name not in get_psd_model_list(): raise ValueError(psd_name + ' not found among analytical ' 'PSD functions.') # make sure length has the right type for CreateREAL8FrequencySeries if not isinstance(length, numbers.Integral): warnings.warn('forcing length argument to int', RuntimeWarning) length = int(length) # if PSD model is in LALSimulation if psd_name in get_lalsim_psd_list(): lalseries = lal.CreateREAL8FrequencySeries('', lal.LIGOTimeGPS(0), 0, delta_f, lal.DimensionlessUnit, length) try: func = lalsimulation.__dict__[_name_prefix + psd_name + _name_suffix] except KeyError: func = lalsimulation.__dict__[_name_prefix + psd_name] func(lalseries, low_freq_cutoff) else: lalsimulation.SimNoisePSD(lalseries, 0, func) psd = FrequencySeries(lalseries.data.data, delta_f=delta_f) # if PSD model is coded in PyCBC else: func = pycbc_analytical_psds[psd_name] psd = func(length, delta_f, low_freq_cutoff) # zero-out content below low-frequency cutoff kmin = int(low_freq_cutoff / delta_f) psd.data[:kmin] = 0 return psd
def sngl_inspiral_psd(sngl, waveform, f_min=10, f_max=2048, f_ref=0): # FIXME: uberbank mass criterion. Should find a way to get this from # pipeline output metadata. if waveform == 'o1-uberbank': log.warn('Template is unspecified; using ER8/O1 uberbank criterion') if sngl.mass1 + sngl.mass2 < 4: waveform = 'TaylorF2threePointFivePN' else: waveform = 'SEOBNRv2_ROM_DoubleSpin' approx, ampo, phaseo = get_approximant_and_orders_from_string(waveform) log.info('Selected template: %s', waveform) # Generate conditioned template. params = lal.CreateDict() lalsimulation.SimInspiralWaveformParamsInsertPNPhaseOrder(params, phaseo) lalsimulation.SimInspiralWaveformParamsInsertPNAmplitudeOrder(params, ampo) hplus, hcross = lalsimulation.SimInspiralFD( m1=sngl.mass1*lal.MSUN_SI, m2=sngl.mass2*lal.MSUN_SI, S1x=getattr(sngl, 'spin1x', 0) or 0, S1y=getattr(sngl, 'spin1y', 0) or 0, S1z=getattr(sngl, 'spin1z', 0) or 0, S2x=getattr(sngl, 'spin2x', 0) or 0, S2y=getattr(sngl, 'spin2y', 0) or 0, S2z=getattr(sngl, 'spin2z', 0) or 0, distance=1e6*lal.PC_SI, inclination=0, phiRef=0, longAscNodes=0, eccentricity=0, meanPerAno=0, deltaF=0, f_min=f_min, f_max=f_max, f_ref=f_ref, LALparams=params, approximant=approx) # Force `plus' and `cross' waveform to be in quadrature. h = 0.5 * (hplus.data.data + 1j * hcross.data.data) # For inspiral-only waveforms, nullify frequencies beyond ISCO. # FIXME: the waveform generation functions pick the end frequency # automatically. Shouldn't SimInspiralFD? inspiral_only_waveforms = ( lalsimulation.TaylorF2, lalsimulation.SpinTaylorF2, lalsimulation.TaylorF2RedSpin, lalsimulation.TaylorF2RedSpinTidal, lalsimulation.SpinTaylorT4Fourier) if approx in inspiral_only_waveforms: h[abscissa(hplus) >= get_f_lso(sngl.mass1, sngl.mass2)] = 0 # Drop Nyquist frequency. if len(h) % 2: h = h[:-1] # Create output frequency series. psd = lal.CreateREAL8FrequencySeries( 'signal PSD', 0, hplus.f0, hcross.deltaF, hplus.sampleUnits**2, len(h)) psd.data.data = abs2(h) # Done! return psd
def upload(self, fname, psds, low_frequency_cutoff, testing=True): """Upload this trigger to gracedb Parameters ---------- fname: str The name to give the xml file associated with this trigger pds: dict of pybc.types.FrequencySeries A ifo keyed dictionary of psds to be uploaded in association with this trigger. low_frequency_cutoff: float The low frequency cutoff of the psds. testing: bool Switch to determine if the upload should be sent to gracedb as a test trigger (True) or a production trigger (False) """ from ligo.gracedb.rest import GraceDb import lal import lal.series self.save(fname) if testing: group = 'Test' else: group = 'CBC' gracedb = GraceDb() r = gracedb.createEvent(group, "pycbc", fname, "AllSky").json() logging.info("Uploaded event %s.", r["graceid"]) if self.is_hardware_injection: gracedb.writeLabel(r['graceid'], 'INJ') logging.info("Tagging event %s as an injection", r["graceid"]) # Convert our psds to the xml psd format. # FIXME: we should not use lal.series!!! psds_lal = {} for ifo in psds: psd = psds[ifo] kmin = int(low_frequency_cutoff / psd.delta_f) fseries = lal.CreateREAL8FrequencySeries( "psd", psd.epoch, low_frequency_cutoff, psd.delta_f, lal.StrainUnit**2 / lal.HertzUnit, len(psd) - kmin) fseries.data.data = psd.numpy()[kmin:] / pycbc.DYN_RANGE_FAC**2.0 psds_lal[ifo] = fseries psd_xmldoc = lal.series.make_psd_xmldoc(psds_lal) ligolw_utils.write_filename(psd_xmldoc, "tmp_psd.xml.gz", gz=True) gracedb.writeLog(r["graceid"], "PyCBC PSD estimate from the time of event", "psd.xml.gz", open("tmp_psd.xml.gz", "rb").read(), "psd").json() logging.info("Uploaded file psd.xml.gz to event %s.", r["graceid"])
def main(args=None): p = parser() opts = p.parse_args(args) import lal.series import lalsimulation import numpy as np from ..bayestar.filter import vectorize_swig_psd_func # Add basic options. psds = {} n = int(opts.f_max // opts.df) f = np.arange(n) * opts.df detectors = [d.frDetector.prefix for d in lal.CachedDetectors] for detector in detectors: psd_name = getattr(opts, detector, None) if psd_name is None: continue scale = 1 / np.square(getattr(opts, detector + '_scale', 1.0)) func = getattr(lalsimulation, psd_name_prefix + psd_name) series = lal.CreateREAL8FrequencySeries( psd_name, 0, 0, opts.df, lal.SecondUnit, n) if '(double f) -> double' in func.__doc__: series.data.data = vectorize_swig_psd_func( psd_name_prefix + psd_name)(f) else: func(series, 0.0) # Find indices of first and last nonzero samples. nonzero = np.flatnonzero(series.data.data) # FIXME: int cast seems to be needed on old versions of Numpy first_nonzero = int(nonzero[0]) last_nonzero = int(nonzero[-1]) # Truncate series = lal.CutREAL8FrequencySeries( series, first_nonzero, last_nonzero - first_nonzero + 1) series.f0 = first_nonzero * series.deltaF series.name = psd_name series.data.data *= scale psds[detector] = series xmldoc = lal.series.make_psd_xmldoc(psds) register_to_xmldoc(xmldoc, p, opts) write_fileobj(xmldoc, opts.output)
def __call__(self, f): fa = np.asarray(f) df = np.diff(fa) if fa.ndim == 1 and df.size > 1 and np.all(df[0] == df[1:]): fa = np.concatenate((fa, [fa[-1] + df[0]])) ret = lal.CreateREAL8FrequencySeries( None, 0, fa[0], df[0], lal.DimensionlessUnit, fa.size) lalsimulation.SimNoisePSD(ret, 0, self.__func) ret = ret.data.data[:-1] else: ret = self.__npyfunc(f) if not np.isscalar(ret): ret = ret.astype(float) return ret
def generate_PSD(psd_name="aLIGOZeroDetHighPower", length=None, delta_f=None): psd_list = get_lalsim_psd_list() if psd_name in psd_list: # print (psd_name) # Function for PSD func = lalsim.__dict__["SimNoisePSD" + psd_name + "Ptr"] # Generate a lal frequency series PSDseries = lal.CreateREAL8FrequencySeries("", lal.LIGOTimeGPS(0), 0, delta_f, lal.DimensionlessUnit, length) # func(PSDseries) lalsim.SimNoisePSD(PSDseries, 0, func) return PSDseries
def get_PSD_from_xml(PSD_filename, df, f_min=15., f_max=1024.): "Gets the PSD from lal from an ASD file" PSD = lal.CreateREAL8FrequencySeries('PSD', lal.LIGOTimeGPS(0), 0.0, df, lal.SecondUnit, int(round(f_max / df)) + 1) #FIXME: how shall I read the PSD?? lalsimulation.SimNoisePSDFromFile(PSD, f_min, filename) #see documentation here: #https://lscsoft.docs.ligo.org/lalsuite/lalsimulation/group___l_a_l_sim_noise_p_s_d__c.html#ga67d250556e4e8647c50d379364eb7911 # SimNoisePSDFromFile expects ASD in the file, but this one # contains the PSD, so take the square root PSD.data.data = PSD.data.data**0.5 return PSD
def getPSD(deltaF, npts, psd="SimNoisePSDaLIGOZeroDetHighPowerPtr"): """ deltaF :: The frequency interval between data points. npts :: Total number of date points psd :: The noise model in lalsimulation. To get info use lalsim.__dict__ in interpretor and search string SimNoisePSD """ lalseries = lal.CreateREAL8FrequencySeries('', lal.LIGOTimeGPS(0), 0, deltaF, lal.DimensionlessUnit, npts) func = lalsim.__dict__[psd] lalsim.SimNoisePSD(lalseries, 0, func) f_end = lalseries.f0 + len(lalseries.data.data) * lalseries.deltaF freq = np.linspace(lalseries.f0, f_end, len((lalseries.data.data))) output = np.vstack((freq, lalseries.data.data)).T return output
def psd(self): try: psd = self._psds[self._psds.find(self.zerolag_time)].psd except ValueError: raise ValueError( 'No PSD found for detector {} at zero-lag GPS time {}'.format( self.detector, self.zerolag_time)) dyn_range_fac = psd.file.attrs['dynamic_range_factor'] flow = psd.file.attrs['low_frequency_cutoff'] df = psd.attrs['delta_f'] kmin = int(flow / df) fseries = lal.CreateREAL8FrequencySeries('psd', 0, kmin * df, df, lal.DimensionlessUnit, len(psd.value) - kmin) fseries.data.data = psd.value[kmin:] / np.square(dyn_range_fac) return fseries
def test_z_at_snr(mtotal, z): gwcosmo = GWCosmo(default_cosmology.get_cosmology_from_string('Planck15')) f_low = 10 f_high = 4096 df = 0.1 mass1 = mass2 = 0.5 * mtotal psd = lal.CreateREAL8FrequencySeries('', 0, f_low, df, lal.DimensionlessUnit, int((f_high - f_low) // df)) lalsimulation.SimNoisePSDaLIGODesignSensitivityP1200087(psd, f_low) snr = get_snr_at_z_lalsimulation(gwcosmo.cosmo, z, mass1, mass2, f_low, f_high, psd) z_solution = gwcosmo.z_at_snr([psd], 'IMRPhenomPv2', f_low, snr, mass1, mass2, 0, 0) assert z_solution == pytest.approx(z, rel=1e-2)
def reference_psd_for_sngl(sngl): psd = psdseglistdict[sngl.ifo] try: psd = psd[psd.find(sngl.get_end())].psd except ValueError: raise ValueError( 'No PSD found for detector {0} at GPS time {1}'.format( sngl.ifo, sngl.get_end())) flow = psd.file.attrs['low_frequency_cutoff'] df = psd.attrs['delta_f'] kmin = int(flow / df) fseries = lal.CreateREAL8FrequencySeries( 'psd', psd.attrs['epoch'], kmin * df, df, lal.StrainUnit**2 / lal.HertzUnit, len(psd.value) - kmin) fseries.data.data = psd.value[kmin:] / np.square(DYN_RANGE_FAC) return timing.InterpolatedPSD( filter.abscissa(fseries), fseries.data.data, f_high_truncate=opts.f_high_truncate)
def parse_REAL8FrequencySeries(elem): t, = elem.getElementsByTagName(ligolw.Time.tagName) a, = elem.getElementsByTagName(ligolw.Array.tagName) dims = a.getElementsByTagName(ligolw.Dim.tagName) f0 = ligolw_param.get_param(elem, u"f0") epoch = lal.LIGOTimeGPS(str(t.pcdata)) # Target units: inverse seconds inverse_seconds_unit = lal.Unit() lal.ParseUnitString(inverse_seconds_unit, "s^-1") # Parse units of f0 field f0_unit = lal.Unit() lal.ParseUnitString(f0_unit, str(f0.get_unit())) # Parse units of deltaF field deltaF_unit = lal.Unit() lal.ParseUnitString(deltaF_unit, str(dims[0].getAttribute(u"Unit"))) # Parse units of data sample_unit = lal.Unit() lal.ParseUnitString(sample_unit, str(a.getAttribute(u"Unit"))) # Parse data data = a.array[1] # Initialize data structure series = lal.CreateREAL8FrequencySeries( str(a.getAttribute(u"Name")), epoch, float(f0.pcdata) * lal.UnitRatio(f0_unit, inverse_seconds_unit), float(dims[0].getAttribute(u"Scale")) * lal.UnitRatio(deltaF_unit, inverse_seconds_unit), sample_unit, len(data)) # Copy data series.data.data = data # Done! return series
def test_localize_1_detector(): """Running on an event with 1 detector should produce a sky map that reflects the antenna pattern.""" psd = lal.CreateREAL8FrequencySeries(None, 0, 0, 32, lal.DimensionlessUnit, 128) psd.data.data[:] = 1 test_single_event = MockSingleEvent('H1', 12.345, 0.6789, 0.1234, psd, None) test_event = MockEvent([test_single_event], template_args) skymap = localize(test_event) # Make sure that none of the extrinsic parameters are in the event history history = '\n'.join(skymap.meta['history']) for forbidden in [ 'snr=', '12.345', 'time=', '0.6789', 'phase=', '0.1234', 'mass1=', 'mass2=', '1.414' ]: assert forbidden not in history # FIXME: work out what this should be rasterized = rasterize(skymap) assert rasterized
def getPSD(deltaF, npts, psd="SimNoisePSDaLIGOZeroDetHighPowerPtr"): """ This function accepts a frequency step-size and number of frequency points. It then computes from there the noise PSD for ligo. The default psd is SimNoisePSDaLIGOZeroDetHighPowerPtr which can be changed using the argument psd. deltaF :: The frequency interval between data points. npts :: Total number of date points psd :: The noise model in lalsimulation. To get info use lalsim.__dict__ in interpretor and search string SimNoisePSD """ lalseries = lal.CreateREAL8FrequencySeries('', lal.LIGOTimeGPS(0), 0, deltaF, lal.DimensionlessUnit, npts) func = lalsim.__dict__[psd] lalsim.SimNoisePSD(lalseries, 0, func) f_end = lalseries.f0 + len(lalseries.data.data) * lalseries.deltaF freq = np.linspace(lalseries.f0, f_end, len((lalseries.data.data))) output = np.vstack((freq, lalseries.data.data)).T return output
def from_string(psd_name, length, delta_f, low_freq_cutoff): """Generate a frequency series containing a LALSimulation PSD specified by name. Parameters ---------- psd_name : string PSD name as found in LALSimulation, minus the SimNoisePSD prefix. length : int Length of the frequency series in samples. delta_f : float Frequency resolution of the frequency series. low_freq_cutoff : float Frequencies below this value are set to zero. Returns ------- psd : FrequencySeries The generated frequency series. """ if psd_name not in _psd_list: raise ValueError(psd_name + ' not found among LALSimulation PSD functions.') kmin = int(low_freq_cutoff / delta_f) lalseries = lal.CreateREAL8FrequencySeries('', lal.LIGOTimeGPS(0), 0, delta_f, lal.DimensionlessUnit, length) try: func = lalsimulation.__dict__[_name_prefix + psd_name + _name_suffix] except KeyError: func = lalsimulation.__dict__[_name_prefix + psd_name] func(lalseries, low_freq_cutoff) else: lalsimulation.SimNoisePSD(lalseries, 0, func) psd = FrequencySeries(lalseries.data.data, delta_f=delta_f) psd.data[:kmin] = 0 return psd
if args: parser.error('Did not expect any positional command line arguments') psds = {} unit = lal.Unit() unit = lal.UnitInvert(unit, lal.HertzUnit) n = int(opts.f_max // opts.df) epoch = lal.LIGOTimeGPS() progress = glue.text_progress_bar.ProgressBar() for detector in detectors: psd_name = getattr(opts, detector) if psd_name is None: continue psd_func = getattr(lalsimulation, psd_name_prefix + psd_name) series = lal.CreateREAL8FrequencySeries(None, epoch, 0, opts.df, unit, n) fmt = '%s (%%d / %d)' % (detector, n) for i in progress.iterate(range(1, n), format=fmt): f = i * opts.df series.data.data[i] = psd_func(f) series.data.data[0] = series.data.data[1] psds[detector] = series progress.update(-1, 'writing ' + opts.output) glue.ligolw.utils.write_filename(lal.series.make_psd_xmldoc(psds), opts.output, gz=(os.path.splitext( opts.output)[-1] == ".gz"))
data_O1 = numpy.loadtxt("O1-H1-GDS-CALIB_STRAIN.txt",dtype={'names':('f','asd'), 'formats':('f8','f8')}) #filename = "psds_2016-17.xml" filename = "psd.xml" duration = 32 # sec sample_rate = 1024 # Hz xmldoc = ligolw_utils.load_filename( filename, contenthandler=lal.series.PSDContentHandler) input_psds = lal.series.read_psd_xmldoc(xmldoc) psd_models = dict( (key, timing.InterpolatedPSD(filter.abscissa(psd), psd.data.data)) for key, psd in input_psds.iteritems() if psd is not None) for detector, model in psd_models.iteritems(): psd = lal.CreateREAL8FrequencySeries(None, lal.LIGOTimeGPS(0), 0, 1./duration, filter.unitInverseHertz, int((duration * sample_rate) / 2 + 1)) psd.data.data = model(filter.abscissa(psd)) plot.loglog(filter.abscissa(psd), psd.data.data, label=detector) # plot.loglog(data[:,0],data[:,1]) # plot.loglog(data[:,0],data[:,2]) plot.loglog(data_adv['f'],data_adv['psd'], label="V1 from Prospects paper") plot.loglog(data_aligo['f'],data_aligo['psd'], label="H1 and L1 from Prospects paper") plot.loglog(data_O1['f'],data_O1['asd']**2, label="H1 -- O1") plot.legend(loc=1) plot.grid(True) plot.xlabel('Frequency Hz') plot.ylabel('Strain 1/Hz') plot.ylim([1e-47, 1e-38])
psd_dict_raw[ifo] = lalsimutils.get_psd_series_from_xmldoc( opts.psd_file, ifo) npts_orig = len(psd_dict_raw[ifo].data.data) df = psd_dict_raw[ifo].deltaF f0 = psd_dict_raw[ifo].f0 nyquist = int(len(psd_dict_raw[ifo].data.data) * df + f0) epoch = psd_dict_raw[ifo].epoch print(ifo, len(psd_dict_raw[ifo].data.data), 1. / psd_dict_raw[ifo].deltaF, nyquist) npts_desired = int(nyquist / df + 0.5) indx_start = int(f0 / df + 0.5) # Loop for ifo in ifos: print(" Writing for ", ifo) dat_here = psd_dict_raw[ifo].data.data psddict = {} psd_s = lal.CreateREAL8FrequencySeries(name=ifo, epoch=epoch, f0=0, deltaF=df, sampleUnits="s", length=npts_desired) psd_s.data.data[indx_start:indx_start + npts_orig] = dat_here[:npts_orig - 1] psddict[ifo] = psd_s xmldoc = make_psd_xmldoc(psddict) utils.write_filename(xmldoc, ifo + "-psd.xml.gz", gz=True)
def sngl_inspiral_psd(waveform, mass1, mass2, f_min=10, f_final=None, f_ref=None, **kwargs): # FIXME: uberbank mass criterion. Should find a way to get this from # pipeline output metadata. if waveform == 'o1-uberbank': log.warning('Template is unspecified; ' 'using ER8/O1 uberbank criterion') if mass1 + mass2 < 4: waveform = 'TaylorF2threePointFivePN' else: waveform = 'SEOBNRv2_ROM_DoubleSpin' elif waveform == 'o2-uberbank': log.warning('Template is unspecified; ' 'using ER10/O2 uberbank criterion') if mass1 + mass2 < 4: waveform = 'TaylorF2threePointFivePN' else: waveform = 'SEOBNRv4_ROM' approx, ampo, phaseo = get_approximant_and_orders_from_string(waveform) log.info('Selected template: %s', waveform) # Generate conditioned template. params = lal.CreateDict() lalsimulation.SimInspiralWaveformParamsInsertPNPhaseOrder(params, phaseo) lalsimulation.SimInspiralWaveformParamsInsertPNAmplitudeOrder(params, ampo) hplus, hcross = lalsimulation.SimInspiralFD( m1=float(mass1) * lal.MSUN_SI, m2=float(mass2) * lal.MSUN_SI, S1x=float(kwargs.get('spin1x') or 0), S1y=float(kwargs.get('spin1y') or 0), S1z=float(kwargs.get('spin1z') or 0), S2x=float(kwargs.get('spin2x') or 0), S2y=float(kwargs.get('spin2y') or 0), S2z=float(kwargs.get('spin2z') or 0), distance=1e6 * lal.PC_SI, inclination=0, phiRef=0, longAscNodes=0, eccentricity=0, meanPerAno=0, deltaF=0, f_min=f_min, # Note: code elsewhere ensures that the sample rate is at least two # times f_final; the factor of 2 below is just a safety factor to make # sure that the sample rate is 2-4 times f_final. f_max=ceil_pow_2(2 * (f_final or 2048)), f_ref=float(f_ref or 0), LALparams=params, approximant=approx) # Force `plus' and `cross' waveform to be in quadrature. h = 0.5 * (hplus.data.data + 1j * hcross.data.data) # For inspiral-only waveforms, nullify frequencies beyond ISCO. # FIXME: the waveform generation functions pick the end frequency # automatically. Shouldn't SimInspiralFD? inspiral_only_waveforms = (lalsimulation.TaylorF2, lalsimulation.SpinTaylorF2, lalsimulation.TaylorF2RedSpin, lalsimulation.TaylorF2RedSpinTidal, lalsimulation.SpinTaylorT4Fourier) if approx in inspiral_only_waveforms: h[abscissa(hplus) >= get_f_lso(mass1, mass2)] = 0 # Throw away any frequencies above high frequency cutoff h[abscissa(hplus) >= (f_final or 2048)] = 0 # Drop Nyquist frequency. if len(h) % 2: h = h[:-1] # Create output frequency series. psd = lal.CreateREAL8FrequencySeries('signal PSD', 0, hplus.f0, hcross.deltaF, hplus.sampleUnits**2, len(h)) psd.data.data = abs2(h) # Done! return psd
def __init__(self, ifos, coinc_results, **kwargs): """Initialize a ligolw xml representation of a zerolag trigger for upload from pycbc live to gracedb. Parameters ---------- ifos: list of strs A list of the ifos pariticipating in this trigger coinc_results: dict of values A dictionary of values. The format is defined in pycbc/events/coinc.py and matches the on disk representation in the hdf file for this time. psds: dict of FrequencySeries Dictionary providing PSD estimates for all involved detectors. low_frequency_cutoff: float Minimum valid frequency for the PSD estimates. followup_data: dict of dicts, optional Dictionary providing SNR time series for each detector, to be used in sky localization with BAYESTAR. The format should be `followup_data['H1']['snr_series']`. More detectors can be present than given in `ifos`. If so, the extra detectors will only be used for sky localization. channel_names: dict of strings, optional Strain channel names for each detector. Will be recorded in the sngl_inspiral table. """ self.template_id = coinc_results['foreground/%s/template_id' % ifos[0]] self.coinc_results = coinc_results self.ifos = ifos # remember if this should be marked as HWINJ self.is_hardware_injection = ('HWINJ' in coinc_results and coinc_results['HWINJ']) if 'followup_data' in kwargs: fud = kwargs['followup_data'] assert len({fud[ifo]['snr_series'].delta_t for ifo in fud}) == 1, \ "delta_t for all ifos do not match" self.snr_series = {ifo: fud[ifo]['snr_series'] for ifo in fud} usable_ifos = fud.keys() followup_ifos = list(set(usable_ifos) - set(ifos)) else: self.snr_series = None usable_ifos = ifos followup_ifos = [] # Set up the bare structure of the xml document outdoc = ligolw.Document() outdoc.appendChild(ligolw.LIGO_LW()) proc_id = ligolw_process.register_to_xmldoc( outdoc, 'pycbc', {}, ifos=usable_ifos, comment='', version=pycbc_version.git_hash, cvs_repository='pycbc/'+pycbc_version.git_branch, cvs_entry_time=pycbc_version.date).process_id # Set up coinc_definer table coinc_def_table = lsctables.New(lsctables.CoincDefTable) coinc_def_id = lsctables.CoincDefID(0) coinc_def_row = lsctables.CoincDef() coinc_def_row.search = "inspiral" coinc_def_row.description = "sngl_inspiral<-->sngl_inspiral coincs" coinc_def_row.coinc_def_id = coinc_def_id coinc_def_row.search_coinc_type = 0 coinc_def_table.append(coinc_def_row) outdoc.childNodes[0].appendChild(coinc_def_table) # Set up coinc inspiral and coinc event tables coinc_id = lsctables.CoincID(0) coinc_event_table = lsctables.New(lsctables.CoincTable) coinc_event_row = lsctables.Coinc() coinc_event_row.coinc_def_id = coinc_def_id coinc_event_row.nevents = len(usable_ifos) coinc_event_row.instruments = ','.join(usable_ifos) coinc_event_row.time_slide_id = lsctables.TimeSlideID(0) coinc_event_row.process_id = proc_id coinc_event_row.coinc_event_id = coinc_id coinc_event_row.likelihood = 0. coinc_event_table.append(coinc_event_row) outdoc.childNodes[0].appendChild(coinc_event_table) # Set up sngls sngl_inspiral_table = lsctables.New(lsctables.SnglInspiralTable) coinc_event_map_table = lsctables.New(lsctables.CoincMapTable) sngl_populated = None network_snrsq = 0 for sngl_id, ifo in enumerate(usable_ifos): sngl = return_empty_sngl(nones=True) sngl.event_id = lsctables.SnglInspiralID(sngl_id) sngl.process_id = proc_id sngl.ifo = ifo names = [n.split('/')[-1] for n in coinc_results if 'foreground/%s' % ifo in n] for name in names: val = coinc_results['foreground/%s/%s' % (ifo, name)] if name == 'end_time': sngl.set_end(lal.LIGOTimeGPS(val)) else: try: setattr(sngl, name, val) except AttributeError: pass if sngl.mass1 and sngl.mass2: sngl.mtotal, sngl.eta = pnutils.mass1_mass2_to_mtotal_eta( sngl.mass1, sngl.mass2) sngl.mchirp, _ = pnutils.mass1_mass2_to_mchirp_eta( sngl.mass1, sngl.mass2) sngl_populated = sngl if sngl.snr: sngl.eff_distance = (sngl.sigmasq)**0.5 / sngl.snr network_snrsq += sngl.snr ** 2.0 if 'channel_names' in kwargs and ifo in kwargs['channel_names']: sngl.channel = kwargs['channel_names'][ifo] sngl_inspiral_table.append(sngl) # Set up coinc_map entry coinc_map_row = lsctables.CoincMap() coinc_map_row.table_name = 'sngl_inspiral' coinc_map_row.coinc_event_id = coinc_id coinc_map_row.event_id = sngl.event_id coinc_event_map_table.append(coinc_map_row) if self.snr_series is not None: snr_series_to_xml(self.snr_series[ifo], outdoc, sngl.event_id) # for subthreshold detectors, respect BAYESTAR's assumptions and checks bayestar_check_fields = ('mass1 mass2 mtotal mchirp eta spin1x ' 'spin1y spin1z spin2x spin2y spin2z').split() subthreshold_sngl_time = numpy.mean( [coinc_results['foreground/{}/end_time'.format(ifo)] for ifo in ifos]) for sngl in sngl_inspiral_table: if sngl.ifo in followup_ifos: for bcf in bayestar_check_fields: setattr(sngl, bcf, getattr(sngl_populated, bcf)) sngl.set_end(lal.LIGOTimeGPS(subthreshold_sngl_time)) outdoc.childNodes[0].appendChild(coinc_event_map_table) outdoc.childNodes[0].appendChild(sngl_inspiral_table) # Set up the coinc inspiral table coinc_inspiral_table = lsctables.New(lsctables.CoincInspiralTable) coinc_inspiral_row = lsctables.CoincInspiral() # This seems to be used as FAP, which should not be in gracedb coinc_inspiral_row.false_alarm_rate = 0 coinc_inspiral_row.minimum_duration = 0. coinc_inspiral_row.set_ifos(usable_ifos) coinc_inspiral_row.coinc_event_id = coinc_id coinc_inspiral_row.mchirp = sngl_populated.mchirp coinc_inspiral_row.mass = sngl_populated.mtotal coinc_inspiral_row.end_time = sngl_populated.end_time coinc_inspiral_row.end_time_ns = sngl_populated.end_time_ns coinc_inspiral_row.snr = network_snrsq ** 0.5 far = 1.0 / (lal.YRJUL_SI * coinc_results['foreground/ifar']) coinc_inspiral_row.combined_far = far coinc_inspiral_table.append(coinc_inspiral_row) outdoc.childNodes[0].appendChild(coinc_inspiral_table) # append the PSDs self.psds = kwargs['psds'] psds_lal = {} for ifo in self.psds: psd = self.psds[ifo] kmin = int(kwargs['low_frequency_cutoff'] / psd.delta_f) fseries = lal.CreateREAL8FrequencySeries( "psd", psd.epoch, kwargs['low_frequency_cutoff'], psd.delta_f, lal.StrainUnit**2 / lal.HertzUnit, len(psd) - kmin) fseries.data.data = psd.numpy()[kmin:] / pycbc.DYN_RANGE_FAC ** 2.0 psds_lal[ifo] = fseries make_psd_xmldoc(psds_lal, outdoc) self.outdoc = outdoc self.time = sngl_populated.get_end()
def upload( self, fname, psds, low_frequency_cutoff, testing=True, extra_strings=None, ): """Upload this trigger to gracedb Parameters ---------- fname: str The name to give the xml file associated with this trigger pds: dict of pybc.types.FrequencySeries A ifo keyed dictionary of psds to be uploaded in association with this trigger. low_frequency_cutoff: float The low frequency cutoff of the psds. testing: bool Switch to determine if the upload should be sent to gracedb as a test trigger (True) or a production trigger (False) """ from ligo.gracedb.rest import GraceDb self.save(fname) extra_strings = [] if extra_strings is None else extra_strings if testing: group = 'Test' else: group = 'CBC' gracedb = GraceDb() r = gracedb.createEvent(group, "pycbc", fname, "AllSky").json() logging.info("Uploaded event %s.", r["graceid"]) if self.is_hardware_injection: gracedb.writeLabel(r['graceid'], 'INJ') logging.info("Tagging event %s as an injection", r["graceid"]) psds_lal = {} for ifo in psds: psd = psds[ifo] kmin = int(low_frequency_cutoff / psd.delta_f) fseries = lal.CreateREAL8FrequencySeries( "psd", psd.epoch, low_frequency_cutoff, psd.delta_f, lal.StrainUnit**2 / lal.HertzUnit, len(psd) - kmin) fseries.data.data = psd.numpy()[kmin:] / pycbc.DYN_RANGE_FAC**2.0 psds_lal[ifo] = fseries psd_xmldoc = make_psd_xmldoc(psds_lal) ligolw_utils.write_filename(psd_xmldoc, "tmp_psd.xml.gz", gz=True) gracedb.writeLog(r["graceid"], "PyCBC PSD estimate from the time of event", "psd.xml.gz", open("tmp_psd.xml.gz", "rb").read(), "psd").json() gracedb.writeLog(r["graceid"], "using pycbc code hash %s" % pycbc_version.git_hash).json() for text in extra_strings: gracedb.writeLog(r["graceid"], text).json() logging.info("Uploaded file psd.xml.gz to event %s.", r["graceid"]) if self.upload_snr_series: snr_series_fname = fname + '.hdf' for ifo in self.snr_series: self.snr_series[ifo].save(snr_series_fname, group='%s/snr' % ifo) self.snr_series_psd[ifo].save(snr_series_fname, group='%s/psd' % ifo) GraceDb().writeFile(r['graceid'], snr_series_fname) return r['graceid']
# Sample rate in Hz sample_rate = 4096 # Data duration in seconds data_duration = 100 # Number of samples data_length = data_duration * sample_rate # Start time of data epoch = lal.LIGOTimeGPS() # Discretely sampled power spectrum psd = lal.CreateREAL8FrequencySeries(None, epoch, 0, 1 / data_duration, filter.unitInverseHertz, data_length // 2 + 1) S = timing.get_noise_psd_func("H1") f = filter.abscissa(psd) psd.data.data = [S(ff) for ff in f] psd.data.data[(f < 10) | (f > 2048)] = 0 # Generate colored Gaussian noise data = filter.colored_noise(lal.LIGOTimeGPS(), data_duration, sample_rate, psd) # Plot measured power spectrum of data [power, freqs] = plt.psd(data.data.data, NFFT=sample_rate, Fs=sample_rate, detrend=mlab.detrend_mean, noverlap=sample_rate // 2)