Loading [MathJax]/extensions/TeX/AMSsymbols.js
LALSimulation 6.2.0.1-b246709
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
hybrid_spin_evolution.py
Go to the documentation of this file.
1"""
2This script computes the tilt angles at infinity from a given reference frequency, by combining orbit-averaged evolution at higher frequencies
3until a transition frequency, with precession-averaged evolution until infinite separation.
4There is also an option to compute the bounds on the tilts and an average value at a finite separation, though this has not been tested extensively.
5This implementation is described in the paper, <https://dcc.ligo.org/P2100029>, arXiv:2107.11902
6
7Sumeet Kulkarni, 2021
8"""
9
10import numpy as np
11import lal
12from .calc_tilts_prec_avg_regularized import prec_avg_tilt_comp
13from .tilts_at_infinity_utils import *
14import lalsimulation as lalsim
15from warnings import warn
16
17# Define a function to transform spin basis:
18def get_tilts(chi1x, chi1y, chi1z, chi2x, chi2y, chi2z, Lnx, Lny, Lnz):
19
20 """
21 Given the spins and ang momentum at a given frequency, find the tilt and in-plane spin angles at that frequency.
22
23 Inputs:
24 chi1x, chi1y, chi1z: Cartesian spin-magnitude components for the primary object (m1) of the binary
25 chi2x, chi2y, chi2z: Cartesian spin-magnitude components for the secondary object (m2) of the binary
26 Lnx, Lny, Lnz: Cartesian components of the direction of the Newtonian orbital angular momentum (will be normalized) of the binary
27
28 Output:
29 tilt1, tilt2: tilt angles of the binary spin-vectors w.r.t. the z-axis: the direction of the Newtonian orbital angular momentum
30 phi12: angle between projection of the two spin-vectors onto the xy plane
31 """
32
33 chi1 = np.array([chi1x, chi1y, chi1z])
34 chi2 = np.array([chi2x, chi2y, chi2z])
35
36 Ln = np.array([Lnx, Lny, Lnz])
37
38 # norms and normalizing
39 chi1_norm = np.linalg.norm(chi1)
40 chi2_norm = np.linalg.norm(chi2)
41
42 Ln /= np.linalg.norm(Ln)
43
44 # dot products
45 chi1dL = np.dot(chi1, Ln)
46 chi2dL = np.dot(chi2, Ln)
47
48 # in-plane spins
49 chi1inplane = chi1 - chi1dL*Ln
50 chi2inplane = chi2 - chi2dL*Ln
51
52 # Defining cosine of tilts and phi12
53 cos_tilt1 = np.clip(chi1dL/chi1_norm, -1., 1.)
54 cos_tilt2 = np.clip(chi2dL/chi2_norm, -1., 1.)
55 cos_phi12 = np.clip(np.dot(chi1inplane,chi2inplane)/(np.linalg.norm(chi1inplane) * np.linalg.norm(chi2inplane)),-1.,1.)
56
57 # set quadrant of phi12
58 phi12_evol_i = np.arccos(cos_phi12)
59 if np.sign(np.dot(Ln,np.cross(chi1, chi2))) < 0:
60 phi12_evol_i = 2.*np.pi - phi12_evol_i
61
62 return np.arccos(cos_tilt1), np.arccos(cos_tilt2), phi12_evol_i
63
64
65# Define a function to calculate v_trans based on the fitting curve, for a given mass ratio
66def calc_v_trans(q):
67 """
68 Calculates the transition orbital speed (v_trans) to shift from orbit-averaged to precession-averaged evolution in this
69 hybrid spin evolution code. v_trans depends on the mass ratio, (q), and is determined using the fitting curve from the
70 paper [Eq. (31) in the paper, <https://dcc.ligo.org/P2100029>, arXiv:2107.11902]
71
72 Input:
73
74 q, the binary mass ratio defined as m2/m1, with m1 being the primary (heavier) object; range (0,1].
75
76 Output:
77 v_transition (float)
78 """
79 if q <= 0. or q > 1.:
80 raise ValueError("The mass ratio must be a float between 0 and 1, defined as m2/m1 where m1 is the heavier component")
81 # Coefficients of the fit:
82 a = -0.05
83 b = 0.06
84 return(a*q**2 + b)
85
86
87# The number of steps in integration, based on the v_trans:
88def get_nsteps(v_trans):
89 """
90 Determine the number of frequency steps to use in each segment of the integration while performing orbit-averaged evolution
91 from fref to v_trans
92
93 Input:
94 v_trans (float): the transition orbital speed determined by the fit in calc_v_trans()
95 The value for v_trans must be >= 0.01, which is the least transition orbital speed given in our fit in the paper [Eq. (31) in
96 <https://dcc.ligo.org/P2100029>, arXiv:2107.11902]
97
98 Output:
99 n_steps: (int), the number of steps for evolution to be used in calc_tilts_at_infty_hybrid_evolve()
100 """
101 if v_trans >= 0.05:
102 n = 200
103 elif 0.03 < v_trans <= 0.05:
104 n = 800
105 elif 0.02 < v_trans <= 0.03:
106 n = 3200
107 elif 0.01 <= v_trans <= 0.02:
108 n = 12800
109 else:
110 raise ValueError("The number of steps has not been calibrated for v_trans < 0.01 and might lead to memory errors")
111 return n
112
113
114# The timesteps based on how low to go in v:
115def get_dt_constant(v_trans):
116 """
117 Determine the step-size (dt) to use in each frequency interval used for orbit-averaged evolution from fref to v_trans.
118 This function returns the denominator X in the constant c = 1/X, such that f_high*dt = c in determining the timestep
119 of orbital evolution. Here, f_high is the higher frequency in the frequency interval.
120
121 Input:
122 v_trans (float): the transition orbital speed determined by the fit in calc_v_trans()
123
124 Output:
125 dt_constant: (int) to be used in calc_tilts_at_infty_hybrid_evolve()
126 """
127 if v_trans > 0.05:
128 dt_c = 256
129 elif 0.03 < v_trans <= 0.05:
130 dt_c = 128
131 elif 0.01 <= v_trans <= 0.03:
132 dt_c = 64
133 else:
134 raise ValueError("Evolution to v_trans lower than 0.01 not possible with current configuration")
135 return dt_c
136
137
138def calc_tilts_at_infty_hybrid_evolve(m1, m2, chi1, chi2, tilt1, tilt2, phi12, fref, approx="SpinTaylorT5", spinO=6, lscorr=1, verbose=False, prec_only=False, version='v1', failure_mode='None', **kwargs):
139 """
140 Calculate tilts at infinity with hybrid orbit-averaged and precession-averaged evolution
141 Evolves tilt1 and tilt2 for a given binary from a reference frequency, fref, to infinite separation by first evolving using orbit-averaged evolution
142 until a transition orbital speed (v_trans) given by calc_v_trans(), and from that point until infinity using precession-averaged evolution.
143
144 There is also an option to compute the bounds on the tilts and average values at a finite separation (given by the value of the orbital angular momentum, Lf)
145 but the application of the hybrid evolution to this case is not so well tested. In particular, for small enough values of Lf, the hybrid evolution will end
146 at a larger value of the orbital angular momentum than Lf and the precession-averaged evolution will fail because of this. This function does not check for
147 this case.
148
149 Inputs:
150
151 --Required--
152 m1, m2: Detector frame masses of the binary, in kg
153 chi1, chi2: The dimensionless spin-magnitudes of the binary
154 tilt1, tilt2: tilt angles of the binary spin-vectors w.r.t. the z-axis: the direction of the Newtonian orbital angular momentum
155 phi12: angle between projection of the two spin-vectors onto the xy plane
156 fref: Reference frequency, in Hz; must be <= 20 Hz, since the stepwise evolution is currently only calibrated for such values
157
158 --Optional--
159 approx: The approximant to use (options: "SpinTaylorT1", "SpinTaylorT4", "SpinTaylorT5"), default: "SpinTaylorT5"
160 spinO: The order of the spin contributions included in the post-Newtonian expansion (possible values:[4,5,6]), default: 6
161 lscorr: activates spin contributions to the orbital angular momentum in the precession equations, default: 1 (active)
162 verbose (bool): display details of integration steps and print output of orbit-averaged evolution, default: False
163 prec_only: Use only the precession-averaged evolution for a quick but less accurate result, default: False
164 version: Version of the calculation to use--currently, two versions are available: v1 divides the orbit-averaged part of the hybrid evolution into a series of multiple integration steps, while in v2 it proceeds in a single step using a modified integrator that only outputs the final spin values, default: "v1", though this will be changed to "v2" in a near future release, since the "v2" evolution is much faster and somewhat more accurate
165 failure_mode: How the code behaves when the evolution fails. 'Error' means that the code raises a RuntimeError, while 'NAN' and 'None' mean that the code raises a RuntimeWarning and returns np.nan or None for the output, respectively, default: 'None'
166
167 **kwargs: dict, optional: precession-averaged evolution settings, passed through **kwargs to prec_avg_tilt_comp()
168 Please refer to the prec_avg_tilt_comp() documentation in calc_tilts_prec_avg_regularized.py for the list of settings
169
170 NOTE: The keyword argument Lf: Final magnitude of orbital angular momentum, if set to None, gives the output at infinity; this is the default.
171 To obtain tilts at a finite separation, provide the corresponding Lf in total mass = 1 units
172
173 NOTE: prec_avg_tilt_comp() options LPNorder and LPNspins are not available through here, but are set automatically by the choice of spinO and lscorr.
174
175 Output:
176
177 Dictionary with entries 'tilt1_inf', 'tilt2_inf' for evolution to infinity, and entries 'tilt1_transition', 'tilt2_transition',
178 'phi12_transition' for the tilts at the transition orbital speed (v_trans).
179
180 NOTE: If kwarg Lf is not set to None in prec_avg_tilt_comp(), the output gives bounds and average values for the tilts at a final separation determined by Lf.
181 In this case, the entries 'tilt1_inf' and 'tilt2_inf' will be replaced by 'tilt1_sep_min', 'tilt1_sep_max', 'tilt1_sep_avg', 'tilt2_sep_min', 'tilt2_sep_max',
182 and 'tilt2_sep_avg'.
183 """
184
185 # Check version
186 if version in ['v1','v2']:
187 version_prec_avg = 'v1'
188
189 if version == 'v1':
190 warn("v1 of the hybrid tilts at infinity calculation is deprecated, since v2 is much faster and somewhat more accurate. In a near future release, the default version will be changed to v2.", FutureWarning)
191 else:
192 raise ValueError("Only versions ['v1', 'v2'] are available at the moment, while version = %s"%version)
193
194 # Set the failure output and the string corresponding to it
195 # These default to None, since they are not used if failure_mode == 'Error'
196
197 if failure_mode == 'NAN':
198 failure_output = np.nan
199 failure_output_string = 'np.nan'
200 else:
201 failure_output = None
202 failure_output_string = 'None'
203
204 # Check if Lf is defined in kwargs:
205 if 'Lf' in kwargs:
206 Lf = kwargs['Lf']
207 else:
208 Lf = None
209
210 ## Run checks for input parameter values of the masses, spin magnitudes, tilts and reference frequency:
211
212 # Masses
213 check_masses(m1, m2)
214 # Exactly equal masses:
215 eq_mass_check(m1, m2, Lf)
216 # Spin Magnitudes:
217 check_spin_mags(chi1, chi2)
218 # Tilt inclinations:
219 check_tilts(tilt1, tilt2)
220 # Reference Frequency:
221 check_fref(fref, m1, m2, evol_type="hybrid")
222
223 # Return tilts as they are for non-spinning and exactly aligned/anti-aligned cases:
224 if (tilt1 == np.pi and tilt2 in [0., np.pi]) or (tilt1 == 0. and tilt2 == 0.):
225 return package_tilts(tilt1, tilt2, Lf, swap=False)
226
227 # Note: returning the input tilts for single non-spinning cases not appropriate if the instantaneous terms in the orbit-averaged evolution are activated.
228 if chi1 == 0. or chi2 == 0.:
229 return package_tilts(tilt1, tilt2, Lf, swap=False)
230
231 # If prec_only is set to True, omit hybrid evolution and return tilts at infinity using only precession-averaged evolution for fast results.
232 if prec_only:
233 spin_angles_output = prec_avg_tilt_comp(m1, m2, chi1, chi2, tilt1, tilt2, phi12, fref, LPNorder = 2, LPNspins = False, **kwargs)
234 spin_angles_output["tilt1_transition"] = None
235 spin_angles_output["tilt2_transition"] = None
236 spin_angles_output["phi12_transition"] = None
237 spin_angles_output["f_transition"] = None
238 return spin_angles_output
239
240
241 M = m1 + m2 #total mass, in kg.
242 q = min(m1/m2,m2/m1) #mass ratio (make sure this is in the range [0,1) )
243
244 # Save input masses in kg.
245 m1_kg = m1
246 m2_kg = m2
247
248 # Rescale masses and frequency to the stellar-mass scale of total mass = 200 M_sun units:
249 fac = 200*MSUN_SI/M
250 m1 *= fac
251 m2 *= fac
252 fref /= fac
253
254 # Define the rescaled total mass in seconds, for usage in converting from frequencies to orbital speeds, and vice versa:
255 MT_s = (m1 + m2) * kg_to_s
256
257 # Transition orbital speed:
258 v_trans = calc_v_trans(q)
259 if verbose:
260 print("v_trans = {}".format(v_trans))
261 f_trans = v_trans**3/np.pi/MT_s
262
263 # Set parameters:
264 v_ref = np.power((fref*(np.pi*MT_s)),1./3)
265
266 phaseO = 7
267 tideO = 0
268
269
270 if lscorr == 0:
271 LPNspins = False
272 elif lscorr == 1:
273 LPNspins = True
274 else:
275 raise ValueError("The value of lscorr should either be 0 or 1")
276 inst = 0
277 approx = lalsim.GetApproximantFromString(approx)
278
279 if spinO == 4:
280 LPNorder = 0
281 elif spinO == 5 and lscorr == 0:
282 LPNorder = 1
283 elif spinO == 5 and lscorr == 1:
284 LPNorder = 1.5
285 elif spinO == 6 and lscorr == 0:
286 LPNorder = 1
287 elif spinO == 6 and lscorr == 1:
288 LPNorder = 1.5
289 # spinO == 7 will only be available when the instantaneous evolution is implemented
290 #elif spinO == 7 and lscorr == 0:
291 # LPNorder = 2
292 #elif spinO == 7 and lscorr == 1:
293 # LPNorder = 2.5
294 else:
295 raise ValueError("Check your SpinO input, which must be one from [4,5,6]; given input = {}".format(spinO))
296
297 # Transform from spherical to cartesian for initial values of the tilts:
298 chi1x_high, chi1y_high, chi1z_high = chi1*np.sin(tilt1), 0.0, chi1*np.cos(tilt1)
299 chi2x_high, chi2y_high, chi2z_high = chi2*np.sin(tilt2)*np.cos(phi12), chi2*np.sin(tilt2)*np.sin(phi12), chi2*np.cos(tilt2)
300
301 Lnx_high = 0.0
302 Lny_high = 0.0
303 Lnz_high = 1.0
304
305 E1x_high = 1.0
306 E1y_high = 0.0
307 E1z_high = 0.0
308
309 lalpars=lal.CreateDict()
310 lalsim.SimInspiralWaveformParamsInsertFinalFreq(lalpars, f_trans)
311 lalsim.SimInspiralWaveformParamsInsertPNSpinOrder(lalpars, spinO)
312 lalsim.SimInspiralWaveformParamsInsertPNPhaseOrder(lalpars, phaseO)
313 lalsim.SimInspiralWaveformParamsInsertLscorr(lalpars, lscorr)
314
315 if f_trans < fref:
316
317 ###################### v2: single-step evolution ############################################
318
319 if version == "v2":
320
321 # Use a uniform timestep (with dt_constant = 64) for all binary parameters:
322 dt = 1./(64 * fref)
323 # Activate option to save only final values in Spin Taylor evolution:
324 lalsim.SimInspiralWaveformParamsInsertOnlyFinal(lalpars, 1)
325
326 dictparams = {'phiRef':0., 'deltaT': dt, 'm1_SI': m1, 'm2_SI': m2, 'fStart': fref, 'fRef': fref, 's1x': chi1x_high, 's1y': chi1y_high, 's1z': chi1z_high,
327 's2x': chi2x_high, 's2y': chi2y_high, 's2z': chi2z_high, 'lnhatx': Lnx_high, 'lnhaty': Lny_high, 'lnhatz': Lnz_high,
328 'e1x': E1x_high, 'e1y': E1y_high, 'e1z': E1z_high, 'LALparams': lalpars, 'approx': approx}
329
330 try:
331 _,_,c1x, c1y, c1z, c2x, c2y, c2z, Lnx, Lny, Lnz, E1x, E1y, E1z = lalsim.SimInspiralSpinTaylorOrbitalDriver(**dictparams)
332 except:
333 failure_message = "The orbit-averaged evolution failed."
334 return evolution_error_handling(failure_mode, failure_message, failure_output, failure_output_string, Lf, swap=False, hybrid_evol=True)
335
336 c1x = c1x.data.data[-1]
337 c2x = c2x.data.data[-1]
338 c1y = c1y.data.data[-1]
339 c2y = c2y.data.data[-1]
340 c2z = c2z.data.data[-1]
341 c1z = c1z.data.data[-1]
342 Lnx = Lnx.data.data[-1]
343 Lny = Lny.data.data[-1]
344 Lnz = Lnz.data.data[-1]
345
346 tilt1_transition, tilt2_transition, phi12_transition = get_tilts(c1x, c1y, c1z, c2x, c2y, c2z, Lnx, Lny, Lnz)
347
348 if verbose:
349 print("The tilts at transition are: tilt1 = {0}, tilt2 = {1}, phi12 = {2}".format(tilt1_transition, tilt2_transition, phi12_transition))
350
351 spin_angles_output = prec_avg_tilt_comp(m1, m2, chi1, chi2, tilt1_transition, tilt2_transition, phi12_transition, f_trans, LPNorder = LPNorder, LPNspins = LPNspins,
352 version=version_prec_avg, **kwargs)
353 spin_angles_output["tilt1_transition"] = tilt1_transition
354 spin_angles_output["tilt2_transition"] = tilt2_transition
355 spin_angles_output["phi12_transition"] = phi12_transition
356 spin_angles_output["f_transition"] = v_trans**3/np.pi/(M*kg_to_s) #return the transition frequency based on the original input masses in kg.
357
358
359 ################### v1: multi-step evolution #############################
360
361 elif version == 'v1':
362
363 # Use a timestep optimized by the get_dt_constant() function:
364 dt_constant = get_dt_constant(v_trans)
365 dt = 1./(dt_constant * fref)
366
367 dictparams = {'phiRef':0., 'deltaT': dt, 'm1_SI': m1, 'm2_SI': m2, 'fStart': fref, 'fRef': fref, 's1x': chi1x_high, 's1y': chi1y_high, 's1z': chi1z_high,
368 's2x': chi2x_high, 's2y': chi2y_high, 's2z': chi2z_high, 'lnhatx': Lnx_high, 'lnhaty': Lny_high, 'lnhatz': Lnz_high,
369 'e1x': E1x_high, 'e1y': E1y_high, 'e1z': E1z_high, 'LALparams': lalpars, 'approx': approx}
370
371
372 ####################### Step 1: Use LALSIM.SimInspiralSpinTaylorPNEvolveOrbit to get orbit-averaged spins at the transition frequency #########################
373
374 n_steps = get_nsteps(v_trans)
375
376 if verbose:
377 print("Starting orbital evolution in nsteps = ",n_steps)
378
379 v_start = 0.5*(v_ref + v_trans) # This is the v-value until which all binaries can be evolved from a given fref without segfaulting # NEEDS CALIBRATION FOR fref > 20 Hz
380 v_arr = np.geomspace(v_start,v_trans,n_steps+1)
381 v_arr = np.insert(v_arr, 0, v_ref) # start the orbital speed integration steps array with v_ref
382
383 for i in range(len(v_arr)-1):
384 if verbose:
385 print("starting step {}".format(i+1))
386 v_high = v_arr[i]
387 f_high = v_high**3/np.pi/MT_s
388 dictparams['fStart'] = f_high
389 dictparams['fRef'] = f_high
390
391 v_low = v_arr[i+1]
392 f_low = v_low**3/np.pi/MT_s
393 lalsim.SimInspiralWaveformParamsInsertFinalFreq(lalpars, f_low)
394 dictparams['LALparams'] = lalpars
395 dictparams['deltaT'] = 1./(dt_constant * f_high)
396 if verbose:
397 print("Evolving to v_low = {0} corresponding to f_low = {1} with dt = {2}".format(v_low, f_low, dictparams['deltaT']))
398
399 try:
400 v_out,_,chi1x_low, chi1y_low, chi1z_low, chi2x_low, chi2y_low, chi2z_low, Lnx_low, Lny_low, Lnz_low, E1x, E1y, E1z = lalsim.SimInspiralSpinTaylorOrbitalDriver(**dictparams)
401 except:
402 failure_message = "The orbit-averaged evolution failed."
403 return evolution_error_handling(failure_mode, failure_message, failure_output, failure_output_string, Lf, swap=False, hybrid_evol=True)
404
405 if abs(v_out.data.data[0] - v_low) > 1.e-4:
406 failure_message = f"The orbit-averaged evolution failed to reached the specified final velocity, v={v_low} at step {i+1}. The input binary parameters cannot be evolved from the given frequency {fref*fac} Hz."
407 return evolution_error_handling(failure_mode, failure_message, failure_output, failure_output_string, Lf, swap=False, hybrid_evol=True)
408
409
410 dictparams['s1x'] = chi1x_low.data.data[0]
411 dictparams['s1y'] = chi1y_low.data.data[0]
412 dictparams['s1z'] = chi1z_low.data.data[0]
413
414 dictparams['s2x'] = chi2x_low.data.data[0]
415 dictparams['s2y'] = chi2y_low.data.data[0]
416 dictparams['s2z'] = chi2z_low.data.data[0]
417
418 dictparams['lnhatx'] = Lnx_low.data.data[0]
419 dictparams['lnhaty'] = Lny_low.data.data[0]
420 dictparams['lnhatz'] = Lnz_low.data.data[0]
421
422 dictparams['e1x'] = E1x.data.data[0]
423 dictparams['e1y'] = E1y.data.data[0]
424 dictparams['e1z'] = E1z.data.data[0]
425
426 c1x = dictparams['s1x']
427 c1y = dictparams['s1y']
428 c1z = dictparams['s1z']
429
430 c2x = dictparams['s2x']
431 c2y = dictparams['s2y']
432 c2z = dictparams['s2z']
433
434 Lnx = dictparams['lnhatx']
435 Lny = dictparams['lnhaty']
436 Lnz = dictparams['lnhatz']
437
438 tilt1_transition, tilt2_transition, phi12_transition = get_tilts(c1x, c1y, c1z, c2x, c2y, c2z, Lnx, Lny, Lnz)
439
440 if verbose:
441 print("The tilts at transition are: tilt1 = {0}, tilt2 = {1}, phi12 = {2}".format(tilt1_transition, tilt2_transition, phi12_transition))
442
443 ################################# Step 2: Use precession-averaged evolution to compute tilts at infinity ###################################################
444 spin_angles_output = prec_avg_tilt_comp(m1, m2, chi1, chi2, tilt1_transition, tilt2_transition, phi12_transition, f_trans, LPNorder = LPNorder, LPNspins = LPNspins,
445 version=version_prec_avg, **kwargs)
446 spin_angles_output["tilt1_transition"] = tilt1_transition
447 spin_angles_output["tilt2_transition"] = tilt2_transition
448 spin_angles_output["phi12_transition"] = phi12_transition
449 spin_angles_output["f_transition"] = v_trans**3/np.pi/(M*kg_to_s) #return the transition frequency based on the original input masses in kg.
450
451 else:
452 if verbose:
453 print("The fitted transition frequency is higher than fref; Computing tilts at infinity from {} Hz. instead using precession-averaged evolution only".format(fref))
454 spin_angles_output = prec_avg_tilt_comp(m1, m2, chi1, chi2, tilt1, tilt2, phi12, fref, LPNorder = LPNorder, LPNspins = LPNspins, version=version_prec_avg,
455 **kwargs)
456 spin_angles_output["tilt1_transition"] = None
457 spin_angles_output["tilt2_transition"] = None
458 spin_angles_output["phi12_transition"] = None
459 spin_angles_output["f_transition"] = None
460
461 return spin_angles_output
def prec_avg_tilt_comp(m1, m2, chi1, chi2, tilt1, tilt2, phi12, fref, Lf=None, **kwargs)
Compute tilt angles at infinite separation or bounds and average value of tilt angles at finite separ...
def calc_v_trans(q)
Calculates the transition orbital speed (v_trans) to shift from orbit-averaged to precession-averaged...
def get_dt_constant(v_trans)
Determine the step-size (dt) to use in each frequency interval used for orbit-averaged evolution from...
def get_nsteps(v_trans)
Determine the number of frequency steps to use in each segment of the integration while performing or...
def get_tilts(chi1x, chi1y, chi1z, chi2x, chi2y, chi2z, Lnx, Lny, Lnz)
Given the spins and ang momentum at a given frequency, find the tilt and in-plane spin angles at that...
def calc_tilts_at_infty_hybrid_evolve(m1, m2, chi1, chi2, tilt1, tilt2, phi12, fref, approx="SpinTaylorT5", spinO=6, lscorr=1, verbose=False, prec_only=False, version='v1', failure_mode='None', **kwargs)
Calculate tilts at infinity with hybrid orbit-averaged and precession-averaged evolution Evolves tilt...
def evolution_error_handling(failure_mode, failure_message, failure_output, failure_output_string, Lf, swap, hybrid_evol=False)
Take care of the error message or warning and returning something for the tilts when the precession-a...
def package_tilts(tilt1, tilt2, Lf, swap)
Package tilts to be returned by prec_avg_tilt_comp_vec_inputs() or prec_avg_tilt_comp() depending on ...