def generate_LAL_modes(approximant, q, chiA0, chiB0, dt, M, \ dist_mpc, f_low, f_ref, phi_ref, ellMax=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) dictParams = lal.CreateDict() if ellMax is not None: ma = lalsim.SimInspiralCreateModeArray() for ell in range(2, ellMax + 1): lalsim.SimInspiralModeArrayActivateAllModesAtL(ma, ell) lalsim.SimInspiralWaveformParamsInsertModeArray(dictParams, ma) lmax = 5 # This in unused hmodes = lalsim.SimInspiralChooseTDModes(phi_ref, dt, m1_kg, m2_kg, \ chiA0[0], chiA0[1], chiA0[2], chiB0[0], chiB0[1], chiB0[2], \ f_low, f_ref, distance, dictParams, lmax, approxTag) t = np.arange(len(hmodes.mode.data.data)) * dt mode_dict = {} while hmodes is not None: mode_dict['h_l%dm%d' % (hmodes.l, hmodes.m)] = hmodes.mode.data.data hmodes = hmodes.next return t, mode_dict
def gen_waveform(event_params, flow=10.0, deltaf=0.125, fhigh=2048., fref=10., approximant="IMRPhenomPv2"): """ Generate the h_+ and h_x polarizations for an event, as well as an associated frequency array. """ eprm = _defaults.copy() eprm.update(event_params) freq_ar = numpy.arange(0, fhigh + deltaf, deltaf) params = None hp, hx = lalsimulation.SimInspiralFD( # Masses eprm["m1"] * lal.MSUN_SI, eprm["m2"] * lal.MSUN_SI, \ # Spins eprm["spin1x"], eprm["spin1y"], eprm["spin1z"], \ eprm["spin1x"], eprm["spin1y"], eprm["spin1z"], \ # distance and inclination eprm["distance"] * 1e6 * lal.PC_SI, eprm["inclination"], # These are eccentricity and other orbital parameters 0.0, 0.0, 0.0, 0.0, # frequency binning params deltaf, flow, fhigh, fref, \ # Other extraneous options params, lalsimulation.SimInspiralGetApproximantFromString(approximant)) return freq_ar, hp.data.data, hx.data.data
def get_SEOBNRv2_WF(q, M, chi1, chi2, f_start, deltaT=1. / (4096 * 4.)): m1 = q * M / (1 + q) m2 = M / (1 + q) hp, hc = lalsim.SimInspiralChooseTDWaveform( #where is its definition and documentation???? m1 * lalsim.lal.MSUN_SI, #m1 m2 * lalsim.lal.MSUN_SI, #m2 0., 0., chi1, #spin vector 1 0., 0., chi2, #spin vector 2 1e6 * lalsim.lal.PC_SI, #distance to source 0., #inclination 0., #phi 0., #longAscNodes 0., #eccentricity 0., #meanPerAno deltaT, # time incremental step f_start, # lowest value of freq f_start, #some reference value of freq (??) lal.CreateDict(), #some lal dictionary lalsim.SimInspiralGetApproximantFromString( 'SpinTaylorT4') #approx method for the model ) h_p, h_c = hp.data.data, hc.data.data times = np.linspace(0, len(h_c) * deltaT, len(h_c)) ph = np.unwrap(np.angle(h_p + 1j * h_c)) omega_22 = (ph[2] - ph[0]) / (2 * deltaT) print("FREQUENCY of THE WF (NP): ", omega_22, omega_22 / (2 * np.pi)) t_max = times[np.argmax(np.abs(h_p + 1j * h_c))] times = times - t_max return times, h_p + 1j * h_c
def _get_surrogate_dynamics(self, q, chiA0, chiB0, init_quat, \ init_orbphase, omega_ref, unlimited_extrapolation): """ A wrapper for NRSur7dq4 dynamics. Inputs: q: Mass ratio, mA/mB >= 1. chiA0: Dimless spin of BhA in the coorbital frame at omega_ref. chiB0: Dimless spin of BhB in the coorbital frame at omega_ref. init_quat: Coprecessing frame quaternion at omega_ref. init_orbphase: Orbital phase in the coprecessing frame at omega_ref. omega_ref: Orbital frequency in the coprecessing frame at the reference epoch where the input spins are given. Note: This is total-mass times the angular orbital frequency. unlimited_extrapolation: If True, allows unlimited extrapolation to regions well outside the surrogate's training region. Else, raises an error. Outputs: t_dyn: Time values at which the dynamics are returned. These are nonuniform and sparse. copr_quat: Time series of coprecessing frame quaternions. orbphase: Orbital phase time series in the coprecessing frame. chiA_copr: Time series of spin of BhA in the coprecessing frame. chiB_copr: Time series of spin of BhB in the coprecessing frame. """ approxTag = lalsim.SimInspiralGetApproximantFromString("NRSur7dq4") LALParams = lal.CreateDict() if unlimited_extrapolation: lal.DictInsertUINT4Value(LALParams, "unlimited_extrapolation", 1) t_dyn, quat0, quat1, quat2, quat3, orbphase, chiAx, chiAy, chiAz, \ chiBx, chiBy, chiBz = lalsim.PrecessingNRSurDynamics(q, \ chiA0[0], chiA0[1], chiA0[2], chiB0[0], chiB0[1], chiB0[2], \ omega_ref, init_quat[0], init_quat[1], init_quat[2], init_quat[3], \ init_orbphase, LALParams, approxTag) t_dyn = t_dyn.data orbphase = orbphase.data copr_quat = np.array([quat0.data, quat1.data, quat2.data, quat3.data]) chiA_copr = np.array([chiAx.data, chiAy.data, chiAz.data]).T chiB_copr = np.array([chiBx.data, chiBy.data, chiBz.data]).T return t_dyn, copr_quat, orbphase, chiA_copr, chiB_copr
def get_SEOBNRv4PHM_modes(q, M, chi1, chi2, f_start, deltaT=1. / (4096 * 4.)): #See the paper: https://arxiv.org/pdf/2004.09442.pdf """Generate SEOBNRv4PHM modes""" prefactor = 4.7864188273360336e-20 # G/c^2*(M_sun/Mpc) distance = 1. * 1e6 * lal.PC_SI # 1 Mpc in m amp_prefactor = prefactor * M / 1. # G/c^2 (M / d_L) nu = q / (1 + q)**2 m1SI = lal.MSUN_SI * q * M / (1.0 + q) m2SI = lal.MSUN_SI * M / (1.0 + q) #approx = lalsim.SEOBNRv4PHM approx = lalsim.SimInspiralGetApproximantFromString('SEOBNRv4PHM') hlm = lalsim.SimInspiralChooseTDModes( 0., deltaT, m1SI, m2SI, chi1[0], chi1[1], chi1[2], chi2[0], chi2[1], chi2[2], f_start, #/**< starting GW frequency (Hz) */ #what is this f_start?? f_start, #/**< reference GW frequency (Hz) */ distance, None, 5, approx, ) hI = {} modes = [(2, 2), (2, 1), (2, -1), (3, 3), (4, 4), (5, 5)] for lm in modes: hI[lm] = lalsim.SphHarmTimeSeriesGetMode( hlm, lm[0], lm[1]).data.data / amp_prefactor / nu times = np.linspace(0, len(hI[(2, 2)]) * deltaT, len(hI[(2, 2)])) h_22 = hI[(2, 2)] ph = np.unwrap(np.angle(np.conj(h_22))) omega_22 = (ph[2] - ph[0]) / (2 * deltaT) print("FREQUENCY of THE WF: ", omega_22, omega_22 / (2 * np.pi)) t_max = times[np.argmax(np.abs(h_22))] times = times - t_max return times, hI
def generate_LAL_waveform(approximant, q, chiA0, chiB0, dt, M, \ dist_mpc, f_low, 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.SimInspiralChooseTDWaveform(\ m1_kg, m2_kg, chiA0[0], chiA0[1], chiA0[2], \ chiB0[0], chiB0[1], chiB0[2], \ distance, inclination, phi_ref, 0, 0, 0,\ dt, f_low, f_ref, dictParams, approxTag) h = np.array(hp.data.data - 1.j * hc.data.data) t = dt * np.arange(len(h)) return t, h
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 create_dataset_TD(N_data, N_grid, filename=None, t_coal=0.5, q_range=(1., 5.), m2_range=None, s1_range=(-0.8, 0.8), s2_range=(-0.8, 0.8), t_step=1e-5, approximant="SEOBNRv2_opt", alpha=0.35, path_TEOBResumS=None): """ create_dataset_TD ================= Create a dataset for training a ML model to fit GW waveforms in time 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 as well as spins are drawn randomly in the range given by the user: it holds m1 = q *m2 M_sun. The waveforms are computed with a time step t_step; starting from a frequency f_min (set by the routine according to t_coal and m_tot). Waves are given in a rescaled time grid (i.e. t/m_tot) with N_grid points: t=0 occurs when at time of maximum amplitude. A higher density of grid points is placed in the post merger phase. Dataset can be generated either with a lal method (the approximant should be specified by the approximant keyword) either with an implementation of TEOBResumS (in this case a path to a local installation of TEOBResumS should be provided). If lal is used, lalsuite package shall be installed (note that lalsuite is not a prerequisite for mlgw) Dataset can be loaded with load_dataset. Input: N_data size of dataset N_grid number of grid points to evaluate filename name of the file to save dataset in (If is None, nothing is saved on a file) t_coal time to coalescence to start computation from (measured in reduced grid) 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. If None, m2 will be chosen s.t. m_tot = m1+m2 = 20. M_sun 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 t_step time step to generate the wave with approximant string for the approximant model to be used (in lal convention; to be used only if lal ought to be used) alpha distorsion factor for time grid. (In range (0,1], when it's close to 0, more grid points are around merger) path_TEOBResumS path to a local installation of TEOBResumS with routine 'EOBRun_module' (if given, it overwrites the aprroximant entry) 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 times (N_grid,) vector holding times at which waves are evaluated (t=0 is the time of maximum amplitude) """ d = 1. inclination = 0. #np.pi/2. if path_TEOBResumS is not None: approximant = "TEOBResumS" if approximant == "TEOBResumS": #see https://bitbucket.org/eob_ihes/teobresums/src/development/ for the implementation of TEOBResumS try: import sys sys.path.append( path_TEOBResumS) #path to local installation of TEOBResumS import EOBRun_module except: raise RuntimeError( "No valid imput source for module 'EOBRun_module' for TEOBResumS. Unable to continue." ) else: try: import lal import lalsimulation as lalsim except: raise RuntimeError( "Impossible to load lalsimulation: try pip install lalsuite") LALpars = lal.CreateDict() approx = lalsim.SimInspiralGetApproximantFromString(approximant) #checking if N_grid is fine if not isinstance(N_grid, int): raise TypeError("N_grid is " + str(type(N_grid)) + "! Expected to be a int.") if isinstance(m2_range, tuple): D_theta = 4 #m2 must be included as a feature else: D_theta = 3 #creating time_grid t_end = 5.2e-4 #estimated maximum time for ringdown: WF will be killed after that time #t_end = 6e-5 #ONLY FOR mode = 3 (very ugly here...) time_grid = np.linspace(-np.power(np.abs(t_coal), alpha), np.power(t_end, alpha), N_grid) time_grid = np.multiply(np.sign(time_grid), np.power(np.abs(time_grid), 1. / alpha)) #adding 0 to time grid index_0 = np.argmin(np.abs(time_grid)) time_grid[index_0] = 0. #0 is alway set in the grid #setting t_coal_freq for generating a waves if np.abs(t_coal) < 0.05: t_coal_freq = 0.05 else: t_coal_freq = np.abs(t_coal) 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, )), time_grid, time_grid)) freq_header = np.reshape(freq_header, (1, len(freq_header))) np.savetxt(filebuff, freq_header, header="# row: theta " + str(D_theta) + " | amp (1," + str(N_grid) + ")| ph (1," + str(N_grid) + ")\n# N_grid = " + str(N_grid) + " | t_coal =" + str(t_coal) + " | t_step =" + str(t_step) + " | q_range = " + str(q_range) + " | m2_range = " + str(m2_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, D_theta)) for i in range(N_data): #loop on data to be created if i % 50 == 0 and i != 0: #if i%1 == 0 and i != 0: #debug print("Generated WF ", i) #setting value for data if isinstance(m2_range, tuple): m2 = np.random.uniform(m2_range[0], m2_range[1]) elif m2_range is not None: m2 = float(m2_range) if isinstance(q_range, tuple): q = np.random.uniform(q_range[0], q_range[1]) else: q = float(q_range) if isinstance(s1_range, tuple): spin1z = np.random.uniform(s1_range[0], s1_range[1]) else: spin1z = float(s1_range) if isinstance(s2_range, tuple): spin2z = np.random.uniform(s2_range[0], s2_range[1]) else: spin2z = float(s2_range) if m2_range is None: m2 = 20. / (1 + q) m1 = q * m2 else: m1 = q * m2 #computing f_min f_min = .9 * ((151 * (t_coal_freq)**(-3. / 8.) * (((1 + q)**2) / q)**(3. / 8.)) / (m1 + m2)) #in () there is the right scaling formula for frequency in order to get always the right reduced time #this should be multiplied by a prefactor (~1) for dealing with some small variation due to spins #getting the wave if approximant != "TEOBResumS": #using lal to create WFs hptilde, hctilde = lalsim.SimInspiralChooseTDWaveform( #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 inclination, #inclination 0., #phi ref 0., #longAscNodes 0., #eccentricity 0., #meanPerAno t_step, # time incremental step f_min, # lowest value of time f_min, #some reference value of time (??) lal.CreateDict(), #some lal dictionary approx #approx method for the model ) #print(f_min, t_step)#debug #print(m1,m2, spin1z,spin2z) #debug h_p, h_c = np.array(hptilde.data.data), np.array( hctilde.data.data) #complex waveform time_full = np.linspace( 0.0, hptilde.data.length * t_step, hptilde.data.length) #time grid at which wave is computed if approximant == "TEOBResumS": #using TEOBResumS mode = 1 pars = { 'M': m1 + m2, 'q': m1 / m2, 'Lambda1': 0., 'Lambda2': 0., 'chi1': spin1z, 'chi2': spin2z, 'domain': 0, # TD 'arg_out': 0, # Output hlm/hflm. Default = 0 'use_mode_lm': [mode], # List of modes to use/output through EOBRunPy 'srate_interp': 1. / t_step, # srate at which to interpolate. Default = 4096. 'use_geometric_units': 0, # Output quantities in geometric units. Default = 1 'initial_frequency': f_min, # in Hz if use_geometric_units = 0, else in geometric units 'interp_uniform_grid': 2, # Interpolate mode by mode on a uniform grid. Default = 0 (no interpolation) 'distance': d, 'inclination': inclination, #'nqc':2, #{"no", "auto", "manual"} #'nqc_coefs_flx': 2, # {"none", "nrfit_nospin20160209", "fit_spin_202002", "fromfile"} #'nqc_coefs_hlm':0 } if mode != 1: warnings.warn("Using non dominant mode " + str(mode)) time_full, h_p, h_c = EOBRun_module.EOBRunPy(pars) if isinstance(m2_range, tuple): temp_theta = [m1, m2, spin1z, spin2z] else: temp_theta = [m1 / m2, spin1z, spin2z] temp_amp = np.sqrt(np.square(h_p) + np.square(h_c)) temp_ph = np.unwrap(np.arctan2(h_c, h_p)) time_full = (time_full - time_full[np.argmax(temp_amp)]) / ( m1 + m2) #grid is scaled to standard grid #setting waves to the chosen std grid temp_amp = np.interp(time_grid, time_full, temp_amp) temp_ph = np.interp(time_grid, time_full, temp_ph) #here you need to decide what is better #temp_ph = temp_ph - temp_ph[0] #all phases are shifted by a constant to make every wave start with 0 phase id0 = np.where(time_grid == 0)[0] temp_ph = temp_ph - temp_ph[ id0] #all phases are shifted by a constant to make every wave start with 0 phase at t=0 (i.e. at maximum amplitude) #removing spourious gaps (if present) (do I need it??) (index, ) = np.where( temp_amp / np.max(temp_amp) < 1e-10) #there should be a way to choose the right threshold... if len(index) > 0: #print("Wave killed") temp_amp[index] = 0 #temp_amp[index[0]-1] 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, time_grid else: filebuff.close() return None
detectors = dict([(d.frDetector.prefix, d) for d in lal.CachedDetectors]) import lalsimulation """ _ref_h, _ = lalsimulation.SimInspiralFD( 1.4 * lal.MSUN_SI, 1.4 * lal.MSUN_SI, 0., 0., 0., 0., 0., 0., 100e6 * lal.PC_SI, 0.0, 0.0, 0.0, 0.0, 0.0, 0.125, 10.0, 2048., None, lalsimulation.SimInspiralGetApproximantFromString("IMRPhenomPv2")) """ _ref_h_bns, _ = lalsimulation.SimInspiralFD( 0.0, 0.125, 1.4 * lal.MSUN_SI, 1.4 * lal.MSUN_SI, 0., 0., 0., 0., 0., 0., 10., 2048., 10., 100e6 * lal.PC_SI, 0.0, 0.0, 0.0, 0.0, None, None, -1, -1, lalsimulation.SimInspiralGetApproximantFromString("IMRPhenomPv2")) _ref_h_nsbh, _ = lalsimulation.SimInspiralFD( 0.0, 0.125, 1.4 * lal.MSUN_SI, 10. * lal.MSUN_SI, 0., 0., 0., 0., 0., 0., 10., 2048., 10., 100e6 * lal.PC_SI, 0.0, 0.0, 0.0, 0.0, None, None, -1, -1, lalsimulation.SimInspiralGetApproximantFromString("IMRPhenomPv2")) _ref_h_nsbh_ms, _ = lalsimulation.SimInspiralFD( 0.0, 0.125, 1.4 * lal.MSUN_SI, 10. * lal.MSUN_SI, 0., 0., 0., 0., 0., 0.9, 10., 2048., 10., 100e6 * lal.PC_SI, 0.0, 0.0, 0.0, 0.0, None, None, -1, -1, lalsimulation.SimInspiralGetApproximantFromString("IMRPhenomPv2")) _default_psds = { "H1": lalsimulation.SimNoisePSDaLIGOZeroDetHighPower, "I1": lalsimulation.SimNoisePSDaLIGOZeroDetHighPower, "K1": lalsimulation.SimNoisePSDaLIGOZeroDetHighPower,
def lal_spin_evloution_wrapper(approximant, q, omega0, chiA0, chiB0, dt, spinO, phaseO): """ Inputs: approximant: 'SpinTaylorT1/T2/T4' q: Mass ratio (q>=1) omega0: Initial orbital frequency in dimless units. chiA0: Dimless spin of BhA at initial freq. chiB0: Dimless spin of BhB at initial freq. dt: Dimless step time for evolution. spinO: Twice PN order of spin effects. phaseO: Twice PN order in phase. Outputs (all are time series): Omega: Dimensionless orbital frequency. Phi: Orbital phase (radians) ChiA: Dimensionless spin of BhA ChiB: Dimensionless spin of BhB LNhat: Orbital angular momentum direction E1: Orbital plane basis vector The frame is defined at the initial frequency, as follows: z-axis is set by the orbital angular momentum direction. x-axis is the separation vector from BhB to BhA. y-axis completes the triad by right-hand rule. All quantities are defined in this fixed frame, including initial spins, returned spins, other vectors like LNhat, etc. """ approxTag = lalsim.SimInspiralGetApproximantFromString(approximant) # Total mass in solar masses M = 100 # This does not affect the returned values as they are # dimension less # time step and initial GW freq in SI units MT = M * MTSUN_SI deltaT = dt * MT fStart = omega0 / np.pi / MT # component masses of the binary m1_SI = M * MSUN_SI * q / (1. + q) m2_SI = M * MSUN_SI / (1. + q) # spins at fStart s1x, s1y, s1z = chiA0 s2x, s2y, s2z = chiB0 # integrate as far forward as possible fEnd = 0 # initial value of orbital angular momentum unit vector, i.e at fStart lnhatx, lnhaty, lnhatz = 0, 0, 1 # initial value of orbital plane basis vector, i.e at fStart e1x, e1y, e1z = 1, 0, 0 # tidal deformability parameters lambda1, lambda2 = 0, 0 quadparam1, quadparam2 = 1, 1 # twice PN order of tidal effects tideO = 0 # include some L-S terms lscorr = 1 ### This function evolves the orbital equations for a precessing binary ### using the "TaylorT1/T2/T4" approximant for solving the orbital dynamics ### (see arXiv:0907.0700 for a review of the various PN approximants). ### ### It returns time series of the "orbital velocity", orbital phase, ### and components for both individual spin vectors, the "Newtonian" ### orbital angular momentum (which defines the instantaneous plane) ### and "E1", a basis vector in the instantaneous orbital plane. Note that ### LNhat and E1 completely specify the instantaneous orbital plane. ### It also returns the time and phase of the final time step ### ### For input, the function takes the two masses, the initial orbital phase, ### Values of S1, S2, LNhat, E1 vectors at starting time, ### the desired time step size, the starting GW frequency, ### and PN order at which to evolve the phase, ### ### NOTE: All vectors are given in the frame ### where the z-axis is set by the angular momentum at reference frequency, ### the x-axis is chosen orthogonal to it, and the y-axis is given by the ### RH rule. Initial values must be passed in this frame, and the time ### series of the vector components will also be returned in this frame. ### ### ### V, post-Newtonian parameter [returned] ### Phi, orbital phase [returned] ### S1x, Spin1 vector x component [returned] ### S1y, " " " y component [returned] ### S1z, " " " z component [returned] ### S2x, Spin2 vector x component [returned] ### S2y, " " " y component [returned] ### S2z, " " " z component [returned] ### LNhatx, unit orbital ang. mom. x [returned] ### LNhaty, " " " y component [returned] ### LNhatz, " " " z component [returned] ### E1x, orb. plane basis vector x[returned] ### E1y, " " " y component [returned] ### E1z, " " " z component [returned] ### ### ### deltaT, sampling interval (s) ### m1_SI, mass of companion 1 (kg) ### m2_SI, mass of companion 2 (kg) ### fStart, starting GW frequency ### fEnd, ending GW frequency, fEnd=0 means integrate as far ### forward as possible ### s1x, initial value of S1x ### s1y, initial value of S1y ### s1z, initial value of S1z ### s2x, initial value of S2x ### s2y, initial value of S2y ### s2z, initial value of S2z ### lnhatx, initial value of LNhatx ### lnhaty, initial value of LNhaty ### lnhatz, initial value of LNhatz ### e1x, initial value of E1x ### e1y, initial value of E1y ### e1z, initial value of E1z ### lambda1, tidal deformability of mass 1 ### lambda2, tidal deformability of mass 2 ### quadparam1, phenom. parameter describing induced quad. ### moment of body 1 (=1 for BHs, ~2-12 for NSs) ### quadparam2, phenom. parameter describing induced quad. ### moment of body 2 (=1 for BHs, ~2-12 for NSs) ### spinO, twice PN order of spin effects ### tideO, twice PN order of tidal effects ### phaseO, twice post-Newtonian order ### lscorr, Flag to include L-S correction terms ### approx PN approximant (SpinTaylorT1/T2/T4) V, Phi, S1x, S1y, S1z, S2x, S2y, S2z, LNhatx, LNhaty, LNhatz, \ E1x, E1y, E1z = lalsim.SimInspiralSpinTaylorPNEvolveOrbit(deltaT, \ m1_SI, m2_SI, fStart, fEnd, s1x, s1y, s1z, s2x, s2y, s2z, \ lnhatx, lnhaty, lnhatz, e1x, e1y, e1z, lambda1, lambda2, \ quadparam1, quadparam2, spinO, tideO, phaseO, lscorr, approxTag) V = np.array(V.data.data) Phi = np.array(Phi.data.data) ChiA = np.array([S1x.data.data, S1y.data.data, S1z.data.data]).T ChiB = np.array([S2x.data.data, S2y.data.data, S2z.data.data]).T LNhat = np.array([LNhatx.data.data, LNhaty.data.data, LNhatz.data.data]).T E1 = np.array([E1x.data.data, E1y.data.data, E1z.data.data]).T Omega = V**3 return Omega, Phi, ChiA, ChiB, LNhat, E1
def spin_evolution(q, chiA0, chiB0, omega0, approximant='SpinTaylorT4', dt=0.1, spinO=7, phaseO=7): """ Wrapper for PN spin and dynamics evolution in LAL. Inputs: - q: Mass ratio (q>=1) - chiA0: Dimensionless spin of BhA at initial freq. - chiB0: Dimensionless spin of BhB at initial freq. - omega0: Initial orbital frequency in dimensionless units. - approximant: 'SpinTaylorT1/T4/T5'. Default: SpinTaylorT4. - dt: Dimensionless step time for evolution. Default: 0.1 - spinO: Twice PN order of spin effects. Default: 7. - phaseO: Twice PN order in phase. Default: 7. Outputs (all are time series): - Omega: Dimensionless orbital frequency. - Phi: Orbital phase (radians) - ChiA: Dimensionless spin of BhA - ChiB: Dimensionless spin of BhB - LNhat: Orbital angular momentum direction - E1: Orbital plane basis vector The frame is defined at the initial frequency omega0, as follows: \n - z-axis is set by the orbital angular momentum direction. - x-axis is the separation vector from the lighter BH to the heavier BH. - y-axis completes the triad by right-hand rule. \n All quantities are defined in this fixed frame, including initial spins, returned spins, other vectors like LNhat, etc. """ approxTag = lalsim.SimInspiralGetApproximantFromString(approximant) # Total mass in solar masses M = 100 # This does not affect the returned values as they are # dimensionless # time step and initial GW freq in SI units MT = M * MTSUN_SI deltaT = dt * MT fStart = omega0 / np.pi / MT # component masses of the binary m1_SI = M * MSUN_SI * q / (1. + q) m2_SI = M * MSUN_SI / (1. + q) # spins at fStart s1x, s1y, s1z = chiA0 s2x, s2y, s2z = chiB0 # integrate as far forward as possible fEnd = 0 # initial value of orbital angular momentum unit vector, i.e at fStart lnhatx, lnhaty, lnhatz = 0, 0, 1 # initial value of orbital plane basis vector, i.e at fStart e1x, e1y, e1z = 1, 0, 0 # tidal deformability parameters lambda1, lambda2 = 0, 0 # spin-induced quadrupole moments quadparam1, quadparam2 = 1, 1 # twice PN order of tidal effects tideO = 0 # include some known L-S terms lscorr = 1 # evolve spins and collect data into a nice format. The input values start # with lower-case letters, while output values start with upper-case # letters. V, Phi, S1x, S1y, S1z, S2x, S2y, S2z, LNhatx, LNhaty, LNhatz, \ E1x, E1y, E1z = lalsim.SimInspiralSpinTaylorPNEvolveOrbit(deltaT, \ m1_SI, m2_SI, fStart, fEnd, s1x, s1y, s1z, s2x, s2y, s2z, \ lnhatx, lnhaty, lnhatz, e1x, e1y, e1z, lambda1, lambda2, \ quadparam1, quadparam2, spinO, tideO, phaseO, lscorr, approxTag) V = np.array(V.data.data) Phi = np.array(Phi.data.data) ChiA = np.array([S1x.data.data, S1y.data.data, S1z.data.data]).T ChiB = np.array([S2x.data.data, S2y.data.data, S2z.data.data]).T LNhat = np.array([LNhatx.data.data, LNhaty.data.data, LNhatz.data.data]).T E1 = np.array([E1x.data.data, E1y.data.data, E1z.data.data]).T # orbital frequency Omega = V**3 return Omega, Phi, ChiA, ChiB, LNhat
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 create_dataset_TD(N_data, N_grid, modes, basefilename, t_coal = 0.5, q_range = (1.,5.), m2_range = None, s1_range = (-0.8,0.8), s2_range = (-0.8,0.8), t_step = 1e-5, alpha = 0.35, approximant = "SEOBNRv2_opt", path_TEOBResumS = None): """ create_dataset_TD ================= Create datasets for training a ML model to fit GW modes in time domain. Each dataset is saved in a different file (basefilename.mode). The dataset consists in 3 parameters theta=(q, spin1z, spin2z) associated to the modes computed in time 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 discrete grid points ph_vector vector holding phase for each source evaluated at some discrete grid 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. Values of q and m2 as well as spins are drawn randomly in the range given by the user: it holds m1 = q *m2 M_sun. The waveforms are computed with a time step t_step; starting from a time in reduced grid tau min (s/M_Sun). Waves are given in a rescaled time grid (i.e. t/m_tot) with N_grid points: t=0 occurs when the 22 mode has a peak. A higher density of grid points is placed close to the merger. Dataset is generated either with an implementation of TEOBResumS (a path to a local installation of TEOBResumS should be provided) either with SEOBNRv4HM (lalsuite installation required). It can be given an TD lal approximant with no HM; in this case, only the 22 mode can be generated. Datasets can be loaded with load_dataset. Input: N_data size of dataset N_grid number of grid points to evaluate modes [] list of modes (each a (l,m) tuple) to generate and fill the dataset with basefilename basename of the file to save dataset in (each dataset is saved in basefilename.lm) t_coal time to coalescence to start computation from (measured in reduced grid) 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. If None, m2 will be chosen s.t. m_tot = m1+m2 = 20. M_sun 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 t_step time step to generate the wave with approximant string for the approximant model to be used (in lal convention; to be used only if lal is to be used) alpha distorsion factor for time grid. (In range (0,1], when it's close to 0, more grid points are around merger) approximant lal approximant to be used for generating the modes, or "TEOBResumS" (in the latter case a local installation must be provided by the argument path_TEOBResumS) path_TEOBResumS path to a local installation of TEOBResumS with routine 'EOBRun_module' (if given, it overwrites the aproximant entry) """ #imports if path_TEOBResumS is not None: approximant = "TEOBResumS" if isinstance(modes,tuple): modes = [modes] if not isinstance(modes,list): raise TypeError("Wrong kind of mode {} given. Expected a list [(l,m)]".format(modes)) if approximant == "TEOBResumS": #see https://bitbucket.org/eob_ihes/teobresums/src/development/ for the implementation of TEOBResumS try: import sys sys.path.append(path_TEOBResumS) #path to local installation of TEOBResumS import EOBRun_module except: raise RuntimeError("No valid imput source for module 'EOBRun_module' for TEOBResumS. Unable to continue.") else: try: import lal import lalsimulation as lalsim except: raise RuntimeError("Impossible to load lalsimulation: try pip install lalsuite") LALpars = lal.CreateDict() approx = lalsim.SimInspiralGetApproximantFromString(approximant) prefactor = 4.7864188273360336e-20 # G/c^2*(M_sun/Mpc) #checking that all is good with modes if approximant == "SEOBNRv4HM": for mode in modes: if mode not in [(2,2),(2,1), (3,3), (4,4), (5,5)]: raise ValueError("Currently SEOBNRv4HM approximants do not implement the chosen HM") else: if modes != [(2,2)]: raise ValueError("The chosen lal approximant does not implement HMs") #checking if N_grid is fine if not isinstance(N_grid, int): raise TypeError("N_grid is "+str(type(N_grid))+"! Expected to be a int.") if isinstance(m2_range, tuple): D_theta = 4 #m2 must be included as a feature else: D_theta = 3 ######setting the time grid time_grid_list = [] t_end_list = [] if approximant == "TEOBResumS": modes_to_k = lambda modes:[int(x[0]*(x[0]-1)/2 + x[1]-2) for x in modes] # [(l,m)] -> [k] k_modes = modes_to_k(modes) #setting a list of time grids for mode in modes: #ugly setting of t_end in TEOBResumS: required to kill bad features after merger if mode == (2,2): t_end = 5.2e-4 #estimated maximum time for ringdown: WF will be killed after that time elif mode == (2,1) or mode == (3,3): #special treatment for 21 and 33 t_end = 1e-6 else: t_end = 3e-5 #for other modes t_end_list.append(t_end) else: for mode in modes: t_end_list.append(5.2e-4) print("Generating modes: "+str(modes)) #creating time_grid for i,mode in enumerate(modes): time_grid = np.linspace(-np.power(np.abs(t_coal), alpha), np.power(t_end_list[i], alpha), N_grid) time_grid = np.multiply( np.sign(time_grid) , np.power(np.abs(time_grid), 1./alpha)) #adding 0 to time grid index_0 = np.argmin(np.abs(time_grid)) time_grid[index_0] = 0. #0 is alway set in the grid time_grid_list.append(time_grid) #setting t_coal_freq for generating a waves if np.abs(t_coal) < 0.05: t_coal_freq = 0.05 else: t_coal_freq = np.abs(t_coal) #####create a list of buffer to save the WFs buff_list = [] for i, mode in enumerate(modes): filename = basefilename+'.'+str(mode[0])+str(mode[1]) 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") time_header = np.concatenate((np.zeros((3,)), time_grid_list[i], time_grid_list[i]) )[None,:] np.savetxt(filebuff, time_header, header = "#Mode:"+ str(mode[0])+str(mode[1]) +"\n# row: theta "+str(D_theta)+" | amp (None,"+str(N_grid)+")| ph (None,"+str(N_grid)+")\n# N_grid = "+str(N_grid)+" | t_coal ="+str(t_coal)+" | t_step ="+str(t_step)+" | q_range = "+str(q_range)+" | m2_range = "+str(m2_range)+" | s1_range = "+str(s1_range)+" | s2_range = "+str(s2_range), newline = '\n') else: filebuff = open(filename,'a') buff_list.append(filebuff) #####creating WFs for n_WF in range(N_data): #setting value for data if isinstance(m2_range, tuple): m2 = np.random.uniform(m2_range[0],m2_range[1]) elif m2_range is not None: m2 = float(m2_range) if isinstance(q_range, tuple): q = np.random.uniform(q_range[0],q_range[1]) else: q = float(q_range) if isinstance(s1_range, tuple): spin1z = np.random.uniform(s1_range[0],s1_range[1]) else: spin1z = float(s1_range) if isinstance(s2_range, tuple): spin2z = np.random.uniform(s2_range[0],s2_range[1]) else: spin2z = float(s2_range) if m2_range is None: m2 = 20. / (1+q) m1 = q * m2 else: m1 = q* m2 nu = np.divide(q, np.square(1+q)) #symmetric mass ratio #computing f_min f_min = .9* ((151*(t_coal_freq)**(-3./8.) * (((1+q)**2)/q)**(3./8.))/(m1+m2)) #in () there is the right scaling formula for frequency in order to get always the right reduced time #this should be multiplied by a prefactor (~1) for dealing with some small variation due to spins if isinstance(m2_range, tuple): temp_theta = [m1, m2, spin1z, spin2z] else: temp_theta = [m1/m2, spin1z, spin2z] #getting the wave #output of the if: #amp_list, ph_list (same order as in modes) #time_full, argpeak amp_list, ph_list = [None for i in range(len(modes))],[None for i in range(len(modes))] if approximant == "TEOBResumS": #using TEOBResumS pars = { 'M' : m1+m2, 'q' : m1/m2, 'Lambda1' : 0., 'Lambda2' : 0., 'chi1' : spin1z, 'chi2' : spin2z, 'domain' : 0, # TD 'arg_out' : 1, # Output hlm/hflm. Default = 0 'use_mode_lm' : list(set(k_modes + [1])), # List of modes to use/output through EOBRunPy (added 22 mode in case there isn't) #'srate_interp' : 1./t_step, # srate at which to interpolate. Default = 4096. 'use_geometric_units': 0, # Output quantities in geometric units. Default = 1 'initial_frequency' : f_min, # in Hz if use_geometric_units = 0, else in geometric units 'interp_uniform_grid': 0, # Interpolate mode by mode on a uniform grid. Default = 0 (no interpolation) 'distance': 1., 'inclination':0., } time_full, h_p, h_c, hlm = EOBRun_module.EOBRunPy(pars) for i, k_mode in enumerate(k_modes): temp_amp = hlm[str(k_mode)][0]*nu #TEOBResumS has weird conventions on the modes temp_ph = hlm[str(k_mode)][1] amp_list[i] = temp_amp ph_list[i] = temp_ph argpeak = locate_peak(hlm['1'][0]*nu) #aligned at the peak of the 22 elif approximant == "SEOBNRv4HM": #using SEOBNRv4HM nqcCoeffsInput=lal.CreateREAL8Vector(10) sp, dyn, dynHi = lalsim.SimIMRSpinAlignedEOBModes(t_step, m1*lal.MSUN_SI, m2*lal.MSUN_SI, f_min, 1e6*lal.PC_SI, spin1z, spin2z,41, 0., 0., 0.,0.,0.,0.,0.,0.,1.,1.,nqcCoeffsInput, 0) amp_prefactor = prefactor*(m1+m2)/1. # G/c^2 (M / d_L) while sp is not None: lm = (sp.l, sp.m) if lm not in modes: #skipping a non-necessary mode continue else: #computing index and saving the mode i = modes.index(lm) hlm = sp.mode.data.data #complex mode vector temp_amp = np.abs(hlm)/ amp_prefactor / nu #scaling with the convention of SEOB temp_ph = np.unwrap(np.angle(hlm)) amp_list[i] = temp_amp ph_list[i] = temp_ph if (sp.l, sp.m) == (2,2): #get grid amp_22 = np.abs(sp.mode.data.data) #amp of 22 mode (for time grid alignment) time_full = np.linspace(0.0, sp.mode.data.length*t_step, sp.mode.data.length) #time grid at which wave is computed argpeak = locate_peak(amp_22) #aligned at the peak of the 22 sp = sp.next else: #another lal approximant (only 22 mode) hp, hc = lalsim.SimInspiralChooseTDWaveform( #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 1e6*lalsim.lal.PC_SI, #distance to source 0., #inclination 0., #phi 0., #longAscNodes 0., #eccentricity 0., #meanPerAno t_step, # time incremental step f_min, # lowest value of freq f_min, #some reference value of freq (??) LALpars, #some lal dictionary approx #approx method for the model ) h_p, h_c = hp.data.data, hc.data.data time_full = np.linspace(0.0, hp.data.length*t_step, hp.data.length) #time grid at which wave is computed amp_prefactor = prefactor*(m1+m2)/1. # G/c^2 (M / d_L) temp_amp = np.sqrt(np.square(h_p)+np.square(h_c)) / amp_prefactor / (4*np.sqrt(5/(64*np.pi))) temp_ph = np.unwrap(np.arctan2(h_c,h_p)) amp_list = [temp_amp] ph_list = [temp_ph] argpeak = locate_peak(temp_amp) #aligned at the peak of the 22 #setting time grid t_peak = time_full[argpeak] time_full = (time_full - t_peak)/(m1+m2) #grid is scaled to standard grid #computing waves to the chosen std grid and saving to file for i in range(len(amp_list)): temp_amp, temp_ph = amp_list[i], ph_list[i] #print(temp_amp.shape, time_full.shape, time_grid_list[i].shape) temp_amp = np.interp(time_grid_list[i], time_full, temp_amp) temp_ph = np.interp(time_grid_list[i], time_full, temp_ph) temp_ph = temp_ph - temp_ph[0] #all phases are shifted by a constant to make sure every wave has 0 phase at beginning of grid to_save = np.concatenate((temp_theta, temp_amp, temp_ph))[None,:] #(1,D) np.savetxt(buff_list[i], to_save) #user communication if n_WF%100 == 0 and n_WF != 0: #if n_WF%1 == 0 and n_WF != 0: #debug print("Generated WF ", n_WF) if filename is None: return theta_vector, amp_dataset.real, ph_dataset.real, time_grid else: filebuff.close() return None
def getApprox(type, name, m1=10.0, m2=10.0, f_ref=0.0, f_low=50.0, distance=1, delta_t=1.0 / 4096.0, s1x=0, s1y=0, s1z=0, s2x=0, s2y=0, s2z=0, inclination=0, tidal1=0, tidal2=0): if type == 'pycbc': hp, hc = get_td_waveform(approximant=name, mass1=m1, mass2=m2, f_lower=f_low, f_ref=f_ref, distance=distance, delta_t=delta_t, spin1x=s1x, spin1y=s1y, spin1z=s1z, spin2x=s2x, spin2y=s2y, spin2z=s2z, lambda1=tidal1, lambda2=tidal2, inclination=inclination) new_hp = np.array(hp) new_hc = np.array(hc) h = new_hp + new_hc * 1j times = np.array(hp.sample_times) shift_times = times - times[0] return (shift_times, h) elif type == 'laltd': mpc = 1.0e6 * lal.PC_SI m1 = m1 * lal.MSUN_SI m2 = m2 * lal.MSUN_SI distance = distance * mpc tidal_params = lal.CreateDict() lalsim.SimInspiralWaveformParamsInsertTidalLambda1( tidal_params, tidal1) lalsim.SimInspiralWaveformParamsInsertTidalLambda2( tidal_params, tidal2) hp, hc = lalsim.SimInspiralTD( m1, m2, s1x, s1y, s1z, s2x, s2y, s2z, distance, inclination, phiRef, 0., 0., 0., delta_t, f_low, f_ref, tidal_params, lalsim.SimInspiralGetApproximantFromString(name)) times = np.arange(len(hp.data.data)) * delta_t + hp.epoch shift_times = times - times[0] h = np.array(hp.data.data + 1j * hc.data.data) return (shift_times, h) else: print 'Specify pycbc or laltd for approx type'
#maggiore gravitational waves vol 1 per cose un po' teoriche... #leggi nested sampling meglio #leggi articoli https://arxiv.org/abs/0907.0700 + https://arxiv.org/abs/1801.08009 #studia meglio metodi probabilistici a rete... M = [5, 100] #m1>m2 spin = [-.9, .9] m1 = 10 m2 = 1 spin1z = 0.2 spin2z = 0.4 d = 1 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,
spin1x = 0.0 spin1y = 0.0 spin1z = 0.0 spin2x = 0.0 spin2y = 0.0 spin2z = 0.0 d = 500 phi0 = 2.0 inclination = 0.0 sampling_rate = 2048 dt = 1. / sampling_rate flow = 20 fref = 20 LALpars = lal.CreateDict() approx = lalsim.SimInspiralGetApproximantFromString('SEOBNRv2') hp, hc = lalsim.SimInspiralChooseTDWaveform( m1 * lalsim.lal.MSUN_SI, m2 * lalsim.lal.MSUN_SI, spin1x, spin1y, spin1z, spin2x, spin2y, spin2z, d * 1e6 * lalsim.lal.PC_SI, inclination, phi0, 0, #longAscNodes 0, #eccentricity