Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def dependencies(self, controller, description, **kwargs):
Returns:
None
"""
step_limiter_keys = ['dt_min', 'dt_max', 'dt_slope_min', 'dt_slope_max']
step_limiter_keys = ['dt_min', 'dt_max', 'dt_slope_min', 'dt_slope_max', 'dt_rel_min_slope']
available_keys = [me for me in step_limiter_keys if me in self.params.__dict__.keys()]

if len(available_keys) > 0:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def dependencies(self, controller, description, **kwargs):
Returns:
None
"""
slope_limiter_keys = ['dt_slope_min', 'dt_slope_max']
slope_limiter_keys = ['dt_slope_min', 'dt_slope_max', 'dt_rel_min_slope']
available_keys = [me for me in slope_limiter_keys if me in self.params.__dict__.keys()]

if len(available_keys) > 0:
Expand Down Expand Up @@ -90,7 +90,9 @@ class StepSizeSlopeLimiter(ConvergenceController):
"""
Class to set limits to adaptive step size computation during run time

Please supply dt_min or dt_max in the params to limit in either direction
Please supply `dt_slope_min` or `dt_slope_max` in the params to limit in either direction.
You can also supply `dt_rel_min_slope` in order to keep the old step size in case the relative change is smaller
than this minimum.
"""

def setup(self, controller, params, description, **kwargs):
Expand All @@ -109,6 +111,7 @@ def setup(self, controller, params, description, **kwargs):
"control_order": 91,
"dt_slope_min": 0,
"dt_slope_max": np.inf,
"dt_rel_min_slope": 0,
}
return {**defaults, **super().setup(controller, params, description, **kwargs)}

Expand Down Expand Up @@ -143,5 +146,11 @@ def get_new_step_size(self, controller, S, **kwargs):
S,
)
L.status.dt_new = dt_new
elif abs(L.status.dt_new / L.params.dt - 1) < self.params.dt_rel_min_slope:
L.status.dt_new = L.params.dt
self.log(
f"Step size did not change sufficiently to warrant step size change, keeping {L.status.dt_new:.2e}",
S,
)

return None
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ def get_controller(dt, num_nodes, useMPI, adaptivity, adaptivity_params, **kwarg
adaptivity_params (dict): Parameters for convergence controller

Returns:
(dict): Stats object generated during the run
(pySDC.Controller.controller): Controller used in the run
"""
from pySDC.implementations.problem_classes.polynomial_test_problem import polynomial_testequation
Expand Down
112 changes: 112 additions & 0 deletions pySDC/tests/test_convergence_controllers/test_step_size_limiter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import pytest


def get_controller(step_size_limier_params):
"""
Runs a single advection problem with certain parameters

Args:
step_size_limier_params (dict): Parameters for convergence controller

Returns:
(pySDC.Controller.controller): Controller used in the run
"""
from pySDC.implementations.problem_classes.polynomial_test_problem import polynomial_testequation
from pySDC.implementations.controller_classes.controller_nonMPI import controller_nonMPI
from pySDC.implementations.sweeper_classes.generic_implicit import generic_implicit
from pySDC.implementations.convergence_controller_classes.step_size_limiter import StepSizeLimiter

level_params = {}
level_params['dt'] = 1.0
level_params['restol'] = 1.0

sweeper_params = {}
sweeper_params['quad_type'] = 'GAUSS'
sweeper_params['num_nodes'] = 1
sweeper_params['do_coll_update'] = True

problem_params = {'degree': 10}

step_params = {}
step_params['maxiter'] = 0

controller_params = {}
controller_params['logger_level'] = 30

description = {}
description['problem_class'] = polynomial_testequation
description['problem_params'] = problem_params
description['sweeper_class'] = generic_implicit
description['sweeper_params'] = sweeper_params
description['level_params'] = level_params
description['step_params'] = step_params
description['convergence_controllers'] = {StepSizeLimiter: step_size_limier_params}

controller = controller_nonMPI(num_procs=1, controller_params=controller_params, description=description)

controller.add_convergence_controller(StepSizeLimiter, description, step_size_limier_params)

return controller


@pytest.mark.base
def test_step_size_slope_limiter():
from pySDC.implementations.convergence_controller_classes.step_size_limiter import StepSizeSlopeLimiter

params = {'dt_slope_max': 2, 'dt_slope_min': 1e-3, 'dt_rel_min_slope': 1e-1}
controller = get_controller(params)

limiter = controller.convergence_controllers[
[type(me) for me in controller.convergence_controllers].index(StepSizeSlopeLimiter)
]

S = controller.MS[0]
S.status.slot = 0
L = S.levels[0]
L.status.time = 0

L.params.dt = 1
L.status.dt_new = 3
limiter.get_new_step_size(controller, S)
assert L.status.dt_new == 2

L.params.dt = 1
L.status.dt_new = 0
limiter.get_new_step_size(controller, S)
assert L.status.dt_new == 1e-3

L.params.dt = 1
L.status.dt_new = 1 + 1e-3
limiter.get_new_step_size(controller, S)
assert L.status.dt_new == 1


@pytest.mark.base
def test_step_size_limiter():
from pySDC.implementations.convergence_controller_classes.step_size_limiter import StepSizeLimiter

params = {'dt_max': 2, 'dt_min': 0.5}
controller = get_controller(params)

limiter = controller.convergence_controllers[
[type(me) for me in controller.convergence_controllers].index(StepSizeLimiter)
]

S = controller.MS[0]
S.status.slot = 0
L = S.levels[0]
L.status.time = 0

L.params.dt = 1
L.status.dt_new = 3
limiter.get_new_step_size(controller, S)
assert L.status.dt_new == 2

L.params.dt = 1
L.status.dt_new = 0
limiter.get_new_step_size(controller, S)
assert L.status.dt_new == 0.5


if __name__ == '__main__':
test_step_size_slope_limiter()