Skip to content

Commit c64e391

Browse files
committed
first solar system problem up and running
1 parent 1904e91 commit c64e391

File tree

3 files changed

+273
-0
lines changed

3 files changed

+273
-0
lines changed
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
from __future__ import division
2+
3+
import numpy as np
4+
5+
from pySDC.core.Problem import ptype
6+
from pySDC.implementations.datatype_classes.particles import particles, fields, acceleration
7+
from pySDC.core.Errors import ParameterError, ProblemError
8+
9+
10+
# noinspection PyUnusedLocal
11+
class outer_solar_system(ptype):
12+
"""
13+
Example implementing the harmonic oscillator
14+
"""
15+
16+
def __init__(self, problem_params, dtype_u, dtype_f):
17+
"""
18+
Initialization routine
19+
20+
Args:
21+
problem_params (dict): custom parameters for the example
22+
dtype_u: particle data type (will be passed parent class)
23+
dtype_f: acceleration data type (will be passed parent class)
24+
"""
25+
26+
# these parameters will be used later, so assert their existence
27+
essential_keys = []
28+
for key in essential_keys:
29+
if key not in problem_params:
30+
msg = 'need %s to instantiate problem, only got %s' % (key, str(problem_params.keys()))
31+
raise ParameterError(msg)
32+
33+
# invoke super init, passing nparts, dtype_u and dtype_f
34+
super(outer_solar_system, self).__init__((3, 6), dtype_u, dtype_f, problem_params)
35+
self.G = 2.95912208286E-4
36+
37+
def eval_f(self, u, t):
38+
"""
39+
Routine to compute the RHS
40+
41+
Args:
42+
u (dtype_u): the particles
43+
t (float): current time (not used here)
44+
Returns:
45+
dtype_f: RHS
46+
"""
47+
me = acceleration(self.init, val=0.0)
48+
49+
for i in range(self.init[-1]):
50+
for j in range(i):
51+
dx = u.pos.values[:, i] - u.pos.values[:, j]
52+
r = np.sqrt(np.dot(dx, dx))
53+
df = self.G * dx / (r ** 3)
54+
me.values[:, i] -= u.m[j] * df
55+
me.values[:, j] += u.m[i] * df
56+
57+
return me
58+
59+
def u_exact(self, t):
60+
"""
61+
Routine to compute the exact trajectory at time t
62+
63+
Args:
64+
t (float): current time
65+
Returns:
66+
dtype_u: exact position and velocity
67+
"""
68+
assert t == 0.0, 'error, u_exact only works for the initial time t0=0'
69+
me = particles(self.init)
70+
71+
me.pos.values[:, 0] = [0.0, 0.0, 0.0]
72+
me.pos.values[:, 1] = [-3.5025653,-3.8169847,-1.5507963]
73+
me.pos.values[:, 2] = [9.0755314,-3.0458353,-1.6483708]
74+
me.pos.values[:, 3] = [8.3101420,-16.2901086,-7.2521278]
75+
me.pos.values[:, 4] = [11.4707666,-25.7294829,-10.8169456]
76+
me.pos.values[:, 5] = [-15.5387357,-25.2225594,-3.1902382]
77+
78+
me.vel.values[:, 0] = [0.0, 0.0, 0.0]
79+
me.vel.values[:, 1] = [0.00565429,-0.00412490,-0.00190589]
80+
me.vel.values[:, 2] = [0.00168318, 0.00483525, 0.00192462]
81+
me.vel.values[:, 3] = [0.00354178, 0.00137102, 0.00055029]
82+
me.vel.values[:, 4] = [0.00288930, 0.00114527, 0.00039677]
83+
me.vel.values[:, 5] = [0.00276725, -0.0017072,-0.00136504]
84+
85+
me.m[0] = 1.00000597682
86+
me.m[1] = 0.000954786104043
87+
me.m[2] = 0.000285583733151
88+
me.m[3] = 0.0000437273164546
89+
me.m[4] = 0.0000517759138449
90+
me.m[5] = 1.0 / 130000000.0
91+
92+
return me
93+
94+
def eval_hamiltonian(self, u):
95+
"""
96+
Routine to compute the Hamiltonian
97+
98+
Args:
99+
u (dtype_u): the particles
100+
Returns:
101+
float: hamiltonian
102+
"""
103+
104+
ham = 0
105+
106+
for i in range(self.init[-1]):
107+
ham += 0.5 * u.m[i] * np.dot(u.vel.values[:, i], u.vel.values[:, i])
108+
109+
for i in range(self.init[-1]):
110+
for j in range(i):
111+
dx = u.pos.values[:, i] - u.pos.values[:, j]
112+
r = np.sqrt(np.dot(dx, dx))
113+
ham -= self.G * u.m[i] * u.m[j] / r
114+
115+
return ham

pySDC/implementations/sweeper_classes/verlet.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,8 @@ def integrate(self):
156156
for j in range(1, self.coll.num_nodes + 1):
157157
p[-1].pos += L.dt * (L.dt * self.QQ[m, j] * L.f[j]) + L.dt * self.coll.Qmat[m, j] * L.u[0].vel
158158
p[-1].vel += L.dt * self.coll.Qmat[m, j] * L.f[j]
159+
p[-1].m = L.u[0].m
160+
p[-1].q = L.u[0].q
159161

