Skip to content

Commit 53d6faf

Browse files
authored
Merge pull request #256 from brownbaerchen/test_faults
Test faults
2 parents 8b987cd + 68f3111 commit 53d6faf

File tree

16 files changed

+595
-353
lines changed

16 files changed

+595
-353
lines changed

pySDC/implementations/hooks/log_errors.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,33 @@
22
from pySDC.core.Hooks import hooks
33

44

5+
class LogGlobalError(hooks):
6+
"""
7+
Log the global error with respect to `u_exact` defined in the problem class as "e_global".
8+
Be aware that this requires the problems to be compatible with this. We need some kind of "exact" solution for this
9+
to work, be it a reference solution or something analytical.
10+
"""
11+
12+
def post_step(self, step, level_number):
13+
14+
super(LogGlobalError, self).post_step(step, level_number)
15+
16+
# some abbreviations
17+
L = step.levels[level_number]
18+
19+
L.sweep.compute_end_point()
20+
21+
self.add_to_stats(
22+
process=step.status.slot,
23+
time=L.time + L.dt,
24+
level=L.level_index,
25+
iter=step.status.iter,
26+
sweep=L.status.sweep,
27+
type='e_global',
28+
value=abs(L.prob.u_exact(t=L.time + L.dt) - L.uend),
29+
)
30+
31+
532
class LogGlobalErrorPostRun(hooks):
633
"""
734
Compute the global error once after the run is finished.
@@ -60,3 +87,30 @@ def post_run(self, step, level_number):
6087
type='e_global',
6188
value=e_glob,
6289
)
90+
91+
92+
class LogLocalError(hooks):
93+
"""
94+
Log the local error with respect to `u_exact` defined in the problem class as "e_local".
95+
Be aware that this requires the problems to be compatible with this. In particular, a reference solution needs to
96+
be made available from the initial conditions of the step, not of the run. Otherwise you compute the global error.
97+
"""
98+
99+
def post_step(self, step, level_number):
100+
101+
super(LogLocalError, self).post_step(step, level_number)
102+
103+
# some abbreviations
104+
L = step.levels[level_number]
105+
106+
L.sweep.compute_end_point()
107+
108+
self.add_to_stats(
109+
process=step.status.slot,
110+
time=L.time + L.dt,
111+
level=L.level_index,
112+
iter=step.status.iter,
113+
sweep=L.status.sweep,
114+
type='e_local',
115+
value=abs(L.prob.u_exact(t=L.time + L.dt, u_init=L.u[0], t_init=L.time) - L.uend),
116+
)

pySDC/implementations/hooks/log_solution.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,35 @@ def post_step(self, step, level_number):
3131
type='u',
3232
value=L.uend,
3333
)
34+
35+
36+
class LogSolutionAfterIteration(hooks):
37+
"""
38+
Store the solution at the end of each iteration as "u".
39+
"""
40+
41+
def post_iteration(self, step, level_number):
42+
"""
43+
Record solution at the end of the iteration
44+
45+
Args:
46+
step (pySDC.Step.step): the current step
47+
level_number (int): the current level number
48+
49+
Returns:
50+
None
51+
"""
52+
super().post_iteration(step, level_number)
53+
54+
L = step.levels[level_number]
55+
L.sweep.compute_end_point()
56+
57+
self.add_to_stats(
58+
process=step.status.slot,
59+
time=L.time + L.dt,
60+
level=L.level_index,
61+
iter=step.status.iter,
62+
sweep=L.status.sweep,
63+
type='u',
64+
value=L.uend,
65+
)

pySDC/projects/Resilience/Adaptivity.ipynb

Lines changed: 6 additions & 5 deletions
Large diffs are not rendered by default.

pySDC/projects/Resilience/Lorenz.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@
88
from pySDC.implementations.controller_classes.controller_nonMPI import controller_nonMPI
99
from pySDC.implementations.convergence_controller_classes.adaptivity import Adaptivity
1010
from pySDC.core.Errors import ProblemError
11-
from pySDC.projects.Resilience.hook import log_data, hook_collection
11+
from pySDC.projects.Resilience.hook import LogData, hook_collection
1212

1313

1414
def run_Lorenz(
1515
custom_description=None,
1616
num_procs=1,
1717
Tend=1.0,
18-
hook_class=log_data,
18+
hook_class=LogData,
1919
fault_stuff=None,
2020
custom_controller_params=None,
2121
custom_problem_params=None,
@@ -181,12 +181,12 @@ def main(plotting=True):
181181

182182
custom_description = {}
183183
custom_description['convergence_controllers'] = {Adaptivity: {'e_tol': 1e-5}}
184-
custom_controller_params = {'logger_level': 15}
184+
custom_controller_params = {'logger_level': 30}
185185
stats, controller, _ = run_Lorenz(
186186
custom_description=custom_description,
187187
custom_controller_params=custom_controller_params,
188188
Tend=10,
189-
hook_class=[log_data, LogGlobalErrorPostRun],
189+
hook_class=[LogData, LogGlobalErrorPostRun],
190190
)
191191
check_solution(stats, controller, 5e-4)
192192
if plotting: # pragma: no cover

pySDC/projects/Resilience/ResilienceStatistics.ipynb

Lines changed: 16 additions & 16 deletions
Large diffs are not rendered by default.

pySDC/projects/Resilience/accuracy_check.py

Lines changed: 12 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -9,42 +9,16 @@
99
EstimateExtrapolationErrorNonMPI,
1010
)
1111
from pySDC.core.Hooks import hooks
12+
from pySDC.implementations.hooks.log_errors import LogLocalError
1213

1314
import pySDC.helpers.plot_helper as plt_helper
1415
from pySDC.projects.Resilience.piline import run_piline
1516

1617

17-
class do_nothing(hooks):
18+
class DoNothing(hooks):
1819
pass
1920

2021

21-
class log_errors(hooks):
22-
"""
23-
A hook that only logs errors, but includes a local error that is not estimated during runtime.
24-
What that means is problem specific. If an analytical solution is available, the local error is exact,
25-
otherwise it is estimated using a reference solution generated with scipy.
26-
"""
27-
28-
def post_step(self, step, level_number):
29-
30-
super(log_errors, self).post_step(step, level_number)
31-
32-
# some abbreviations
33-
L = step.levels[level_number]
34-
35-
L.sweep.compute_end_point()
36-
37-
self.add_to_stats(
38-
process=step.status.slot,
39-
time=L.time,
40-
level=L.level_index,
41-
iter=0,
42-
sweep=L.status.sweep,
43-
type='e_loc',
44-
value=abs(L.prob.u_exact(t=L.time + L.dt, u_init=L.u[0], t_init=L.time) - L.u[-1]),
45-
)
46-
47-
4822
def setup_mpl(font_size=8):
4923
"""
5024
Setup matplotlib to fit in with TeX scipt.
@@ -66,7 +40,7 @@ def setup_mpl(font_size=8):
6640
mpl.rcParams.update(style_options)
6741

