Пример #1
0
def test_04():
    from mpmath import mp, mpc
    import random
    from weierstrass_elliptic import weierstrass_elliptic as we
    random.seed(0)
    mp.dps = 50
    # Generate 20 random objects.
    l = [we(random.uniform(-10,20),random.uniform(-10,10)) for _ in range(0,20)]
    # Add a couple of cases wih g2/g3 = 0.
    l.append(we(random.uniform(-10,20),0.))
    l.append(we(random.uniform(-10,20),0.))
    l.append(we(random.uniform(-10,20),0.))
    l.append(we(0.,random.uniform(-10,10)))
    l.append(we(0.,random.uniform(-10,10)))
    l.append(we(0.,random.uniform(-10,10)))
    retval = []
    for w in l:
        p1,p2 = w.periods
        g2,g3 = w.invariants
        # Generate 100 random values within 10 real periods.
        z_list = [p1.real*random.uniform(-10,10) for _ in range(0,100)]
        values_list = [w.Pprime(_) for _ in z_list]
        res = [(t[0],t[1].real) for t in zip(z_list,values_list)]
        retval.append([str(g2),str(g3)] + [str(item) for sublist in res for item in sublist])
    # Build the string.
    return "\n".join([','.join(t) for t in retval])
Пример #2
0
def test_01():
    from mpmath import mp, mpc
    import random
    from weierstrass_elliptic import weierstrass_elliptic as we
    random.seed(0)
    mp.dps = 50
    l = [we(random.uniform(-10,20),random.uniform(-10,10)) for _ in range(0,1000)]
    # Add a couple of cases wih g2/g3 = 0.
    l.append(we(random.uniform(-10,20),0.))
    l.append(we(random.uniform(-10,20),0.))
    l.append(we(random.uniform(-10,20),0.))
    l.append(we(0.,random.uniform(-10,10)))
    l.append(we(0.,random.uniform(-10,10)))
    l.append(we(0.,random.uniform(-10,10)))
    # Extract the tuple of interest.
    lt = [(w.invariants[0],w.invariants[1],w.roots[0],w.roots[1],w.roots[2],w.periods[0],w.periods[1]) for w in l]
    # Fix negative periods and put everything in mpc (apart from invariants).
    lt = [[t[0],t[1],mpc(t[2]),mpc(t[3]),mpc(t[4]),mpc(t[5]),t[6] if t[6].real > 0 else mpc(-t[6].real,t[6].imag)] for t in lt]
    # Add also eta.
    lt = [t[1] + [t[0].zeta(t[0].periods[0]/2)] for t in zip(l,lt)]
    # Convert to suitable string format.
    lt = [[str(t[0]),str(t[1]),str(t[2].real),str(t[2].imag),str(t[3].real),str(t[3].imag),str(t[4].real),str(t[4].imag),str(t[5].real),str(t[5].imag),
        str(t[6].real),str(t[6].imag),str(t[7].real),str(t[7].imag)] for t in lt]
    # Build the string.
    return "\n".join([','.join(t) for t in lt])
	def __set_params(self,d):
		from copy import deepcopy
		from mpmath import mpf, sqrt, polyroots, cos, acos, pi, mp
		from weierstrass_elliptic import weierstrass_elliptic as we
		names = ['m2','r2','rot2','r1','rot1','i_a','ht','a','e','i','h']
		if not all([s in d for s in names]):
			raise ValueError('invalid set of parameters')
		# Convert all the values to mpf and introduce convenience shortcuts.
		m2, r2, rot2, r1, rot1, i_a, ht_in, a, e, i, h_in = [mpf(d[s]) for s in names]
		L_in = sqrt(self.__GG_val * m2 * a)
		G_in = L_in * sqrt(1. - e**2)
		H_in = G_in * cos(i)
		Gt_in = (2 * r1**2 * rot1) / 5
		Ht_in = Gt_in * cos(i_a)
		Hts_in = H_in + Ht_in
		hs_in = h_in - ht_in
		Gxy_in = sqrt(G_in**2 - H_in**2)
		Gtxys_in = sqrt(Gt_in**2 - Ht_in**2)
		J2 = (2 * m2 * r2**2 * rot2) / 5
		II_1 = mpf(5) / (2 * r1**2)
		# Evaluation dictionary.
		eval_names = ['L','G','H','\\tilde{G}','\\tilde{H}_\\ast','h_\\ast','\\tilde{G}_{xy\\ast}','m_2','\\mathcal{G}','J_2','G_{xy}',\
			'\\varepsilon','\\mathcal{I}_1']
		eval_values = [L_in,G_in,H_in,Gt_in,Hts_in,hs_in,Gtxys_in,m2,self.__GG_val,J2,Gxy_in,self.__eps_val,II_1]
		d_eval = dict(zip(eval_names,eval_values))
		# Evaluate Hamiltonian with initial conditions.
		HHp_val = self.__HHp.trim().evaluate(d_eval)
		# Add the value of the Hamiltonian to the eval dictionary.
		d_eval['\\mathcal{H}^\\prime'] = HHp_val
		# Evaluate g2 and g3.
		g2_val, g3_val = self.__g2.trim().evaluate(d_eval), self.__g3.trim().evaluate(d_eval)
		# Create the Weierstrass object.
		wp = we(g2_val,g3_val)
		# Store the period.
		self.__wp_period = wp.periods[0]
		# Now let's find the roots of the quartic polynomial.
		# NOTE: in theory here we could use the exact solution for the quartic.
		p4coeffs = [t[0] * t[1].trim().evaluate(d_eval) for t in zip([1,4,6,4,1],self.__f4_cf)]
		p4roots, err = polyroots(p4coeffs,error = True, maxsteps = 1000)
		# Find a reachable root.
		Hr, H_max, n_lobes, lobe_idx = self.__reachable_root(p4roots,H_in)
		# Determine t_r
		t_r = self.__compute_t_r(n_lobes,lobe_idx,H_in,Hr,d_eval,p4roots,p4coeffs[0])
		# Now evaluate the derivatives of the polynomial. We will need to replace H_in with Hr in the eval dict.
		d_eval['H'] = Hr
		_, f4Hp, f4Hpp, _, _ = self.__f4
		f4p_eval = f4Hp.trim().evaluate(d_eval)
		f4pp_eval = f4Hpp.trim().evaluate(d_eval)
		# Build and store the expression for H(t).
		self.__H_time = lambda t: Hr + f4p_eval / (4 * (wp.P(t - t_r) - f4pp_eval / 24))
		# H will not be needed any more, replace with H_r
		del d_eval['H']
		d_eval['H_r'] = Hr
		# Inject the invariants and the other two constants into the evaluation dictionary.
		d_eval['g_2'] = g2_val
		d_eval['g_3'] = g3_val
		d_eval['A'] = f4p_eval / 4
		d_eval['B'] = f4pp_eval / 24
		# Verify the formulae in solutions.py
		self.__verify_solutions(d_eval)
		# Assuming g = 0 as initial angle.
		self.__g_time = spin_gr_theory.__get_g_time(d_eval,t_r,0.)
		self.__hs_time = spin_gr_theory.__get_hs_time(d_eval,t_r,hs_in)
		self.__ht_time = spin_gr_theory.__get_ht_time(d_eval,t_r,ht_in)
		def obliquity(t):
			from mpmath import acos, cos, sqrt
			H = self.__H_time(t)
			hs = self.__hs_time(t)
			G = d_eval['G']
			Gt = d_eval['\\tilde{G}']
			Hts = d_eval['\\tilde{H}_\\ast']
			Gxy = sqrt(G**2-H**2)
			Gtxys = sqrt(Gt**2-(Hts-H)**2)
			retval = (Gxy*Gtxys*cos(hs)+H*(Hts-H))/(G*Gt)
			return acos(retval)
		self.__obliquity_time = obliquity
		def spin_vector(t):
			import numpy
			ht = self.__ht_time(t)
			H = self.__H_time(t)
			G = d_eval['G']
			Gt = d_eval['\\tilde{G}']
			Hts = d_eval['\\tilde{H}_\\ast']
			Gtxys = sqrt(Gt**2-(Hts-H)**2)
			return numpy.array([x.real for x in [Gtxys*sin(ht),-Gtxys*cos(ht),Hts-H]])
		self.__spin_vector_time = spin_vector
		def orbit_vector(t):
			import numpy
			ht = self.__ht_time(t)
			hs = self.__hs_time(t)
			h = hs + ht
			H = self.__H_time(t)
			G = d_eval['G']
			Gxy = sqrt(G**2-H**2)
			return numpy.array([x.real for x in [Gxy*sin(h),-Gxy*cos(h),H]])
		self.__orbit_vector_time = orbit_vector
		# Store the params of the system.
		self.__params = dict(zip(names,[mpf(d[s]) for s in names]))
		# Final report.
		rad_conv = 360 / (2 * pi())
		print("\x1b[31mAccuracy in the identification of the poly roots:\x1b[0m")
		print(err)
		print("\n\x1b[31mPeriod (years):\x1b[0m")
		print(wp.periods[0] / (3600*24*365))
		print("\n\x1b[31mMin and max orbital inclination (deg):\x1b[0m")
		print(acos(Hr/G_in) * rad_conv,acos(H_max/G_in) * rad_conv)
		print("\n\x1b[31mMin and max axial inclination (deg):\x1b[0m")
		print(acos((Hts_in - Hr)/Gt_in) * rad_conv,acos((Hts_in-H_max)/Gt_in)  * rad_conv)
		print("\n\x1b[31mNumber of lobes:\x1b[0m " + str(n_lobes))
		print("\n\x1b[31mLobe idx:\x1b[0m " + str(lobe_idx))
		# Report the known results for simplified system for comparison.
		H = H_in
		HHp,G,L,GG,eps,m2,Hts,Gt,J2 = [d_eval[s] for s in ['\\mathcal{H}^\\prime','G','L','\\mathcal{G}',\
			'\\varepsilon','m_2','\\tilde{H}_\\ast','\\tilde{G}','J_2']]
		print("\n\x1b[31mEinstein (g):\x1b[0m " + str((3 * eps * GG**4 * m2**4/(G**2*L**3))))
		print("\n\x1b[31mLense-Thirring (g):\x1b[0m " + str(((eps * ((-6*H*J2*GG**4*m2**3)/(G**4*L**3)+3*GG**4*m2**4/(G**2*L**3))))))
		print("\n\x1b[31mLense-Thirring (h):\x1b[0m " + str((2*eps*J2*GG**4*m2**3/(G**3*L**3))))
		# These are the Delta_ constants of quasi-periodicity.
		f_period = self.wp_period
		print("\n\x1b[31mDelta_g:\x1b[0m " + str(self.g_time(f_period) - self.g_time(0)))
		print("\n\x1b[31mg_rate:\x1b[0m " + str((self.g_time(f_period) - self.g_time(0))/f_period))
		Delta_hs = self.hs_time(f_period) - self.hs_time(0)
		print("\n\x1b[31mDelta_hs:\x1b[0m " + str(Delta_hs))
		print("\n\x1b[31mhs_rate:\x1b[0m " + str(Delta_hs/f_period))
		Delta_ht = self.ht_time(f_period) - self.ht_time(0)
		print("\n\x1b[31mDelta_ht:\x1b[0m " + str(Delta_ht))
		print("\n\x1b[31mht_rate:\x1b[0m " + str(Delta_ht/f_period))
		print("\n\x1b[31mDelta_h:\x1b[0m " + str(Delta_ht+Delta_hs))
		print("\n\x1b[31mh_rate:\x1b[0m " + str((Delta_ht+Delta_hs)/f_period))
		print("\n\n")
