def test_ZsGammaConversion(self): avars = Andoyer.from_Simulation(self.sim, 4, 1) Z = avars.Z phiZ = avars.psi1 Zcom = avars.Zcom phiZcom = avars.phiZcom sGamma1, gamma1, sGamma2, gamma2 = avars.Zs_to_sGammas(Z, phiZ, Zcom, phiZcom) nZ, nphiZ, nZcom, nphiZcom = avars.sGammas_to_Zs(sGamma1, gamma1, sGamma2, gamma2) self.assertAlmostEqual(nZ,Z, delta=1.e-15) self.assertAlmostEqual(np.mod(nphiZ, 2*np.pi), np.mod(phiZ, 2*np.pi), delta=1.e-15) self.assertAlmostEqual(nZcom, Zcom, delta=1.e-15) self.assertAlmostEqual(np.mod(nphiZcom, 2*np.pi), np.mod(phiZcom, 2*np.pi), delta=1.e-15) # should also be equivalent for 2 massive particles to rotation pvars = Poincare.from_Simulation(self.sim) ps = pvars.particles p = avars.params f, g = p['f'], p['g'] ff = f*np.sqrt(p['eta']/p['m1']/p['sLambda10']) gg = g*np.sqrt(p['eta']/p['m2']/p['sLambda20']) norm = np.sqrt(ff*ff + gg*gg) psirotmatrix = np.array([[ff,gg],[-gg,ff]]) / norm invpsirotmatrix = np.array([[ff,-gg],[gg,ff]]) / norm Psi1,psi1,Psi2,psi2 = self.rotate_actions(ps[1].Gamma/p['eta'],ps[1].gamma,ps[2].Gamma/p['eta'],ps[2].gamma, psirotmatrix) self.assertAlmostEqual(Psi1, avars.Psi1, delta=1.e-15) self.assertAlmostEqual(np.mod(psi1, 2*np.pi), np.mod(avars.psi1, 2*np.pi), delta=1.e-15) self.assertAlmostEqual(Psi2, avars.Psi2, delta=1.e-15) self.assertAlmostEqual(np.mod(psi2, 2*np.pi), np.mod(avars.psi2, 2*np.pi), delta=1.e-15)
def setUp(self): self.sim = get_sim() self.pvars = Poincare.from_Simulation(self.sim) self.pham = PoincareHamiltonian(self.pvars) self.terms_list = SecularTermsList(4, 4) for i in range(1, self.pvars.N): for j in range(i + 1, self.pvars.N): for term in self.terms_list: k, z = term self.pham.add_monomial_term(k, z, indexIn=i, indexOut=j, update=False) self.pham._update() qpsymbols = [S('eta{}'.format(i)) for i in range(1,self.pvars.N)] +\ [S('rho{}'.format(i)) for i in range(1,self.pvars.N)] +\ [S('kappa{}'.format(i)) for i in range(1,self.pvars.N)] +\ [S('sigma{}'.format(i)) for i in range(1,self.pvars.N)] self.secular_variable_indices = [ self.pham.varsymbols.index(s) for s in qpsymbols ] self.secular_sim = SecularSystemSimulation(self.pvars, dtFraction=1 / 50., max_order=4)
def test_particles(self): m = 1.e-5 M = 3. G = 2. a = 7. e = 0.1 pomega = 1.3 l = 0.7 sLambda = np.sqrt(G * M * a) sGamma = sLambda * (1. - np.sqrt(1. - e**2)) Lambda = m * sLambda Gamma = m * sGamma p = PoincareParticle(m=m, M=M, G=G, Lambda=Lambda, l=l, Gamma=Gamma, gamma=-pomega) tp = PoincareParticle(m=0., M=M, G=G, sLambda=sLambda, l=l, sGamma=sGamma, gamma=-pomega) self.assertAlmostEqual(p.a, a, delta=1.e-15) self.assertAlmostEqual(p.e, e, delta=1.e-15) self.assertAlmostEqual(p.pomega, pomega, delta=1.e-15) self.assertAlmostEqual(tp.a, a, delta=1.e-15) self.assertAlmostEqual(tp.e, e, delta=1.e-15) self.assertAlmostEqual(tp.pomega, pomega, delta=1.e-15) pvars = Poincare(G, poincareparticles=[p, tp]) ps = pvars.particles self.assertAlmostEqual(ps[1].a, a, delta=1.e-15) self.assertAlmostEqual(ps[1].e, e, delta=1.e-15) self.assertAlmostEqual(ps[1].pomega, pomega, delta=1.e-15) self.assertAlmostEqual(ps[2].a, a, delta=1.e-15) self.assertAlmostEqual(ps[2].e, e, delta=1.e-15) self.assertAlmostEqual(ps[2].pomega, pomega, delta=1.e-15) pvars = Poincare(G=G) pvars.add(m=m, M=M, Lambda=Lambda, l=l, Gamma=Gamma, gamma=-pomega) pvars.add(m=0., M=M, sLambda=sLambda, l=l, sGamma=sGamma, gamma=-pomega) ps = pvars.particles self.assertAlmostEqual(ps[1].a, a, delta=1.e-15) self.assertAlmostEqual(ps[1].e, e, delta=1.e-15) self.assertAlmostEqual(ps[1].pomega, pomega, delta=1.e-15) self.assertAlmostEqual(ps[2].a, a, delta=1.e-15) self.assertAlmostEqual(ps[2].e, e, delta=1.e-15) self.assertAlmostEqual(ps[2].pomega, pomega, delta=1.e-15)
def test_orbelements(self): pvars = Poincare.from_Simulation(self.sim, average=False) ps = pvars.particles o = self.sim.calculate_orbits(jacobi_masses=True) for i in range(1, 4): self.assertAlmostEqual(o[i - 1].a, ps[i].a, delta=1.e-15) self.assertAlmostEqual(o[i - 1].e, ps[i].e, delta=1.e-15) self.assertAlmostEqual(o[i - 1].l, ps[i].l, delta=1.e-15) self.assertAlmostEqual(o[i - 1].pomega, ps[i].pomega, delta=1.e-15)
def test_particles(self): m=1.e-5 M=3. G=2. a=7. e=0.1 pomega = 1.3 Omega = 2.1 inc = 0.07 l=0.7 sLambda = np.sqrt(G*M*a) sGamma = sLambda*(1.-np.sqrt(1.-e**2)) sQ = (sLambda-sGamma)*(1-np.cos(inc)) Lambda = m*sLambda Gamma = m*sGamma Q = m*sQ p = PoincareParticle(m=m, M=M, G=G, Lambda=Lambda, l=l, Gamma=Gamma, gamma=-pomega, Q=Q, q=-Omega) tp = PoincareParticle(m=0., M=M, G=G, sLambda=sLambda, l=l, sGamma=sGamma, gamma=-pomega, sQ=sQ, q=-Omega) self.assertAlmostEqual(p.a, a, delta=1.e-15) self.assertAlmostEqual(p.e, e, delta=1.e-15) self.assertAlmostEqual(p.inc, inc, delta=1.e-15) self.assertAlmostEqual(p.pomega, pomega, delta=1.e-15) self.assertAlmostEqual(p.Omega, Omega, delta=1.e-15) self.assertAlmostEqual(tp.a, a, delta=1.e-15) self.assertAlmostEqual(tp.e, e, delta=1.e-15) self.assertAlmostEqual(tp.inc, inc, delta=1.e-15) self.assertAlmostEqual(tp.pomega, pomega, delta=1.e-15) self.assertAlmostEqual(tp.Omega, Omega, delta=1.e-15) pvars = Poincare(G, poincareparticles=[p, tp]) ps = pvars.particles self.assertAlmostEqual(ps[1].a, a, delta=1.e-15) self.assertAlmostEqual(ps[1].e, e, delta=1.e-15) self.assertAlmostEqual(ps[1].inc, inc, delta=1.e-15) self.assertAlmostEqual(ps[1].pomega, pomega, delta=1.e-15) self.assertAlmostEqual(ps[1].Omega, Omega, delta=1.e-15) self.assertAlmostEqual(ps[2].a, a, delta=1.e-15) self.assertAlmostEqual(ps[2].e, e, delta=1.e-15) self.assertAlmostEqual(ps[2].inc, inc, delta=1.e-15) self.assertAlmostEqual(ps[2].pomega, pomega, delta=1.e-15) self.assertAlmostEqual(ps[2].Omega, Omega, delta=1.e-15) pvars = Poincare(G=G) pvars.add(m=m, M=M, Lambda=Lambda, l=l, Gamma=Gamma, gamma=-pomega, Q=Q, q=-Omega) pvars.add(m=0., M=M, sLambda=sLambda, l=l, sGamma=sGamma, gamma=-pomega, sQ=sQ, q=-Omega) ps = pvars.particles self.assertAlmostEqual(ps[1].a, a, delta=1.e-15) self.assertAlmostEqual(ps[1].e, e, delta=1.e-15) self.assertAlmostEqual(ps[1].inc, inc, delta=1.e-15) self.assertAlmostEqual(ps[1].pomega, pomega, delta=1.e-15) self.assertAlmostEqual(ps[1].Omega, Omega, delta=1.e-15) self.assertAlmostEqual(ps[2].a, a, delta=1.e-15) self.assertAlmostEqual(ps[2].e, e, delta=1.e-15) self.assertAlmostEqual(ps[2].inc, inc, delta=1.e-15) self.assertAlmostEqual(ps[2].pomega, pomega, delta=1.e-15) self.assertAlmostEqual(ps[2].Omega, Omega, delta=1.e-15)
def averaging_error(Nseed): sim = packed_sim(Nseed) ps = sim.particles o = sim.calculate_orbits(jacobi_masses=True) a10 = o[0].a a20 = o[1].a a30 = o[2].a tsyn = 2 * np.pi / (o[0].n - o[1].n) tmax = 30 * tsyn Nout = 100 times = np.linspace(0, tmax, Nout) pvars = Poincare.from_Simulation(sim) Hsim = PoincareHamiltonian(pvars) Nsma = np.zeros((3, Nout)) Hsma = np.zeros((3, Nout)) for i, t in enumerate(times): # Store N-body data o = sim.calculate_orbits(jacobi_masses=True) Nsma[0, i] = o[0].a Nsma[1, i] = o[1].a Nsma[2, i] = o[2].a ps = Hsim.particles Hsma[0, i] = ps[1].a Hsma[1, i] = ps[2].a Hsma[2, i] = ps[3].a sim.integrate(t) Hsim.integrate(t) Nmad1 = mad((Nsma[0] - a10) / a10) Nmad2 = mad((Nsma[1] - a20) / a20) Nmad3 = mad((Nsma[2] - a30) / a30) Nmed1 = np.median((Nsma[0] - a10) / a10) Pmed1 = np.median((Hsma[0] - a10) / a10) err1 = abs(Pmed1 - Nmed1) / Nmad1 Nmed2 = np.median((Nsma[1] - a20) / a20) Pmed2 = np.median((Hsma[1] - a20) / a20) err2 = abs(Pmed2 - Nmed2) / Nmad2 Nmed3 = np.median((Nsma[2] - a30) / a30) Pmed3 = np.median((Hsma[2] - a30) / a30) err3 = abs(Pmed3 - Nmed3) / Nmad3 return max(err1, err2, err3)
def test_jacobi_masses(self): pvars = Poincare.from_Simulation(self.sim, average=False) sim = pvars.to_Simulation(average=False) self.compare_simulations_orb(self.sim, sim, delta=1.e-14) sim = pvars.to_Simulation(masses=[1., 1.e-3, 1.e-7, 1.e-5], average=False) self.compare_simulations_orb(self.sim, sim, delta=1.e-14) # use default jacobi masses but pass it an inconsistent set of jacobi masses pvars.particles[1].M = 1. pvars.particles[2].M = 1. pvars.particles[3].M = 1. sim = pvars.to_Simulation(average=False) with self.assertRaises(AssertionError): self.compare_simulations_orb(self.sim, sim, delta=1.e-14)
def test_H(self): j=3 k=1 a10 = 1.02 sim = rebound.Simulation() sim.G = 4*np.pi**2 sim.add(m=1.) sim.add(m=1.e-6, e=0.01, P=1., pomega=-np.pi/2, f=np.pi, jacobi_masses=True) sim.add(m=3.e-6, e=0.03, pomega=np.pi/2, P=float(j)/(j-k), jacobi_masses=True)#float(j)/(j-k), theta=3.14) sim.move_to_com() avars = Andoyer.from_Simulation(sim,j,k, a10=a10, average=True) p = avars.params pvars = Poincare.from_Simulation(sim, average=True) sGamma1 = pvars.particles[1].sGamma sGamma2 = pvars.particles[2].sGamma sLambda1 = pvars.particles[1].sLambda sLambda2 = pvars.particles[2].sLambda lambda1 = pvars.particles[1].l lambda2 = pvars.particles[2].l gamma1 = pvars.particles[1].gamma gamma2 = pvars.particles[2].gamma n10 = np.sqrt(p['G']*p['M1']/p['a10']**3) n20 = np.sqrt(p['G']*p['M2']/p['a10']**3*p['alpha']**3) z1 = np.sqrt(2*sGamma1/p['sLambda10']) z2 = np.sqrt(2*sGamma2/p['sLambda20']) Hkep = -0.5*(n10*p['m1']*p['sLambda10']**3/sLambda1**2 + n20*p['m2']*p['sLambda20']**3/sLambda2**2) sL10 = p['sLambda10'] sL20 = p['sLambda20'] Hkepexpanded = -n10*p['m1']*sL10/2*(1. - 2*avars.dL1hat + 3*avars.dL1hat**2)-n20*p['m2']*sL20/2*(1. - 2*avars.dL2hat + 3*avars.dL2hat**2) Hresprefac = -p['G']*p['m1']*p['m2']/p['a10']*p['alpha'] Hres = Hresprefac*(p['f']*z1*np.cos(j*lambda2 - (j-k)*lambda1 + gamma1)+p['g']*z2*np.cos(j*lambda2 - (j-k)*lambda1 + gamma2)) H0 = -p['n0']*p['K0']/2 H1 = p['eta']*p['n0']*avars.dK*(1-1.5*p['eta']/p['K0']*avars.dK) H2 = p['eta']*p['a']*avars.dP**2 Hkeptransformed = H0 + H1 + H2 Hrestransformed = p['eta']*p['c']*(2*avars.Psi1)**(k/2.)*np.cos(avars.theta+k*avars.psi1) self.assertAlmostEqual(Hkeptransformed, Hkepexpanded, delta=1.e-15) # should be exact self.assertAlmostEqual(Hrestransformed, Hres, delta=1.e-15) # should be exact for first order resonance (k=1) self.assertAlmostEqual(Hkepexpanded, Hkep, delta=(a10-1.)**2) # should match to O(da/a)^2, atrue=1, a10=a10 #Hfinal = -p['eta']*p['Phi0']/p['tau']*(4.*avars.Phi**2 - 3.*avars.Phiprime*avars.Phi + 9./16.*avars.Phiprime**2 + (2.*avars.Phi)**(k/2.)*np.cos(avars.phi) - p['n0']*p['tau']/p['Phi0']*avars.dK*(1.-1.5*p['eta']/p['K0']*avars.dK))+ H0 Hfinal = -p['eta']*p['Phi0']/p['tau']*(4.*(avars.Phi-avars.B)**2 + (2.*avars.Phi)**(k/2.)*np.cos(avars.phi) - p['n0']*p['tau']/p['Phi0']*avars.dK*(1.-1.5*p['eta']/p['K0']*avars.dK))+ H0 self.assertAlmostEqual(Hfinal, Hkepexpanded+Hres, delta=1.e-15) # should be exact
def calc_tau(sim): if np.isnan( sim.dt ): # init_sim_parameters sets timestep to nan if any orbit is hyperbolic. Return tau=inf, i.e. chaotic/unstable tau = np.inf return tau lsys = LaplaceLagrangeSystem.from_Simulation(sim) pvars = Poincare.from_Simulation(sim) Lambda = np.array([p.Lambda for p in pvars.particles[1:]]) tau_max = 0 for i in range(1, sim.N_real): tau = 0 if i - 1 >= 1: tau += calc_tau_pair(sim, lsys, Lambda, i - 1, i) if i + 1 < sim.N_real: tau += calc_tau_pair(sim, lsys, Lambda, i, i + 1) if tau > tau_max: tau_max = tau return tau_max
def get_resonant(seed, Nplanets=3): r = random.Random() r.seed(seed) Phiprimecrits = [0, 1., -2. / 3.] pairs = ['inner', 'outer', 'split'] k = r.randint(1, 2) pairindex = r.randint(0, 2) pair = pairs[pairindex] m1 = logunif(r, 1.e-7, 1.e-4) m2 = logunif(r, 1.e-7, 1.e-4) eH = ((m1 + m2) / 3.)**(1. / 3.) ehillstable = 3.5 * eH jmax = k / (1 - 1 / (1 + 3.5 * eH)**1.5) if pair == 'split': if Nplanets == 2: return # don't want 2planet systems 60 hill radii apart maxHillradii = 60. # 3rd planet will go in middle so draw up to 60 else: maxHillradii = 30. jmin = max(k + 1, k / (1 - 1 / (1 + maxHillradii * eH)**1.5)) jmin = int(np.ceil(jmin)) jmax = int(np.floor(jmax)) if k == 2: # if k = 2, want odd j so we don't get e.g. 8:6 = 4:3 if jmin % 2 == 0: # even jmin += 1 if jmax % 2 == 0: jmax -= 1 j = r.randrange( jmin, jmax + 1, k) # choose randomly between limits in steps of k e.g. (3,5,7,9) a1 = 1. a2 = (float(j) / (j - k))**(2. / 3.) ecross1 = (a2 - a1) / a1 ecross2 = (a2 - a1) / a2 emin1 = m2 / ecross1**2 emin2 = m1 / ecross2**2 emin = max( emin1, emin2 ) # take as min Z the larger of the kicks a planet gets at conjunction emin = max( emin, (m1 + m2)**(1. / k) ) # below mtot^1/k, the resonant term is smaller than the second order mass terms we ignore emax = min(ecross1, ecross2) avars = Andoyer(j=j, k=k, X=0, Y=0, m1=m1, m2=m2) Phiprimecrit = Phiprimecrits[k] Xcrit = get_Xstarres(k, Phiprimecrit) Phicrit = 0.5 * Xcrit**2 emin = max( avars.Phi_to_Z(Phicrit), emin ) # first quantity is value of Z at bifurcation when res first appears Zstar = logunif(r, emin, emax) libfac = logunif(r, 3.e-3, 3) negative = r.randint(0, 1) if negative: libfac *= -1 Zcom = logunif(r, emin, emax) avars = Andoyer.from_elements(j=j, k=k, Zstar=Zstar, libfac=libfac, m1=m1, m2=m2, Zcom=Zcom, phiZcom=r.uniform(0, 2 * np.pi), theta=r.uniform(0, 2 * np.pi), theta1=r.uniform(0, 2 * np.pi)) tmax = r.uniform(0, 10 * avars.tlib) H = AndoyerHamiltonian(avars) H.integrate(tmax) pvars = avars.to_Poincare() ps = pvars.particles if Nplanets == 3: m3 = logunif(r, 1.e-7, 1.e-4) pvarssorted = Poincare(G=pvars.G) if pair == "inner": eH = ((m2 + m3) / 3.)**(1. / 3.) beta = r.uniform(3.5, 30) a3 = a2 * (1 + beta * eH) ecross3 = (a3 - a2) / a3 emin3 = m2 / ecross3**2 e3 = logunif(r, emin3, ecross3) pvarssorted.add(m=ps[1].m, M=ps[1].M, a=ps[1].a, e=ps[1].e, gamma=ps[1].gamma, l=ps[1].l) pvarssorted.add(m=ps[2].m, M=ps[2].M, a=ps[2].a, e=ps[2].e, gamma=ps[2].gamma, l=ps[2].l) pvarssorted.add(m=m3, M=1, a=a3, e=e3, gamma=r.uniform(0, 2 * np.pi), l=r.uniform(0, 2 * np.pi)) elif pair == "outer": eH = ((m1 + m3) / 3.)**(1. / 3.) beta = r.uniform(3.5, 30) a3 = a1 / (1 + beta * eH) ecross3 = (a1 - a3) / a3 emin3 = m1 / ecross3**2 e3 = logunif(r, emin3, ecross3) pvarssorted.add(m=m3, M=1, a=a3, e=e3, gamma=r.uniform(0, 2 * np.pi), l=r.uniform(0, 2 * np.pi)) pvarssorted.add(m=ps[1].m, M=ps[1].M, a=ps[1].a, e=ps[1].e, gamma=ps[1].gamma, l=ps[1].l) pvarssorted.add(m=ps[2].m, M=ps[2].M, a=ps[2].a, e=ps[2].e, gamma=ps[2].gamma, l=ps[2].l) elif pair == "split": eH1 = ((m1 + m3) / 3.)**(1. / 3.) eH2 = ((m2 + m3) / 3.)**(1. / 3.) amin = a1 * (1 + 3.5 * eH1) amax = min(a1 * (1 + 30 * eH1), a2 / (1 + 3.5 * eH2)) if amin > amax: seed += 900000 return get_resonant( seed=seed) # draw new sample (may not be 'split') a3 = r.uniform(amin, amax) ecross3 = min((a3 - a1) / a1, (a2 - a3) / a3) emin3 = max(m1 / ((a3 - a1) / a3)**2, m2 / ((a2 - a3) / a3)**2) e3 = logunif(r, emin3, ecross3) pvarssorted.add(m=ps[1].m, M=ps[1].M, a=ps[1].a, e=ps[1].e, gamma=ps[1].gamma, l=ps[1].l) pvarssorted.add(m=m3, M=1, a=a3, e=e3, gamma=r.uniform(0, 2 * np.pi), l=r.uniform(0, 2 * np.pi)) pvarssorted.add(m=ps[2].m, M=ps[2].M, a=ps[2].a, e=ps[2].e, gamma=ps[2].gamma, l=ps[2].l) sim = pvarssorted.to_Simulation() else: sim = avars.to_Simulation() # add inclinations and scale s.t. a1 = 1, Mprimary=1. and G = 4*pi**2 ps = sim.particles siminc = rebound.Simulation() siminc.G = 4 * np.pi**2 dscale = ps[1].a tscale = ps[1].P mscale = siminc.G * dscale**3 / tscale**2 # ps[0].m + ps[1].m siminc.add(m=ps[0].m / mscale, x=ps[0].x / dscale, y=ps[0].y / dscale, vx=ps[0].vx / dscale * tscale, vy=ps[0].vy / dscale * tscale) for p in ps[1:]: siminc.add(m=p.m / mscale, a=p.a / dscale, e=p.e, inc=logunif(r, 1.e-3, 1.e-1), Omega=r.uniform(0, 2 * np.pi), pomega=p.pomega, l=p.l) rH = siminc.particles[-1].a * (siminc.particles[-1].m / 3. / siminc.particles[0].m)**(1. / 3.) siminc.particles[-1].r = rH siminc.move_to_com() siminc.integrator = "whfast" siminc.dt = 2. * np.sqrt(3) / 100. * siminc.particles[1].P siminc.ri_whfast.safe_mode = 0 siminc.collision = "line" return siminc, j, k, pairindex, Zstar, libfac, Zcom
def test_rebound_transformations(self): # averaging operation is not symmetric because have to use current # Lambdas to calculate correction. So turn off averaging for test pvars = Poincare.from_Simulation(self.sim, average=False) sim = pvars.to_Simulation(average=False) self.compare_simulations_orb(self.sim, sim, delta=1.e-14)
def test_copy(self): pvars = Poincare.from_Simulation(self.sim) pvars2 = pvars.copy() self.compare_poincare_particles( pvars.particles, pvars2.particles) # ignore nans in particles[0]