def kepler_trig_expand(s): """ Transform trigonometric part of series s [sin(nM) and cos(nM)] to sum of items like cos(M)^k1 * sin(M)^k2, where n=k1+k2. - s is series of e and M, - n is number of terms. """ from math import ceil from pyranha.math import binomial, cos, sin, degree temp, e, M, ecosM, esinM = 0, epst('e'), epst('M'), epst('ecosM'), epst( 'esinM') n = degree(s).numerator s_list = s.list for i in range(len(s_list)): for j in range(n + 1): trig_cos, trig_sin = 0, 0 # calculate cos(nM): if s_list[i][1] == cos(j * M): for k in range(int(ceil(j / 2)) + 1): trig_cos = trig_cos + (-1)**k * binomial( j, 2 * k) * ecosM**(j - 2 * k) * esinM**(2 * k) * e**-j temp = temp + s_list[i][0] * trig_cos # calculate sin(nM): if s_list[i][1] == sin(j * M): for k in range(int(ceil((j - 1) / 2)) + 1): trig_sin = trig_sin + (-1)**k * binomial( j, 2 * k + 1) * ecosM**(j - 2 * k - 1) * esinM**(2 * k + 1) * e**-j temp = temp + s_list[i][0] * trig_sin if type(temp) != type(1): temp = temp.trim() return temp
def a_r(e, M, order): """ Celestial mechanics classical expansion of a/r. """ from pyranha.math import cos from fractions import Fraction as F temp = 1 for k in range(1, order + 1): temp = temp + F(2, 1) * besselJ(k, k * e, order) * cos(k * M) return temp
def cos_E(e, M, order): """ Celestial mechanics classical expansion of cosE. """ from pyranha.math import cos from fractions import Fraction as F temp = F(-1, 2) * e for k in range(1, order + 2): temp = temp + F(1, k) * (besselJ(k - 1, k * e, order) - besselJ(k + 1, k * e, order)) * cos(k * M) return temp
def r_a(e, M, order): """ Celestial mechanics classical expansion of r/a. """ from pyranha.math import cos from fractions import Fraction as F temp = 1 + F(1, 2) * e**2 for k in range(1, order + 1): temp = temp - e * F(1, k) * (besselJ(k - 1, k * e, order - 1) - besselJ(k + 1, k * e, order - 1)) * cos( k * M) return temp
def cos_f(e, M, order): """ Celestial mechanics classical expansion of cosf. """ from pyranha.math import cos temp = 0 for k in range(1, order + 2): temp = temp + (besselJ(k - 1, k * e, order) + besselJ(k + 1, k * e, order)) * cos(k * M) temp = temp * (1 - e**2) - e return temp.transform( lambda t: (t[0].filter(lambda u: u[1].degree(['e']) <= order), t[1]))
def rrr(q, n, deg): """ Calculation expansions for r and them powers. - n is maximum degree of variables. """ from pyranha.math import cos, sin from eps.keproc import binomial_exp, r_a deg_max, e_max = n / 2 + 1, n MM, LL, xx, yy, uu, vv, qq = [ epst(i + str(q)) for i in ('m', 'L', 'x', 'y', 'u', 'v', 'q') ] K0, ee, MA = epst('K0'), epst('e'), epst('M') S1 = epst('s' + str(q - 1)) if q != 1 else F(1, 1) S2 = epst('s' + str(q)) ################################################## temp2 = binomial_exp(epst(1), -epst('eps'), F(1, 2), deg_max) temp5 = LL**F(-1, 2) * temp2.subs('eps', F(1, 4) * LL**-1 * (xx**2 + yy**2)) ecospi = xx * temp5 esinpi = -yy * temp5 ################################################## ra = r_a(ee, MA, e_max) ra = kepler_trig_expand(ra) ra = ra.subs('e', ee**F(1, 2)) subs1 = ecospi * cos(qq) + esinpi * sin(qq) subs2 = ecospi * sin(qq) - esinpi * cos(qq) subs3 = LL**-1 * (xx**2 + yy**2) * (1 - F(1, 4) * LL**-1 * (xx**2 + yy**2)) ################################################## pt.set_auto_truncate_degree(F(n), ['x' + str(q), 'y' + str(q)]) ra = ra.subs('ecosM', subs1) ra = ra.subs('esinM', subs2) ra = ra.subs('e', subs3) ra = ra.trim() aa = (K0 * MM**2 * S1)**-1 * S2 * LL**2 ra_deg = (ra * aa)**deg pt.unset_auto_truncate_degree() return ra_deg.trim()
def one_r(p, n, deg): """ Calculation expansions for 1/r and their powers (deg). - n is maximum degree of variables. """ from pyranha.math import cos, sin from eps.keproc import binomial_exp, a_r deg_max, e_max = n / 2 + 1, n MM, LL, xx, yy, uu, vv, qq = [ epst(i + str(p)) for i in ('m', 'L', 'x', 'y', 'u', 'v', 'q') ] K0, ee, MA = epst('K0'), epst('e'), epst('M') S1 = epst('s' + str(p - 1)) if p != 1 else F(1, 1) S2 = epst('s' + str(p)) ######################################################################## temp2 = binomial_exp(epst(1), -epst('eps'), F(1, 2), deg_max) temp5 = LL**F(-1, 2) * temp2.subs('eps', F(1, 4) * LL**-1 * (xx**2 + yy**2)) ecospi = xx * temp5 esinpi = -yy * temp5 ######################################################################## ar = a_r(ee, MA, e_max) ar = kepler_trig_expand(ar) ar = ar.subs('e', ee**F(1, 2)) subs1 = ecospi * cos(qq) + esinpi * sin(qq) subs2 = ecospi * sin(qq) - esinpi * cos(qq) subs3 = LL**-1 * (xx**2 + yy**2) * (1 - F(1, 4) * LL**-1 * (xx**2 + yy**2)) ######################################################################## pt.set_auto_truncate_degree(F(n), ['x' + str(p), 'y' + str(p)]) ar = ar.subs('ecosM', subs1) ar = ar.subs('esinM', subs2) ar = ar.subs('e', subs3) ar = ar.trim() aa = (K0 * MM**2 * S1)**-1 * S2 * LL**2 ar_deg = (ar * aa**-1)**deg pt.unset_auto_truncate_degree() return ar_deg.trim()
def xyz(p, n): """ Calculation expansions for vector of x, y, z-coordinates. - n is maximum degree of variables. """ from pyranha.math import cos, sin from eps.keproc import binomial_exp, cos_E, sin_E deg_max, e_max = n / 2 + 1, n MM, LL, xx, yy, uu, vv, qq = [ epst(i + str(p)) for i in ('m', 'L', 'x', 'y', 'u', 'v', 'q') ] K0, ee, MA, ecosM, esinM = epst('K0'), epst('e'), epst('M'), epst( 'ecosM'), epst('esinM') S1 = epst('s' + str(p - 1)) if p != 1 else F(1, 1) S2 = epst('s' + str(p)) ################################################## temp1 = binomial_exp(epst(1), -epst('eps'), -1, deg_max) temp2 = binomial_exp(epst(1), -epst('eps'), F(1, 2), deg_max) temp3 = F(1, 4) * LL**-1 * temp1.subs('eps', F(1, 2) * LL**-1 * (xx**2 + yy**2)) temp5 = LL**F(-1, 2) * temp2.subs('eps', F(1, 4) * LL**-1 * (xx**2 + yy**2)) temp4 = LL**F(-1,2) * temp1.subs('eps', F(1,2)*LL**-1 * (xx**2 + yy**2)) * \ temp2.subs('eps', F(1,4)*LL**-1 * (2*(xx**2 + yy**2) + (uu**2 + vv**2))) cos2I = 1 - (uu**2 + vv**2) * temp3 sin2Icos2Om = (uu**2 - vv**2) * temp3 sin2Isin2Om = -2 * (uu * vv) * temp3 sinIsinOm = -vv * temp4 sinIcosOm = uu * temp4 ecospi = xx * temp5 esinpi = -yy * temp5 ################################################## temp = binomial_exp(epst(1), -ee**2, F(1, 2), e_max) sqrt1 = F(1, 2) * (1 + temp) sqrt2 = F(1, 2) * (1 - temp) cosEM1 = cos_E(ee, MA, e_max) * cos(MA) + sin_E(ee, MA, e_max) * sin(MA) cosEM2 = cos_E(ee, MA, e_max) * cos(MA) - sin_E(ee, MA, e_max) * sin(MA) sinEM1 = sin_E(ee, MA, e_max) * cos(MA) - cos_E(ee, MA, e_max) * sin(MA) sinEM2 = sin_E(ee, MA, e_max) * cos(MA) + cos_E(ee, MA, e_max) * sin(MA) cosEM1 = (sqrt1 * cosEM1).truncate_degree(e_max, ['e']) cosEM2 = (sqrt2 * cosEM2).truncate_degree(e_max, ['e']) sinEM1 = (sqrt1 * sinEM1).truncate_degree(e_max, ['e']) sinEM2 = (sqrt2 * sinEM2).truncate_degree(e_max, ['e']) cosEM1 = kepler_trig_expand(cosEM1) cosEM2 = kepler_trig_expand(cosEM2) sinEM1 = kepler_trig_expand(sinEM1) sinEM2 = kepler_trig_expand(sinEM2) X_a = -ecosM + cosEM1 + cosEM2 Y_a = esinM + sinEM1 - sinEM2 X_a = X_a.subs('e', ee**F(1, 2)) Y_a = Y_a.subs('e', ee**F(1, 2)) subs1 = ecospi * cos(qq) + esinpi * sin(qq) subs2 = ecospi * sin(qq) - esinpi * cos(qq) subs3 = LL**-1 * (xx**2 + yy**2) * (1 - F(1, 4) * LL**-1 * (xx**2 + yy**2)) ################################################## pt.set_auto_truncate_degree( F(n), ['x' + str(p), 'y' + str(p), 'u' + str(p), 'v' + str(p)]) X_a = X_a.subs('ecosM', subs1) X_a = X_a.subs('esinM', subs2) X_a = X_a.subs('e', subs3) Y_a = Y_a.subs('ecosM', subs1) Y_a = Y_a.subs('esinM', subs2) Y_a = Y_a.subs('e', subs3) aa = (K0 * MM**2 * S1)**-1 * S2 * LL**2 xa = aa * (X_a * (cos2I * cos(qq) + sin2Icos2Om * cos(qq) + sin2Isin2Om * sin(qq)) -\ Y_a * (cos2I * sin(qq) + sin2Icos2Om * sin(qq) - sin2Isin2Om * cos(qq))) ya = aa * (X_a * (cos2I * sin(qq) - sin2Icos2Om * sin(qq) + sin2Isin2Om * cos(qq)) +\ Y_a * (cos2I * cos(qq) - sin2Icos2Om * cos(qq) - sin2Isin2Om * sin(qq))) za = aa * (X_a * (sinIcosOm * sin(qq) - sinIsinOm * cos(qq)) +\ Y_a * (sinIcosOm * cos(qq) + sinIsinOm * sin(qq))) pt.unset_auto_truncate_degree() return [xa.trim(), ya.trim(), za.trim()]
def __init__(self,params = __default_params): from numpy import dot from mpmath import mpf from fractions import Fraction as Frac import sympy from IPython.parallel import Client # Set up constants. self.__eps_val = (1./mpf(299792458.))**2 self.__GG_val = mpf(6.673E-11) # Various variables. Gt,I1,GG,m2,L,r,a,v2,Gtxy,ht,Ht,Gxy,h,H,J2,g,G,f,e,E,eps,hs,Hts,Gtxys = [pt(name) for name in ['\\tilde{G}','\\mathcal{I}_1',\ '\\mathcal{G}','m_2','L','r','a','v2','\\tilde{G}_{xy}','\\tilde{h}','\\tilde{H}','G_{xy}','h','H','J_2','g','G','f','e','E',\ '\\varepsilon','h_\\ast','\\tilde{H}_\\ast','\\tilde{G}_{xy\\ast}']] # The unperturbed Hamiltonian. H0 = Gt**2 * I1 / 2 - GG**2 * m2**2 * L**-2 / 2 self.__HH0 = H0 # Pieces of the perturbed Hamiltonian. Gt_vec = [Gtxy * math.sin(ht),-Gtxy * math.cos(ht),Ht] J2_vec = [0,0,J2] r_vec = dot(celmec.orbitalR([math.cos(g),math.sin(g),H*G**-1,Gxy*G**-1,math.cos(h),math.sin(h)]),[r*math.cos(f),r*math.sin(f),0]) r_cross_v = [Gxy * math.sin(h),-Gxy * math.cos(h),H] H1 = -Frac(1,8) * v2 ** 2 - Frac(3,2) * v2 * GG * m2 * r ** -1 + Frac(1,2) * GG**2 * m2**2 * r**-2 +\ Frac(3,2) * GG * m2 * r**-3 * dot(Gt_vec,r_cross_v) + 2 * GG * r**-3 * dot(J2_vec,r_cross_v) +\ GG * r**-3 * (3 * dot(Gt_vec,r_vec) * dot(J2_vec,r_vec) * r**-2 - dot(Gt_vec,J2_vec)) H1 = H1.subs('v2',GG * m2 * (2 * r**-1 - a ** -1)).subs('a',L ** 2 * (GG * m2)**-1) # Verify formula in the paper. assert(-Frac(1,8)*GG**4*m2**4*L**-4+r**-1*2*GG**3*m2**3*L**-2-r**-2*3*GG**2*m2**2+GG*r**-3*(\ 2*J2*H+3*J2*Gxy**2*Ht*(G**-2)/2+3*m2*Ht*H/2-J2*Ht+(3*m2/2*Gtxy*Gxy-3*J2/2*H*Gxy*Gtxy*G**-2)*math.cos(ht-h)+\ 3*J2*(-Frac(1,2)*Gxy**2*Ht*G**-2*math.cos(2*f+2*g)-Frac(1,4)*Gxy*Gtxy*G**-1*(1-H*G**-1)*math.cos(2*f+2*g+ht-h)+\ Frac(1,4)*Gxy*Gtxy*G**-1*(1+H*G**-1)*math.cos(2*f+2*g-ht+h))) == H1) # Split the Hamiltonian in parts. A0 = H1.transform(lambda t: (t[0].filter(lambda t: t[1].degree(['r']) == 0),t[1])).filter(lambda t: t[1] == pt(1)).subs('r',pt(1)) A1 = H1.transform(lambda t: (t[0].filter(lambda t: t[1].degree(['r']) == -1),t[1])).filter(lambda t: t[1] == pt(1)).subs('r',pt(1)) A2 = H1.transform(lambda t: (t[0].filter(lambda t: t[1].degree(['r']) == -2),t[1])).filter(lambda t: t[1] == pt(1)).subs('r',pt(1)) A3a = H1.transform(lambda t: (t[0].filter(lambda t: t[1].degree(['r']) == -3),t[1])).filter(lambda t: t[1] == pt(1)).subs('r',pt(1)) A3b = H1.filter(lambda t: t[1] == math.cos(ht - h)).transform(lambda t: (t[0],pt(1))).subs('r',pt(1)) B0 = H1.filter(lambda t: t[1] == math.cos(2*f + 2*g)).transform(lambda t: (t[0],pt(1))).subs('r',pt(1)) B1 = H1.filter(lambda t: t[1] == math.cos(2*f + 2*g + ht - h)).transform(lambda t: (t[0],pt(1))).subs('r',pt(1)) B2 = H1.filter(lambda t: t[1] == math.cos(2*f + 2*g - ht + h)).transform(lambda t: (t[0],pt(1))).subs('r',pt(1)) # Make sure we got them right. assert(A0 + A1 * r**-1 + A2 * r**-2 + r**-3 * (A3a + A3b * math.cos(ht - h)) + r**-3 * (B0 * math.cos(2*f + 2*g) +\ B1 * math.cos(2*f + 2*g + ht - h) + B2 * math.cos(2*f + 2*g - ht + h)) == H1) # This is the integrand in f (without the part that is integrated in E). f_int = A2 * r**-2 + r**-3 * (A3a + A3b * math.cos(ht - h)) + r**-3 * (B0 * math.cos(2*f + 2*g) + B1 * math.cos(2*f + 2*g + ht - h) + B2 * math.cos(2*f + 2*g - ht + h)) # Change the integration variable to f (with the constant parts already taken out of the integral). f_int *= r**2 # Substitute the definition of 1/r in terms of f. f_int = f_int.subs('r',pt('rm1')**-1).subs('rm1',GG*m2*G**-2*(1+e*math.cos(f))) # This is the integrand in E. E_int = A1 * r**-1 # Change the integration variable to f. E_int *= r**2 # Change the integration variable to E. E_int *= L*G*r**-1*GG**-1*m2**-1 assert(E_int == A1*G*L*GG**-1*m2**-1) # K1. K1 = GG**2 * m2**2 * G**-1 * L**-3 * (f_int + E_int).filter(lambda t: t[1].t_degree(['f']) == 0) # K. K = K1 + A0 # The generator. chi = G**-1 * (E_int.integrate('E') + f_int.integrate('f')) - L**3 * GG**-2 * m2**-2 * K1.integrate('l') # Verifiy that chi satisfies the homological equation, yielding K. assert((math.pbracket(H0,chi,['L','G','H','\\tilde{G}','\\tilde{H}'],['l','g','h','\\tilde{g}','\\tilde{h}']) + H1)\ .subs('r',pt('rm1')**-1).subs('rm1',GG*m2*G**-2*(1+e*math.cos(f))) == K) # This is the complete Hamiltonian, with the two coordinates compressed into a single one. HHp = H0 + eps * K.subs('h',ht+hs).subs('\\tilde{H}',Hts-H).subs('\\tilde{G}_{xy}',Gtxys) # Record it as a member. self.__HHp = HHp # F0 and F1. F0 = HHp.filter(lambda t: t[1].t_degree(['h_\\ast']) == 0).transform(lambda t: (t[0].filter(lambda t: t[1].degree(['\\varepsilon']) == 1),t[1])).subs('\\varepsilon',pt(1)) F1 = HHp.filter(lambda t: t[1].t_degree(['h_\\ast']) == 1).transform(lambda t: (t[0].filter(lambda t: t[1].degree(['\\varepsilon']) == 1),t[1])).subs('\\varepsilon',pt(1)).subs('h_\\ast',pt(0)) assert(H0 + eps * F0 + eps * F1 * math.cos(pt('h_\\ast')) == H0 + eps * K.subs('h',ht+hs).subs('\\tilde{H}',Hts-H).subs('\\tilde{G}_{xy}',Gtxys)) self.__F0 = F0 self.__F1 = F1 # Quartic polynomial. f4H = (eps**2 * F1 ** 2 - (pt('\\mathcal{H}^\\prime') - H0 - eps * F0)**2)\ .ipow_subs('G_{xy}',2,G**2-H**2)\ .ipow_subs('\\tilde{G}_{xy\\ast}',2,Gt**2-(Hts-H)**2) a4 = f4H.transform(lambda t: (t[0].filter(lambda t: t[1].degree(['H']) == 0),t[1])) a3 = f4H.transform(lambda t: (t[0].filter(lambda t: t[1].degree(['H']) == 1),t[1])).subs('H',pt(1)) / 4 a2 = f4H.transform(lambda t: (t[0].filter(lambda t: t[1].degree(['H']) == 2),t[1])).subs('H',pt(1)) / 6 a1 = f4H.transform(lambda t: (t[0].filter(lambda t: t[1].degree(['H']) == 3),t[1])).subs('H',pt(1)) / 4 a0 = f4H.transform(lambda t: (t[0].filter(lambda t: t[1].degree(['H']) == 4),t[1])).subs('H',pt(1)) # NOTE: these are not the polynomial coefficient strictly speaking, they are normalised by 4, 6 and 4 # as shown above and in the assert below. self.__f4_cf = (a0,a1,a2,a3,a4) # Check we got them right. assert(a4+4*a3*H+6*a2*H**2+4*a1*H**3+a0*H**4 == f4H) # Store the coefficients - from high degree to low. self.__f4_coeffs = [t[0] * t[1].trim() for t in zip([1,4,6,4,1],self.__f4_cf)] # Derivatives of the quartic poly. f4Hp = math.partial(f4H,'H') f4Hpp = math.partial(f4Hp,'H') f4Hppp = math.partial(f4Hpp,'H') f4Hpppp = math.partial(f4Hppp,'H') # Check the derivatives for consistency. assert(f4Hp == 4*a3 + 12*a2*H + 12*a1*H**2 + 4*a0*H**3) assert(f4Hpp == 12*a2 + 24*a1*H + 12*a0*H**2) assert(f4Hppp == 24*a1 + 24*a0*H) assert(f4Hpppp == 24*a0) self.__f4 = [f4H, f4Hp, f4Hpp, f4Hppp, f4Hpppp] # Invariants for wp. g2 = a0*a4 - 4*a1*a3 + 3*a2**2 g3 = a0*a2*a4 + 2*a1*a2*a3 - (a2**3) - (a0*a3**2) - (a1**2*a4) self.__g2 = g2 self.__g3 = g3 # Solve the angles. # Extract cosine of h_s. #chs = sympy.solve((spin_gr_theory.__to_sympy(self.HHp.trim())-sympy.Symbol('\\mathcal{H}^\\prime')).replace(sympy.cos(sympy.Symbol('h_\\ast')),sympy.Symbol('chs')),sympy.Symbol('chs'))[0] #ipy_view = Client().load_balanced_view() #g_sol = ipy_view.apply_async(spin_gr_theory.__solve_g,chs,spin_gr_theory.__to_sympy(math.partial(self.HHp.trim(),'G'))) #hs_sol = ipy_view.apply_async(spin_gr_theory.__solve_hs,chs,spin_gr_theory.__to_sympy(math.partial(self.HHp.trim(),'H'))) #ht_sol = ipy_view.apply_async(spin_gr_theory.__solve_ht,chs,spin_gr_theory.__to_sympy(math.partial(self.HHp.trim(),'\\tilde{H}_\\ast'))) #self.__g_sol = g_sol.get() #self.__hs_sol = hs_sol.get() #self.__ht_sol = ht_sol.get() import pickle self.__g_sol = pickle.load(open('g_sol.pickle','rb')) self.__hs_sol = pickle.load(open('hs_sol.pickle','rb')) self.__ht_sol = pickle.load(open('ht_sol.pickle','rb')) # Set the parameters of the theory. self.__set_params(params) # Some sanity checks. HHp,G,L,H,GG,eps,m2,Hts,Gt,J2,hs,Gxy,Gtxys = [sympy.Symbol(s) for s in ['\\mathcal{H}^\\prime','G','L','H','\\mathcal{G}',\ '\\varepsilon','m_2','\\tilde{H}_\\ast','\\tilde{G}','J_2','h_\\ast','G_{xy}','\\tilde{G}_{xy\\ast}']] # Phi_g^4 going to zero in the equilibrium point. assert(self.g_sol[0][3][1].subs(HHp,spin_gr_theory.__to_sympy(self.HHp.ipow_subs('G_{xy}',2,pt('G')**2\ -pt('H')**2).subs('H',pt('G')**2*pt('m_2')*pt('J_2')**-1))).ratsimp() == 0) # Reduction to Einstein precession. simpl_HHp_ein = spin_gr_theory.__to_sympy(self.HHp.subs('J_2',0).subs('\\tilde{G}_{xy\\ast}',0).subs('\\tilde{H}_\\ast',pt('H'))\ .subs('\\tilde{G}',0)) ein_prec = sum([t[0]*t[1] for t in self.g_sol[0]]).subs('J_2',0).subs(Hts,H).subs(Gt,0)\ .subs(HHp,simpl_HHp_ein).ratsimp() assert(ein_prec == 3 * eps * GG**4 * m2**4/(G**2*L**3)) # Lense-Thirring precession for g. simpl_HHp_lt = spin_gr_theory.__to_sympy(self.HHp.subs('\\tilde{G}_{xy\\ast}',0).subs('\\tilde{H}_\\ast',pt('H'))\ .subs('\\tilde{G}',0)) lt_prec = sum([t[0]*t[1] for t in self.g_sol[0]]).subs(Hts,H).subs(Gt,0).subs(HHp,simpl_HHp_lt).ratsimp() assert(lt_prec == (eps * ((-6*H*J2*GG**4*m2**3)/(G**4*L**3)+3*GG**4*m2**4/(G**2*L**3))).ratsimp()) # Geodetic effect on g. simpl_HHp_ge = spin_gr_theory.__to_sympy(self.HHp.subs('J_2',0)).subs(sympy.cos(hs),-1).subs(Gxy,sympy.sqrt(G**2-H**2))\ .subs(Gtxys,sympy.sqrt(Gt**2-(Hts-H)**2)).subs(H,(Hts**2+G**2-Gt**2)/(2*Hts)) ge_g = sum([t[0]*t[1] for t in self.g_sol[0]]).subs(J2,0).subs(Gxy,sympy.sqrt(G**2-H**2))\ .subs(Gtxys,sympy.sqrt(Gt**2-(Hts-H)**2)).subs(H,(Hts**2+G**2-Gt**2)/(2*Hts)).subs(HHp,simpl_HHp_ge).ratsimp() assert(ge_g == (1 / (4*G**4*L**3) * (15*G**2*GG**4*eps*m2**4+9*GG**4*Gt**2*eps*m2**4-9*GG**4*Hts**2*eps*m2**4)).ratsimp()) # No precession in h for Einstein case. assert((sum([t[0]*t[1] for t in self.hs_sol[0]]) + sum([t[0]*t[1] for t in self.ht_sol[0]])).subs(HHp,simpl_HHp_ein)\ .subs('J_2',0).subs(Hts,H).ratsimp().subs(Gt,0) == 0) # h precession in LT. assert((sum([t[0]*t[1] for t in self.hs_sol[0]]) + sum([t[0]*t[1] for t in self.ht_sol[0]])).subs(HHp,simpl_HHp_lt)\ .subs(Hts,H).ratsimp().subs(Gt,0).ratsimp() == 2*eps*J2*GG**4*m2**3/(G**3*L**3)) # Geodetic effect for h and ht. assert((sum([t[0]*t[1] for t in self.hs_sol[0]]) + sum([t[0]*t[1] for t in self.ht_sol[0]])).subs(HHp,simpl_HHp_ge)\ .subs(J2,0).subs(H,(Hts**2+G**2-Gt**2)/(2*Hts)).ratsimp() == 3*GG**4*Hts*eps*m2**4/(2*G**3*L**3)) assert((sum([t[0]*t[1] for t in self.ht_sol[0]])).subs(HHp,simpl_HHp_ge)\ .subs(J2,0).subs(H,(Hts**2+G**2-Gt**2)/(2*Hts)).ratsimp() == 3*GG**4*Hts*eps*m2**4/(2*G**3*L**3))