Пример #4
0
 def __init__(self, eps, x0, v0):
     from numpy import dot
     from mpmath import polyroots, mpf, mpc, sqrt, atan2, polyval
     from weierstrass_elliptic import weierstrass_elliptic as we
     if eps <= 0:
         raise ValueError('thrust must be strictly positive')
     eps = mpf(eps)
     # Unitary grav. parameter.
     mu = mpf(1.)
     x, y, z = [mpf(x) for x in x0]
     vx, vy, vz = [mpf(v) for v in v0]
     r = sqrt(x**2 + y**2 + z**2)
     xi = sqrt(r + z)
     eta = sqrt(r - z)
     phi = atan2(y, x)
     vr = dot(v0, x0) / r
     vxi = (vr + vz) / (2 * sqrt(r + z))
     veta = (vr - vz) / (2 * sqrt(r - z))
     vphi = (vy * x - vx * y) / (x**2 + y**2)
     pxi = (xi**2 + eta**2) * vxi
     peta = (xi**2 + eta**2) * veta
     pphi = xi**2 * eta**2 * vphi
     if pphi == 0:
         raise ValueError('bidimensional case')
     # Energy constant.
     h = (pxi**2 + peta**2) / (2 * (xi**2 + eta**2)) + pphi**2 / (
         2 * xi**2 *
         eta**2) - (2 * mu) / (xi**2 + eta**2) - eps * (xi**2 - eta**2) / 2
     # Alpha constants.
     alpha1 = -eps * xi**4 / 2 - h * xi**2 + pxi**2 / 2 + pphi**2 / (2 *
                                                                     xi**2)
     alpha2 = eps * eta**4 / 2 - h * eta**2 + peta**2 / 2 + pphi**2 / (
         2 * eta**2)
     # Analysis of the cubic polynomials in the equations for pxi and peta.
     roots_xi, _ = polyroots([8 * eps, 8 * h, 4 * alpha1, -pphi**2],
                             error=True,
                             maxsteps=100)
     roots_eta, _ = polyroots([-8 * eps, 8 * h, 4 * alpha2, -pphi**2],
                              error=True,
                              maxsteps=100)
     # NOTE: these are all paranoia checks that could go away if we used the exact cubic formula.
     if not (all([isinstance(x, mpf) for x in roots_xi]) or
             (isinstance(roots_xi[0], mpf) and isinstance(roots_xi[1], mpc)
              and isinstance(roots_xi[2], mpc))):
         raise ValueError('invalid xi roots detected: ' + str(roots_xi))
     if not (all([isinstance(x, mpf) for x in roots_eta]) or
             (isinstance(roots_eta[0], mpf) and isinstance(
                 roots_eta[1], mpc) and isinstance(roots_eta[2], mpc))):
         raise ValueError('invalid eta roots detected: ' + str(roots_eta))
     # For xi we need to understand which of the real positive roots will be or was reached
     # given the initial condition.
     rp_roots_extract = lambda x: isinstance(x, mpf) and x > 0
     rp_roots_xi = [sqrt(2 * _) for _ in filter(rp_roots_extract, roots_xi)]
     rp_roots_eta = [
         sqrt(2. * _) for _ in filter(rp_roots_extract, roots_eta)
     ]
     # Paranoia.
     if not len(rp_roots_xi) in [1, 3]:
         raise ValueError('invalid xi roots detected: ' + str(roots_xi))
     if len(rp_roots_eta) != 2:
         raise ValueError('invalid eta roots detected: ' + str(roots_eta))
     # We choose as reachable/reached roots always those corresponding to the "pericentre"
     # for the two coordinates.
     if len(rp_roots_xi) == 1:
         # Here there's really no choice, only 1 root available.
         rr_xi = rp_roots_xi[0]
     else:
         # If motion is unbound, take the only root, otherwise take the smallest of the
         # two roots of the bound motion.
         rr_xi = rp_roots_xi[-1] if xi >= rp_roots_xi[-1] else rp_roots_xi[0]
     # No choice to be made here.
     rr_eta = rp_roots_eta[0]
     # Store parameters and constants.
     self.__init_coordinates = [xi, eta, phi]
     self.__init_momenta = [pxi, peta, pphi]
     self.__eps = eps
     self.__h = h
     self.__alpha1 = alpha1
     self.__alpha2 = alpha2
     self.__rp_roots_xi = rp_roots_xi
     self.__rp_roots_eta = rp_roots_eta
     self.__rr_xi = rr_xi
     self.__rr_eta = rr_eta
     self.__roots_xi = roots_xi
     self.__roots_eta = roots_eta
     # Create the Weierstrass objects for xi and eta.
     a1, a2, a3, a4 = 2 * eps, (4 * h) / 3, alpha1, -pphi**2
     g2 = -4 * a1 * a3 + 3 * a2**2
     g3 = 2 * a1 * a2 * a3 - a2**3 - a1**2 * a4
     self.__f_xi = [4 * a1, 6 * a2, 4 * a3, a4]
     self.__fp_xi = [12 * a1, 12 * a2, 4 * a3]
     self.__fpp_xi = [24 * a1, 12 * a2]
     self.__w_xi = we(g2, g3)
     # Eta.
     a1, a3 = -a1, alpha2
     g2 = -4 * a1 * a3 + 3 * a2**2
     g3 = 2 * a1 * a2 * a3 - a2**3 - a1**2 * a4
     self.__f_eta = [4 * a1, 6 * a2, 4 * a3, a4]
     self.__fp_eta = [12 * a1, 12 * a2, 4 * a3]
     self.__fpp_eta = [24 * a1, 12 * a2]
     self.__w_eta = we(g2, g3)
     # Compute the taus.
     tau_xi = self.__compute_tau_xi()
     tau_eta = self.__compute_tau_eta()
     self.__tau_xi = tau_xi
     self.__tau_eta = tau_eta
     # Store the real periods.
     self.__T_xi = self.__w_xi.periods[0]
     self.__T_eta = self.__w_eta.periods[0]
     # Delta bound (for debugging).
     xi_roots = self.__w_xi.roots
     # Determine the root corresponding to the real half-period.
     e_R = min(xi_roots,
               key=lambda x: abs(self.__w_xi.P(self.__T_xi / 2) - x))
     self.__Dbound = e_R - polyval(self.__fpp_xi, xi**2 / 2) / 24
