Peano
Loading...
Searching...
No Matches
ComputeTimeStepSize.py
Go to the documentation of this file.
1# This file is part of the ExaHyPE2 project. For conditions of distribution and
2# use, please see the copyright notice at www.peano-framework.org
3from .AbstractRKFD4ActionSet import AbstractRKFD4ActionSet
4
5import peano4.api
6
7
9 """!
10
11 Determine the time step size of the next Runge-Kutta step and advance
12 the solver's time stamp
13
14 The action set supports two modes:
15
16 - Fixed time step sizes: the next time step size is the one passed to
17 the constructor.
18 - Adaptive time step sizes: exahype2.api.rkfd4.actionsets.ComputeMaxEigenvalue
19 stores the maximum eigenvalue of every patch in the cell data
20 solver._max_eigenvalue. touchCellFirstTime() folds each cell's value
21 into the static _maxEigenvalue, and unprepareTraversal() derives the
22 next time step size from the global maximum through the CFL condition
23 @f$ \\Delta t = C h / (d \\lambda _{max}) @f$, with h the minimal grid
24 cell size, d the dimension and C the CFL constant.
25
26 In both modes, unprepareTraversal() feeds the next time step size into
27 ::exahype2::Solver's own time step bookkeeping
28 (updateCell()/finishTimeStep()/startTimeStep()). The time stamp
29 advances by the time step size the Runge-Kutta step has just used. The
30 last time step is not truncated: it may overshoot MaxTerminalTime, and
31 the simulation stops afterwards, i.e. MaxTerminalTime is a lower bound
32 on the final time. The solver starts with a time step size of zero, so
33 the very first Runge-Kutta step does not alter the solution: it only
34 yields the first time step size.
35
36 Global time stepping: all cells share one time stamp and time step size.
37 As getMinTimeStamp()==getMaxTimeStamp() and
38 getMinTimeStepSize()==getMaxTimeStepSize() always hold, a single
39 updateCell() call per time step is enough.
40
41 The class is derived from exahype2.api.fv.actionsets.ComputeGlobalCFLCondition,
42 as rkfd4 does not depend on the Finite Volume package. Consult the
43 latter for details on the reduction over threads and ranks.
44
45 """
46
48 self, solver, patch_size, guard, cfl_constant=None, time_step_size=None
49 ):
50 """!
51
52 @param solver: exahype2.api.Solver
53 With adaptive time stepping, solver._max_eigenvalue has to be set.
54
55 @param patch_size: int
56 Number of grid cells per patch and axis. The CFL condition is
57 evaluated over the grid cell size, i.e. the mesh cell size divided
58 by patch_size.
59
60 @param guard: str
61 C++ boolean expression, evaluated per cell in touchCellFirstTime,
62 guarding whether that cell contributes to the CFL condition. Has
63 to match the guard of exahype2.api.rkfd4.actionsets.ComputeMaxEigenvalue.
64
65 @param cfl_constant: float or None
66 CFL constant for adaptive time stepping.
67
68 @param time_step_size: float or None
69 Time step size for fixed time stepping. Exactly one of
70 cfl_constant and time_step_size has to be set.
71
72 """
73 AbstractRKFD4ActionSet.__init__(self, solver)
74 if (cfl_constant is None) == (time_step_size is None):
75 raise ValueError("Set exactly one of cfl_constant and time_step_size")
76 self.guard = guard
77 self.patch_size = patch_size
78 self.cfl_constant = cfl_constant
79 self.time_step_size = time_step_size
80
81 @property
82 def is_adaptive(self) -> bool:
83 return self.cfl_constant is not None
84
86 return " _maxEigenvalue = 0.0;\n" if self.is_adaptive else ""
87
89 instance = "repositories::" + self._solver.get_name_of_global_instance()
90 if self.is_adaptive:
91 admissible_time_step_size = f"""
92 const peano4::grid::GridStatistics globalStatistics = peano4::parallel::SpacetreeSet::getInstance().getGridStatistics();
93 const double globalMinGridCellH = tarch::la::max( globalStatistics.getMinH() ) / {self.patch_size};
94
95 // No semaphore required here, as it is only called once per rank
96 double localMaxEigenvalue = _maxEigenvalue;
97 double globalMaxEigenvalue = localMaxEigenvalue;
98 #ifdef Parallel
99 tarch::mpi::Rank::getInstance().allReduce(
100 &localMaxEigenvalue, &globalMaxEigenvalue, 1, MPI_DOUBLE, MPI_MAX,
101 [&]() -> void {{ tarch::services::ServiceRepository::getInstance().receiveDanglingMessages(); }}
102 );
103 #endif
104 const double admissibleTimeStepSize = {self.cfl_constant!r} * globalMinGridCellH / globalMaxEigenvalue / Dimensions;
105"""
106 else:
107 admissible_time_step_size = f"""
108 const double admissibleTimeStepSize = {self.time_step_size!r};
109"""
110 return (
111 admissible_time_step_size
112 + f"""
113 // The time stamp advances by the time step size the update used,
114 // newTimeStepSize is the one the next update will use
115 const double usedTimeStepSize = {instance}.getMaxTimeStepSize();
116 const double newTimeStamp = {instance}.getMaxTimeStamp() + usedTimeStepSize;
117 // The last time step is not truncated, i.e. it may overshoot MaxTerminalTime
118 const double newTimeStepSize = admissibleTimeStepSize;
119
120 {instance}.updateCell( newTimeStepSize, newTimeStamp );
121 {instance}.finishTimeStep();
122 {instance}.startTimeStep(
123 {instance}.getMinTimeStamp(),
124 {instance}.getMaxTimeStamp(),
125 {instance}.getMinTimeStepSize(),
126 {instance}.getMaxTimeStepSize()
127 );
128 logInfo( "unprepareTraversal()", "t=" << {instance}.getMaxTimeStamp() << ", new dt=" << newTimeStepSize );
129"""
130 )
131
132 def get_attributes(self):
133 if not self.is_adaptive:
134 return ""
135 return """
136 static double _maxEigenvalue;
137 static tarch::multicore::BooleanSemaphore _semaphore;
138"""
139
140 def get_static_initialisations(self, full_qualified_classname):
141 if not self.is_adaptive:
142 return ""
143 return (
144 "double "
145 + full_qualified_classname
146 + "::_maxEigenvalue = 0.0;\n"
147 + "tarch::multicore::BooleanSemaphore "
148 + full_qualified_classname
149 + "::_semaphore;\n"
150 )
151
152 def get_includes(self):
153 return (
154 AbstractRKFD4ActionSet.get_includes(self)
155 + """
156#include <algorithm>
157#include "tarch/multicore/BooleanSemaphore.h"
158#include "tarch/multicore/Lock.h"
159#include "tarch/mpi/Rank.h"
160#include "tarch/services/ServiceRepository.h"
161#include "tarch/la/VectorOperations.h"
162#include "peano4/parallel/SpacetreeSet.h"
163#include "peano4/grid/grid.h"
164"""
165 )
166
167 def get_body_of_operation(self, operation_name):
168 if (
169 self.is_adaptive
170 and operation_name
171 == peano4.api.solversteps.ActionSet.OPERATION_TOUCH_CELL_FIRST_TIME
172 ):
173 return f"""
174 tarch::multicore::Lock lock(_semaphore);
175 _maxEigenvalue = std::max( fineGridCell{self._solver._max_eigenvalue.name}.getMaxEigenvalue(0), _maxEigenvalue );
176"""
177 return ""
178
179 def get_guard_of_operation(self, operation_name):
180 if (
181 operation_name
182 == peano4.api.solversteps.ActionSet.OPERATION_TOUCH_CELL_FIRST_TIME
183 ):
184 return self.guard
185 return "true"
186
188 return __name__.replace(".py", "").replace(".", "_")
Base class of the action sets of exahype2.api.rkfd4 which work against the solver.
Determine the time step size of the next Runge-Kutta step and advance the solver's time stamp.
get_attributes(self)
Return attributes as copied and pasted into the generated class.
get_action_set_name(self)
You should replicate this function in each subclass, so you get meaningful action set names (otherwis...
get_includes(self)
The includes cover the kernels the numerical scheme generates (exahype2.api.rkfd4....
get_guard_of_operation(self, operation_name)
Return the guard of an operation.
get_body_of_operation(self, operation_name)
Return actual C++ code snippets to be inserted into C++ code.
__init__(self, solver, patch_size, guard, cfl_constant=None, time_step_size=None)