Skip to content

Commit f1b8fbd

Browse files
Added option to skip dt change if insignificant (#482)
1 parent 32549d9 commit f1b8fbd

File tree

4 files changed

+124
-4
lines changed

4 files changed

+124
-4
lines changed

pySDC/implementations/convergence_controller_classes/adaptivity.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def dependencies(self, controller, description, **kwargs):
5252
Returns:
5353
None
5454
"""
55-
step_limiter_keys = ['dt_min', 'dt_max', 'dt_slope_min', 'dt_slope_max']
55+
step_limiter_keys = ['dt_min', 'dt_max', 'dt_slope_min', 'dt_slope_max', 'dt_rel_min_slope']
5656
available_keys = [me for me in step_limiter_keys if me in self.params.__dict__.keys()]
5757

5858
if len(available_keys) > 0:

pySDC/implementations/convergence_controller_classes/step_size_limiter.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ def dependencies(self, controller, description, **kwargs):
3939
Returns:
4040
None
4141
"""
42-
slope_limiter_keys = ['dt_slope_min', 'dt_slope_max']
42+
slope_limiter_keys = ['dt_slope_min', 'dt_slope_max', 'dt_rel_min_slope']
4343
available_keys = [me for me in slope_limiter_keys if me in self.params.__dict__.keys()]
4444

4545
if len(available_keys) > 0:
@@ -90,7 +90,9 @@ class StepSizeSlopeLimiter(ConvergenceController):
9090
"""
9191
Class to set limits to adaptive step size computation during run time
9292
93-
Please supply dt_min or dt_max in the params to limit in either direction
93+
Please supply `dt_slope_min` or `dt_slope_max` in the params to limit in either direction.
94+
You can also supply `dt_rel_min_slope` in order to keep the old step size in case the relative change is smaller
95+
than this minimum.
9496
"""
9597

9698
def setup(self, controller, params, description, **kwargs):
@@ -109,6 +111,7 @@ def setup(self, controller, params, description, **kwargs):
109111
"control_order": 91,
110112
"dt_slope_min": 0,
111113
"dt_slope_max": np.inf,
114+
"dt_rel_min_slope": 0,
112115
}
113116
return {**defaults, **super().setup(controller, params, description, **kwargs)}
114117

@@ -143,5 +146,11 @@ def get_new_step_size(self, controller, S, **kwargs):
143146
S,
144147
)
145148
L.status.dt_new = dt_new
149+
elif abs(L.status.dt_new / L.params.dt - 1) < self.params.dt_rel_min_slope:
150+
L.status.dt_new = L.params.dt
151+
self.log(
152+
f"Step size did not change sufficiently to warrant step size change, keeping {L.status.dt_new:.2e}",
153+
S,
154+
)
146155

147156
return None

pySDC/tests/test_convergence_controllers/test_adaptivity.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ def get_controller(dt, num_nodes, useMPI, adaptivity, adaptivity_params, **kwarg
1313
adaptivity_params (dict): Parameters for convergence controller
1414
1515
Returns:
16-
(dict): Stats object generated during the run
1716
(pySDC.Controller.controller): Controller used in the run
1817
"""
1918
from pySDC.implementations.problem_classes.polynomial_test_problem import polynomial_testequation
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
import pytest
2+
3+
4+
def get_controller(step_size_limier_params):
5+
"""
6+
Runs a single advection problem with certain parameters
7+
8+
Args:
9+
step_size_limier_params (dict): Parameters for convergence controller
10+
11+
Returns:
12+
(pySDC.Controller.controller): Controller used in the run
13+
"""
14+
from pySDC.implementations.problem_classes.polynomial_test_problem import polynomial_testequation
15+
from pySDC.implementations.controller_classes.controller_nonMPI import controller_nonMPI
16+
from pySDC.implementations.sweeper_classes.generic_implicit import generic_implicit
17+
from pySDC.implementations.convergence_controller_classes.step_size_limiter import StepSizeLimiter
18+
19+
level_params = {}
20+
level_params['dt'] = 1.0
21+
level_params['restol'] = 1.0
22+
23+
sweeper_params = {}
24+
sweeper_params['quad_type'] = 'GAUSS'
25+
sweeper_params['num_nodes'] = 1
26+
sweeper_params['do_coll_update'] = True
27+
28+
problem_params = {'degree': 10}
29+
30+
step_params = {}
31+
step_params['maxiter'] = 0
32+
33+
controller_params = {}
34+
controller_params['logger_level'] = 30
35+
36+
description = {}
37+
description['problem_class'] = polynomial_testequation
38+
description['problem_params'] = problem_params
39+
description['sweeper_class'] = generic_implicit
40+
description['sweeper_params'] = sweeper_params
41+
description['level_params'] = level_params
42+
description['step_params'] = step_params
43+
description['convergence_controllers'] = {StepSizeLimiter: step_size_limier_params}
44+
45+
controller = controller_nonMPI(num_procs=1, controller_params=controller_params, description=description)
46+
47+
controller.add_convergence_controller(StepSizeLimiter, description, step_size_limier_params)
48+
49+
return controller
50+
51+
52+
@pytest.mark.base
53+
def test_step_size_slope_limiter():
54+
from pySDC.implementations.convergence_controller_classes.step_size_limiter import StepSizeSlopeLimiter
55+
56+
params = {'dt_slope_max': 2, 'dt_slope_min': 1e-3, 'dt_rel_min_slope': 1e-1}
57+
controller = get_controller(params)
58+
59+
limiter = controller.convergence_controllers[
60+
[type(me) for me in controller.convergence_controllers].index(StepSizeSlopeLimiter)
61+
]
62+
63+
S = controller.MS[0]
64+
S.status.slot = 0
65+
L = S.levels[0]
66+
L.status.time = 0
67+
68+
L.params.dt = 1
69+
L.status.dt_new = 3
70+
limiter.get_new_step_size(controller, S)
71+
assert L.status.dt_new == 2
72+
73+
L.params.dt = 1
74+
L.status.dt_new = 0
75+
limiter.get_new_step_size(controller, S)
76+
assert L.status.dt_new == 1e-3
77+
78+
L.params.dt = 1
79+
L.status.dt_new = 1 + 1e-3
80+
limiter.get_new_step_size(controller, S)
81+
assert L.status.dt_new == 1
82+
83+
84+
@pytest.mark.base
85+
def test_step_size_limiter():
86+
from pySDC.implementations.convergence_controller_classes.step_size_limiter import StepSizeLimiter
87+
88+
params = {'dt_max': 2, 'dt_min': 0.5}
89+
controller = get_controller(params)
90+
91+
limiter = controller.convergence_controllers[
92+
[type(me) for me in controller.convergence_controllers].index(StepSizeLimiter)
93+
]
94+
95+
S = controller.MS[0]
96+
S.status.slot = 0
97+
L = S.levels[0]
98+
L.status.time = 0
99+
100+
L.params.dt = 1
101+
L.status.dt_new = 3
102+
limiter.get_new_step_size(controller, S)
103+
assert L.status.dt_new == 2
104+
105+
L.params.dt = 1
106+
L.status.dt_new = 0
107+
limiter.get_new_step_size(controller, S)
108+
assert L.status.dt_new == 0.5
109+
110+
111+
if __name__ == '__main__':
112+
test_step_size_slope_limiter()

0 commit comments

Comments
 (0)