Skip to content

Commit bf74069

Browse files
author
Thomas Baumann
committed
Fixed type and confirmed the order of the embedded estimate
1 parent d40eab0 commit bf74069

File tree

5 files changed

+58
-21
lines changed

5 files changed

+58
-21
lines changed

pySDC/implementations/convergence_controller_classes/adaptivity.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ def get_new_step_size(self, controller, S):
6767
'''
6868
raise NotImplementedError('Please implement a rule for updating the step size!')
6969

70-
def compute_optimatal_step_size(self, beta, dt, e_tol, e_est, order):
70+
def compute_optimal_step_size(self, beta, dt, e_tol, e_est, order):
7171
'''
7272
Compute the optimal step size for the current step based on the order of the scheme.
7373
This function can be called from `get_new_step_size` for various implementations of adaptivity, but notably not
@@ -192,8 +192,8 @@ def get_new_step_size(self, controller, S):
192192
# compute next step size
193193
order = S.status.iter # embedded error estimate is same order as time marching
194194
e_est = self.get_local_error_estimate(controller, S)
195-
L.status.dt_new = self.compute_optimatal_step_size(self.params.beta, L.params.dt, self.params.e_tol, e_est,
196-
order)
195+
L.status.dt_new = self.compute_optimal_step_size(self.params.beta, L.params.dt, self.params.e_tol, e_est,
196+
order)
197197
self.log(f'Adjusting step size from {L.params.dt:.2e} to {L.status.dt_new:.2e}', S)
198198

199199
return None
@@ -254,8 +254,8 @@ def get_new_step_size(self, controller, S):
254254
# compute next step size
255255
order = self.params.update_order
256256
e_est = self.get_local_error_estimate(controller, S)
257-
L.status.dt_new = self.compute_optimatal_step_size(self.params.beta, L.params.dt, self.params.e_tol, e_est,
258-
order)
257+
L.status.dt_new = self.compute_optimal_step_size(self.params.beta, L.params.dt, self.params.e_tol, e_est,
258+
order)
259259
self.log(f'Adjusting step size from {L.params.dt:.2e} to {L.status.dt_new:.2e}', S)
260260

261261
return None

pySDC/implementations/convergence_controller_classes/estimate_embedded_error.py

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class EstimateEmbeddedError(ConvergenceController):
1616

1717
def setup(self, controller, params, description):
1818
'''
19-
Add a default value for control order to the parameters
19+
Add a default value for control order to the parameters and check if we are using a Runge-Kutta sweeper
2020
2121
Args:
2222
controller (pySDC.Controller): The controller
@@ -26,7 +26,8 @@ def setup(self, controller, params, description):
2626
Returns:
2727
dict: Updated parameters
2828
'''
29-
return {'control_order': -80, **params}
29+
sweeper_type = 'RK' if RungeKutta in description['sweeper_class'].__bases__ else 'SDC'
30+
return {'control_order': -80, 'sweeper_type': sweeper_type, **params}
3031