6842

69-
def get_results_from_stats(stats, var, val, hook_class=log_errors):
43+
def get_results_from_stats(stats, var, val, hook_class=LogLocalError):
7044
"""
7145
Extract results from the stats are used to compute the order.
7246
@@ -86,16 +60,16 @@ def get_results_from_stats(stats, var, val, hook_class=log_errors):
8660
var: val,
8761
}
8862

89-
if hook_class == log_errors:
63+
if hook_class == LogLocalError:
9064
e_extrapolated = np.array(get_sorted(stats, type='error_extrapolation_estimate'))[:, 1]
9165
e_embedded = np.array(get_sorted(stats, type='error_embedded_estimate'))[:, 1]
92-
e_loc = np.array(get_sorted(stats, type='e_loc'))[:, 1]
66+
e_local = np.array(get_sorted(stats, type='e_local'))[:, 1]
9367

9468
if len(e_extrapolated[e_extrapolated != [None]]) > 0:
9569
results['e_extrapolated'] = e_extrapolated[e_extrapolated != [None]][-1]
9670

97-
if len(e_loc[e_loc != [None]]) > 0:
98-
results['e'] = max([e_loc[e_loc != [None]][-1], np.finfo(float).eps])
71+
if len(e_local[e_local != [None]]) > 0:
72+
results['e'] = max([e_local[e_local != [None]][-1], np.finfo(float).eps])
9973

10074
if len(e_embedded[e_embedded != [None]]) > 0:
10175
results['e_embedded'] = e_embedded[e_embedded != [None]][-1]
@@ -110,7 +84,7 @@ def multiple_runs(
11084
custom_description=None,
11185
prob=run_piline,
11286
dt_list=None,
113-
hook_class=log_errors,
87+
hook_class=LogLocalError,
11488
custom_controller_params=None,
11589
var='dt',
11690
avoid_restarts=False,
@@ -176,11 +150,11 @@ def multiple_runs(
176150

177151
level = controller.MS[-1].levels[-1]
178152
e_glob = abs(level.prob.u_exact(t=level.time + level.dt) - level.u[-1])
179-
e_loc = abs(level.prob.u_exact(t=level.time + level.dt, u_init=level.u[0], t_init=level.time) - level.u[-1])
153+
e_local = abs(level.prob.u_exact(t=level.time + level.dt, u_init=level.u[0], t_init=level.time) - level.u[-1])
180154

181155
res_ = get_results_from_stats(stats, var, dt_list[i], hook_class)
182156
res_['e_glob'] = e_glob
183-
res_['e_loc'] = e_loc
157+
res_['e_local'] = e_local
184158

185159
if i == 0:
186160
res = res_.copy()
@@ -206,7 +180,7 @@ def plot_order(res, ax, k):
206180
"""
207181
color = plt.rcParams['axes.prop_cycle'].by_key()['color'][k - 2]
208182

