2Code to use post-Newtonian equations [from Ajith, PRD 84, 084037 (2011), arXiv:1107.1267] to evolve spins in a binary black hole
4P. Ajith, A. Gupta, and N. K. Johnson-McDaniel, 04.2016, based on earlier code
7from scipy.integrate
import ode
9import lalsimulation
as lalsim
10from lal
import PI, MTSUN_SI, MSUN_SI, GAMMA
12from numpy.linalg
import norm
15"""Preccesion frequency spins """
16def Omega(v, m1, m2, S1, S2, Ln):
18 ''' Eqs.(3.8) of Ajith (2011) (http://arxiv.org/pdf/1107.1267v2.pdf)'''
22 eta = (m1*m2)/(m1+m2)**2.
23 return (v**5./m)*((3./4+eta/2.-3.*deltam/m/4.)*Ln+0.5*v/m**2.*(-3.0*np.dot((S2 +(m2/m1)*S1), Ln)*Ln+S2)+v**2.*(9./16.+5.*eta/4.-eta**2./24.-9.*deltam/m/16.+5.*deltam*eta/8./m)*Ln)
26""" compute the re-expanded dEnergy/flux """
27def denergy_by_flux(v, eta, delta, chiadL, chisdL, chiasqr, chissqr, chisdchia, order):
29 ''' Eqs.(3.2) of Ajith (2011) http://arxiv.org/pdf/1107.1267v2.pdf '''
32 v2 = v*v; v3 = v2*v; v4 = v3*v; v5 = v4*v; v6 = v5*v; v7 = v6*v; v9 = v7*v2
35 dEbF0 = dEbF2 = dEbF3 = dEbF4 = dEbF5 = dEbF6 = dEbF6L = dEbF7 = 0.
40 dEbF2 = 2.2113095238095237 + (11*eta)/4.
42 dEbF3 = (113*chiadL*delta)/12. + chisdL*(9.416666666666666 - (19.*eta)/3.) - 4.*PI
44 dEbF4 = 3.010315295099521 + (233*chisdchia*delta)/48. - (719.*chiadL*chisdL*delta)/48. + \
45 chiasqr*(2.4270833333333335 - 10.*eta) + chisdL*chisdL*(-7.489583333333333 - eta/24.) + \
46 chissqr*(2.4270833333333335 + (7.*eta)/24.) + (5429.*eta)/1008. + (617*eta*eta)/144. + \
47 chiadL*chiadL*(-7.489583333333333 + 30.*eta)
49 dEbF5 = chiadL*delta*(72.71676587301587 + (7*eta)/2.) + chisdL*(72.71676587301587 - \
50 (1213*eta)/18. - 17*eta*eta/2.) - (7729*PI)/672. + (13*eta*PI)/8.
52 dEbF6 = -115.2253249962622 - 15211*eta*eta/6912. + 25565*eta*eta*eta/5184. + \
53 32*PI*PI/3. + eta*(258.1491854023631 - 451*PI*PI/48.) + (1712*GAMMA)/105.
56 dEbF7 = (-15419335.*PI)/1.016064e6 - (75703.*eta*PI)/6048. + (14809.*eta*eta*PI)/3024.
58 return (dEbF0/v9)*(1. + dEbF2*v2 + dEbF3*v3 + dEbF4*v4 + dEbF5*v5 + (dEbF6+dEbF6L*log(4.*v))*v6 + dEbF7*v7)
62 """ The coupled set of ODEs containing the PN precession eqns as well as the evolution of dv/dt
63 All these equations are listed in Ajith (2011) (http://arxiv.org/pdf/1107.1267v2.pdf).
66 # unpack the vector of variables
67 v, S1x, S1y, S1z, S2x, S2y, S2z, Lx, Ly, Lz = y_vec
72 eta = m1*m2/(m1+m2)**2
73 delta = (m1-m2)/(m1+m2)
75 # spin and angular momentum vectors
76 Ln = np.array([Lx, Ly, Lz])
77 S1 = np.array([S1x, S1y, S1z])
78 S2 = np.array([S2x, S2y, S2z])
81 chi_s = (chi1+chi2)/2.
82 chi_a = (chi1-chi2)/2.
84 #print 'v = ', v , ' chi1 = ', chi1, ' chi2 = ', chi2
87 chiadL = np.dot(chi_a, Ln)
88 chisdL = np.dot(chi_s, Ln)
89 chissqr = np.dot(chi_s, chi_s)
90 chiasqr = np.dot(chi_a, chi_a)
91 chisdchia = np.dot(chi_s, chi_a)
93 # magnitude of the orb ang momentum. The prefactor of dLN/dt in Eq.(3.6) of Ajith (2011)
94 Lmag = (eta*m**2./v)*(1.+(1.5+eta/6.)*v**2.)
96 # precession freqs. Eqs.(3.8) of Ajith (2011)
97 Omega1= Omega(v, m1, m2, S1, S2, Ln)
98 Omega2= Omega(v, m2, m1, S2, S1, Ln)
100 # spin precession eqns. Eqs.(3.7) of Ajith (2011)
101 dS1_dt = np.cross(Omega1, S1)
102 dS2_dt = np.cross(Omega2, S2)
104 # ang momentum precession eqn. Eqs.(3.6) of Ajith (2011)
105 dL_dt =-(dS1_dt+dS2_dt)/Lmag
107 # orb frequency evolution. Eqs.(3.5) of Ajith (2011)
108 dv_dt = -1./(m*denergy_by_flux(v, eta, delta, chiadL, chisdL, chiasqr, chissqr, chisdchia, 7))
110 return [dv_dt, dS1_dt[0], dS1_dt[1], dS1_dt[2], dS2_dt[0], dS2_dt[1], dS2_dt[2], dL_dt[0], dL_dt[1], dL_dt[2]]
112def evolve_spins_dt(v0, m1, m2, chi1x, chi1y, chi1z, chi2x, chi2y, chi2z, Lnx, Lny, Lnz, v_final, dt):
113 """ evolve the spins and orb ang momentum according to the PN precession eqns."""
125 delta_Lnorm_max = 1.e-8
137 raise ValueError(
"ERROR: mass1 is negative")
139 raise ValueError(
"ERROR: mass2 is negative")
140 if (chi1x**2+chi1y**2+chi1z**2)>1.:
141 raise ValueError(
"ERROR: magnitude of spin1 is greater than 1")
142 if (chi2x**2+chi2y**2+chi2z**2)>1.:
143 raise ValueError(
"ERROR: magnitude of spin2 is greater than 1")
145 raise ValueError(
"ERROR: time step is negative")
151 y_vec0 = [v0, chi1x*m1_sqr, chi1y*m1_sqr, chi1z*m1_sqr, chi2x*m2_sqr, chi2y*m2_sqr, chi2z*m2_sqr, Lnx, Lny, Lnz]
155 chi_eff = lalsim.SimInspiralTaylorF2ReducedSpinComputeChi(m1, m2, chi1z, chi2z)
156 T_MAX = 2.* lalsim.SimInspiralTaylorF2ReducedSpinChirpTime(v0**3./(PI*(m1+m2)*MTSUN_SI), m1*MSUN_SI, m2*MSUN_SI, chi_eff, 0)/MTSUN_SI
164 solver = ode(precession_eqns)
165 solver.set_integrator(backend, atol=R_TOL, rtol=R_TOL)
166 solver.set_initial_value(y_vec0, t0)
167 solver.set_f_params(m1, m2)
171 y_result.append(y_vec0)
181 while solver.successful()
and solver.t < 2.*T_MAX
and v_current <= v_final
and dvdt_current > 0.
and dvdt_current < dvdt_max
and abs(Lnorm_current - 1.) < delta_Lnorm_max:
183 solver.integrate(solver.t + dt, step=1)
184 y_result.append(solver.y)
185 t_output.append(solver.t)
189 v_current = solver.y[V_POS]
191 Lnorm_current = np.sqrt((solver.y[LNX_POS])**2+(solver.y[LNY_POS])**2+(solver.y[LNZ_POS])**2)
193 Y = np.array(y_result)
194 t = np.array(t_output)
198 v_last = Y.T[V_POS][-1]
200 if abs(v_last-v_final) > delta_vf_max:
201 if dvdt_current <= 0
or dvdt_current > dvdt_max:
202 Y = np.delete(Y, -1, axis = 0)
203 print(
"Warning: Integration stopped at v_max = {0}, more than {1} different from v_final = {2}, because dv/dt became negative or exceeded {3}, with a value of {4}. The final value used is {5}.".format(v_last, delta_vf_max, v_final, dvdt_max, dvdt_current,
precession_eqns(t,Y[-1],m1,m2)[V_POS]))
205 raise ValueError(
"v_max = {0} is more than {1} different from v_final = {2} and dv/dt is positive and less than {3}".format(v_v[-1], delta_vf, v_final, dvdt_max))
207 if abs(Lnorm_current - 1.) >= delta_Lnorm_max:
208 raise ValueError(
"norm of Ln is more than {0:e} different from 1, with distance {1:e}".format(delta_Lnorm_max, abs(Lnorm_current - 1.)))
210 v_v, S1x_v, S1y_v, S1z_v, S2x_v, S2y_v, S2z_v, Lx_v, Ly_v, Lz_v = Y.T
212 return v_v, S1x_v/m1_sqr, S1y_v/m1_sqr, S1z_v/m1_sqr, S2x_v/m2_sqr, S2y_v/m2_sqr, S2z_v/m2_sqr, Lx_v, Ly_v, Lz_v
215def find_tilts_and_phi12_at_freq(v0, m1, m2, chi1x, chi1y, chi1z, chi2x, chi2y, chi2z, Lnx, Lny, Lnz, v_final, dt):
216 """ given the spins and ang momentum at a given frequency, find the tilt and in-plane spin angles at a later frequency """
218 print(
"v0 = %f, m1 = %f, m2 = %f, chi1x = %f, chi1y = %f, chi1z = %f, chi2x = %f, chi2y = %f, chi2z = %f"%(v0, m1, m2, chi1x, chi1y, chi1z, chi2x, chi2y, chi2z))
221 v_v, chi1x_v, chi1y_v, chi1z_v, chi2x_v, chi2y_v, chi2z_v, Lnx_v, Lny_v, Lnz_v =
evolve_spins_dt(v0, m1, m2, chi1x, chi1y, chi1z, chi2x, chi2y, chi2z, Lnx, Lny, Lnz, v_final, dt)
223 chi1_v = np.array([chi1x_v[-1], chi1y_v[-1], chi1z_v[-1]])
224 chi2_v = np.array([chi2x_v[-1], chi2y_v[-1], chi2z_v[-1]])
226 Ln_v = np.array([Lnx_v[-1], Lny_v[-1], Lnz_v[-1]])
229 chi1_norm =
norm(chi1_v)
230 chi2_norm =
norm(chi2_v)
235 chi1dL_v = np.dot(chi1_v, Ln_v)
236 chi2dL_v = np.dot(chi2_v, Ln_v)
240 chi1inplane = chi1_v - chi1dL_v*Ln_v
241 chi2inplane = chi2_v - chi2dL_v*Ln_v
244 cos_tilt1 = chi1dL_v/chi1_norm
245 cos_tilt2 = chi2dL_v/chi2_norm
246 cos_phi12 = np.dot(chi1inplane,chi2inplane)/(
norm(chi1inplane)*
norm(chi2inplane))
248 print(
"cos tilt1 = %f, cos tilt2 = %f, cos phi12 = %f"%(cos_tilt1, cos_tilt2, cos_phi12))
250 return np.arccos(cos_tilt1), np.arccos(cos_tilt2), np.arccos(cos_phi12)
static REAL8 norm(const REAL8 x[3])
def precession_eqns(t, y_vec, m1, m2)
The coupled set of ODEs containing the PN precession eqns as well as the evolution of dv/dt All these...
def find_tilts_and_phi12_at_freq(v0, m1, m2, chi1x, chi1y, chi1z, chi2x, chi2y, chi2z, Lnx, Lny, Lnz, v_final, dt)
given the spins and ang momentum at a given frequency, find the tilt and in-plane spin angles at a la...
def denergy_by_flux(v, eta, delta, chiadL, chisdL, chiasqr, chissqr, chisdchia, order)
Eqs.
def Omega(v, m1, m2, S1, S2, Ln)
Preccesion frequency spins Eqs.
def evolve_spins_dt(v0, m1, m2, chi1x, chi1y, chi1z, chi2x, chi2y, chi2z, Lnx, Lny, Lnz, v_final, dt)
evolve the spins and orb ang momentum according to the PN precession eqns.