160162
return p
161163

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
from __future__ import division
2+
from collections import defaultdict
3+
import os
4+
import dill
5+
6+
import pySDC.helpers.plot_helper as plt_helper
7+
8+
from pySDC.implementations.collocation_classes.gauss_lobatto import CollGaussLobatto
9+
from pySDC.implementations.controller_classes.allinclusive_classic_nonMPI import allinclusive_classic_nonMPI
10+
from pySDC.implementations.sweeper_classes.verlet import verlet
11+
from pySDC.implementations.datatype_classes.particles import particles, acceleration
12+
from pySDC.implementations.problem_classes.OuterSolarSystem import outer_solar_system
13+
from pySDC.implementations.transfer_classes.TransferParticles_NoCoarse import particles_to_particles
14+
15+
from pySDC.helpers.stats_helper import filter_stats
16+
from pySDC.projects.Hamiltonian.hamiltonian_output import hamiltonian_output
17+
18+
19+
def setup_outer_solar_system():
20+
"""
21+
Helper routine for setting up everything for the outer solar system problem
22+
23+
Returns:
24+
description (dict): description of the controller
25+
controller_params (dict): controller parameters
26+
"""
27+
28+
# initialize level parameters
29+
level_params = dict()
30+
level_params['restol'] = 1E-10
31+
level_params['dt'] = 100.0
32+
33+
# initialize sweeper parameters
34+
sweeper_params = dict()
35+
sweeper_params['collocation_class'] = CollGaussLobatto
36+
sweeper_params['num_nodes'] = [5]
37+
sweeper_params['spread'] = False
38+
39+
# initialize problem parameters for the Penning trap
40+
problem_params = dict()
41+
42+
# initialize step parameters
43+
step_params = dict()
44+
step_params['maxiter'] = 50
45+
46+
# initialize controller parameters
47+
controller_params = dict()
48+
controller_params['hook_class'] = hamiltonian_output # specialized hook class for more statistics and output
49+
controller_params['logger_level'] = 30
50+
controller_params['predict'] = False
51+
52+
# Fill description dictionary for easy hierarchy creation
53+
description = dict()
54+
description['problem_class'] = outer_solar_system
55+
description['problem_params'] = problem_params
56+
description['dtype_u'] = particles
57+
description['dtype_f'] = acceleration
58+
description['sweeper_class'] = verlet
59+
description['sweeper_params'] = sweeper_params
60+
description['level_params'] = level_params
61+
description['step_params'] = step_params
62+
# description['space_transfer_class'] = particles_to_particles
63+
64+
return description, controller_params
65+
66+
67+
def run_simulation(prob=None):
68+
"""
69+
Routine to run the simulation of a second order problem
70+
71+
Args:
72+
prob (str): name of the problem
73+
74+
"""
75+
76+
if prob == 'outer_solar_system':
77+
description, controller_params = setup_outer_solar_system()
78+
# set time parameters
79+
t0 = 0.0
80+
Tend = 100000.0
81+
num_procs = 1
82+
else:
83+
raise NotImplemented('Problem type not implemented, got %s' % prob)
84+
85+
# instantiate the controller
86+
controller = allinclusive_classic_nonMPI(num_procs=num_procs, controller_params=controller_params,
87+
description=description)
88+
89+
# get initial values on finest level
90+
P = controller.MS[0].levels[0].prob
91+
uinit = P.u_exact(t=t0)
92+
93+
# call main function to get things done...
94+
uend, stats = controller.run(u0=uinit, t0=t0, Tend=Tend)
95+
96+
fname = 'data/' + prob + '.dat'
97+
f = open(fname, 'wb')
98+
dill.dump(stats, f)
99+
f.close()
100+
101+
assert os.path.isfile(fname), 'Run for %s did not create stats file' % prob
102+
103+
104+
def show_results(prob=None, cwd=''):
105+
"""
106+
Helper function to plot the error of the Hamiltonian
107+
108+
Args:
109+
prob (str): name of the problem
110+
cwd (str): current working directory
111+
"""
112+
f = open(cwd + 'data/' + prob + '.dat', 'rb')
113+
stats = dill.load(f)
114+
f.close()
115+
116+
extract_stats = filter_stats(stats, type='err_hamiltonian')
117+
result = defaultdict(list)
118+
for k, v in extract_stats.items():
119+
result[k.iter].append((k.time, v))
120+
for k, v in result.items():
121+
# assert k <= 6, 'Number of iterations is too high for %s, got %s' % (prob, k)
122+
result[k] = sorted(result[k], key=lambda x: x[0])
123+
124+
plt_helper.mpl.style.use('classic')
125+
plt_helper.setup_mpl()
126+
plt_helper.newfig(textwidth=238.96, scale=0.89)
127+
128+
err_ham = 1
129+
for k, v in result.items():
130+
time = [item[0] for item in v]
131+
ham = [item[1] for item in v]
132+
err_ham = ham[-1]
133+
plt_helper.plt.semilogy(time, ham, '-', lw=1, label='Iter ' + str(k))
134+
135+
# assert err_ham < 2.3E-08, 'Error in the Hamiltonian is too large for %s, got %s' % (prob, err_ham)
136+
137+
plt_helper.plt.xlabel('Time')
138+
plt_helper.plt.ylabel('Error in Hamiltonian')
139+
plt_helper.plt.legend(loc='center left', bbox_to_anchor=(1, 0.5))
140+
141+
fname = 'data/' + prob + '_hamiltonian'
142+
plt_helper.savefig(fname)
143+
144+
assert os.path.isfile(fname + '.pdf'), 'ERROR: plotting did not create PDF file'
145+
assert os.path.isfile(fname + '.pgf'), 'ERROR: plotting did not create PGF file'
146+
assert os.path.isfile(fname + '.png'), 'ERROR: plotting did not create PNG file'
147+
148+
149+
def main():
150+
prob = 'outer_solar_system'
151+
run_simulation(prob)
152+
show_results(prob)
153+
154+
155+
if __name__ == "__main__":
156+
main()

0 commit comments

Comments
 (0)