209-
key = 'e_loc'
183+
key = 'e_local'
210184
order = get_accuracy_order(res, key=key, thresh=1e-11)
211185
label = f'k={k}, p={np.mean(order):.2f}'
212186
ax.loglog(res['dt'], res[key], color=color, ls='-', label=label)
@@ -332,7 +306,7 @@ def plot_orders(
332306
custom_description=custom_description,
333307
prob=prob,
334308
dt_list=dt_list,
335-
hook_class=do_nothing,
309+
hook_class=DoNothing,
336310
custom_controller_params=custom_controller_params,
337311
)
338312
plot_order(res, ax, k)

pySDC/projects/Resilience/advection.py

Lines changed: 38 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -3,45 +3,29 @@
33
from pySDC.implementations.problem_classes.AdvectionEquation_ND_FD import advectionNd
44
from pySDC.implementations.sweeper_classes.generic_implicit import generic_implicit
55
from pySDC.implementations.controller_classes.controller_nonMPI import controller_nonMPI
6-
from pySDC.core.Hooks import hooks
76
from pySDC.helpers.stats_helper import get_sorted
87
import numpy as np
9-
from pySDC.projects.Resilience.hook import log_data
8+
from pySDC.projects.Resilience.hook import LogData, hook_collection
9+
from pySDC.projects.Resilience.fault_injection import prepare_controller_for_faults
1010

1111

