3from __future__
import annotations
7from typing
import Callable, Dict, List, Tuple, Union
12from .PDETerm
import PDETerm
14VariableSpecification = Union[int, Dict[str, int]]
20 Abstract base class for all ExaHyPE 2 solvers
22 Every discretisation ExaHyPE 2 ships (Finite Volumes, ADER-DG, Runge-Kutta
23 Discontinuous Galerkin, Runge-Kutta Finite Differences, ...) is, from the
24 project's point of view, a black box that has to answer a small set of
25 questions: what data does it need on the mesh, which action sets realise
26 its algorithmic steps, and how does it plug into the code generation. This
27 class holds exactly that common contract plus the bits of bookkeeping
28 (name, includes, solver constants, the unknowns/auxiliary_variables
29 variable-shortcut logic) that every concrete solver has historically
30 reimplemented identically. It does not know anything about a concrete
31 discretisation - it neither creates the actual mesh data structures nor
32 the actual action sets, as this remains solver-specific and thus has to be
33 added by all subclasses.
35 A concrete solver typically extends the constructor with its own
36 discretisation-specific parameters (patch size, polynomial order, time
37 stepping scheme, ...), calls `Solver.__init__()` for the shared part, and
38 then implements the abstract methods below.
40 @see exahype2.api.Project
47 Turns a Solver into actual classes.
57 Has to be implemented by subclass
60 class NumericalScheme(abc.ABC):
63 The concrete discretisation (Finite Volumes, ADER-DG, ...) realised
64 by a Solver. Abstract - concrete solvers have to provide a subclass
65 that implements construct_output().
72 @param solver: exahype2.api.Solver
73 The solver which the scheme discretises.
81 Has to be implemented by subclass
83 time_step: peano4.api.taskgraph.Graph
84 The task graph of the surrounding exahype2_project's time
85 stepping phase, so the numerical scheme can add its own tasks
92 The mesh adaptation a solver uses if the user does not assign
93 one to solver.mesh_adaptation
95 @return Solver.MeshAdaptation or None
96 The default returns None, i.e. the solver does not contribute
97 to the mesh adaptation phase.
105 How a Solver drives the construction of the mesh it runs on.
106 Abstract - concrete solvers have to provide a subclass that
107 implements construct_output().
117 Has to be implemented by subclass
119 setup_simulation: peano4.api.taskgraph.Graph
120 The task graph of the surrounding exahype2_project's setup
121 phase, so the grid construction can add its own tasks into it.
124 class Plotter(abc.ABC):
127 How a Solver writes out its solution. Abstract - concrete solvers
128 have to provide a subclass that implements construct_output().
130 A solver can have an arbitrary number of plotters
131 (@ref exahype2.api.Solver.Solver.add_plotter()), e.g. one which
132 writes VTK files for visualisation and one which writes
133 checkpoints. Each plotter has a name which is unique per solver,
134 and it decides itself when it is active. For this, it gives its
135 solver's C++ class a method
137 ~~~~~~~~~~~~~~~~~~~~~~~
138 bool is<Name>Active() const;
139 ~~~~~~~~~~~~~~~~~~~~~~~
143 ~~~~~~~~~~~~~~~~~~~~~~~
144 bool wantsToPlot() const;
145 ~~~~~~~~~~~~~~~~~~~~~~~
147 holds if any of its plotters is active. The generated main asks all
148 solvers with a plotter (repositories::wantsToPlot()) and runs the
149 plot phase if any of them wants to plot. The task graphs of all
150 plotters of all solvers are added to the one plot graph, which the
151 graph compiler then maps onto grid sweeps. Within the plot phase,
152 every action set of a plotter is guarded by its plotter's
153 is<Name>Active(), so only the active plotters do any work.
155 is<Name>Active() must not change throughout the plot phase. Each
156 plotter therefore calls its
158 ~~~~~~~~~~~~~~~~~~~~~~~
160 ~~~~~~~~~~~~~~~~~~~~~~~
162 which moves it on to its next output, in the unprepareTraversal() of
163 its last task, i.e. after all of its tasks have run.
165 The class provides this bookkeeping for plotters which write output
166 in regular time intervals (_add_time_interval_bookkeeping_to_solver()).
170 def __init__(self, solver:
"Solver", name: str =
None):
173 @param solver: exahype2.api.Solver
174 The solver whose solution is written.
176 @param name: str or None
177 Name of the plotter, which is unique per solver. It becomes
178 part of the generated C++ method names, i.e. it has to be a
179 valid C++ identifier. If None, the solver derives a name from
180 the plotter's class name once the plotter is added
181 (@ref exahype2.api.Solver.Solver.add_plotter()).
185 if name
is not None and not name.isidentifier():
186 raise ValueError(f
"Plotter name {name} is no valid C++ identifier")
192 Has to be implemented by subclass
194 plot: peano4.api.taskgraph.Graph
195 The task graph of the surrounding exahype2_project's plotting
196 phase, so the plotter can add its own tasks into it.
202 Prefix of the files the plotter writes, including the path
204 The solver uses it to ensure that no two plotters write into
205 the same files. Plotters which write no files return None.
213 C++ predicate which holds if the plotter is active
215 Combine the guards of all of the plotter's action sets with it.
229 C++ statement which moves the plotter on to its next output
231 Insert it into the unprepareTraversal() of the plotter's last
244 self, first_time_stamp: float, time_in_between: float
248 Make the plotter active in regular time intervals
250 Add the attribute _next<Name>TimeStamp plus the methods
251 is<Name>Active() and finish<Name>() to the solver's C++ class.
252 The plotter is active as soon as the solver's min time stamp has
253 reached _next<Name>TimeStamp. finish<Name>() then increments
254 _next<Name>TimeStamp by time_in_between.
256 The solver keeps these members once added, so we add them only
257 once, even if the Peano 4 project is generated multiple times.
259 @param first_time_stamp: float
260 Time stamp of the first output.
262 @param time_in_between: float
263 Time in between two outputs. Has to be positive.
270 + repr(float(first_time_stamp))
273 if attribute
in self.
_solver._abstract_solver_attributes:
278 "bool is" + self.
name +
"Active() const;",
279 lambda qualified_class_name:
"bool "
280 + qualified_class_name
283 +
"Active() const {\n"
284 " return tarch::la::greaterEquals(getMinTimeStamp(), _next"
290 "void finish" + self.
name +
"();",
291 lambda qualified_class_name:
"void "
292 + qualified_class_name
296 " if (is" + self.
name +
"Active()) {\n"
300 + repr(float(time_in_between))
309 How a Solver adapts its mesh and rebalances its load between two
310 time steps. Abstract - concrete solvers have to provide a subclass
311 that implements construct_output().
313 The mesh adaptation is the fourth phase of an ExaHyPE 2 project
314 next to the setup, the time stepping and the plotting. The
315 generated main runs it right after a time step, and only if this
316 time step has asked for a mesh refinement or erase, or if the load
317 balancing has split recently (@ref exahype2::isMeshAdaptationRequired()).
318 The phase is optional: Solvers without a MeshAdaptation do not
319 contribute to it, and the main never runs an empty phase.
321 The mesh adaptation does not decide where to refine or erase. The
322 numerical scheme's last task of the time step collects these
323 requests (@ref exahype2.api.blockstructured.DynamicMeshRefinement),
324 and the mesh adaptation realises them.
334 Has to be implemented by subclass
336 mesh_adaptation: peano4.api.taskgraph.Graph
337 The task graph of the surrounding exahype2_project's mesh
338 adaptation phase, so the mesh adaptation can add its own tasks
364 SolutionUpdateTaskTag =
"exahype2.api.Solver.SolutionUpdateTaskTag"
373 IntermediateSolutionUpdateTag =
"exahype2.api.Solver.IntermediateSolutionUpdateTag"
378 unknowns: VariableSpecification,
379 auxiliary_variables: VariableSpecification,
386 A unique name for the solver. This one is used for all generated
387 classes. The generated C++ object instance also incorporates this
390 unknowns: int or dict
391 Number of unknowns per mesh entry (Finite Volume voxel, DG degree of
392 freedom, ...). Eventually, unknowns and auxiliary_variables are
393 merged into one big vector, but the solver still has to be able to
394 distinguish them, as only the unknowns are subject to the actual PDE
395 formulation. Can be specified either as a plain int, or as a dict
396 mapping variable name onto multiplicity (e.g.
397 `{"rho": 1, "j": 3}` for a scalar density plus a 3d momentum). If
398 dicts are used, the generated Abstract<SolverName> class hosts a
399 nested struct Variables with one constant per name, so user code
400 can write Q[Variables::j+1] instead of having to remember the
401 offset into the unknowns array by hand.
403 auxiliary_variables: int or dict
404 Same semantics as unknowns, but for variables that may be
405 space-dependent yet do not change over time. Their names follow
406 the unknowns' names, as the auxiliary variables follow the
409 If names are used at all, they have to cover all unknowns and all
410 auxiliary variables, i.e. you cannot pass a dict for one and a
411 non-zero int for the other.
413 The variables cannot be changed after construction: the numerical
414 scheme sizes its data structures from them as soon as it is assigned
421 self._variable_positions: Dict[str, int] = {}
429 sum(variables.values())
430 for variables
in (unknowns, auxiliary_variables)
431 if isinstance(variables, dict)
433 if self._variable_positions
and named_entries != (
437 f
"Solver {name}: the variable names {list(self._variable_positions)} "
438 f
"cover only {named_entries} of the {self._unknowns} unknowns and "
439 f
"{self._auxiliary_variables} auxiliary variables. If you name "
440 f
"variables, name all unknowns and all auxiliary variables, i.e. "
441 f
"pass dicts for both (or 0 for the one that is empty)."
447 self._pde_terms: Dict[Tuple[str, bool], PDETerm] = {}
453 self._abstract_solver_attributes: List[str] = []
454 self._abstract_solver_methods: List[Tuple[str, Callable[[str], str]]] = []
463 from .SolverToCPPFiles
import SolverToCPPFiles
477 self.grid_construction:
"Solver.GridConstruction" =
None
482 self.
_plotters: List[
"Solver.Plotter"] = []
501 self.compute_kernel_call: str =
None
506 Translate a plain int or a name-to-multiplicity dict into a total
507 variable count, and - for the dict case - add each name's position
508 within Q to _variable_positions. Called once for unknowns (offset 0)
509 and once for auxiliary_variables (offset = number of unknowns), so
510 the two end up in one contiguous name/offset table.
513 if isinstance(variables, dict):
514 for variable_name, multiplicity
in variables.items():
515 if variable_name
in self._variable_positions:
517 f
"Solver {self._name}: variable name {variable_name} is used twice"
519 self._variable_positions[variable_name] = offset
520 offset += multiplicity
521 return sum(variables.values())
522 elif isinstance(variables, int):
526 "unknowns/auxiliary_variables have to be an int or a dict "
527 "mapping variable name onto multiplicity, but got "
533 "Name: " + self.
_name +
"\n"
534 "Type: " + self.__class__.__module__ +
"\n"
535 "Unknowns: " + str(self.
_unknowns) +
"\n"
542 Unique solver name. Feeds into all generated class and instance names.
550 @numerical_scheme.setter
554 "numerical_scheme has to be a Solver.NumericalScheme, but got "
562 All plotters of the solver, in the order they have been added.
569 Add a plotter to the solver
571 A solver can have an arbitrary number of plotters, which are
572 independent of each other (@ref exahype2.api.Solver.Solver.Plotter).
573 If the plotter has no name yet, it gets the name of its class,
574 followed by a number if the solver has another plotter of that name
577 @param plotter: exahype2.api.Solver.Plotter
578 The plotter. Its solver has to be this solver.
583 f
"plotter has to be a Solver.Plotter, but got {type(plotter)}"
585 if plotter._solver
is not self:
587 f
"Plotter {type(plotter).__name__} belongs to another solver than {self._name}"
590 if plotter.name
is None:
591 name = type(plotter).__name__
594 name = type(plotter).__name__ + str(counter)
597 elif plotter.name
in names:
599 f
"Solver {self._name} has a plotter named {plotter.name} already"
601 prefix = plotter.output_file_prefix()
602 if prefix
is not None and prefix
in [
603 p.output_file_prefix()
for p
in self.
_plotters
606 f
"Plotter {plotter.name} of solver {self._name} would write into "
607 f
"the files {prefix}* of another plotter. Give it another file "
608 "name or output path."
616 Shorthand for solvers with at most one plotter
618 Reading it yields the solver's only plotter, or None if it has none.
619 Assigning a plotter replaces all plotters of the solver by this one,
620 assigning None removes all plotters. Use add_plotter() to give a
621 solver more than one plotter.
626 f
"Solver {self._name} has {len(self._plotters)} plotters. Use the plotters property."
633 if value
is not None:
647 Add further includes to this property, if your solver requires some
648 additional routines from other header files.
654 Add further includes to this property, if your solver requires some
655 additional routines from other header files.
661 Includes every generated action set can rely on being available,
662 regardless of which action sets a concrete discretisation (e.g.
663 exahype2.api.fv) actually attaches - @see
664 exahype2.api.fv.actionsets.AbstractFVActionSet.get_includes().
667#include "tarch/la/Vector.h"
669#include "peano4/utils/Globals.h"
670#include "peano4/utils/Loop.h"
672#include "repositories/SolverRepository.h"
682 return self.
_name +
"Q"
687 One name per entry of Q, i.e. for the unknowns followed by the
688 auxiliary variables, or the empty list if the variables carry no
689 names. A variable with multiplicity one keeps its name, whereas a
690 variable v with multiplicity k yields the names v[0], ..., v[k-1],
691 i.e. the entries Q[Variables::v+0], ..., Q[Variables::v+k-1].
692 Plotters use these names to label the entries in their output.
695 positions = list(self._variable_positions.items())
697 for i, (variable_name, position)
in enumerate(positions):
700 if i + 1 < len(positions)
703 multiplicity = next_position - position
704 if multiplicity == 1:
705 names.append(variable_name)
707 names += [f
"{variable_name}[{j}]" for j
in range(multiplicity)]
711 return "instanceOf" + self.
_name
716 All PDE terms (flux, eigenvalues, ...) registered with this solver,
717 in registration order. A given name can appear at most twice - once
718 stateless, once not, @see add_pde_term() - since each generates a
719 different C++ method. Read-only - use add_pde_term() to add one and
720 remove_pde_term() to take one away again.
722 return list(self._pde_terms.values())
727 True iff at least one PDE term has no implementation. Only then
728 does the user have to provide one, i.e. only then is a
729 <SolverName> class derived from Abstract<SolverName> generated
730 and added to the Makefile (@see exahype2.api.SolverToCPPFiles).
731 Otherwise, Abstract<SolverName> is complete and the solver
732 repository instantiates it directly. Stateless terms always carry
733 an implementation (@see PDETerm), so they never require one.
739 Name of the C++ class the solver repository instantiates:
740 <SolverName> if requires_user_class, Abstract<SolverName> otherwise.
747 Register a PDE term with this solver, or replace the one already
748 registered under the same name and statelessness. A solver
749 aggregates an arbitrary number of terms - the well-known ones
750 (Flux(), MaxEigenvalue(), ...) as well as new, solver-specific ones
751 users construct themselves via PDETerm(name=..., implementation=...).
753 Each term generates exactly one C++ method: the static,
754 GPU-offloadable overload if term.stateless, otherwise the virtual
755 instance method (@see PDETerm.Generator.generate_declaration()),
756 never both. To get both variants of the same conceptual operation
757 (e.g. a stateless flux for GPU kernels and a stateful one for
758 everything else), add the term twice - once with stateless=True,
759 once without - which is why terms are keyed by (name, stateless)
760 rather than by name alone.
763 if not isinstance(term, PDETerm):
764 raise TypeError(f
"term has to be a PDETerm, but got {type(term)}")
765 self._pde_terms[(term.name, term.stateless)] = term
768 """! Remove a previously registered PDE term by name and statelessness."""
769 del self._pde_terms[(name, stateless)]
772 """! Look up a previously registered PDE term by name and statelessness."""
773 return self._pde_terms[(name, stateless)]
778 Add a raw C++ member attribute declaration to the generated
779 Abstract<SolverName> class (@see exahype2.api.SolverToCPPFiles),
780 e.g. "double _timeStamp = 0.0;" - use an in-class initialiser if
781 the attribute needs one, since there is no hook into the generated
782 constructor for this.
784 Nothing calls this unconditionally: a plain Solver carries no
785 attributes beyond what PDE terms need. It is up to whichever
786 NumericalScheme/GridConstruction/Plotter a solver uses to call
787 this, if it needs solver-level state of its own that genuinely
788 has no home on exahype2::Solver already - e.g.
789 exahype2.api.fv.RusanovWithExplicitEuler deliberately does *not*
790 use this for time stamp/time step size bookkeeping, since
791 ::exahype2::Solver (which every generated Abstract<SolverName>
792 already inherits from) already carries
793 _minTimeStamp/_maxTimeStamp/_minTimeStepSize/_maxTimeStepSize and
794 the updateCell()/startTimeStep()/finishTimeStep() lifecycle to
795 maintain them - @see exahype2.api.fv.actionsets.
796 ComputeGlobalCFLCondition, which drives that
797 lifecycle instead of introducing parallel state via this method.
800 self._abstract_solver_attributes.append(declaration)
803 self, declaration: str, definition_generator: Callable[[str], str]
807 Add a raw C++ method to the generated Abstract<SolverName> class:
808 declaration goes into the class body (public section), verbatim.
809 definition_generator is called with the class' fully qualified
810 name once it is known (@see exahype2.api.SolverToCPPFiles,
811 exactly the way PDETerm.Generator.generate_out_of_class_definitions()
812 already is) and has to return the out-of-class definition - a
813 plain string with a "{qualified_class_name}" placeholder is
814 deliberately not supported here, since a C++ method body is full
815 of literal braces of its own; build the string with concatenation
818 ~~~~~~~~~~~~~~~~~~~~~~~
819 solver.add_abstract_solver_method(
820 "void increaseTimestamp(double dt);",
821 lambda qualified_class_name:
822 "void " + qualified_class_name + "::increaseTimestamp(double dt) {\\n"
823 " _timeStamp += dt;\\n"
826 ~~~~~~~~~~~~~~~~~~~~~~~
828 @see add_abstract_solver_attribute() for the attribute counterpart,
829 and exahype2.api.PDETerm.Generator for the more structured
830 alternative this deliberately is not (that one is for PDE terms a
831 user implements; this one is for solver-level bookkeeping a
832 NumericalScheme/etc. needs that has no equivalent on
833 ::exahype2::Solver already - @see add_abstract_solver_attribute()'s
834 own note on why RusanovWithExplicitEuler does not actually use
835 either method for time stamp/time step size bookkeeping).
838 self._abstract_solver_methods.append((declaration, definition_generator))
843 Add wantsToPlot() to the solver's C++ class: It holds if any of the
844 solver's plotters is active (@ref exahype2.api.Solver.Solver.Plotter).
845 Solvers without plotters do not get the method, as nobody asks them.
846 The method is added only once, even if the Peano 4 project is
847 generated multiple times, and it evaluates the plotters the solver
848 has when the C++ code is written.
851 declaration =
"bool wantsToPlot() const;"
852 if not self.
_plotters or declaration
in [
853 existing
for existing, _
in self._abstract_solver_methods
858 lambda qualified_class_name:
"bool "
859 + qualified_class_name
860 +
"::wantsToPlot() const {\n"
862 +
" or ".join(
"is" + p.name +
"Active()" for p
in self.
_plotters)
870 Override exahype2::Solver::toCheckpointMetaData() in the solver's
871 C++ class such that it also writes the attributes added through
872 add_abstract_solver_attribute(), e.g. the time stamps of the next
873 outputs of the plotters. Only attributes of type double, float or
874 int are written, with their name without leading underscore as key.
876 The counterpart override of exahype2::Solver::fromCheckpointMetaData()
877 restores these attributes. Afterwards, it calls finish<Name>() of
878 all plotters: A plotter which has written output at the time of the
879 checkpoint has done so before it has moved on to its next output, as
880 it only moves on at the end of the plot phase
881 (@ref exahype2.api.Solver.Solver.Plotter). The checkpoint hence holds
882 the time stamp of an output which has already been written.
883 finish<Name>() moves such a plotter on, exactly as the original run
884 has done after the checkpoint, so the restarted simulation does not
885 write this output again.
887 The overrides evaluate the attributes and plotters the solver has
888 when the C++ code is written, and they are added only once, even if
889 several checkpoints use them or the Peano 4 project is generated
893 declaration =
"std::string toCheckpointMetaData() const override;"
894 if declaration
in [existing
for existing, _
in self._abstract_solver_methods]:
897 def checkpointed_attributes():
898 for attribute
in self._abstract_solver_attributes:
899 match = re.match(
r"\s*(?:double|float|int)\s+(\w+)\s*(=|;)", attribute)
900 if match
is not None:
903 def to_definition(qualified_class_name):
906 + qualified_class_name
907 +
"::toCheckpointMetaData() const {\n"
908 " return ::exahype2::Solver::toCheckpointMetaData()"
910 for attribute_name
in checkpointed_attributes():
912 '\n + "\\n" + toCheckpointMetaDataEntry("'
913 + attribute_name.lstrip(
"_")
918 return result +
";\n}\n"
920 def from_definition(qualified_class_name):
923 + qualified_class_name
924 +
"::fromCheckpointMetaData(const std::string& metaData) {\n"
925 " ::exahype2::Solver::fromCheckpointMetaData(metaData);\n"
928 for attribute_name
in checkpointed_attributes():
930 ' if (getCheckpointMetaDataEntry(metaData, "'
931 + attribute_name.lstrip(
"_")
935 +
" = static_cast<decltype("
941 result +=
" finish" + plotter.name +
"();\n"
942 return result +
"}\n"
946 "void fromCheckpointMetaData(const std::string& metaData) override;",
953 Return a human-readable description of this solver instance, to be
954 embedded into the generated project's README.
968 Turn this solver specification into a task graph and create the required C++ kernels/stubs
970 peano_project: peano4.api.Project
971 The Peano 4 project that exahype2_project.generate_Peano4_project() is
972 currently assembling. It is a local variable there, not an attribute -
973 merely passed through here, so this solver can add its own artefacts to it.
975 setup_simulation, time_step, plot, mesh_adaptation: peano4.api.taskgraph.Graph
976 The task graphs of the four algorithmic phases of the surrounding
977 exahype2_project. They are owned by exahype2_project.generate_Peano4_project()
978 and merely passed through here, so this solver can add its own
981 @return peano4.api.taskgraph.Graph
985 assert self.grid_construction
is not None, (
986 f
"Solver {self._name} has no grid_construction set. Assign a "
987 "Solver.GridConstruction subclass instance to grid_construction "
988 "before calling generate_solver_realisation()."
990 assert self.numerical_scheme
is not None, (
991 f
"Solver {self._name} has no numerical_scheme set. Assign a "
992 "Solver.NumericalScheme subclass instance to numerical_scheme "
993 "before calling generate_solver_realisation()."
997 if self.mesh_adaptation
is None:
1002 self.grid_construction.construct_output(
1003 exahype2_project, peano_project, setup_simulation
1006 exahype2_project, peano_project, time_step
1009 plotter.construct_output(exahype2_project, peano_project, plot)
1013 exahype2_project, peano_project, mesh_adaptation
How a Solver drives the construction of the mesh it runs on.
__init__(self, "Solver" solver)
construct_output(self, exahype2_project, peano_project, setup_simulation)
Has to be implemented by subclass.
How a Solver adapts its mesh and rebalances its load between two time steps.
construct_output(self, exahype2_project, peano_project, mesh_adaptation)
Has to be implemented by subclass.
__init__(self, "Solver" solver)
The concrete discretisation (Finite Volumes, ADER-DG, ...) realised by a Solver.
__init__(self, "Solver" solver)
"Solver.MeshAdaptation" create_default_mesh_adaptation(self)
The mesh adaptation a solver uses if the user does not assign one to solver.mesh_adaptation.
construct_output(self, exahype2_project, peano_project, time_step)
Has to be implemented by subclass.
How a Solver writes out its solution.
__init__(self, "Solver" solver, str name=None)
str output_file_prefix(self)
Prefix of the files the plotter writes, including the path.
_add_time_interval_bookkeeping_to_solver(self, float first_time_stamp, float time_in_between)
Make the plotter active in regular time intervals.
str create_is_active_predicate(self)
C++ predicate which holds if the plotter is active.
construct_output(self, exahype2_project, peano_project, plot)
Has to be implemented by subclass.
str create_finish_call(self)
C++ statement which moves the plotter on to its next output.
Turns a Solver into actual classes.
__init__(self, "Solver" solver)
construct_output(self, exahype2_project, peano_project)
Has to be implemented by subclass.
Abstract base class for all ExaHyPE 2 solvers.
str _unknown_identifier(self)
str get_name_of_global_instance(self)
_add_wants_to_plot_to_solver(self)
Add wantsToPlot() to the solver's C++ class: It holds if any of the solver's plotters is active (exah...
add_abstract_solver_method(self, str declaration, Callable[[str], str] definition_generator)
Add a raw C++ method to the generated Abstract<SolverName> class: declaration goes into the class bod...
generate_solver_realisation(self, exahype2_project, peano_project, setup_simulation, time_step, plot, mesh_adaptation)
Turn this solver specification into a task graph and create the required C++ kernels/stubs.
PDETerm get_pde_term(self, str name, bool stateless=False)
Look up a previously registered PDE term by name and statelessness.
"Solver.NumericalScheme" numerical_scheme(self)
add_abstract_solver_attribute(self, str declaration)
Add a raw C++ member attribute declaration to the generated Abstract<SolverName> class (.
_add_checkpoint_meta_data_to_solver(self)
Override exahype2::Solver::toCheckpointMetaData() in the solver's C++ class such that it also writes ...
set_solver_constants(self, str datastring)
str _get_default_includes(self)
Includes every generated action set can rely on being available, regardless of which action sets a co...
add_pde_term(self, PDETerm term)
Register a PDE term with this solver, or replace the one already registered under the same name and s...
__init__(self, str name, VariableSpecification unknowns, VariableSpecification auxiliary_variables)
Create solver.
add_user_solver_includes(self, str value)
Add further includes to this property, if your solver requires some additional routines from other he...
remove_pde_term(self, str name, bool stateless=False)
Remove a previously registered PDE term by name and statelessness.
List[str] variable_names_per_entry(self)
One name per entry of Q, i.e.
bool requires_user_class(self)
True iff at least one PDE term has no implementation.
List[PDETerm] pde_terms(self)
All PDE terms (flux, eigenvalues, ...) registered with this solver, in registration order.
add_solver_constants(self, str datastring)
str create_readme_descriptor(self, domain_offset, domain_size)
Return a human-readable description of this solver instance, to be embedded into the generated projec...
add_plotter(self, "Solver.Plotter" plotter)
Add a plotter to the solver.
str get_name_of_solver_class(self)
Name of the C++ class the solver repository instantiates: <SolverName> if requires_user_class,...
pde_terms
True iff at least one PDE term has no implementation.
str user_solver_includes(self)
Add further includes to this property, if your solver requires some additional routines from other he...
numerical_scheme(self, "Solver.NumericalScheme" value)
str name(self)
Unique solver name.
List["Solver.Plotter"] plotters(self)
All plotters of the solver, in the order they have been added.
int auxiliary_variables(self)
"Solver.Plotter" plotter(self)
Shorthand for solvers with at most one plotter.
_plotters
All plotters of the solver, in the order they have been added.
int _register_variables(self, VariableSpecification variables, int offset)
Translate a plain int or a name-to-multiplicity dict into a total variable count, and - for the dict ...
mesh_adaptation
Turn this solver specification into a task graph and create the required C++ kernels/stubs.
Singleton logger for the Peano 4 Python API.