3132
def dependencies(self, controller, description):
3233
'''
@@ -55,11 +56,15 @@ def estimate_embedded_error_serial(self, L):
5556
Returns:
5657
dtype_u: The embedded error estimate
5758
'''
58-
sweeper = L.sweep
59-
if RungeKutta in type(sweeper).__bases__:
59+
if self.params.sweeper_type == 'RK':
60+
# lower order solution is stored in the second to last entry of L.u
6061
return abs(L.u[-2] - L.u[-1])
61-
else:
62+
elif self.params.sweeper_type == 'SDC':
63+
# order rises by one between sweeps, making this so ridiculously easy
6264
return abs(L.uold[-1] - L.u[-1])
65+
else:
66+
raise NotImplementedError(f'Don\'t know how to estimate embedded error for sweeper type \
67+
{self.params.sweeper_type}')
6368

6469

6570
class EstimateEmbeddedErrorNonMPI(EstimateEmbeddedError):
@@ -105,9 +110,8 @@ def post_iteration_processing(self, controller, S):
105110
raise NotImplementedError('Embedded error estimate only works for serial multi-level or parallel single \
106111
level')
107112

108-
if S.status.iter > 1:
113+
if S.status.iter > 1 or self.params.sweeper_type == 'RK':
109114
for L in S.levels:
110-
# order rises by one between sweeps, making this so ridiculously easy
111115
temp = self.estimate_embedded_error_serial(L)
112116
L.status.error_embedded_estimate = max([abs(temp - self.buffers.e_em_last), np.finfo(float).eps])
113117

pySDC/playgrounds/Runge_Kutta/Runge-Kutta-Methods.ipynb

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@
8989
{
9090
"cell_type": "code",
9191
"execution_count": 2,
92-
"id": "90ae9863",
92+
"id": "bfc3c486",
9393
"metadata": {},
9494
"outputs": [
9595
{
@@ -111,7 +111,7 @@
111111
},
112112
{
113113
"cell_type": "markdown",
114-
"id": "d152c6bb",
114+
"id": "a367d047",
115115
"metadata": {},
116116
"source": [
117117
"in the above plot you can see the regions of stability for implicit and explicit methods.\n",
@@ -125,7 +125,7 @@
125125
{
126126
"cell_type": "code",
127127
"execution_count": 3,
128-
"id": "34d1a1c2",
128+
"id": "d247424b",
129129
"metadata": {},
130130
"outputs": [
131131
{
@@ -147,11 +147,12 @@
147147
},
148148
{
149149
"cell_type": "markdown",
150-
"id": "a407381b",
150+
"id": "927c533f",
151151
"metadata": {},
152152
"source": [
153153
"We can see that the step size in black is refined by about an order of magnitude to properly resolve the fast time-scale region at around $t=5$.\n",
154-
"We have to perfrom quite a few restarts, but we indeed achieve good temporal resolution throughout."
154+
"We have to perfrom quite a few restarts, but we indeed achieve good temporal resolution throughout.\n",
155+
"We also checked that the order of the embedded estimate is one lower than the order of the scheme, meaning it is of order 5."
155156
]
156157
}
157158
],

pySDC/projects/Resilience/accuracy_check.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -141,16 +141,20 @@ def plot(res, ax, k):
141141
color = plt.rcParams['axes.prop_cycle'].by_key()['color'][k - 2]
142142

143143
for i in range(len(keys)):
144+
if all([me == 0. for me in res[keys[i]]]):
145+
continue
144146
order = get_accuracy_order(res, key=keys[i])
145147
if keys[i] == 'e_embedded':
146148
label = rf'$k={{{np.mean(order):.2f}}}$'
147-
assert np.isclose(np.mean(order), k, atol=3e-1), f'Expected embedded error estimate to have order {k} \
149+
assert np.isclose(np.mean(order), k, atol=4e-1), f'Expected embedded error estimate to have order {k} \
148150
but got {np.mean(order):.2f}'
149151

150152
elif keys[i] == 'e_extrapolated':
151153
label = None
152154
assert np.isclose(np.mean(order), k + 1, rtol=3e-1), f'Expected extrapolation error estimate to have order \
153155
{k+1} but got {np.mean(order):.2f}'
156+
else:
157+
label = None
154158
ax.loglog(res['dt'], res[keys[i]], color=color, ls=ls[i], label=label)
155159

156160
ax.set_xlabel(r'$\Delta t$')
@@ -198,11 +202,12 @@ def plot_orders(ax, ks, serial, Tend_fixed=None, custom_description=None, prob=r
198202
plot_order(res, ax, k)
199203

200204

201-
def plot_all_errors(ax, ks, serial, Tend_fixed=None, custom_description=None, prob=run_piline):
205+
def plot_all_errors(ax, ks, serial, Tend_fixed=None, custom_description=None, prob=run_piline, dt_list=None,
206+
custom_controller_params=None):
202207
for i in range(len(ks)):
203208
k = ks[i]
204209
res = multiple_runs(k=k, serial=serial, Tend_fixed=Tend_fixed, custom_description=custom_description,
205-
prob=prob)
210+
prob=prob, dt_list=dt_list, custom_controller_params=custom_controller_params)
206211

207212
# visualize results
208213
plot(res, ax, k)

pySDC/projects/Resilience/test_Runge_Kutta_sweeper.py

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
import matplotlib.pyplot as plt
22
import numpy as np
33

4-
from pySDC.projects.Resilience.accuracy_check import plot_orders
4+
from pySDC.projects.Resilience.accuracy_check import plot_orders, plot_all_errors
55
from pySDC.projects.Resilience.dahlquist import run_dahlquist, plot_stability
66

77
from pySDC.projects.Resilience.advection import run_advection
88
from pySDC.projects.Resilience.vdp import run_vdp, plot_step_sizes
99

1010
from pySDC.implementations.sweeper_classes.Runge_Kutta import RK1, RK4, MidpointMethod, CrankNicholson, Cash_Karp
1111
from pySDC.implementations.convergence_controller_classes.adaptivity import AdaptivityRK
12+
from pySDC.implementations.convergence_controller_classes.estimate_embedded_error import EstimateEmbeddedErrorNonMPI
1213
from pySDC.helpers.stats_helper import get_sorted
1314

1415

@@ -28,6 +29,7 @@ def plot_order(sweeper, prob, dt_list, description=None, ax=None, Tend_fixed=Non
2829
description = dict() if description is None else description
2930
description['sweeper_class'] = sweeper
3031
description['sweeper_params'] = {'implicit': True}
32+
description['step_params'] = {'maxiter': 1}
3133

3234
custom_controller_params = {'logger_level': 40}
3335

@@ -63,6 +65,7 @@ def plot_stability_single(sweeper, ax=None, description=None, implicit=True, re=
6365
description = dict() if description is None else description
6466
description['sweeper_class'] = sweeper
6567
description['sweeper_params'] = {'implicit': implicit}
68+
description['step_params'] = {'maxiter': 1}
6669

6770
custom_controller_params = {'logger_level': 40}
6871

@@ -114,6 +117,28 @@ def test_advection():
114117
plot_all_orders(run_advection, 1.e-3 * 2.**(-np.arange(8)), None, [RK1, MidpointMethod, CrankNicholson])
115118

116119

120+
def test_embedded_estimate_order():
121+
sweeper = Cash_Karp
122+
fig, ax = plt.subplots(1, 1)
123+
124+
# change only the things in the description that we need for adaptivity
125+
convergence_controllers = dict()
126+
convergence_controllers[EstimateEmbeddedErrorNonMPI] = {}
127+
128+
description = dict()
129+
description['convergence_controllers'] = convergence_controllers
130+
description['sweeper_class'] = sweeper
131+
description['step_params'] = {'maxiter': 1}
132+
133+
custom_controller_params = {'logger_level': 40}
134+
135+
Tend = 7e-2
136+
dt_list = Tend * 2.**(-np.arange(8))
137+
prob = run_vdp
138+
plot_all_errors(ax, [5], True, Tend_fixed=Tend, custom_description=description, dt_list=dt_list, prob=prob,
139+
custom_controller_params=custom_controller_params)
140+
141+
117142
def test_embedded_method():
118143
sweeper = Cash_Karp
119144
fig, ax = plt.subplots(1, 1)
@@ -129,6 +154,7 @@ def test_embedded_method():
129154
description = dict()
130155
description['convergence_controllers'] = convergence_controllers
131156
description['sweeper_class'] = sweeper
157+
description['step_params'] = {'maxiter': 1}
132158

133159
custom_controller_params = {'logger_level': 40}
134160

@@ -145,6 +171,7 @@ def test_embedded_method():
145171

146172
if __name__ == '__main__':
147173
test_embedded_method()
174+
test_embedded_estimate_order()
148175
test_vdp()
149176
test_advection()
150177
plot_all_stability()

0 commit comments

Comments
 (0)