def non_herm_hoff(self): """ Returns the 2-sided h(f) associated with the real-valued h(t) seen in a real instrument. Translates epoch as needed. Based on 'non_herm_hoff' in lalsimutils.py """ htR = self.real_hoft( ) # Generate real-valued TD waveform, including detector response if self.P.deltaF == None: # h(t) was not zero-padded, so do it now TDlen = nextPow2(htR.data.length) htR = lal.ResizeREAL8TimeSeries(htR, 0, TDlen) else: # Check zero-padding was done to expected length TDlen = int(1. / self.P.deltaF * 1. / self.P.deltaT) assert TDlen == htR.data.length fwdplan = lal.CreateForwardCOMPLEX16FFTPlan(htR.data.length, 0) htC = lal.CreateCOMPLEX16TimeSeries("hoft", htR.epoch, htR.f0, htR.deltaT, htR.sampleUnits, htR.data.length) # copy h(t) into a COMPLEX16 array which happens to be purely real htC.data.data[:htR.data.length] = htR.data.data # for i in range(htR.data.length): # htC.data.data[i] = htR.data.data[i] hf = lal.CreateCOMPLEX16FrequencySeries( "Template h(f)", htR.epoch, htR.f0, 1. / htR.deltaT / htR.data.length, lalsimutils.lsu_HertzUnit, htR.data.length) lal.COMPLEX16TimeFreqFFT(hf, htC, fwdplan) return hf
def _compute_waveform(self, df, f_final): """ Since EOBNRv2 is a time domain waveform, we have to generate it, then FFT to frequency domain. """ # need to compute dt from df, duration sample_rate = 2**np.ceil(np.log2(2 * f_final)) dt = 1. / sample_rate # get hplus hplus, hcross = lalsim.SimIMREOBNRv2DominantMode( 0., dt, self.m1 * MSUN_SI, self.m2 * MSUN_SI, self.bank.flow, 1e6 * PC_SI, 0.) # zero-pad up to 1/df N = int(sample_rate / df) hplus = lal.ResizeREAL8TimeSeries(hplus, 0, N) # taper lalsim.SimInspiralREAL8WaveTaper(hplus.data, lalsim.SIM_INSPIRAL_TAPER_START) # create vector to hold output and plan htilde = lal.CreateCOMPLEX16FrequencySeries("h(f)", hplus.epoch, hplus.f0, df, lal.HertzUnit, int(N / 2 + 1)) fftplan = lal.CreateForwardREAL8FFTPlan(N, 0) # do the fft lal.REAL8TimeFreqFFT(htilde, hplus, fftplan) return htilde
def frequency_series(self, deltaF, detector=None, fwdplan=None): """ Generate a frequency series at a given frequency bin spacing deltaF (Hz) for the waveform using a call to lalsimulation. The function time_series is called first to generate the waveform in the time domain. If detector is None (default), return only hf with no antenna patterns applied. Otherwise, apply the proper detector anntenna patterns and return the resultant series hf = FFT[F+h+ + Fxhx]. """ # FIXME: This is overkill for BTLWNB, and won't work entirely for # cosmic strings sampling_rate = 4 * (self.frequency + (self.bandwidth or 0)) sampling_rate = 2**(int(math.log(sampling_rate, 2) + 1)) self.__get_fwdplan(sampling_rate, deltaF) if detector is not None: h = self.time_series(sampling_rate, detector) else: hp, hx = self.time_series(sampling_rate, detector) h = lal.CreateREAL8TimeSeries(name="TD signal", epoch=hp.epoch, f0=0, deltaT=hp.deltaT, sampleUnits=lal.DimensionlessUnit, length=hp.data.length) h.data.data = hp.data.data + hx.data.data # zero pad needed_samps = int(sampling_rate / deltaF) prevlen = h.data.length if h.data.length < needed_samps: h = lal.ResizeREAL8TimeSeries(h, 0, needed_samps) elif h.data.length > needed_samps: h = lal.ResizeREAL8TimeSeries(h, h.data.length - needed_samps, needed_samps) # adjust heterodyne frequency to match flow hf = lal.CreateCOMPLEX16FrequencySeries( name="FD signal", epoch=h.epoch, f0=0, deltaF=deltaF, sampleUnits=lal.DimensionlessUnit, length=int(h.data.length / 2 + 1)) # Forward FFT lal.REAL8TimeFreqFFT(hf, h, self._fwdplan) return hf
def _compute_waveform(self, df, f_final): # Time domain, so compute then FFT # need to compute dt from df, duration sample_rate = 2**np.ceil(np.log2(2 * f_final)) dt = 1. / sample_rate # Generate waveform in time domain hplus, hcross = lalsim.SimInspiralSpinTaylorT5( 0, # GW phase at reference freq (rad) dt, # sampling interval (s) self.m1 * lal.MSUN_SI, # mass of companion 1 (kg) self.m2 * lal.MSUN_SI, # mass of companion 2 (kg) self.bank.flow, # start GW frequency (Hz) 1e6 * PC_SI, # distance of source (m) self.s1x, # initial value of S1x self.s1y, # initial value of S1y self.s1z, # initial value of S1z self.s2x, # initial value of S2x self.s2y, # initial value of S2y self.s2z, # initial value of S2z self. inclination, # inclination angle - careful with definition (line of sight to total vs orbital angular momentum) 7, # twice PN phase order 0) # project onto detector hoft = project_hplus_hcross(hplus, hcross, self.theta, self.phi, self.psi) # zero-pad up to 1/df N = int(sample_rate / df) hoft = lal.ResizeREAL8TimeSeries(hoft, 0, N) # taper lalsim.SimInspiralREAL8WaveTaper(hoft.data, lalsim.SIM_INSPIRAL_TAPER_STARTEND) # create vector to hold output and plan htilde = lal.CreateCOMPLEX16FrequencySeries("h(f)", hoft.epoch, hoft.f0, df, lal.HertzUnit, int(N / 2 + 1)) fftplan = lal.CreateForwardREAL8FFTPlan(N, 0) # do the fft lal.REAL8TimeFreqFFT(htilde, hoft, fftplan) return htilde
sv = lal.CreateStringVector("1") assert (sv.length == 1) lal.AppendString2Vector(sv, "2") assert (sv.length == 2) sv = lal.AppendString2Vector(sv, "3") assert (sv.length == 3) sv2 = lal.AppendString2Vector(sv, "4") assert (sv.length == 4) assert (sv2.length == 4) assert (sv == sv2) del sv del sv2 lal.CheckMemoryLeaks() ts = lal.CreateREAL8TimeSeries("ts", 800000000, 100, 0.1, lal.HertzUnit, 10) assert (ts.data.length == 10) lal.ResizeREAL8TimeSeries(ts, 0, 20) assert (ts.data.length == 20) ts = lal.ResizeREAL8TimeSeries(ts, 0, 30) assert (ts.data.length == 30) ts2 = lal.ResizeREAL8TimeSeries(ts, 0, 40) assert (ts.data.length == 40) assert (ts2.data.length == 40) assert (ts == ts2) del ts del ts2 lal.CheckMemoryLeaks() print("PASSED equal return/first argument type handling") # check string conversions print("checking string conversions ...") strs = ["a", "bc", "def"]
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
T_est = P.deltaT * lalsimutils.nextPow2(T_est / P.deltaT) if T_est < opts.seglen: T_est = opts.seglen P.deltaF = 1. / T_est print(" Duration ", T_est) if T_est < opts.seglen: print(" Buffer length too short, automating retuning forced ") # Generate signal hoft = lalsimutils.hoft( P ) # include translation of source, but NOT interpolation onto regular time grid # zero pad to be opts.seglen long, if necessary if opts.seglen / hoft.deltaT > hoft.data.length: TDlenGoal = int(opts.seglen / hoft.deltaT) hoft = lal.ResizeREAL8TimeSeries(hoft, 0, TDlenGoal) # zero pad some more on either side, to make sure the segment covers start to stop if opts.start and hoft.epoch > opts.start: nToAddBefore = int((float(hoft.epoch) - opts.start) / hoft.deltaT) # hoft.epoch - nToAddBefore*hoft.deltaT # this is close to the epoch, but not quite ... we are adjusting it to be within 1 time sample print(nToAddBefore, hoft.data.length) ht = lal.CreateREAL8TimeSeries("Template h(t)", opts.start, 0, hoft.deltaT, lalsimutils.lsu_DimensionlessUnit, hoft.data.length + nToAddBefore) ht.data.data = np.zeros(ht.data.length) # clear ht.data.data[nToAddBefore:nToAddBefore + hoft.data.length] = hoft.data.data hoft = ht if opts.stop and hoft.epoch + hoft.data.length * hoft.deltaT < opts.stop: nToAddAtEnd = int(
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", epoch = h_wnb.epoch, f0 = 0, deltaF = deltaF, sampleUnits = lal.lalDimensionlessUnit, length = h_wnb.data.length/2 + 1
def _compute_waveform(self, df, f_final): # Time domain, so compute then FFT # need to compute dt from df, duration sample_rate = 2**np.ceil(np.log2(2 * f_final)) dt = 1. / sample_rate # Generate waveform in time domain hplus, hcross = lalsim.SimInspiralSpinTaylorT4( 0, # GW phase at reference freq (rad) 1, # tail gauge term (default = 1) dt, # sampling interval (s) self.m1 * lal.MSUN_SI, # mass of companion 1 (kg) self.m2 * lal.MSUN_SI, # mass of companion 2 (kg) self.bank.flow, # start GW frequency (Hz) self.bank. flow, # reference GW frequency at which phase is set (Hz) 1e6 * PC_SI, # distance of source (m) self.s1x, # initial value of S1x self.s1y, # initial value of S1y self.s1z, # initial value of S1z self.s2x, # initial value of S2x self.s2y, # initial value of S2y self.s2z, # initial value of S2z np.sin(self.inclination), # initial value of LNhatx 0, # initial value of LNhaty np.cos(self.inclination), # initial value of LNhatz np.cos(self.inclination), # initial value of E1x 0, # initial value of E1y -np.sin(self.inclination), # initial value of E1z 0, # tidal deformability of mass 1 0, # tidal deformability of mass 2 1, # phenom. parameter describing induced quad. moment of body 1 (=1 for BHs, ~2-12 for NSs) 1, # phenom. parameter describing induced quad. moment of body 2 (=1 for BHs, ~2-12 for NSs) 7, # twice PN spin order 0, # twice PN tidal order 7, # twice PN phase order 0 # twice PN amplitude order ) # project onto detector hoft = project_hplus_hcross(hplus, hcross, self.theta, self.phi, self.psi) # zero-pad up to 1/df N = ceil_pow_2(int(sample_rate / df)) hoft = lal.ResizeREAL8TimeSeries(hoft, 0, N) # taper lalsim.SimInspiralREAL8WaveTaper(hoft.data, lalsim.SIM_INSPIRAL_TAPER_STARTEND) # create vector to hold output and plan htilde = lal.CreateCOMPLEX16FrequencySeries("h(f)", hoft.epoch, hoft.f0, df, lal.HertzUnit, int(N / 2 + 1)) fftplan = lal.CreateForwardREAL8FFTPlan(N, 0) # do the fft lal.REAL8TimeFreqFFT(htilde, hoft, fftplan) return htilde