def __init__(self, mass_1, mass_2, chi_1, chi_2, luminosity_distance, lambda_1=0, lambda_2=0): self.mass_1 = mass_1 self.mass_2 = mass_2 self.chi_1 = chi_1 self.chi_2 = chi_2 self.total_mass = mass_1 + mass_2 self.symmetric_mass_ratio = mass_1 * mass_2 / self.total_mass**2 self.lambda_1 = float(lambda_1) self.lambda_2 = float(lambda_2) self.param_dict = CreateDict() ls.SimInspiralWaveformParamsInsertTidalLambda1(self.param_dict, self.lambda_1) ls.SimInspiralWaveformParamsInsertTidalLambda2(self.param_dict, self.lambda_2) ls.SimInspiralSetQuadMonParamsFromLambdas(self.param_dict) self.luminosity_distance = luminosity_distance * MEGA_PARSEC_SI
def phase(self, frequency_array, phi_c=0): orbital_speed = (np.pi * self.total_mass * SOLAR_RADIUS_IN_S * frequency_array)**(1 / 3) phase_coefficients = ls.SimInspiralTaylorF2AlignedPhasing( self.mass_1, self.mass_2, self.chi_1, self.chi_2, CreateDict()) phasing = xp.zeros_like(orbital_speed) cumulative_power_frequency = orbital_speed**-5 for ii in range(len(phase_coefficients.v)): phasing += phase_coefficients.v[ii] * cumulative_power_frequency phasing += (phase_coefficients.vlogv[ii] * cumulative_power_frequency * xp.log(orbital_speed)) cumulative_power_frequency *= orbital_speed phasing -= 2 * phi_c + np.pi / 4 phasing = phasing % (2 * np.pi) return phasing
def _base_roq_waveform( frequency_array, mass_1, mass_2, luminosity_distance, a_1, tilt_1, phi_12, a_2, tilt_2, lambda_1, lambda_2, phi_jl, theta_jn, phase, **waveform_arguments): """ See https://git.ligo.org/lscsoft/lalsuite/blob/master/lalsimulation/src/LALSimInspiral.c#L1460 Parameters ========== frequency_array: np.array This input is ignored for the roq source model mass_1: float The mass of the heavier object in solar masses mass_2: float The mass of the lighter object in solar masses luminosity_distance: float The luminosity distance in megaparsec a_1: float Dimensionless primary spin magnitude tilt_1: float Primary tilt angle phi_12: float a_2: float Dimensionless secondary spin magnitude tilt_2: float Secondary tilt angle phi_jl: float theta_jn: float Orbital inclination phase: float The phase at coalescence Waveform arguments =================== Non-sampled extra data used in the source model calculation frequency_nodes_linear: np.array frequency_nodes_quadratic: np.array reference_frequency: float approximant: str Note: for the frequency_nodes_linear and frequency_nodes_quadratic arguments, if using data from https://git.ligo.org/lscsoft/ROQ_data, this should be loaded as `np.load(filename).T`. Returns ======= waveform_polarizations: dict Dict containing plus and cross modes evaluated at the linear and quadratic frequency nodes. """ from lal import CreateDict frequency_nodes_linear = waveform_arguments['frequency_nodes_linear'] frequency_nodes_quadratic = waveform_arguments['frequency_nodes_quadratic'] reference_frequency = waveform_arguments['reference_frequency'] approximant = lalsim_GetApproximantFromString( waveform_arguments['waveform_approximant']) luminosity_distance = luminosity_distance * 1e6 * utils.parsec mass_1 = mass_1 * utils.solar_mass mass_2 = mass_2 * utils.solar_mass waveform_dictionary = CreateDict() lalsim_SimInspiralWaveformParamsInsertTidalLambda1( waveform_dictionary, lambda_1) lalsim_SimInspiralWaveformParamsInsertTidalLambda2( waveform_dictionary, lambda_2) iota, spin_1x, spin_1y, spin_1z, spin_2x, spin_2y, spin_2z = bilby_to_lalsimulation_spins( theta_jn=theta_jn, phi_jl=phi_jl, tilt_1=tilt_1, tilt_2=tilt_2, phi_12=phi_12, a_1=a_1, a_2=a_2, mass_1=mass_1, mass_2=mass_2, reference_frequency=reference_frequency, phase=phase) h_linear_plus, h_linear_cross = lalsim_SimInspiralChooseFDWaveformSequence( phase, mass_1, mass_2, spin_1x, spin_1y, spin_1z, spin_2x, spin_2y, spin_2z, reference_frequency, luminosity_distance, iota, waveform_dictionary, approximant, frequency_nodes_linear) waveform_dictionary = CreateDict() lalsim_SimInspiralWaveformParamsInsertTidalLambda1( waveform_dictionary, lambda_1) lalsim_SimInspiralWaveformParamsInsertTidalLambda2( waveform_dictionary, lambda_2) h_quadratic_plus, h_quadratic_cross = lalsim_SimInspiralChooseFDWaveformSequence( phase, mass_1, mass_2, spin_1x, spin_1y, spin_1z, spin_2x, spin_2y, spin_2z, reference_frequency, luminosity_distance, iota, waveform_dictionary, approximant, frequency_nodes_quadratic) waveform_polarizations = dict() waveform_polarizations['linear'] = dict( plus=h_linear_plus.data.data, cross=h_linear_cross.data.data) waveform_polarizations['quadratic'] = dict( plus=h_quadratic_plus.data.data, cross=h_quadratic_cross.data.data) return waveform_polarizations
def _base_waveform_frequency_sequence(frequency_array, mass_1, mass_2, luminosity_distance, a_1, tilt_1, phi_12, a_2, tilt_2, lambda_1, lambda_2, phi_jl, theta_jn, phase, **waveform_kwargs): """ Generate a cbc waveform model on specified frequency samples Parameters ---------- frequency_array: np.array This input is ignored mass_1: float The mass of the heavier object in solar masses mass_2: float The mass of the lighter object in solar masses luminosity_distance: float The luminosity distance in megaparsec a_1: float Dimensionless primary spin magnitude tilt_1: float Primary tilt angle phi_12: float a_2: float Dimensionless secondary spin magnitude tilt_2: float Secondary tilt angle phi_jl: float theta_jn: float Orbital inclination phase: float The phase at coalescence waveform_kwargs: dict Optional keyword arguments Returns ------- waveform_polarizations: dict Dict containing plus and cross modes evaluated at the linear and quadratic frequency nodes. """ from lal import CreateDict import lalsimulation as lalsim frequencies = waveform_kwargs['frequencies'] reference_frequency = waveform_kwargs['reference_frequency'] approximant = lalsim_GetApproximantFromString( waveform_kwargs['waveform_approximant']) catch_waveform_errors = waveform_kwargs['catch_waveform_errors'] pn_spin_order = waveform_kwargs['pn_spin_order'] pn_tidal_order = waveform_kwargs['pn_tidal_order'] pn_phase_order = waveform_kwargs['pn_phase_order'] pn_amplitude_order = waveform_kwargs['pn_amplitude_order'] waveform_dictionary = waveform_kwargs.get('lal_waveform_dictionary', CreateDict()) lalsim.SimInspiralWaveformParamsInsertPNSpinOrder(waveform_dictionary, int(pn_spin_order)) lalsim.SimInspiralWaveformParamsInsertPNTidalOrder(waveform_dictionary, int(pn_tidal_order)) lalsim.SimInspiralWaveformParamsInsertPNPhaseOrder(waveform_dictionary, int(pn_phase_order)) lalsim.SimInspiralWaveformParamsInsertPNAmplitudeOrder( waveform_dictionary, int(pn_amplitude_order)) lalsim_SimInspiralWaveformParamsInsertTidalLambda1(waveform_dictionary, lambda_1) lalsim_SimInspiralWaveformParamsInsertTidalLambda2(waveform_dictionary, lambda_2) for key, value in waveform_kwargs.items(): func = getattr(lalsim, "SimInspiralWaveformParamsInsert" + key, None) if func is not None: func(waveform_dictionary, value) if waveform_kwargs.get('numerical_relativity_file', None) is not None: lalsim.SimInspiralWaveformParamsInsertNumRelData( waveform_dictionary, waveform_kwargs['numerical_relativity_file']) if ('mode_array' in waveform_kwargs) and waveform_kwargs['mode_array'] is not None: mode_array = waveform_kwargs['mode_array'] mode_array_lal = lalsim.SimInspiralCreateModeArray() for mode in mode_array: lalsim.SimInspiralModeArrayActivateMode(mode_array_lal, mode[0], mode[1]) lalsim.SimInspiralWaveformParamsInsertModeArray( waveform_dictionary, mode_array_lal) luminosity_distance = luminosity_distance * 1e6 * utils.parsec mass_1 = mass_1 * utils.solar_mass mass_2 = mass_2 * utils.solar_mass iota, spin_1x, spin_1y, spin_1z, spin_2x, spin_2y, spin_2z = bilby_to_lalsimulation_spins( theta_jn=theta_jn, phi_jl=phi_jl, tilt_1=tilt_1, tilt_2=tilt_2, phi_12=phi_12, a_1=a_1, a_2=a_2, mass_1=mass_1, mass_2=mass_2, reference_frequency=reference_frequency, phase=phase) try: h_plus, h_cross = lalsim_SimInspiralChooseFDWaveformSequence( phase, mass_1, mass_2, spin_1x, spin_1y, spin_1z, spin_2x, spin_2y, spin_2z, reference_frequency, luminosity_distance, iota, waveform_dictionary, approximant, frequencies) except Exception as e: if not catch_waveform_errors: raise else: EDOM = (e.args[0] == 'Internal function call failed: Input domain error') if EDOM: failed_parameters = dict( mass_1=mass_1, mass_2=mass_2, spin_1=(spin_1x, spin_2y, spin_1z), spin_2=(spin_2x, spin_2y, spin_2z), luminosity_distance=luminosity_distance, iota=iota, phase=phase) logger.warning( "Evaluating the waveform failed with error: {}\n".format(e) + "The parameters were {}\n".format(failed_parameters) + "Likelihood will be set to -inf.") return None else: raise return dict(plus=h_plus.data.data, cross=h_cross.data.data)
def get_chirp_params_new(mass1, mass2, spin1z, spin2z, f0, order): """ Take a set of masses and spins and convert to the various lambda coordinates that describe the orbital phase. Accepted PN orders are: {} Parameters ---------- mass1 : float or array Mass1 of input(s). mass2 : float or array Mass2 of input(s). spin1z : float or array Parallel spin component(s) of body 1. spin2z : float or array Parallel spin component(s) of body 2. f0 : float This is an arbitrary scaling factor introduced to avoid the potential for numerical overflow when calculating this. Generally the default value (70) is safe here. **IMPORTANT, if you want to calculate the ethinca metric components later this MUST be set equal to f_low.** This value must also be used consistently (ie. don't change its value when calling different functions!). order : string The Post-Newtonian order that is used to translate from masses and spins to the lambda_i coordinate system. Valid orders given above. Returns -------- lambdas : list of floats or numpy.arrays The lambda coordinates for the input system(s) """ # Determine whether array or single value input sngl_inp = False try: num_points = len(mass1) except TypeError: sngl_inp = True # If you care about speed, you aren't calling this function one entry # at a time. mass1 = numpy.array([mass1]) mass2 = numpy.array([mass2]) spin1z = numpy.array([spin1z]) spin2z = numpy.array([spin2z]) num_points = 1 lal_pars = CreateDict() phasing_vs = numpy.zeros([num_points, 13]) phasing_vlogvs = numpy.zeros([num_points, 13]) phasing_vlogvsqs = numpy.zeros([num_points, 13]) for i in xrange(num_points): phasing = lalsimulation.SimInspiralTaylorF2AlignedPhasing( mass1[i], mass2[i], spin1z[i], spin2z[i], lal_pars) phasing_vs[i] = phasing.v phasing_vlogvs[i] = phasing.vlogv phasing_vlogvsqs[i] = phasing.vlogvsq pmf = PI * (mass1 + mass2)*MTSUN_SI * f0 pmf13 = pmf**(1./3.) mapping = generate_inverse_mapping(order) lambdas = [] lambda_str = '^Lambda([0-9]+)' loglambda_str = '^LogLambda([0-9]+)' logloglambda_str = '^LogLogLambda([0-9]+' for idx in xrange(len(mapping.keys())): # RE magic engage! rematch = re.match(lambda_str, mapping[idx]) if rematch: pn_order = int(rematch.groups()[0]) lambdas.append(phasing_vs[:,pn_order] * pmf13**(-5+pn_order)) continue rematch = re.match(loglambda_str, mapping[idx]) if rematch: pn_order = int(rematch.groups()[0]) lambdas.append(phasing_vlogvs[:,pn_order] * pmf13**(-5+pn_order)) continue rematch = re.match(logloglambda_str, mapping[idx]) if rematch: pn_order = int(rematch.groups()[0]) lambdas.append(phasing_vlogvsqs[:,pn_order] * pmf13**(-5+pn_order)) continue err_msg = "Failed to parse " + mapping[idx] raise ValueError(err_msg) if sngl_inp: return [l[0] for l in lambdas] else: return lambdas