Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Easier generation of description dictionaries #367

Merged
merged 3 commits into from
Oct 26, 2023
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
2 changes: 1 addition & 1 deletion pySDC/core/Level.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ def __init__(self, params):
# freeze class, no further attributes allowed from this point
self._freeze()

self.dt_initial = self.dt * 1.0
self.dt_initial = self.dt * 1.0 if self.dt is not None else None


# short helper class to bundle all status variables
Expand Down
4 changes: 4 additions & 0 deletions pySDC/core/Problem.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ def f_init(self):
"""Generate a data variable for RHS"""
return self.dtype_f(self.init)

@classmethod
def get_default_sweeper_class(cls):
raise NotImplementedError(f'No default sweeper class implemented for {cls} problem!')

def eval_f(self, u, t):
"""
Abstract interface to RHS computation of the ODE
Expand Down
45 changes: 45 additions & 0 deletions pySDC/helpers/setup_helper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
def generate_description(problem_class, **kwargs):
"""
Generate a description object that you can use to run pySDC based on a problem class and various input.
This function does not set any additional defaults, but distributes the values to where they belong.

Args:
problem_class (pySDC.Problem): A problem class

Returns:
dict: A description object for running pySDC
"""
from pySDC.core.Level import _Pars as level_params
from pySDC.core.Step import _Pars as step_params

description = {
'level_params': {},
'problem_params': {},
'sweeper_params': {},
'problem_class': problem_class,
'step_params': {},
'sweeper_class': kwargs.get('sweeper_class', problem_class.get_default_sweeper_class()),
'convergence_controllers': {},
}

problem_keys = problem_class.__init__.__code__.co_varnames
level_keys = level_params({}).__dict__.keys()
sweeper_keys = description['sweeper_class']({'num_nodes': 1, 'quad_type': 'RADAU-RIGHT'}).params.__dict__.keys()
step_keys = step_params({}).__dict__.keys()

# TODO: add convergence controllers
for key, val in kwargs.items():
if key in problem_keys:
description['problem_params'][key] = val
elif key in level_keys:
description['level_params'][key] = val
elif key in sweeper_keys:
description['sweeper_params'][key] = val
elif key in step_keys:
description['step_params'][key] = val
elif key == 'sweeper_class':
pass
else:
raise ValueError(f'Don\'t know what parameter \"{key}\" is for!')

return description
6 changes: 6 additions & 0 deletions pySDC/implementations/problem_classes/generic_ND_FD.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,12 @@ def grids(self):
if self.ndim == 3:
return x[None, :, None], x[:, None, None], x[None, None, :]

@classmethod
def get_default_sweeper_class(cls):
from pySDC.implementations.sweeper_classes.generic_implicit import generic_implicit

return generic_implicit
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is that the default sweeper class for this problem type? Could also be IMEX?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, but I guess the IMEX as standard should come with a bigger rework of pySDC, right ?


def eval_f(self, u, t):
"""
Routine to evaluate the right-hand side of the problem.
Expand Down
59 changes: 59 additions & 0 deletions pySDC/tests/test_helpers/test_setup_helper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import pytest


@pytest.mark.base
def test_setup_helper():
from pySDC.helpers.setup_helper import generate_description
from pySDC.implementations.problem_classes.AdvectionEquation_ND_FD import advectionNd
from pySDC.implementations.sweeper_classes.generic_implicit import generic_implicit

# build classic description
# initialize level parameters
level_params = {}
level_params['dt'] = 0.05

# initialize sweeper parameters
sweeper_params = {}
sweeper_params['quad_type'] = 'RADAU-RIGHT'
sweeper_params['num_nodes'] = 3
sweeper_params['QI'] = 'IE'

problem_params = {'freq': 2, 'nvars': 2**9, 'c': 1.0, 'stencil_type': 'center', 'order': 4, 'bc': 'periodic'}

# initialize step parameters
step_params = {}
step_params['maxiter'] = 5

description = {}
description['problem_class'] = advectionNd
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'] = {}

easy_description = generate_description(
problem_class=advectionNd, **problem_params, **level_params, **sweeper_params, **step_params
)

assert (
easy_description == description
), 'The generate description function did not reproduce the desired description'

easy_description = generate_description(
problem_class=advectionNd,
sweeper_class=generic_implicit,
**problem_params,
**level_params,
**sweeper_params,
**step_params
)

assert (
easy_description == description
), 'The generate description function did not reproduce the desired description when supplying a sweeper class'


if __name__ == '__main__':
test_setup_helper()