def _lalsim_fd_waveform(**p): flags = lalsimulation.SimInspiralCreateWaveformFlags() lalsimulation.SimInspiralSetSpinOrder(flags, p['spin_order']) lalsimulation.SimInspiralSetTidalOrder(flags, p['tidal_order']) hp1, hc1 = lalsimulation.SimInspiralChooseFDWaveform( float(p['coa_phase']), p['delta_f'], float(pnutils.solar_mass_to_kg(p['mass1'])), float(pnutils.solar_mass_to_kg(p['mass2'])), float(p['spin1x']), float(p['spin1y']), float(p['spin1z']), float(p['spin2x']), float(p['spin2y']), float(p['spin2z']), float(p['f_lower']), float(p['f_final']), float(p['f_ref']), pnutils.megaparsecs_to_meters(float(p['distance'])), float(p['inclination']), float(p['lambda1']), float(p['lambda2']), flags, None, int(p['amplitude_order']), int(p['phase_order']), _lalsim_enum[p['approximant']]) hp = FrequencySeries(hp1.data.data[:], delta_f=hp1.deltaF, epoch=hp1.epoch) hc = FrequencySeries(hc1.data.data[:], delta_f=hc1.deltaF, epoch=hc1.epoch) return hp, hc
def get_htildas(m1,m2,dist, phase=0., df=1e-2, s1x=0.0, s1y=0.0, s1z=0.0, s2x=0.0, s2y=0.0, s2z=0.0, fmin=1., fmax=0., fref=1., iota=0., longAscNodes=0., eccentricity=0., meanPerAno=0., LALpars=None, approx=ls.IMRPhenomD ): #hplus_tilda, hcross_tilda = ls.SimInspiralChooseFDWaveform(phase, df, m1*lal.MSUN_SI, m2*lal.MSUN_SI, s1x, s1y, s1z, s2x, s2y, s2z, fmin, fmax, fref, dist*(1E6 * ls.lal.PC_SI), iota, lambda1, lambda2, waveFlags, nonGRparams, amp_order, phase_order, approx) hplus_tilda, hcross_tilda = ls.SimInspiralChooseFDWaveform(m1*lal.MSUN_SI, m2*lal.MSUN_SI, s1x, s1y, s1z, s2x, s2y, s2z, dist*(1E6 * ls.lal.PC_SI),iota,phase, longAscNodes,eccentricity,meanPerAno,df,fmin, fmax, fref,LALpars,approx) freqs=array([hplus_tilda.f0+i*hplus_tilda.deltaF for i in arange(hplus_tilda.data.length)]) return hplus_tilda.data.data,hcross_tilda.data.data,freqs
def _compute_waveform(self, df, f_final): phi0 = 0 # This is a reference phase, and not an intrinsic parameter approx = lalsim.GetApproximantFromString(self.approximant) if lalsim.SimInspiralImplementedFDApproximants(approx): hplus_fd, hcross_fd = lalsim.SimInspiralChooseFDWaveform( self.m1 * MSUN_SI, self.m2 * MSUN_SI, 0., 0., self.spin1z, 0., 0., self.spin2z, 1e6*PC_SI, 0., 0., 0., 0., 0., df, self.flow, f_final, self.flow, None, approx) else: hplus_fd, hcross_fd = lalsim.SimInspiralFD( phi0, df, self.m1*MSUN_SI, self.m2*MSUN_SI, 0, 0, self.spin1z, 0, 0, self.spin2z, 1.e6*PC_SI, 0., 0., 0., 0., 0., df, self.flow, f_final, 40., None, approx) return hplus_fd
def compute_modulus_quad(paramspoint, known_quad_bases, distance, deltaF, f_min, f_max, approximant): waveFlags = lal.CreateDict() m1, m2 = get_m1m2_from_mcq(paramspoint[0], paramspoint[1]) s1x, s1y, s1z = spherical_to_cartesian(paramspoint[2:5]) s2x, s2y, s2z = spherical_to_cartesian(paramspoint[5:8]) iota = paramspoint[8] phiRef = paramspoint[9] ecc = 0 if len(paramspoint) == 11: ecc = paramspoint[10] if len(paramspoint) == 12: lambda1 = paramspoint[10] lambda2 = paramspoint[11] lalsimulation.SimInspiralWaveformParamsInsertTidalLambda1( waveFlags, lambda1) lalsimulation.SimInspiralWaveformParamsInsertTidalLambda2( waveFlags, lambda2) f_ref = 0 RA = 0 DEC = 0 psi = 0 phi = 0 m1 *= lal.lal.MSUN_SI m2 *= lal.lal.MSUN_SI [plus, cross] = lalsimulation.SimInspiralChooseFDWaveform( m1, m2, s1x, s1y, s1z, s2x, s2y, s2z, distance, iota, phiRef, 0, ecc, 0, deltaF, f_min, f_max, f_ref, waveFlags, approximant) hp_tmp = plus.data.data[numpy.int(f_min / deltaF):numpy.int( f_max / deltaF)] # data_tmp is hplus and is a complex vector hp_quad_tmp = (numpy.absolute(hp_tmp))**2 residual = hp_quad_tmp for k in numpy.arange(0, len(known_quad_bases)): residual -= proj(known_quad_bases[k], hp_quad_tmp) modulus = numpy.sqrt(numpy.vdot(residual, residual)) return modulus
def generate_LAL_FDwaveform(approximant, q, chiA0, chiB0, df, M, \ dist_mpc, f_min, f_max, f_ref, inclination=0, phi_ref=0., ellMax=None, \ single_mode=None): distance = dist_mpc * 1.0e6 * PC_SI approxTag = lalsim.SimInspiralGetApproximantFromString(approximant) # component masses of the binary m1_kg = M * MSUN_SI * q / (1. + q) m2_kg = M * MSUN_SI / (1. + q) if single_mode is not None and ellMax is not None: raise Exception("Specify only one of single_mode or ellMax") dictParams = lal.CreateDict() # If ellMax, load all modes with ell<=ellMax if ellMax is not None: ma = lalsim.SimInspiralCreateModeArray() for ell in range(2, ellMax + 1): lalsim.SimInspiralModeArrayActivateAllModesAtL(ma, ell) lalsim.SimInspiralWaveformParamsInsertModeArray(dictParams, ma) elif single_mode is not None: # If a single_mode is given, load only that mode (l,m) and (l,-m) dictParams = set_single_mode(dictParams, single_mode[0], single_mode[1]) hp, hc = lalsim.SimInspiralChooseFDWaveform(\ m1_kg, m2_kg, chiA0[0], chiA0[1], chiA0[2], \ chiB0[0], chiB0[1], chiB0[2], \ distance, inclination, phi_ref, 0, 0, 0,\ df, f_min, f_max, f_ref, dictParams, approxTag) h = np.array(hp.data.data - 1.j * hc.data.data) f = np.arange(f_min, f_min + df * len(h), df) return f, h
def gen_bbh(fs, T_obs, psds, dets=['H1'], beta=[0.75, 0.95], par=None, gw_tmp=False): """ generates a BBH timedomain signal Parameters ---------- fs: sampling frequency T_obs: observation time window psds: power spectral desnity to use dets: detector beta: fractional range of time series to place peak signals par: class containing parameters of waveform to generate gw_tmp: if True: make a template exactly like event to do PE on Returns ------- ts: h-plus and h-cross combined GW time series waveform hp: h-plus GW time series waveform hc: h-cross GW time series waveform ts: this is redundant. need to remove """ N = T_obs * fs # the total number of time samples dt = 1 / fs # time resolution (sec) f_low = 40 # lowest frequency of waveform (Hz) amplitude_order = 0 # amplitude order phase_order = 7 # phase order f_max = fs / 2 # maximum allowed frequency for FD waveforms approximant = lalsimulation.IMRPhenomPv2 # waveform approximant dist = 410e6 * lal.PC_SI # waveform distance # if making event-like template, then fix distance if gw_tmp: dist = 410e6 * lal.PC_SI # make waveform hp, hc = lalsimulation.SimInspiralChooseFDWaveform( par.m1 * lal.MSUN_SI, par.m2 * lal.MSUN_SI, 0, 0, 0, 0, 0, 0, dist, par.iota, par.phi, 0, 0, 0, 1 / T_obs, f_low, f_max, f_low, lal.CreateDict(), approximant) whiten_hp = whiten_data(hp.data.data, T_obs, fs, psds, flag='fd') whiten_hc = whiten_data(hc.data.data, T_obs, fs, psds, flag='fd') orig_hp = np.roll(np.fft.irfft(whiten_hp, T_obs * fs), int(-fs)) orig_hc = np.roll(np.fft.irfft(whiten_hc, T_obs * fs), int(-fs)) # transform back into time domain in upcoming sections # compute reference idx ref_idx = np.argmax(orig_hp**2 + orig_hc**2) # the start index of the central region sidx = int(0.5 * fs * T_obs * (safe - 1.0) / safe) # make aggressive window to cut out signal in central region # window is non-flat for 1/8 of desired Tobs # the window has dropped to 50% at the Tobs boundaries win = np.zeros(N) tempwin = tukey(int((16.0 / 15.0) * N / safe), alpha=1.0 / 8.0) win[int((N - tempwin.size) / 2):int((N - tempwin.size) / 2) + tempwin.size] = tempwin # loop over detectors ndet = 1 ts = np.zeros((ndet, N)) hp = np.zeros((ndet, N)) hc = np.zeros((ndet, N)) intsnr = [] j = 0 for det in dets: # make signal - apply antenna and shifts ht_shift, hp_shift, hc_shift = make_bbh(orig_hp, orig_hc, fs, par.ra, par.dec, par.psi, det) # place signal into timeseries - including shift ht_temp = ht_shift[int(ref_idx - par.idx - 11):] # use 21 if sampling at 2kHz hp_temp = hp_shift[int(ref_idx - par.idx - 11):] # use 21 if sampling at 2kHz hc_temp = hc_shift[int(ref_idx - par.idx - 11):] # use 21 if sampling at 2kHz if len(ht_temp) < N: ts[j, :len(ht_temp)] = ht_temp hp[j, :len(ht_temp)] = hp_temp hc[j, :len(ht_temp)] = hc_temp else: ts[j, :] = ht_temp[:N] hp[j, :] = hp_temp[:N] hc[j, :] = hc_temp[:N] # apply aggressive window to cut out signal in central region # window is non-flat for 1/8 of desired Tobs # the window has dropped to 50% at the Tobs boundaries ts[j, :] *= win hp[j, :] *= win hc[j, :] *= win return ts, hp, hc, ts
def create_dataset_FD(N_data, N_grid=None, filename=None, q_range=(1., 5.), m2_range=20., s1_range=(-0.8, 0.8), s2_range=(-0.8, 0.8), log_space=True, f_high=2000, f_step=1e-2, f_max=None, f_min=None, approximant="IMRPhenomPv2"): """ Create a dataset for training a ML model to fit GW waveforms in frequency domain. The dataset consists in 3 parameters theta=(q, spin1z, spin2z) associated to the waveform computed in frequency domain for a grid of N_grid points in the range given by the user. More specifically, data are stored in 3 vectors: theta_vector vector holding source parameters q, spin1, spin2 amp_vector vector holding amplitudes for each source evaluated at some N_grid equally spaced points ph_vector vector holding phase for each source evaluated at some N_grid equally spaced points This routine add N_data data to filename if one is specified (if file is not empty it must contain data with the same N_grid); otherwise the datasets are returned as np vectors. All the waves are evaluated at a constant distance of 1Mpc. Values of q and m2 are drawn randomly in the range given by the user: it holds m1 = q *m2 M_sun. The waveforms are computed from f_low = 15 to f_high with a step f_step and then evaluated at some N_grid grid points equally spaced in range [f_min, f_max] Dataset can be loaded with load_dataset Input: N_data size of dataset N_grid number of points to be sampled in the grid (if None every point generated is saved) filename name of the file to save dataset in (If is None, nothing is saved on a file) q_range tuple with range for random q values. if single value, q is kept fixed at that value m2_range tuple with range for random m2 values. if single value, m2 is kept fixed at that value spin_mag_max_1 tuple with range for random spin #1 values. if single value, s1 is kept fixed at that value spin_mag_max_2 tuple with range for random spin #1 values. if single value, s2 is kept fixed at that value log_space whether grid should be computed in logspace f_high highest frequency to compute f_step step considered for computation of waveforms f_max maximum frequency returned to the user (if None is the same as f_max) f_min minimum frequency returned to the user (if None is the same as f_low = 15) approximant string for the approximant model to be used (in lal convention) Output: if filename is given None if filename is not given theta_vector (N_data,3) vector holding ordered set of parameters used to generate amp_dataset and ph_dataset amp_dataset (N_data,N_grid) dataset with amplitudes ph_dataset (N_data,N_grid) dataset with phases frequencies (N_grid,) vector holding frequencies at which waves are evaluated """ if f_max is None: f_max = f_high if f_min is None: f_min = 1. f_low = f_min K = int( (f_max - f_min) / f_step) #number of data points to be taken from the returned vector if N_grid is None: N_grid = K full_freq = np.arange(f_low, f_max, f_step) #full frequency vector as returned by lal d = 1. LALpars = lal.CreateDict() approx = lalsim.SimInspiralGetApproximantFromString(approximant) #allocating storage for temp vectors to save a single WF temp_amp = np.zeros((N_grid, )) temp_ph = np.zeros((N_grid, )) temp_theta = np.zeros((3, )) #setting frequencies to be returned to user if log_space: frequencies = np.logspace(np.log10(f_min), np.log10(f_max), N_grid) else: frequencies = np.linspace(f_min, f_max, N_grid) #freq_to_choose = np.arange(0, K, K/N_grid).astype(int) #choosing proper indices s.t. dataset holds N_grid points #frequencies = full_freq[freq_to_choose] #setting only frequencies to be chosen if filename is not None: #doing header if file is empty - nothing otherwise if not os.path.isfile( filename ): #file doesn't exist: must be created with proper header filebuff = open(filename, 'w') print("New file ", filename, " created") freq_header = np.concatenate((np.zeros( (3, )), frequencies, frequencies)) freq_header = np.reshape(freq_header, (1, len(freq_header))) np.savetxt( filebuff, freq_header, header="# row: theta 3 | amp " + str(frequencies.shape[0]) + "| ph " + str(frequencies.shape[0]) + "\n# N_grid = " + str(N_grid) + " | f_step =" + str(f_step) + " | q_range = " + str(q_range) + " | s1_range = " + str(s1_range) + " | s2_range = " + str(s2_range), newline='\n') else: filebuff = open(filename, 'a') if filename is None: amp_dataset = np.zeros( (N_data, N_grid)) #allocating storage for returning data ph_dataset = np.zeros((N_data, N_grid)) theta_vector = np.zeros((N_data, 3)) for i in range(N_data): #loop on data to be created if i % 100 == 0 and i != 0: print("Generated WF ", i) #setting value for data if isinstance(m2_range, tuple): m2 = np.random.uniform(m2_range[0], m2_range[1]) else: m2 = m2_range if isinstance(q_range, tuple): m1 = np.random.uniform(q_range[0], q_range[1]) * m2 else: m1 = q_range * m2 if isinstance(s1_range, tuple): spin1z = np.random.uniform(s1_range[0], s1_range[1]) else: spin1z = s1_range if isinstance(s2_range, tuple): spin2z = np.random.uniform(s2_range[0], s2_range[1]) else: spin2z = s2_range #debug!!! if m1 / m2 > 4.6 and (np.abs(spin1z) > 0.8 or np.abs(spin2z) > 0.8): continue #getting the wave hptilde, hctilde = lalsim.SimInspiralChooseFDWaveform( #where is its definition and documentation???? m1 * lalsim.lal.MSUN_SI, #m1 m2 * lalsim.lal.MSUN_SI, #m2 0., 0., spin1z, #spin vector 1 0., 0., spin2z, #spin vector 2 d * 1e6 * lalsim.lal.PC_SI, #distance to source 0., #inclination 0., #phi ref 0., #longAscNodes (for precession) 0., #eccentricity 0., #meanPerAno (for precession) f_step, # frequency incremental step f_low, # lowest value of frequency f_high, # highest value of frequency f_low, #some reference value of frequency (??) LALpars, #some lal dictionary approx #approx method for the model ) h = np.array(hptilde.data.data) + 1j * np.array( hctilde.data.data) #complex waveform temp_theta = [m1 / m2, spin1z, spin2z] temp_amp = (np.abs(h)[int(f_min / f_step):int(f_max / f_step)].real) temp_ph = (np.unwrap( np.angle(h))[int(f_min / f_step):int(f_max / f_step)].real) #bringing waves on the chosen grid temp_amp = np.interp(frequencies, full_freq, temp_amp) temp_ph = np.interp(frequencies, full_freq, temp_ph) #temp_ph = temp_ph[freq_to_choose]; temp_amp = temp_amp[freq_to_choose] #old version of code temp_ph = temp_ph - temp_ph[ 0] #all frequencies are shifted by a constant to make the wave start at zero phase!!!! IMPORTANT #removing spourious gaps (if present) (index, ) = np.where( temp_amp / temp_amp[0] < 5e-3) #there should be a way to choose right threshold... if len(index) > 0: temp_ph[index] = temp_ph[index[0] - 1] if filename is None: amp_dataset[ i, :] = temp_amp #putting waveform in the dataset to return ph_dataset[i, :] = temp_ph #phase theta_vector[i, :] = temp_theta if filename is not None: #saving to file to_save = np.concatenate((temp_theta, temp_amp, temp_ph)) to_save = np.reshape(to_save, (1, len(to_save))) np.savetxt(filebuff, to_save) if filename is None: return theta_vector, amp_dataset.real, ph_dataset.real, frequencies else: filebuff.close() return None
def make_FDwaveform(paramdict): """Generate FD waveform from lal. Parameters ---------- paramdict: dictionary A dictionary with keys for the different parameters that go into ChooseFDWaveform M : scalar, mass in solar masses q : scalar, mass ratio chi1,chi2: aligned spins approximant_FD: approximant type deltaF: frequency spacing f_min: starting freq f_max: max freq Returns ------- f: array. Array of frequency points Hp: h plus array at frequencies in f Hc: h cross array at frequencies in f """ # define defaults defaultdict = dict() defaultdict['m1'] = 10. defaultdict['m2'] = 10. for key in [ 'phiRef', 'S1x', 'S1y', 'S1z', 'S2x', 'S2y', 'S2z', 'f_ref', 'z', 'i', 'lambda1', 'lambda2', 'longAscNodes', 'eccentricity', 'meanPerAno' ]: defaultdict[key] = 0.0 for key in ['waveFlags', 'nonGRparams', 'LALpars']: defaultdict[key] = None defaultdict['r'] = 1e6 * lal.PC_SI defaultdict['amplitudeO'] = -1 defaultdict['phaseO'] = -1 defaultdict['f_min'] = 40. defaultdict['f_max'] = 4098. defaultdict['deltaF'] = 0.5 defaultdict['approximant_FD'] = LS.IMRPhenomD # update defaults with what is in paramdict for key in paramdict.keys(): defaultdict[key] = paramdict[key] # turn dictionary keys into variable names: for k, v in defaultdict.items(): exec(k + '=v') m1_SI = m1 * lal.MSUN_SI m2_SI = m2 * lal.MSUN_SI try: # old call signature for lalsimulation waveforms Hp, Hc = LS.SimInspiralChooseFDWaveform(phiRef, deltaF, m1_SI, m2_SI, S1x, S1y, S1z, S2x, S2y, S2z, f_min, f_max, f_ref, r, i, lambda1, lambda2, waveFlags, nonGRparams, amplitudeO, phaseO, approximant_FD) print 'using old lalsimulation waveform signature' except TypeError: # newer call signature for lalsimulation waveforms includes parameters for eccentricity Hp, Hc = LS.SimInspiralChooseFDWaveform(m1_SI, m2_SI, S1x, S1y, S1z, S2x, S2y, S2z, r, i, phiRef, longAscNodes, eccentricity, meanPerAno, deltaF, f_min, f_max, f_ref, LALpars, approximant_FD) f = np.arange(Hp.data.length) * deltaF n = len(f) return f, Hp.data.data, Hc.data.data
def __init__(self, mass1, mass2, S, f_low, approximant, amplitude_order, phase_order): """Create a TaylorF2 signal model with the given masses, PSD function S(f), PN amplitude order, and low-frequency cutoff.""" if approximant in (lalsimulation.TaylorF2, lalsimulation.SpinTaylorT4Fourier, lalsimulation.SpinTaylorT2Fourier): # Frequency-domain post-Newtonian inspiral waveform. h, _ = lalsimulation.SimInspiralChooseFDWaveform( phiRef=0, deltaF=1, m1=mass1 * lal.MSUN_SI, m2=mass2 * lal.MSUN_SI, S1x=0, S1y=0, S1z=0, S2x=0, S2y=0, S2z=0, f_min=f_low, f_max=0, f_ref=0, r=1e6 * lal.PC_SI, i=0, lambda1=0, lambda2=0, waveFlags=None, nonGRparams=None, amplitudeO=amplitude_order, phaseO=0, approximant=approximant) # Find indices of first and last nonzero samples. nonzero = np.nonzero(h.data.data)[0] first_nonzero = nonzero[0] last_nonzero = nonzero[-1] elif approximant == lalsimulation.TaylorT4: # Time-domain post-Newtonian inspiral waveform. hplus, hcross = lalsimulation.SimInspiralChooseTDWaveform( phiRef=0, deltaT=1 / 4096, m1=mass1 * lal.MSUN_SI, m2=mass2 * lal.MSUN_SI, s1x=0, s1y=0, s1z=0, s2x=0, s2y=0, s2z=0, f_min=f_low, f_ref=f_low, r=1e6 * lal.PC_SI, i=0, lambda1=0, lambda2=0, waveFlags=None, nonGRparams=None, amplitudeO=amplitude_order, phaseO=phase_order, approximant=approximant) hplus.data.data += hcross.data.data hplus.data.data /= np.sqrt(2) h = lal.CreateCOMPLEX16FrequencySeries( None, lal.LIGOTimeGPS(0), 0, 0, lal.DimensionlessUnit, len(hplus.data.data) // 2 + 1) plan = CreateForwardREAL8FFTPlan(len(hplus.data.data), 0) lal.REAL8TimeFreqFFT(h, hplus, plan) f = h.f0 + len(h.data.data) * h.deltaF first_nonzero = long(np.floor((f_low - h.f0) / h.deltaF)) last_nonzero = long(np.ceil((2048 - h.f0) / h.deltaF)) last_nonzero = min(last_nonzero, len(h.data.data) - 1) else: raise ValueError("unrecognized approximant") # Frequency sample points self.dw = 2 * np.pi * h.deltaF f = h.f0 + h.deltaF * np.arange(first_nonzero, last_nonzero + 1) self.w = 2 * np.pi * f # Throw away leading and trailing zeros. h = h.data.data[first_nonzero:last_nonzero + 1] self.denom_integrand = 4 / (2 * np.pi) * (np.square(h.real) + np.square(h.imag)) / S(f) self.den = np.trapz(self.denom_integrand, dx=self.dw)
duration = lalsimulation.SimInspiralTaylorF2ReducedSpinChirpTime( 10, mass1*lal.MSUN_SI, mass2*lal.MSUN_SI, 0, lalsimulation.PNORDER_THREE_POINT_FIVE) duration = int(np.ceil(filter.ceil_pow_2(duration))) sample_rate = 16384 nsamples = duration * sample_rate nsamples_fft = nsamples//2 + 1 af = lal.CreateCOMPLEX16Vector(nsamples) f = np.arange(nsamples) / duration hplus, hcross = lalsimulation.SimInspiralChooseFDWaveform( 0, 1/duration, mass1*lal.MSUN_SI, mass2*lal.MSUN_SI, 0, 0, 0, 0, 0, 0, 9, 0, 40, 500 * lal.PC_SI, 0, 0, 0, None, None, lalsimulation.PNORDER_THREE_POINT_FIVE, lalsimulation.PNORDER_NEWTONIAN, lalsimulation.TaylorF2) af.data[:len(hplus.data.data)] = abs2(hplus.data.data + 1j * hcross.data.data) af.data[len(hplus.data.data):] = 0 af.data[0] = 0 af.data[1:len(hplus.data.data)] /= S(f[1:len(hplus.data.data)]) a = lal.CreateCOMPLEX16Vector(nsamples) plan = lal.CreateReverseCOMPLEX16FFTPlan(nsamples, 0) lal.COMPLEX16VectorFFT(a, af, plan) a = a.data
def autocorrelation(mass1, mass2, S, f_low, out_duration, approximant, amplitude_order, phase_order): """ Calculate the complex autocorrelation sequence a(t), for t >= 0, of an inspiral signal. Parameters ---------- mass1 : float Mass of component 1 (solar masses). mass2 : float Mass of component 1 (solar masses). S : callable Noise power spectral density function. f_low : float Low frequency cutoff (Hz). out_duration : float Compute the autocorrelation function from time t=0 to t=output_duration. approximant : int Post-Newtonian approximant (e.g. lalsimulation.TaylorF2). amplitude_order : int Twice the post-Newtonian amplitude order (e.g. 3). phase_order : int Twice the post-Newtonian phase order (e.g. 3). Returns ------- acor : `numpy.ndarray` The complex-valued autocorrelation sequence. sample_rate : float Sample rate in Hz. """ # Compute duration of template, rounded up to a power of 2. duration = ceil_pow_2( lalsimulation.SimInspiralTaylorF2ReducedSpinChirpTime( f_low, mass1 * lal.MSUN_SI, mass2 * lal.MSUN_SI, 0, phase_order)) # Evaluate waveform. Terminates at ISCO. hplus, hcross = lalsimulation.SimInspiralChooseFDWaveform( 0, 1 / duration, mass1 * lal.MSUN_SI, mass2 * lal.MSUN_SI, 0, 0, 0, 0, 0, 0, f_low, 0, 0, 1e6 * lal.PC_SI, 0, 0, 0, None, None, amplitude_order, phase_order, approximant) # Force `plus' and `cross' waveform to be in quadrature. h = 0.5 * (hplus.data.data + 1j * hcross.data.data) # Determine length of IFFT; round up to a power of 2. nsamples = 2 * int(ceil_pow_2(len(h))) # Compute autopower spectral density. power = np.empty(nsamples, dtype=hplus.data.data.dtype) power[0] = 0 f = np.arange(1, len(h)) / duration power[1:len(h)] = abs2(h[1:]) / S(f) power[len(h):] = 0 sample_rate = nsamples / duration # Determine length of output FFT. nsamples_out = int(np.ceil(out_duration * sample_rate)) acor = truncated_ifft(power, nsamples_out) acor /= np.abs(acor[0]) # If we have done this right, then the zeroth sample represents lag 0 assert np.argmax(np.abs(acor)) == 0 assert np.isreal(acor[0]) # Done! return acor, float(sample_rate)
def gen_waveform(freq, z=0, omega=OMEGA, **params): """Generate frequency-domain inspiral waveform `freq` should be an array of frequency points at which the waveform should be interpolated. Returns a tuple of (h_tilde^plus, h_tilde^cross) real-valued (amplitude only) arrays. The waveform is generated with lalsimulation.SimInspiralChooseFDWaveform(). Keyword arguments are used to update the default waveform parameters (1.4/1.4 Msolar, optimally-oriented, 100 Mpc, (see DEFAULT_PARAMS macro)). The mass parameters ('m1' and 'm2') should be specified in solar masses and the 'distance' parameter should be specified in parsecs**. Waveform approximants may be given as string names (see `lalsimulation` documentation for more info). If the approximant is not specified explicitly, DEFAULT_APPROXIMANT_BNS waveform will be used if either mass is less than 5 Msolar and DEFAULT_APPROXIMANT_BBH waveform will be used otherwise. If a redshift `z` is specified (with optional `omega`), it's equivalent distance will be used (ignoring any `distance` parameter provided) and the masses will be redshift-corrected appropriately. Otherwise no mass redshift correction will be applied. For example, to generate a 20/20 Msolar BBH waveform: >>> hp,hc = waveform.gen_waveform(freq, 'm1'=20, 'm2'=20) **NOTE: The requirement that masses are specified in solar masses and distances are specified in parsecs is different than that of the underlying lalsimulation method which expects mass and distance parameters to be in SI units. """ iparams = _get_waveform_params(**params) # if redshift specified use that as distance and correct # appropriately, ignoring any distance specified in params. if z != 0: iparams['distance'] = lal.LuminosityDistance(omega, z) * 1e6 iparams['m1'] *= 1.0 + z iparams['m2'] *= 1.0 + z # convert to SI units iparams['distance'] *= lal.PC_SI iparams['m1'] *= lal.MSUN_SI iparams['m2'] *= lal.MSUN_SI iparams['approximant'] = lalsimulation.SimInspiralGetApproximantFromString( iparams['approximant']) iparams['deltaF'] = freq[1] - freq[0] iparams['f_min'] = freq[0] # FIXME: the max frequency in the generated waveform is not always # greater than f_max, so as a workaround we generate over the full # band. Probably room for speedup here # iparams['f_max'] = freq[-1] iparams['f_max'] = 10000 # print(iparams) # logging.debug('waveform params = {}'.format(iparams)) # generate waveform h = lalsimulation.SimInspiralChooseFDWaveform(**iparams) # print(h) freq_h = h[0].f0 + np.arange(len(h[0].data.data)) * h[0].deltaF def interph(h): "interpolate amplitude of h array" # FIXME: this only interpolates/returns the amplitude, and not # the full complex data (throws out phase), because this was # not working: # hir = scipy.interpolate.interp1d(freq_h, np.real(h.data.data))(freq) # hii = scipy.interpolate.interp1d(freq_h, np.imag(h.data.data))(freq) # return hir + 1j * hii return scipy.interpolate.interp1d(freq_h, np.absolute(h.data.data))(freq) hi = map(interph, h) return hi
def make_FDwaveform(M, q, chi1, chi2, approximant_FD, deltaF=0.5, f_min=10, f_max=4096): """Generate FD waveform from lal. Parameters ---------- M : scalar, mass in solar masses q : scalar, mass ratio chi1,chi2: aligned spins approximant_FD: approximant type deltaF: frequency spacing f_min: starting freq f_max: max freq Returns ------- [frequency array, H plus] """ m1 = M * 1.0 / (1.0 + q) m2 = M * q / (1.0 + q) phiRef = 0.0 m1_SI = m1 * lal.MSUN_SI m2_SI = m2 * lal.MSUN_SI S1x = 0.0 S1y = 0.0 S1z = chi1 S2x = 0.0 S2y = 0.0 S2z = chi2 f_ref = 0.0 r = 1e6 * lal.PC_SI z = 0.0 i = 0.0 lambda1 = 0.0 lambda2 = 0.0 waveFlags = None nonGRparams = None amplitudeO = -1 phaseO = -1 # try: # # old call signature for lalsimulation waveforms # Hp, Hc = LS.SimInspiralChooseFDWaveform(phiRef, deltaF, m1_SI, m2_SI, S1x, S1y, S1z, S2x, S2y, S2z, # f_min, f_max, f_ref, r, i, lambda1, lambda2, waveFlags, nonGRparams, amplitudeO, phaseO, # approximant_FD) # print 'using old lalsimulation waveform signature' # except TypeError: # # newer call signature for lalsimulation waveforms includes parameters for eccentricity # longAscNodes, eccentricity, meanPerAno = 0.0, 0.0, 0.0 # # If we need extra parameters put them into the Dict; I assume we don't need anything special # LALpars = None # phaseO = None # Hp, Hc = LS.SimInspiralChooseFDWaveform(m1_SI, m2_SI, # S1x, S1y, S1z, S2x, S2y, S2z, # r, i, phiRef, # longAscNodes, eccentricity, meanPerAno, # deltaF, f_min, f_max, f_ref, # LALpars, # approximant_FD) # Hp, Hc = LS.SimInspiralChooseFDWaveform(phiRef, deltaF, m1_SI, m2_SI, S1x, S1y, S1z, S2x, S2y, S2z, f_min, f_max, f_ref, r, i, lambda1, lambda2, waveFlags, nonGRparams, amplitudeO, phaseO, approximant_FD) f = np.arange(Hp.data.length) * deltaF n = len(f) return [f, Hp.data.data]
LALpars = lal.CreateDict() approx = lalsim.SimInspiralGetApproximantFromString('IMRPhenomD') print(approx) hptilde, hctilde = lalsim.SimInspiralChooseFDWaveform( m1 * lalsim.lal.MSUN_SI, m2 * lalsim.lal.MSUN_SI, 0, 0, spin1z, 0, 0, spin2z, d * 1e6 * lalsim.lal.PC_SI, 0, 0, 0, #longAscNodes 0, #eccentricity 0, #meanPerAno 1 / 16, 10, 2048, #4096, 30, LALpars, approx) print(hptilde.data.data.shape, (2048) / 0.1) hptilde2, hctilde2 = lalsim.SimInspiralChooseFDWaveform( m1 * lalsim.lal.MSUN_SI,
def test_taylorf2_array(): cl_context, cl_device, cl_queue = bagwacl_init() tf2_kernels, BAGWACLTaylorF2Params_new, _ = taylorf2.init_kernels( cl_context, cl_device) ## generate multiple waveforms and test each one against LAL/CPU code... nwaveforms = 100 params = [] h_vecarray_cpu = [] # Other IFO data params psdstart = 0 psdlength = 120000 trigtime = 6000 seglen = 10. srate = 4096. cbc_params_lst = [] for i in xrange(nwaveforms): cbc_params = lalsupport.sample_cbc_params_from_prior() cbc_params_lst.append(cbc_params) li_cbc_params = lalsupport.create_livariables_from_cbc_params( cbc_params) params.append(BAGWACLTaylorF2Params_new()) (fStart, fEnd, deltaF) = t2_wfm_params_init(seglen, srate) #(phic,deltaF,m1_SI,m2_SI,S1z,S2z,fStart,fEnd,distance_SI,lambda1,lambda2,spinO,tidalO,phaseO,amplitudeO)=generate_random_wfm_params() taylorf2.tf2_pn_params_init( params[i], cbc_params.phase, deltaF, cbc_params.mass1 * LAL_MSUN_SI, cbc_params.mass2 * LAL_MSUN_SI, cbc_params.S1z, cbc_params.S2z, fStart, fEnd, cbc_params.distance * LAL_PC_SI * 1e6, cbc_params.lambda1, cbc_params.lambda2, cbc_params.spinO, cbc_params.tidalO, cbc_params.LAL_PNORDER, cbc_params.LAL_AMPORDER, ) # Fake some interferometer data #ifos=[ #['H1','LALSimAdLIGO',fStart,'DUMMY'], #] #data=lalsupport.generate_ifoData( #ifos, #psdstart, #psdlength, #seglen, #trigtime, #srate=4096., #) #lalsupport.init_ifoData(data) #data.modelParams=li_cbc_params # Call equivalent LALSimulation/Inference CPU-only function #lalinference.TemplateXLALSimInspiralChooseWaveform(data) waveFlags = lalsimulation.SimInspiralCreateWaveformFlags() lalsimulation.SimInspiralSetSpinOrder( waveFlags, lalsimulation.LAL_SIM_INSPIRAL_SPINLESS) lalsimulation.SimInspiralSetTidalOrder( waveFlags, lalsimulation.LAL_SIM_INSPIRAL_TIDAL_ORDER_0PN) h_vec_cpu, _ = lalsimulation.SimInspiralChooseFDWaveform( cbc_params.phase, deltaF, cbc_params.mass1 * LAL_MSUN_SI, cbc_params.mass2 * LAL_MSUN_SI, cbc_params.S1x, cbc_params.S1y, cbc_params.S1z, cbc_params.S2x, cbc_params.S2y, cbc_params.S2z, fStart, fEnd, cbc_params.distance * LAL_PC_SI * 1e6, cbc_params.inclination, cbc_params.lambda1, cbc_params.lambda2, waveFlags, None, cbc_params.LAL_AMPORDER, cbc_params.LAL_PNORDER, cbc_params.LAL_APPROXIMANT, ) # Extract output complex strain vector from LALSimulation output h_vecarray_cpu.append(h_vec_cpu.data.data) length = int(params[0]['n'][0]) params = np.array(params, dtype=params[0].dtype) mem_pool = cl_tools.MemoryPool( cl_tools.ImmediateAllocator(cl_queue, cl.mem_flags.READ_ONLY)) params_cl = cl.array.to_device(cl_queue, params) hTilde_vecarray_cl = cl.array.zeros(cl_queue, (length * nwaveforms), np.complex128) tf2_kernels.BAGWACLTaylorF2threePointFivePN_array.set_scalar_arg_dtypes([ None, None, np.int32, ]) tf2_kernels.BAGWACLTaylorF2threePointFivePN_array( cl_queue, ( length, nwaveforms, ), None, hTilde_vecarray_cl.data, params_cl.data, np.int32(0), ) h_vecarray_gpu = hTilde_vecarray_cl.get() np.savetxt( 'htilde_gpu.dat', lalsupport.convert_bagwacl_templates_to_lal_templates( h_vecarray_gpu[0:length], cbc_params_lst[-1].inclination)[0]) np.savetxt('htilde_cpu.dat', h_vecarray_cpu[0]) failure_count = 0 for i, h_vec_cpu in enumerate(h_vecarray_cpu): h_vec_gpu, _ = lalsupport.convert_bagwacl_templates_to_lal_templates( h_vecarray_gpu[i * length:(i + 1) * length], cbc_params_lst[0].inclination) try: assert np.allclose(h_vec_cpu, h_vec_gpu, atol=0., rtol=1e-6) except AssertionError: failure_count += 1 print "Failure count is", failure_count
def get_waveform(approximant, phase_order, amplitude_order, spin_order, template_params, start_frequency, sample_rate, length, datafile=None, verbose=False): #{{{ print("IN hERE") delta_t = 1. / sample_rate delta_f = 1. / length filter_N = int(length) filter_n = filter_N / 2 + 1 if approximant in fd_approximants() and 'Eccentric' not in approximant: print("NORMAL FD WAVEFORM for", approximant) delta_f = sample_rate / length hplus, hcross = get_fd_waveform(template_params, approximant=approximant, spin_order=spin_order, phase_order=phase_order, delta_f=delta_f, f_lower=start_frequency, amplitude_order=amplitude_order) elif approximant in td_approximants() and 'Eccentric' not in approximant: print("NORMAL TD WAVEFORM for", approximant) hplus, hcross = get_td_waveform(template_params, approximant=approximant, spin_order=spin_order, phase_order=phase_order, delta_t=1.0 / sample_rate, f_lower=start_frequency, amplitude_order=amplitude_order) elif 'EccentricIMR' in approximant: #{{{ # Legacy support import sys sys.path.append('/home/kuma/grav/kuma/src/Eccentric_IMR/Codes/Python/') import EccentricIMR as Ecc try: mass1 = getattr(template_params, 'mass1') mass2 = getattr(template_params, 'mass2') except: raise RuntimeError("template_params does not have mass1 or mass2!") try: ecc = getattr(template_params, 'alpha1') if 'E0' in approximant: ecc = 0 anom = getattr(template_params, 'alpha2') inc = getattr(template_params, 'inclination') rtrans = getattr(template_params, 'alpha') beta = 0 except: raise RuntimeError(\ "template_params does not have alpha{,1,2} or inclination") tol = 1.e-16 fmin = start_frequency sample_rate = sample_rate # print(" Using phase order: %d" % phase_order, file=sys.stdout) sys.stdout.flush() hplus, hcross = Ecc.generate_eccentric_waveform(mass1, mass2,\ ecc, anom, inc, beta,\ tol,\ r_transition=rtrans,\ phase_order=phase_order,\ fmin=fmin,\ sample_rate=sample_rate,\ inspiral_only=False) #}}} elif 'EccentricInspiral' in approximant: #{{{ # Legacy support import sys sys.path.append('/home/kuma/grav/kuma/src/Eccentric_IMR/Codes/Python/') import EccentricIMR as Ecc try: mass1 = getattr(template_params, 'mass1') mass2 = getattr(template_params, 'mass2') except: raise RuntimeError("template_params does not have mass1 or mass2!") try: ecc = getattr(template_params, 'alpha1') if 'E0' in approximant: ecc = 0 anom = getattr(template_params, 'alpha2') inc = getattr(template_params, 'inclination') beta = getattr(template_params, 'alpha') except: raise RuntimeError(\ "template_params does not have alpha{,1,2} or inclination") tol = 1.e-16 fmin = start_frequency sample_rate = sample_rate # hplus, hcross = Ecc.generate_eccentric_waveform(mass1, mass2,\ ecc, anom, inc, beta,\ tol,\ phase_order=phase_order,\ fmin=fmin,\ sample_rate=sample_rate,\ inspiral_only=True) #}}} elif 'EccentricFD' in approximant: #{{{ # Legacy support import lalsimulation as ls import lal delta_f = sample_rate / length try: mass1 = getattr(template_params, 'mass1') mass2 = getattr(template_params, 'mass2') except: raise RuntimeError("template_params does not have mass1 or mass2!") try: ecc = getattr(template_params, 'alpha1') if 'E0' in approximant: ecc = 0 anom = getattr(template_params, 'alpha2') inc = getattr(template_params, 'inclination') except: raise RuntimeError(\ "template_params does not have alpha{1,2} or inclination") eccPar = ls.SimInspiralCreateTestGRParam("inclination_azimuth", inc) ls.SimInspiralAddTestGRParam(eccPar, "e_min", ecc) fmin = start_frequency fmax = sample_rate / 2 # thp, thc = ls.SimInspiralChooseFDWaveform(0, delta_f,\ mass1*lal.MSUN_SI, mass2*lal.MSUN_SI,\ 0,0,0,0,0,0,\ fmin, fmax, 0, 1.e6 * lal.PC_SI,\ inc, 0, 0, None, eccPar, -1, 7, ls.EccentricFD) hplus = FrequencySeries(thp.data.data[:], delta_f=thp.deltaF, epoch=thp.epoch) hcross = FrequencySeries(thc.data.data[:], delta_f=thc.deltaF, epoch=thc.epoch) #}}} elif 'FromDataFile' in approximant: #{{{ # Legacy support if not os.path.exists(datafile): raise IOError("File %s not found!" % datafile) if verbose: print("Reading from data file %s" % datafile) # Figure out waveform parameters from filename #q_value, M_value, w_value, _, _ = EA.get_q_m_e_pn_o_from_filename(datafile) q_value, M_value, w_value = EA.get_q_m_e_from_filename(datafile) # Read data, down-sample (assume data file is more finely sampled than # needed, i.e. interpolation is NOT supported, nor will be) data = np.loadtxt(datafile) dt = data[1, 0] - data[0, 0] delta_t = 1. / sample_rate downsample_ratio = delta_t / dt if not approx_equal(downsample_ratio, np.int(downsample_ratio)): raise RuntimeError( "Cannot handling resampling at a fractional factor = %e" % downsample_ratio) elif verbose: print("Downsampling by a factor of %d" % int(downsample_ratio)) h_real = TimeSeries(data[::int(downsample_ratio), 1] / DYN_RANGE_FAC, delta_t=delta_t) h_imag = TimeSeries(data[::int(downsample_ratio), 2] / DYN_RANGE_FAC, delta_t=delta_t) if verbose: print("max, min,len of h_real = ", max(h_real.data), min(h_real.data), len(h_real.data)) # Compute Strain tmplt_pars = template_params wav = generate_detector_strain(tmplt_pars, h_real, h_imag) wav = extend_waveform_TimeSeries(wav, filter_N) # Return TimeSeries with (m1, m2, w_value) m1, m2 = mtotal_eta_to_mass1_mass2(M_value, q_value / (1. + q_value)**2) htilde = make_frequency_series(wav) htilde = extend_waveform_FrequencySeries(htilde, filter_n) if verbose: print("ISNAN(htilde from file) = ", np.any(np.isnan(htilde.data))) return htilde, [m1, m2, w_value, dt] #}}} else: raise IOError(".. APPROXIMANT %s not found.." % approximant) ## hvec = hplus htilde = make_frequency_series(hvec) htilde = extend_waveform_FrequencySeries(htilde, filter_n) # print("type of hplus, hcross = ", type(hplus.data), type(hcross.data)) if any(isnan(hplus.data)) or any(isnan(hcross.data)): print("..### %s hplus or hcross have NANS!!" % approximant) # if any(isinf(hplus.data)) or any(isinf(hcross.data)): print("..### %s hplus or hcross have INFS!!" % approximant) # if any(isnan(htilde.data)): print("..### %s Fourier transform htilde has NANS!!" % approximant) # if any(isinf(htilde.data)): print("..### %s Fourier transform htilde has INFS!!" % approximant) # return htilde
m2 = m2v * LS.lal.MSUN_SI # In[3]: nongrParams = lal.CreateDict() hPlus, hCross = LS.SimInspiralChooseFDWaveform(m1=m1, m2=m2, S1x=S1x, S1y=S1y, S1z=S1z, S2x=S2x, S2y=S2y, S2z=S2z, distance=r, inclination=i, phiRef=phi0, longAscNodes=0., eccentricity=0., meanPerAno=0., deltaF=deltaF, f_min=f_min, f_max=f_max, f_ref=f_ref, LALpars=nongrParams, approximant=approximant) f = hPlus.deltaF * np.arange(len(hPlus.data.data)) + hPlus.f0 h = hPlus.data.data + (1j) * hCross.data.data print(hPlus.data.data, hCross.data.data)
def least_match_quadratic_waveform_unnormalized(paramspoints, known_quad_bases, npts, distance, deltaF, f_min, f_max, waveFlags, approximant): overlaps = numpy.zeros(npts) modula = numpy.zeros(npts) for i in numpy.arange(0, len(paramspoints)): paramspoint = paramspoints[i] m1, m2 = get_m1m2_from_mcq(paramspoint[0], paramspoint[1]) s1x, s1y, s1z = spherical_to_cartesian(paramspoint[2:5]) s2x, s2y, s2z = spherical_to_cartesian(paramspoint[5:8]) iota = paramspoint[8] phiRef = paramspoint[9] ecc = 0 if len(paramspoint) == 11: ecc = paramspoint[10] if len(paramspoint) == 12: lambda1 = paramspoint[10] lambda2 = paramspoint[11] lalsimulation.SimInspiralWaveformParamsInsertTidalLambda1( waveFlags, lambda1) lalsimulation.SimInspiralWaveformParamsInsertTidalLambda2( waveFlags, lambda2) f_ref = 0 RA = 0 DEC = 0 psi = 0 phi = 0 m1 *= lal.lal.MSUN_SI m2 *= lal.lal.MSUN_SI [plus, cross] = lalsimulation.SimInspiralChooseFDWaveform( m1, m2, s1x, s1y, s1z, s2x, s2y, s2z, distance, iota, phiRef, 0, ecc, 0, deltaF, f_min, f_max, f_ref, waveFlags, approximant) hp_tmp = plus.data.data[numpy.int(f_min / deltaF):numpy.int( f_max / deltaF)] # data_tmp is hplus and is a complex vector hp_quad_tmp = (numpy.absolute(hp_tmp))**2 residual = hp_quad_tmp for k in numpy.arange(0, len(known_quad_bases)): residual -= proj(known_quad_bases[k], hp_quad_tmp) modula[i] = numpy.sqrt(numpy.vdot(residual, residual)) arg_newbasis = numpy.argmax(modula) mass1, mass2 = get_m1m2_from_mcq(paramspoints[arg_newbasis][0], paramspoints[arg_newbasis][1]) mass1 *= lal.lal.MSUN_SI mass2 *= lal.lal.MSUN_SI sp1x, sp1y, sp1z = spherical_to_cartesian(paramspoints[arg_newbasis, 2:5]) sp2x, sp2y, sp2z = spherical_to_cartesian(paramspoints[arg_newbasis, 5:8]) inclination = paramspoints[arg_newbasis][8] phi_ref = paramspoints[arg_newbasis][9] ecc = 0 if len(paramspoint) == 11: ecc = paramspoints[arg_newbasis][10] if len(paramspoint) == 12: lambda1 = paramspoints[arg_newbasis][10] lambda2 = paramspoints[arg_newbasis][11] lalsimulation.SimInspiralWaveformParamsInsertTidalLambda1( waveFlags, lambda1) lalsimulation.SimInspiralWaveformParamsInsertTidalLambda2( waveFlags, lambda2) [plus_new, cross_new] = lalsimulation.SimInspiralChooseFDWaveform( mass1, mass2, sp1x, sp1y, sp1z, sp2x, sp2y, sp2z, distance, inclination, phi_ref, 0, ecc, 0, deltaF, f_min, f_max, 0, waveFlags, approximant) hp_new = plus_new.data.data hp_new = hp_new[numpy.int(f_min / deltaF):numpy.int(f_max / deltaF)] hp_quad_new = (numpy.absolute(hp_new))**2 basis_quad_new = gram_schmidt(known_quad_bases, hp_quad_new) return numpy.array( [basis_quad_new, paramspoints[arg_newbasis], modula[arg_newbasis]]) # elements, masses&spins, residual mod
def lalsim_FD_waveform(m1, m2, s1x, s1y, s1z, s2x, s2y, s2z, theta_jn, phase, duration, dL, fmax, lambda_1=None, lambda_2=None, **kwarg): mass1 = m1 * lal.MSUN_SI mass2 = m2 * lal.MSUN_SI spin_1x = s1x spin_1y = s1y spin_1z = s1z spin_2x = s2x spin_2y = s2y spin_2z = s2z iota = theta_jn phaseC = phase # Phase is hard coded to be zero eccentricity = 0 longitude_ascending_nodes = 0 mean_per_ano = 0 waveform_arg = dict(minimum_freq=20.0, reference_frequency=20) waveform_arg.update(kwarg) dL = dL * lal.PC_SI * 1e6 # MPC --> Km approximant = lalsim.GetApproximantFromString( waveform_arg["waveform_approximant"]) flow = waveform_arg["minimum_freq"] delta_freq = 1.0 / duration maximum_frequency = fmax # 1024.0 # ISCO(m1, m2) fref = waveform_arg["reference_frequency"] waveform_dictionary = lal.CreateDict() if lambda_1 is not None: lalsim.SimInspiralWaveformParamsInsertTidalLambda1( waveform_dictionary, float(lambda_1)) if lambda_2 is not None: lalsim.SimInspiralWaveformParamsInsertTidalLambda2( waveform_dictionary, float(lambda_2)) hplus, hcross = lalsim.SimInspiralChooseFDWaveform( mass1, mass2, spin_1x, spin_1y, spin_1z, spin_2x, spin_2y, spin_2z, dL, iota, phaseC, longitude_ascending_nodes, eccentricity, mean_per_ano, delta_freq, flow, maximum_frequency, fref, waveform_dictionary, approximant, ) h_plus = hplus.data.data[:] h_cross = hcross.data.data[:] return {"plus": h_plus, "cross": h_cross}
def Get_LALSuite_Waveform(source, waveform_dict, out_frame="observer"): """Gets the frequency domain waveform of a particular source using a waveform modelled in LIGO's ``lalsuite`` package. The source is given plus and cross properties with their phase and amplitude for user convenience. Parameters ---------- source: object source object from ``binary``, contains all source parameters waveform_dict: dictionary The dictionary is comprised of necessities for the ``SimInspiralChooseFDWaveform`` call in ``lalsimulation`` comprised of: ``m1`` mass of companion 1 (kg) ``m2`` mass of companion 2 (kg) ``S1x`` x-component of the dimensionless spin of object 1 ``S1y`` y-component of the dimensionless spin of object 1 ``S1z`` z-component of the dimensionless spin of object 1 ``S2x`` x-component of the dimensionless spin of object 2 ``S2y`` y-component of the dimensionless spin of object 2 ``S2z`` z-component of the dimensionless spin of object 2 ``distance`` distance of source (m) ``inclination`` inclination of source (rad) ``phiRef`` reference orbital phase (rad) ``longAscNodes`` longitude of ascending nodes, degenerate with the polarization angle, Omega in documentation ``eccentricity`` eccentricity at reference epoch ``meanPerAno`` mean anomaly of periastron ``deltaF`` sampling interval (Hz) ``f_min`` starting GW frequency (Hz) ``f_max`` ending GW frequency (Hz) ``f_ref`` Reference frequency (Hz) ``LALparams`` LAL dictionary containing accessory parameters ``approximant`` post-Newtonian approximant to use for waveform production out_frame: str, {'observer','source'} Determines whether the returned frequency is in the source or observer frame. """ h_f_plus, h_f_cross = lalsimulation.SimInspiralChooseFDWaveform(**waveform_dict) h_f_plus_amp, h_f_plus_phase = Get_Amp_Phase(h_f_plus.data.data) h_f_cross_amp, h_f_cross_phase = Get_Amp_Phase(h_f_cross.data.data) source.h_f_plus_amp = h_f_plus_amp source.h_f_plus_phase = h_f_plus_phase source.h_f_cross_amp = h_f_cross_amp source.h_f_cross_phase = h_f_cross_phase full_amp = Get_Full_Amp(h_f_plus_amp, h_f_cross_amp) # Need to trim because SimInspiralChooseFDWaveform returns nans and zeros outside of ranges (f_min,f_cutoff) trimmed_full_amp = [] for amp in full_amp: if not np.isnan(amp) and amp != 0.0: trimmed_full_amp.append(amp) trimmed_full_amp = np.asarray(trimmed_full_amp) lin_freqs = np.arange(0, waveform_dict["f_max"], waveform_dict["deltaF"]) trimmed_freqs = lin_freqs[1 : trimmed_full_amp.shape[0] + 1] # The difference between the two is `gwent` has a factor of :math:`\sqrt{\frac{1}{24}}(1+z)^{2}` # and `LALSuite` has a factor of :math:`2\sqrt{\frac{1}{64}}`. # Thus, :math:`h_{\mathrm{gwent}} = \sqrt{\frac{2}{3}}(1+z)^{2}h_{\mathrm{LAL}}`, # this factor is reduced by :math:`\sqrt{\frac{1}{2}}` if using the cross and plus polarizations to get the total Fourier strain amplitude. if out_frame == "observer": # frequency and strain of source in detector frame and physical units: Hertz and raw Fourier strain amplitude (1/Hertz) freqs = trimmed_freqs / (1 + source.z) * u.Hz strain = np.sqrt(1 / 3) * (1 + source.z) ** 2 * trimmed_full_amp / u.Hz elif out_frame == "source": # frequency and strain of source in source frame and physical units: Hertz and raw Fourier strain amplitude (1/Hertz) freqs = trimmed_freqs * u.Hz strain = np.sqrt(1 / 3) * trimmed_full_amp / u.Hz else: raise ValueError("The reference frame can only be observer or source.") return [freqs, strain]
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.MSUN_SI, mass2 * lal.MSUN_SI, 0, 0, 0, 0, 0, 0, f_low, 0, 0, 1e6 * 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.DimensionlessUnit, 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.MSUN_SI, mass2 * lal.MSUN_SI, 0, 0, 0, 0, 0, 0, f_low, f_low, 1e6 * 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.DimensionlessUnit, 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.DimensionlessUnit, 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 lalsim_fd_waveform(long_asc_nodes=0.0, eccentricity=0.0, mean_per_ano=0.0, phi_ref=0.0, f_ref=None, phase_order=-1, amplitude_order=-1, spin_order=-1, tidal_order=-1, quad1=None, quad2=None, **p): """Wrapper for lalsimulation.SimInspiralChooseTDWaveform. Simplified version of pycbc.waveform.get_td_waveform wrapper. Parameters ---------- f_ref : Reference frequency (?For setting phi_ref? Not sure.) Defaults to f_min. phi_ref : Reference phase (?at f_ref?). Returns ------- h : Waveform """ if f_ref == None: f_ref = p['f_min'] # Set extra arguments in the lal Dict structure lal_pars = lal.CreateDict() if phase_order != -1: lalsimulation.SimInspiralWaveformParamsInsertPNPhaseOrder( lal_pars, int(phase_order)) if amplitude_order != -1: lalsimulation.SimInspiralWaveformParamsInsertPNAmplitudeOrder( lal_pars, int(amplitude_order)) if spin_order != -1: lalsimulation.SimInspiralWaveformParamsInsertPNSpinOrder( lal_pars, int(spin_order)) if tidal_order != -1: lalsimulation.SimInspiralWaveformParamsInsertPNTidalOrder( lal_pars, int(tidal_order)) if p['lambda1']: lalsimulation.SimInspiralWaveformParamsInsertTidalLambda1( lal_pars, p['lambda1']) if p['lambda2']: lalsimulation.SimInspiralWaveformParamsInsertTidalLambda2( lal_pars, p['lambda2']) # Add spin-induced quadrupole terms. Default is universal relations. # dQuadMon1 = quad1 - 1 # dQuadMon2 = quad2 - 1 if quad1 == None: quad1 = taylorf2.quad_of_lambda_fit(p['lambda1']) if quad2 == None: quad2 = taylorf2.quad_of_lambda_fit(p['lambda2']) lalsimulation.SimInspiralWaveformParamsInsertdQuadMon1( lal_pars, quad1 - 1.0) lalsimulation.SimInspiralWaveformParamsInsertdQuadMon2( lal_pars, quad2 - 1.0) print quad1, quad2 print 'dQuadMon1 =', lalsimulation.SimInspiralWaveformParamsLookupdQuadMon1( lal_pars) print 'dQuadMon2 =', lalsimulation.SimInspiralWaveformParamsLookupdQuadMon2( lal_pars) # Set Approximant (C enum structure) corresponding to approximant string lal_approx = lalsimulation.GetApproximantFromString(p['approximant']) hp, hc = lalsimulation.SimInspiralChooseFDWaveform( float(MSUN_SI * p['mass1']), float(MSUN_SI * p['mass2']), float(p['spin1x']), float(p['spin1y']), float(p['spin1z']), float(p['spin2x']), float(p['spin2y']), float(p['spin2z']), float(MPC_SI * p['distance']), float(p['inclination']), float(phi_ref), float(long_asc_nodes), float(eccentricity), float(mean_per_ano), float(p['delta_f']), float(p['f_min']), float(p['f_max']), float(f_ref), lal_pars, lal_approx) # Extract data from lalsimulation's structures # The first data point in hp.data.data corresponds to f=0 not f=f_min fs = hp.deltaF * np.arange(hp.data.length) return wave.Waveform.from_hp_hc(fs, hp.data.data, hc.data.data)