Пример #5
0
	def __init__(self,eps,x0,v0):
		from numpy import dot
		from mpmath import polyroots, mpf, mpc, sqrt, atan2, polyval
		from weierstrass_elliptic import weierstrass_elliptic as we
		if eps <= 0:
			raise ValueError('thrust must be strictly positive')
		eps = mpf(eps)
		# Unitary grav. parameter.
		mu = mpf(1.)
		x,y,z = [mpf(x) for x in x0]
		vx,vy,vz = [mpf(v) for v in v0]
		r = sqrt(x**2 + y**2 + z**2)
		xi = sqrt(r+z)
		eta = sqrt(r-z)
		phi = atan2(y,x)
		vr = dot(v0,x0) / r
		vxi = (vr + vz) / (2 * sqrt(r+z))
		veta = (vr - vz) / (2 * sqrt(r-z))
		vphi = (vy*x - vx*y) / (x**2 + y**2)
		pxi = (xi**2 + eta**2) * vxi
		peta = (xi**2 + eta**2) * veta
		pphi = xi**2*eta**2*vphi
		if pphi == 0:
			raise ValueError('bidimensional case')
		# Energy constant.
		h = (pxi**2 + peta**2) / (2*(xi**2 + eta**2)) + pphi**2 / (2*xi**2*eta**2) - (2 * mu) / (xi**2+eta**2) - eps * (xi**2 - eta**2) / 2
		# Alpha constants.
		alpha1 = -eps * xi**4 / 2 - h * xi**2 + pxi**2 / 2 + pphi**2 / (2*xi**2)
		alpha2 = eps * eta**4 / 2 - h * eta**2 + peta**2 / 2 + pphi**2 / (2*eta**2)
		# Analysis of the cubic polynomials in the equations for pxi and peta.
		roots_xi, _ = polyroots([8*eps,8*h,4*alpha1,-pphi**2],error=True,maxsteps=100)
		roots_eta, _ = polyroots([-8*eps,8*h,4*alpha2,-pphi**2],error=True,maxsteps=100)
		# NOTE: these are all paranoia checks that could go away if we used the exact cubic formula.
		if not (all([isinstance(x,mpf) for x in roots_xi]) or (isinstance(roots_xi[0],mpf) and isinstance(roots_xi[1],mpc) and isinstance(roots_xi[2],mpc))):
			raise ValueError('invalid xi roots detected: ' + str(roots_xi))
		if not (all([isinstance(x,mpf) for x in roots_eta]) or (isinstance(roots_eta[0],mpf) and isinstance(roots_eta[1],mpc) and isinstance(roots_eta[2],mpc))):
			raise ValueError('invalid eta roots detected: ' + str(roots_eta))
		# For xi we need to understand which of the real positive roots will be or was reached
		# given the initial condition.
		rp_roots_extract = lambda x: isinstance(x,mpf) and x > 0
		rp_roots_xi = [sqrt(2 * _) for _ in filter(rp_roots_extract,roots_xi)]
		rp_roots_eta = [sqrt(2. * _) for _ in filter(rp_roots_extract,roots_eta)]
		# Paranoia.
		if not len(rp_roots_xi) in [1,3]:
			raise ValueError('invalid xi roots detected: ' + str(roots_xi))
		if len(rp_roots_eta) != 2:
			raise ValueError('invalid eta roots detected: ' + str(roots_eta))
		# We choose as reachable/reached roots always those corresponding to the "pericentre"
		# for the two coordinates.
		if len(rp_roots_xi) == 1:
			# Here there's really no choice, only 1 root available.
			rr_xi = rp_roots_xi[0]
		else:
			# If motion is unbound, take the only root, otherwise take the smallest of the
			# two roots of the bound motion.
			rr_xi = rp_roots_xi[-1] if xi >= rp_roots_xi[-1] else rp_roots_xi[0]
		# No choice to be made here.
		rr_eta = rp_roots_eta[0]
		# Store parameters and constants.
		self.__init_coordinates = [xi,eta,phi]
		self.__init_momenta = [pxi,peta,pphi]
		self.__eps = eps
		self.__h = h
		self.__alpha1 = alpha1
		self.__alpha2 = alpha2
		self.__rp_roots_xi = rp_roots_xi
		self.__rp_roots_eta = rp_roots_eta
		self.__rr_xi = rr_xi
		self.__rr_eta = rr_eta
		self.__roots_xi = roots_xi
		self.__roots_eta = roots_eta
		# Create the Weierstrass objects for xi and eta.
		a1, a2, a3, a4 = 2*eps, (4 * h)/3, alpha1, -pphi**2
		g2 = -4 * a1 * a3 + 3 * a2**2
		g3 = 2 * a1 * a2 * a3 - a2**3 - a1**2*a4
		self.__f_xi = [4*a1,6*a2,4*a3,a4]
		self.__fp_xi = [12*a1,12*a2,4*a3]
		self.__fpp_xi = [24*a1,12*a2]
		self.__w_xi = we(g2,g3)
		# Eta.
		a1,a3 = -a1,alpha2
		g2 = -4 * a1 * a3 + 3 * a2**2
		g3 = 2 * a1 * a2 * a3 - a2**3 - a1**2*a4
		self.__f_eta = [4*a1,6*a2,4*a3,a4]
		self.__fp_eta = [12*a1,12*a2,4*a3]
		self.__fpp_eta = [24*a1,12*a2]
		self.__w_eta = we(g2,g3)
		# Compute the taus.
		tau_xi = self.__compute_tau_xi()
		tau_eta = self.__compute_tau_eta()
		self.__tau_xi = tau_xi
		self.__tau_eta = tau_eta
		# Store the real periods.
		self.__T_xi = self.__w_xi.periods[0]
		self.__T_eta = self.__w_eta.periods[0]
		# Delta bound (for debugging).
		xi_roots = self.__w_xi.roots
		# Determine the root corresponding to the real half-period.
		e_R = min(xi_roots,key = lambda x: abs(self.__w_xi.P(self.__T_xi/2) - x))
		self.__Dbound = e_R - polyval(self.__fpp_xi,xi**2/2) / 24