Coverage for pySDC/projects/Hamiltonian/simple_problems.py: 100%
128 statements
« prev ^ index » next coverage.py v7.6.9, created at 2024-12-20 14:51 +0000
« prev ^ index » next coverage.py v7.6.9, created at 2024-12-20 14:51 +0000
1import os
2from collections import defaultdict
4import dill
5import numpy as np
7import pySDC.helpers.plot_helper as plt_helper
8from pySDC.helpers.stats_helper import get_sorted, filter_stats
10from pySDC.implementations.controller_classes.controller_nonMPI import controller_nonMPI
11from pySDC.implementations.problem_classes.HarmonicOscillator import harmonic_oscillator
12from pySDC.implementations.problem_classes.HenonHeiles import henon_heiles
13from pySDC.implementations.sweeper_classes.verlet import verlet
14from pySDC.implementations.transfer_classes.TransferParticles_NoCoarse import particles_to_particles
15from pySDC.projects.Hamiltonian.hamiltonian_output import hamiltonian_output
18def setup_harmonic():
19 """
20 Helper routine for setting up everything for the harmonic oscillator
22 Returns:
23 description (dict): description of the controller
24 controller_params (dict): controller parameters
25 """
27 # initialize level parameters
28 level_params = dict()
29 level_params['restol'] = 1e-10
30 level_params['dt'] = 0.5
32 # initialize sweeper parameters
33 sweeper_params = dict()
34 sweeper_params['quad_type'] = 'LOBATTO'
35 sweeper_params['num_nodes'] = [5, 3]
36 sweeper_params['initial_guess'] = 'zero'
38 # initialize problem parameters for the Penning trap
39 problem_params = dict()
40 problem_params['k'] = 1.0
41 problem_params['phase'] = 0.0
42 problem_params['amp'] = 1.0
44 # initialize step parameters
45 step_params = dict()
46 step_params['maxiter'] = 50
48 # initialize controller parameters
49 controller_params = dict()
50 controller_params['hook_class'] = hamiltonian_output # specialized hook class for more statistics and output
51 controller_params['logger_level'] = 30
53 # Fill description dictionary for easy hierarchy creation
54 description = dict()
55 description['problem_class'] = harmonic_oscillator
56 description['problem_params'] = problem_params
57 description['sweeper_class'] = verlet
58 description['sweeper_params'] = sweeper_params
59 description['level_params'] = level_params
60 description['step_params'] = step_params
61 description['space_transfer_class'] = particles_to_particles
63 return description, controller_params
66def setup_henonheiles():
67 """
68 Helper routine for setting up everything for the Henon Heiles problem
70 Returns:
71 description (dict): description of the controller
72 controller_params (dict): controller parameters
73 """
75 # initialize level parameters
76 level_params = dict()
77 level_params['restol'] = 1e-10
78 level_params['dt'] = 0.25
80 # initialize sweeper parameters
81 sweeper_params = dict()
82 sweeper_params['quad_type'] = 'LOBATTO'
83 sweeper_params['num_nodes'] = [5, 3]
84 sweeper_params['initial_guess'] = 'zero'
86 # initialize problem parameters for the Penning trap
87 problem_params = dict()
89 # initialize step parameters
90 step_params = dict()
91 step_params['maxiter'] = 50
93 # initialize controller parameters
94 controller_params = dict()
95 controller_params['hook_class'] = hamiltonian_output # specialized hook class for more statistics and output
96 controller_params['logger_level'] = 30
98 # Fill description dictionary for easy hierarchy creation
99 description = dict()
100 description['problem_class'] = henon_heiles
101 description['problem_params'] = problem_params
102 description['sweeper_class'] = verlet
103 description['sweeper_params'] = sweeper_params
104 description['level_params'] = level_params
105 description['step_params'] = step_params
106 description['space_transfer_class'] = particles_to_particles
108 return description, controller_params
111def run_simulation(prob=None):
112 """
113 Routine to run the simulation of a second order problem
115 Args:
116 prob (str): name of the problem
118 """
120 # check what problem type we have and set up corresponding description and variables
121 if prob == 'harmonic':
122 description, controller_params = setup_harmonic()
123 # set time parameters
124 t0 = 0.0
125 Tend = 50.0
126 num_procs = 100
127 maxmeaniter = 6.5
128 elif prob == 'henonheiles':
129 description, controller_params = setup_henonheiles()
130 # set time parameters
131 t0 = 0.0
132 Tend = 25.0
133 num_procs = 100
134 maxmeaniter = 5.0
135 else:
136 raise NotImplementedError('Problem type not implemented, got %s' % prob)
138 # instantiate the controller
139 controller = controller_nonMPI(num_procs=num_procs, controller_params=controller_params, description=description)
141 # get initial values on finest level
142 P = controller.MS[0].levels[0].prob
143 uinit = P.u_exact(t=t0)
145 # call main function to get things done...
146 uend, stats = controller.run(u0=uinit, t0=t0, Tend=Tend)
148 # filter statistics by type (number of iterations)
149 iter_counts = get_sorted(stats, type='niter', sortby='time')
151 # compute and print statistics
152 # for item in iter_counts:
153 # out = 'Number of iterations for time %4.2f: %2i' % item
154 # print(out)
156 niters = np.array([item[1] for item in iter_counts])
157 out = ' Mean number of iterations: %4.2f' % np.mean(niters)
158 print(out)
159 out = ' Range of values for number of iterations: %2i ' % np.ptp(niters)
160 print(out)
161 out = ' Position of max/min number of iterations: %2i -- %2i' % (int(np.argmax(niters)), int(np.argmin(niters)))
162 print(out)
163 out = ' Std and var for number of iterations: %4.2f -- %4.2f' % (float(np.std(niters)), float(np.var(niters)))
164 print(out)
166 assert np.mean(niters) <= maxmeaniter, 'Mean number of iterations is too high, got %s' % np.mean(niters)
168 fname = 'data/' + prob + '.dat'
169 f = open(fname, 'wb')
170 dill.dump(stats, f)
171 f.close()
173 assert os.path.isfile(fname), 'Run for %s did not create stats file' % prob
176def show_results(prob=None, cwd=''):
177 """
178 Helper function to plot the error of the Hamiltonian
180 Args:
181 prob (str): name of the problem
182 cwd (str): current working directory
183 """
185 # read in the dill data
186 f = open(cwd + 'data/' + prob + '.dat', 'rb')
187 stats = dill.load(f)
188 f.close()
190 # extract error in hamiltonian and prepare for plotting
191 extract_stats = filter_stats(stats, type='err_hamiltonian')
192 result = defaultdict(list)
193 for k, v in extract_stats.items():
194 result[k.iter].append((k.time, v))
195 for k, _ in result.items():
196 result[k] = sorted(result[k], key=lambda x: x[0])
198 plt_helper.mpl.style.use('classic')
199 plt_helper.setup_mpl()
200 plt_helper.newfig(textwidth=238.96, scale=0.89)
202 # Rearrange data for easy plotting
203 err_ham = 1
204 for k, v in result.items():
205 time = [item[0] for item in v]
206 ham = [item[1] for item in v]
207 err_ham = ham[-1]
208 plt_helper.plt.semilogy(time, ham, '-', lw=1, label='Iter ' + str(k))
210 assert err_ham < 3.7e-08, 'Error in the Hamiltonian is too large for %s, got %s' % (prob, err_ham)
212 plt_helper.plt.xlabel('Time')
213 plt_helper.plt.ylabel('Error in Hamiltonian')
214 plt_helper.plt.legend(loc='center left', bbox_to_anchor=(1, 0.5))
216 fname = 'data/' + prob + '_hamiltonian'
217 plt_helper.savefig(fname)
219 assert os.path.isfile(fname + '.pdf'), 'ERROR: plotting did not create PDF file'
220 # assert os.path.isfile(fname + '.pgf'), 'ERROR: plotting did not create PGF file'
221 assert os.path.isfile(fname + '.png'), 'ERROR: plotting did not create PNG file'
224def main():
225 prob = 'harmonic'
226 run_simulation(prob)
227 show_results(prob)
228 prob = 'henonheiles'
229 run_simulation(prob)
230 show_results(prob)
233if __name__ == "__main__":
234 main()