def project_wave(self, hp, hc, longitude, latitude, polarization): """Return the strain of a wave with given amplitudes and angles as measured by the detector. """ h_lal = lalsimulation.SimDetectorStrainREAL8TimeSeries( hp.astype(np.float64).lal(), hc.astype(np.float64).lal(), longitude, latitude, polarization, self.frDetector) return TimeSeries( h_lal.data.data, delta_t=h_lal.deltaT, epoch=h_lal.epoch, dtype=np.float64, copy=False)
def generate_for_detector(source, ifos, sample_rate, epoch, distance, total_mass, ra, dec, psi): ''' Generate an injection for a given waveform. Parameters ---------- source : ``minke.Source`` object The source which should generate the waveform. ifos : list A list of interferometer initialisms, e.g. ['L1', 'H1'] sample_rate : int The sample rate in hertz for the generated signal. epoch : str The epoch (start time) for the injection. Note that this should be provided as a string to prevent overflows. distance : float The distance for the injection, in megaparsecs. total_mass : float The total mass for the injected signal. ra : float The right ascension of the source, in radians. dec : float The declination of the source, in radians. psi : float The polarisation angle of the source, in radians. ''' nr_waveform = source.datafile data = {} data['data'] = {} data['times'] = {} data['meta'] = {} data['epoch'] = epoch data['meta']['ra'] = ra data['meta']['dec'] = dec data['meta']['psi'] = psi data['meta']['distance'] = distance data['meta']['total_mass'] = total_mass data['meta']['sample rate'] = sample_rate data['meta']['waveform'] = nr_waveform for ifo in ifos: det = lalsimulation.DetectorPrefixToLALDetector(ifo) hp, hx = source._generate(half=True, epoch=epoch, rate=sample_rate)[:2] h_tot = lalsimulation.SimDetectorStrainREAL8TimeSeries( hp, hx, ra, dec, psi, det) data['data'][ifo] = h_tot.data.data.tolist() data['times'][ifo] = np.linspace(0, len(h_tot.data.data) * h_tot.deltaT, len(h_tot.data.data)).tolist() return data
def project_wave(self, hp, hc, longitude, latitude, polarization): """Return the strain of a waveform as measured by the detector. Apply the time shift for the given detector relative to the assumed geocentric frame and apply the antenna patterns to the plus and cross polarizations. """ h_lal = lalsimulation.SimDetectorStrainREAL8TimeSeries( hp.astype(np.float64).lal(), hc.astype(np.float64).lal(), longitude, latitude, polarization, self.frDetector) return TimeSeries( h_lal.data.data, delta_t=h_lal.deltaT, epoch=h_lal.epoch, dtype=np.float64, copy=False)
def time_series(self, sampling_rate, detector=None): """ Generate a time series at a given sampling_rate (Hz) for the waveform using a call to lalsimulation. If detector is None (default), return only the (h+, hx) tuple. Otherwise, apply the proper detector anntenna patterns and return the resultant series F+h+ + Fxhx. """ hp, hx = lalburst.GenerateSimBurst(copy_sim_burst(self), 1.0 / sampling_rate) if detector is None: return hp, hx detector = LAL_DETECTORS[detector] return lalsimulation.SimDetectorStrainREAL8TimeSeries( hp, hx, self.ra, self.dec, self.psi, detector)
def real_hoft(self, Fp=None, Fc=None): """ Returns the real-valued h(t) that would be produced in a single instrument. Translates epoch as needed. Based on 'hoft' in lalsimutils.py """ # Create complex timessereis htC = self.complex_hoft( force_T=1. / self.P.deltaF, deltaT=self.P.deltaT ) # note P.tref is NOT used in the low-level code TDlen = htC.data.length if rosDebug: print("Size sanity check ", TDlen, 1 / (self.P.deltaF * self.P.deltaT)) print(" Raw complex magnitude , ", np.max(htC.data.data)) # Create working buffers to extract data from it -- wasteful. hp = lal.CreateREAL8TimeSeries("h(t)", htC.epoch, 0., self.P.deltaT, lalsimutils.lsu_DimensionlessUnit, TDlen) hc = lal.CreateREAL8TimeSeries("h(t)", htC.epoch, 0., self.P.deltaT, lalsimutils.lsu_DimensionlessUnit, TDlen) hT = lal.CreateREAL8TimeSeries("h(t)", htC.epoch, 0., self.P.deltaT, lalsimutils.lsu_DimensionlessUnit, TDlen) # Copy data components over hp.data.data = np.real(htC.data.data) hc.data.data = np.imag(htC.data.data) # transform as in lalsimutils.hoft if Fp != None and Fc != None: hp.data.data *= Fp hc.data.data *= Fc hp = lal.AddREAL8TimeSeries(hp, hc) hoft = hp elif self.P.radec == False: fp = lalsimutils.Fplus(self.P.theta, self.P.phi, self.P.psi) fc = lalsimutils.Fcross(self.P.theta, self.P.phi, self.P.psi) hp.data.data *= fp hc.data.data *= fc hp.data.data = lal.AddREAL8TimeSeries(hp, hc) hoft = hp else: # Note epoch must be applied FIRST, to make sure the correct event time is being used to construct the modulation functions hp.epoch = hp.epoch + self.P.tref hc.epoch = hc.epoch + self.P.tref if rosDebug: print(" Real h(t) before detector weighting, ", np.max(hp.data.data), np.max(hc.data.data)) hoft = lalsim.SimDetectorStrainREAL8TimeSeries( hp, hc, # beware, this MAY alter the series length?? self.P.phi, self.P.theta, self.P.psi, lalsim.DetectorPrefixToLALDetector(str(self.P.detector))) hoft = lal.CutREAL8TimeSeries( hoft, 0, hp.data.length) # force same length as before?? if rosDebug: print("Size before and after detector weighting ", hp.data.length, hoft.data.length) if rosDebug: print(" Real h_{IFO}(t) generated, pre-taper : max strain =", np.max(hoft.data.data)) if self.P.taper != lalsimutils.lsu_TAPER_NONE: # Taper if requested lalsim.SimInspiralREAL8WaveTaper(hoft.data, self.P.taper) if self.P.deltaF is not None: TDlen = int(1. / self.P.deltaF * 1. / self.P.deltaT) print("Size sanity check 2 ", int(1. / self.P.deltaF * 1. / self.P.deltaT), hoft.data.length) assert TDlen >= hoft.data.length npts = hoft.data.length hoft = lal.ResizeREAL8TimeSeries(hoft, 0, TDlen) # Zero out the last few data elements -- NOT always reliable for all architectures; SHOULD NOT BE NECESSARY hoft.data.data[npts:TDlen] = 0 if rosDebug: print(" Real h_{IFO}(t) generated : max strain =", np.max(hoft.data.data)) return hoft
def damped_chirp_tmplt(det_data, int_params, ext_params): """ Build a template for the detector in det_data from the intrinsic and extrinsic parameteres in int_params and ext_params """ # # Compute polarisations for damped chirp # # _, hp = damped_chirp(int_params.tmplt_len, # int_params.Amp, int_params.f0, int_params.tau, int_params.df) # # _, hc = damped_chirp(int_params.tmplt_len, # int_params.Amp, int_params.f0, int_params.tau, int_params.df, # phi0=90.0) # Get the epoch for the start of the time series epoch = ext_params.geocent_peak_time # - \ #np.argmax(hp)*det_data.td_response.delta_t # XXX: why don't we need to subtract this bit...? Q = 2.0 * np.pi * int_params.tau * int_params.f0 hp, hc = lalsim.SimBurstChirplet(Q, int_params.f0, int_params.df, int_params.Amp, 0, 0, 1.0 / 16384) hp.data.data[0:hp.data.length / 2] = 0.0 hc.data.data[0:hp.data.length / 2] = 0.0 hplus = lal.CreateREAL8TimeSeries('hplus', epoch, 0, det_data.td_noise.delta_t, lal.StrainUnit, hp.data.length) hplus.data.data = np.copy(hp.data.data) del hp hcross = lal.CreateREAL8TimeSeries('hcross', epoch, 0, det_data.td_noise.delta_t, lal.StrainUnit, hc.data.length) hcross.data.data = np.copy(hc.data.data) del hc # try: # time_delay = lal.TimeDelayFromEarthCenter(det_data.det_site.location, # ext_params.ra, ext_params.dec, ext_params.geocent_peak_time) # except RuntimeError: # time_delay = lal.TimeDelayFromEarthCenter(det_data.det_site.location, # ext_params.ra, ext_params.dec, -1e4) # --- Put the polarisations into LAL TimeSeries # hplus = lal.CreateREAL8TimeSeries('hplus', epoch, 0, # det_data.td_noise.delta_t, lal.StrainUnit, len(hp)) # hplus.data.data=np.copy(hp) # del hp # # hcross = lal.CreateREAL8TimeSeries('hcross', epoch, 0, # det_data.td_noise.delta_t, lal.StrainUnit, len(hc)) # hcross.data.data=np.copy(hc) # del hc # # Project polarisations down to detector # tmplt = lalsim.SimDetectorStrainREAL8TimeSeries(hplus, hcross, ext_params.ra, ext_params.dec, ext_params.polarization, det_data.det_site) del hplus, hcross # Scale for distance (waveforms extracted at 20 Mpc) tmplt.data.data *= 20.0 / ext_params.distance # # Finally make this the same size as the data (useful for fitting) # #lal.ResizeREAL8TimeSeries(tmplt, 0, len(det_data.td_response.data)) no_noise = lal.CreateREAL8TimeSeries( 'blah', det_data.td_noise.start_time, 0, det_data.td_noise.delta_t, lal.StrainUnit, int(det_data.td_noise.duration / det_data.td_noise.delta_t)) no_noise.data.data = np.zeros( int(det_data.td_noise.duration / det_data.td_noise.delta_t)) tmplt = lal.AddREAL8TimeSeries(no_noise, tmplt) return pycbc.types.timeseries.TimeSeries(\ initial_array=np.copy(tmplt.data.data), delta_t=tmplt.deltaT, epoch=tmplt.epoch)
def project_wave(self, hp, hc, ra, dec, polarization, method='lal', reference_time=None): """Return the strain of a waveform as measured by the detector. Apply the time shift for the given detector relative to the assumed geocentric frame and apply the antenna patterns to the plus and cross polarizations. Parameters ---------- hp: pycbc.types.TimeSeries Plus polarization of the GW hc: pycbc.types.TimeSeries Cross polarization of the GW ra: float Right ascension of source location dec: float Declination of source location polarization: float Polarization angle of the source method: {'lal', 'constant', 'vary_polarization'} The method to use for projecting the polarizations into the detector frame. Default is 'lal'. reference_time: float, Optional The time to use as, a reference for some methods of projection. Used by 'constant' and 'vary_polarization' methods. Uses average time if not provided. """ # The robust and most fefature rich method which includes # time changing antenna patterns and doppler shifts due to the # earth rotation and orbit if method == 'lal': import lalsimulation h_lal = lalsimulation.SimDetectorStrainREAL8TimeSeries( hp.astype(np.float64).lal(), hc.astype(np.float64).lal(), ra, dec, polarization, self.lal()) ts = TimeSeries( h_lal.data.data, delta_t=h_lal.deltaT, epoch=h_lal.epoch, dtype=np.float64, copy=False) # 'constant' assume fixed orientation relative to source over the # duration of the signal, accurate for short duration signals # 'fixed_polarization' applies only time changing orientation # but no doppler corrections elif method in ['constant', 'vary_polarization']: if reference_time is not None: rtime = reference_time else: # In many cases, one should set the reference time if using # this method as we don't know where the signal is within # the given time series. If not provided, we'll choose # the midpoint time. rtime = (float(hp.end_time) + float(hp.start_time)) / 2.0 if method == 'constant': time = rtime elif method == 'vary_polarization': if (not isinstance(hp, TimeSeries) or not isinstance(hc, TimeSeries)): raise TypeError('Waveform polarizations must be given' ' as time series for this method') # this is more granular than needed, may be optimized later # assume earth rotation in ~30 ms needed for earth ceneter # to detector is completely negligible. time = hp.sample_times.numpy() fp, fc = self.antenna_pattern(ra, dec, polarization, time) dt = self.time_delay_from_earth_center(ra, dec, rtime) ts = fp * hp + fc * hc ts.start_time = float(ts.start_time) + dt # add in only the correction for the time variance in the polarization # due to the earth's rotation, no doppler correction applied else: raise ValueError("Unkown projection method {}".format(method)) return ts
def get_WF_and_snr(inj, PSD, sample_rate, instrument="H1", plot_dir=None): "Given an injection row, it computes the WF and the SNR" #https://git.ligo.org/lscsoft/gstlal/-/blob/precession_hm-0.2/gstlal-inspiral/bin/gstlal_inspiral_injection_snr #PSD should be a lal PSD obj assert instrument in ["H1", "L1", "V1"] injtime = inj.time_geocent sample_rate = 16384.0 approximant = lalsimulation.GetApproximantFromString(str(inj.waveform)) f_min = inj.f_lower h_plus, h_cross = lalsimulation.SimInspiralTD(m1=inj.mass1 * lal.MSUN_SI, m2=inj.mass2 * lal.MSUN_SI, S1x=inj.spin1x, S1y=inj.spin1y, S1z=inj.spin1z, S2x=inj.spin2x, S2y=inj.spin2y, S2z=inj.spin2z, distance=inj.distance * 1e6 * lal.PC_SI, inclination=inj.inclination, phiRef=inj.coa_phase, longAscNodes=0.0, eccentricity=0.0, meanPerAno=0.0, deltaT=1.0 / sample_rate, f_min=f_min, f_ref=0.0, LALparams=None, approximant=approximant) h_plus.epoch += injtime h_cross.epoch += injtime # Compute strain in the chosen detector. h = lalsimulation.SimDetectorStrainREAL8TimeSeries( h_plus, h_cross, inj.longitude, inj.latitude, inj.polarization, lalsimulation.DetectorPrefixToLALDetector(instrument)) #Compute the SNR if PSD is not None: snr = lalsimulation.MeasureSNR(h, PSD, options.flow, options.fmax) else: snr = 0. if isinstance(plot_dir, str): plt.figure() plt.title( "(m1, m2, s1 (x,y,z), s2 (x,y,z), d_L) =\n {0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} {6:.2f} {7:.2f} {8:.2f} " .format(inj.mass1, inj.mass2, inj.spin1x, inj.spin1y, inj.spin1z, inj.spin2x, inj.spin2y, inj.spin2z, inj.distance)) plt.plot( np.linspace(0, len(h_plus.data.data) / sample_rate, len(h_plus.data.data)), h_plus.data.data) plt.savefig(plot_dir + '/inj_{}.png'.format(injtime)) #plt.show() plt.close('all') return (h.data.data, snr)
def make_signal(self, waveform): """ Generate the signal seeen in this detector """ #print >> sys.stdout, "generating signal..." # --- Set up timing # index of the absolute maximum peak #idx = np.concatenate(np.argwhere(abs(waveform.hplus.data.data)>0))[0] idx = np.argmax(abs(waveform.hplus.data)) # Epoch = GPS start of time series. Want the peak time of the waveform # to be aligned to the geocenter, so set the epoch to the geocentric # peak time minus the time to the waveform peak. In other words: # (waveform epoch) = (geocentric peak time) - (# of seconds to peak) hplus_epoch = self.ext_params.geocent_peak_time - idx * waveform.hplus.delta_t hcross_epoch = self.ext_params.geocent_peak_time - idx * waveform.hcross.delta_t # XXX: create regular lal timeseries objects for this bit (may replace # with pycbc injection routines later) hplus = lal.CreateREAL8TimeSeries( 'hplus', hplus_epoch, 0, waveform.hplus.delta_t, lal.StrainUnit, int(waveform.hplus.duration / waveform.hplus.delta_t)) hplus.data.data = np.array(waveform.hplus.data) hcross = lal.CreateREAL8TimeSeries( 'hcross', hcross_epoch, 0, waveform.hcross.delta_t, lal.StrainUnit, int(waveform.hcross.duration / waveform.hcross.delta_t)) hcross.data.data = np.array(waveform.hcross.data) if self.taper is True: print >> sys.stderr, "Warning: tapering out inspiral (not a realistic strategy)" delay = 0.0e-3 idx = np.argmax(hplus.data.data) + \ np.ceil(delay/self.delta_t) hplus.data.data[0:idx] = 0.0 hcross.data.data[0:idx] = 0.0 lalsim.SimInspiralREAL8WaveTaper(hplus.data, lalsim.SIM_INSPIRAL_TAPER_START) lalsim.SimInspiralREAL8WaveTaper(hcross.data, lalsim.SIM_INSPIRAL_TAPER_START) # Scale for distance (waveforms extracted at 20 Mpc) hplus.data.data *= 20.0 / self.ext_params.distance hcross.data.data *= 20.0 / self.ext_params.distance tmp = lalsim.SimDetectorStrainREAL8TimeSeries( hplus, hcross, self.ext_params.ra, self.ext_params.dec, self.ext_params.polarization, self.det_site) # Pad the end so we have the same length signal and noise (useful for # snr and psds) sigdata = np.zeros(len(self.td_noise)) sigdata[:len(tmp.data.data)] = np.copy(tmp.data.data) # Project waveform onto these extrinsic parameters self.td_signal = \ pycbc.types.timeseries.TimeSeries(initial_array=sigdata, delta_t=tmp.deltaT, epoch=tmp.epoch) del tmp
# compute h(t) = h+(t) + hx(t) h_wnb = wnb_hp.data.data + wnb_hx.data.data h_sg = sg_hp.data.data + sg_hx.data.data # make lal time series to set numpy arrays equal to lal_h_wnb = lal.CreateREAL8TimeSeries(name = "lal_wnb", epoch = wnb_hp.epoch, f0=0, deltaT = deltaT, sampleUnits = lal.lalDimensionlessUnit, length = len(wnb_hp.data.data+wnb_hx.data.data)) lal_h_sg = lal.CreateREAL8TimeSeries(name = "lal_sg", epoch = sg_hp.epoch, f0=0, deltaT =deltaT, sampleUnits = lal.lalDimensionlessUnit, length = len(sg_hp.data.data+sg_hx.data.data)) #h_wnb = lal_h_wnb h_wnb = lal_h_wnb h_sg = lal_h_sg else: # use lal version of h: h(t) = F+ h+(t) + Fx hx(t) h_wnb = lalsimulation.SimDetectorStrainREAL8TimeSeries( wnb_hp, wnb_hx, sim_burst_table.ra, sim_burst_table.dec, sim_burst_table.psi, det ) h_sg = lalsimulation.SimDetectorStrainREAL8TimeSeries( sg_hp, sg_hx, sim_burst_table.ra, sim_burst_table.dec, sim_burst_table.psi, det ) # resize if necessary for FFT if h_wnb.data.length < needed_samps: h_wnb = lal.ResizeREAL8TimeSeries( h_wnb, 0, needed_samps ) elif h_wnb.data.length > needed_samps: h_wnb = lal.ResizeREAL8TimeSeries( h_wnb, h_wnb.data.length-needed_samps, needed_samps ) if h_sg.data.length < needed_samps: h_sg = lal.ResizeREAL8TimeSeries( h_sg, 0, needed_samps ) elif h_sg.data.length > needed_samps: h_sg = lal.ResizeREAL8TimeSeries( h_sg, h_sg.data.length-needed_samps, needed_samps ) hf_wnb = lal.CreateCOMPLEX16FrequencySeries( name = "m1",