1212
def plot_embedded(stats, ax):
1313
u = get_sorted(stats, type='u', recomputed=False)
1414
uold = get_sorted(stats, type='uold', recomputed=False)
15-
t = [get_sorted(stats, type='u', recomputed=False)[i][0] for i in range(len(u))]
16-
e_em = np.array(get_sorted(stats, type='e_embedded', recomputed=False))[:, 1]
15+
t = [me[0] for me in u]
16+
e_em = get_sorted(stats, type='error_embedded_estimate', recomputed=False)
1717
e_em_semi_glob = [abs(u[i][1] - uold[i][1]) for i in range(len(u))]
1818
ax.plot(t, e_em_semi_glob, label=r'$\|u^{\left(k-1\right)}-u^{\left(k\right)}\|$')
19-
ax.plot(t, e_em, linestyle='--', label=r'$\epsilon$')
19+
ax.plot([me[0] for me in e_em], [me[1] for me in e_em], linestyle='--', label=r'$\epsilon$')
2020
ax.set_xlabel(r'$t$')
2121
ax.legend(frameon=False)
2222

2323

24-
class log_every_iteration(hooks):
25-
def post_iteration(self, step, level_number):
26-
if step.status.iter == step.params.maxiter - 1:
27-
L = step.levels[level_number]
28-
L.sweep.compute_end_point()
29-
self.add_to_stats(
30-
process=step.status.slot,
31-
time=L.time + L.dt,
32-
level=L.level_index,
33-
iter=0,
34-
sweep=L.status.sweep,
35-
type='uold',
36-
value=L.uold[-1],
37-
)
38-
39-
4024
def run_advection(
4125
custom_description=None,
4226
num_procs=1,
4327
Tend=2e-1,
44-
hook_class=log_data,
28+
hook_class=LogData,
4529
fault_stuff=None,
4630
custom_controller_params=None,
4731
custom_problem_params=None,
@@ -69,7 +53,7 @@ def run_advection(
6953
# initialize controller parameters
7054
controller_params = dict()
7155
controller_params['logger_level'] = 30
72-
controller_params['hook_class'] = hook_class
56+
controller_params['hook_class'] = hook_collection + (hook_class if type(hook_class) == list else [hook_class])
7357
controller_params['mssdc_jac'] = False
7458

7559
if custom_controller_params is not None:
@@ -99,11 +83,14 @@ def run_advection(
9983

10084
# insert faults
10185
if fault_stuff is not None:
102-
controller.hooks.random_generator = fault_stuff['rng']
103-
controller.hooks.add_fault(
104-
rnd_args={'iteration': 5, **fault_stuff.get('rnd_params', {})},
105-
args={'time': 1e-1, 'target': 0, **fault_stuff.get('args', {})},
106-
)
86+
rnd_args = {
87+
'iteration': 5,
88+
}
89+
args = {
90+
'time': 1e-1,
91+
'target': 0,
92+
}
93+
prepare_controller_for_faults(controller, fault_stuff, rnd_args, args)
10794

10895
# get initial values on finest level
10996
P = controller.MS[0].levels[0].prob
@@ -112,3 +99,26 @@ def run_advection(
11299
# call main function to get things done...
113100
uend, stats = controller.run(u0=uinit, t0=t0, Tend=Tend)
114101
return stats, controller, Tend
102+
103+
104+
if __name__ == '__main__':
105+
import matplotlib.pyplot as plt
106+
from pySDC.implementations.convergence_controller_classes.adaptivity import Adaptivity
107+
from pySDC.projects.Resilience.hook import LogUold
108+
109+
adaptivity_params = dict()
110+
adaptivity_params['e_tol'] = 1e-8
111+
112+
convergence_controllers = dict()
113+
convergence_controllers[Adaptivity] = adaptivity_params
114+
115+
description = dict()
116+
description['convergence_controllers'] = convergence_controllers
117+
118+
fig, axs = plt.subplots(1, 2, figsize=(12, 4), sharex=True, sharey=True)
119+
plot_embedded(run_advection(description, 1, hook_class=LogUold)[0], axs[0])
120+
plot_embedded(run_advection(description, 4, hook_class=LogUold)[0], axs[1])
121+
axs[0].set_title('1 process')
122+
axs[1].set_title('4 processes')
123+
fig.tight_layout()
124+
plt.show()

0 commit comments

Comments
 (0)