Coverage for pySDC/implementations/problem_classes/OuterSolarSystem.py: 100%
58 statements
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-15 10:50 +0000
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-15 10:50 +0000
1import numpy as np
3from pySDC.core.problem import Problem
4from pySDC.implementations.datatype_classes.particles import particles, acceleration
7# noinspection PyUnusedLocal
8class outer_solar_system(Problem):
9 r"""
10 Gravitational N-body problem of the outer solar system: the sun, Jupiter, Saturn, Uranus, Neptune and Pluto.
12 The :math:`N`-body problem describes the mutual influence of the motion of :math:`N` bodies. Formulation of the problem is
13 based on Newton's second law. Therefore, the :math:`N`-body problem is formulated as
15 .. math::
16 m_i \frac{d^2 {\bf r}_i}{d t^2} = \sum_{j=1, i\neq j}^N G \frac{m_i m_j}{|{\bf r}_i - {\bf r}_j|^3}({\bf r}_j - {\bf r}_i),
18 where :math:`m_i` is the :math:`i`-th mass point with position described by the vector :math:`{\bf r}_i`, and :math:`G`
19 is the gravitational constant. If only the sun (body 1) influences the motion of the bodies gravitationally, the
20 equations become
22 .. math::
23 \frac{d^2 {\bf r}_i}{d t^2} = G \frac{m_1}{|{\bf r}_i - {\bf r}_1|^3}({\bf r}_1 - {\bf r}_i), \quad i \geq 2,
25 and the sun is not accelerated.
27 This class implements the outer solar system consisting of the sun and five outer bodies: Jupiter, Saturn, Uranus,
28 Neptune, and Pluto, i.e., :math:`N=6`. The masses of the inner planets are added to the sun.
30 Parameters
31 ----------
32 sun_only : bool, optional
33 If True, only the gravity of the sun acts on the other bodies, see above. If False (default), all bodies
34 attract each other.
36 Attributes
37 ----------
38 G : float
39 Gravitational constant.
40 """
42 dtype_u = particles
43 dtype_f = acceleration
45 G = 2.95912208286e-4
47 def __init__(self, sun_only=False):
48 """Initialization routine"""
50 # invoke super init, passing nparts
51 super().__init__(((3, 6), None, np.dtype('float64')))
52 self._makeAttributeAndRegister('sun_only', localVars=locals())
54 def eval_f(self, u, t):
55 """
56 Routine to compute the right-hand side of the problem.
58 Parameters
59 ----------
60 u : dtype_u
61 The particles.
62 t : float
63 Current time at which the particles are computed (not used here).
65 Returns
66 -------
67 me : dtype_f
68 The right-hand side of the problem.
69 """
70 me = self.dtype_f(self.init, val=0.0)
72 # compute the acceleration due to gravitational forces
73 # ... only with respect to the sun
74 if self.sun_only:
75 for i in range(1, self.init[0][-1]):
76 dx = u.pos[:, i] - u.pos[:, 0]
77 r = np.sqrt(np.dot(dx, dx))
78 df = self.G * dx / (r**3)
79 me[:, i] -= u.m[0] * df
81 # ... or with all planets involved
82 else:
83 for i in range(self.init[0][-1]):
84 for j in range(i):
85 dx = u.pos[:, i] - u.pos[:, j]
86 r = np.sqrt(np.dot(dx, dx))
87 df = self.G * dx / (r**3)
88 me[:, i] -= u.m[j] * df
89 me[:, j] += u.m[i] * df
91 return me
93 def u_exact(self, t):
94 r"""
95 Routine to compute the exact/initial trajectory at time :math:`t`.
97 Parameters
98 ----------
99 t : float
100 Time of the exact/initial trajectory.
102 Returns
103 -------
104 me : dtype_u
105 The exact/initial position and velocity.
106 """
107 assert t == 0.0, 'error, u_exact only works for the initial time t0=0'
108 me = self.dtype_u(self.init)
110 me.pos[:, 0] = [0.0, 0.0, 0.0]
111 me.pos[:, 1] = [-3.5025653, -3.8169847, -1.5507963]
112 me.pos[:, 2] = [9.0755314, -3.0458353, -1.6483708]
113 me.pos[:, 3] = [8.3101420, -16.2901086, -7.2521278]
114 me.pos[:, 4] = [11.4707666, -25.7294829, -10.8169456]
115 me.pos[:, 5] = [-15.5387357, -25.2225594, -3.1902382]
117 me.vel[:, 0] = [0.0, 0.0, 0.0]
118 me.vel[:, 1] = [0.00565429, -0.00412490, -0.00190589]
119 me.vel[:, 2] = [0.00168318, 0.00483525, 0.00192462]
120 me.vel[:, 3] = [0.00354178, 0.00137102, 0.00055029]
121 me.vel[:, 4] = [0.00288930, 0.00114527, 0.00039677]
122 me.vel[:, 5] = [0.00276725, -0.0017072, -0.00136504]
124 me.m[0] = 1.00000597682 # Sun
125 me.m[1] = 0.000954786104043 # Jupiter
126 me.m[2] = 0.000285583733151 # Saturn
127 me.m[3] = 0.0000437273164546 # Uranus
128 me.m[4] = 0.0000517759138449 # Neptune
129 me.m[5] = 1.0 / 130000000.0 # Pluto
131 return me
133 def eval_hamiltonian(self, u):
134 """
135 Routine to compute the Hamiltonian.
137 Parameters
138 ----------
139 u : dtype_u
140 The particles.
142 Returns
143 -------
144 ham : float
145 The Hamiltonian.
146 """
148 ham = 0
150 for i in range(self.init[0][-1]):
151 ham += 0.5 * u.m[i] * np.dot(u.vel[:, i], u.vel[:, i])
153 for i in range(self.init[0][-1]):
154 for j in range(i):
155 dx = u.pos[:, i] - u.pos[:, j]
156 r = np.sqrt(np.dot(dx, dx))
157 ham -= self.G * u.m[i] * u.m[j] / r
159 return ham