Peano
Loading...
Searching...
No Matches
LoadCheckpoint.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
3import os
4
5import peano4.api
8import toolbox.loadbalancing.api.actionsets
9from peano4.api.solversteps.ActionSet import ActionSet
10
11from ..Solver import Solver
12
13
14def _create_reader(index_file_name, time_stamp, halo_width):
15 """!
16
17 C++ expression which yields the exahype2::CheckpointReader of the
18 checkpoint
19
20 """
21 return (
22 "::exahype2::CheckpointReader::getInstance("
23 f'"{index_file_name}", {repr(float(time_stamp))}, {halo_width}, DomainOffset, DomainSize)'
24 )
25
26
28 """!
29
30 Refine the mesh such that it matches the mesh of a checkpoint
31
32 The action set hands the refinement events of the checkpoint
33 (@ref exahype2::CheckpointReader::getRefinementEvents()) to Peano. As the
34 mesh setup over a regular grid, it pauses the refinement while the load
35 balancing has just split.
36
37 """
38
39 def __init__(self, reader, includes):
40 super().__init__(descend_invocation_order=1, parallel=False)
41 self._reader = reader
42 self._includes = includes
43
45 return f"""
46 if (
47 ::toolbox::loadbalancing::LoadBalancingService::getInstance().hasLoadBalancing()
48 and
49 ::toolbox::loadbalancing::LoadBalancingService::getInstance().getLoadBalancing()->hasSplitRecently()
50 ) {{
51 return std::vector< peano4::grid::GridControlEvent >();
52 }}
53 return {self._reader}.getRefinementEvents();
54"""
55
56 def get_body_of_operation(self, operation_name):
57 return "\n"
58
60 return "\n"
61
63 return "\n"
64
66 return ""
67
69 return "RefineFromCheckpoint"
70
72 return False
73
74 def get_attributes(self):
75 return ""
76
77 def get_includes(self):
78 return (
79 """
80#include "exahype2/CheckpointReader.h"
81#include "toolbox/loadbalancing/AbstractLoadBalancing.h"
82#include "toolbox/loadbalancing/LoadBalancingService.h"
83"""
84 + self._includes
85 )
86
87
89 """!
90
91 Read each cell's patch with halo from a checkpoint and restore the
92 solver's state
93
94 In touchCellFirstTime(), the action set copies the cell's patch with halo
95 from the checkpoint into solver._patch_with_halo, and the patch without
96 the halo into solver._patch. Every cell selected by the guard has to have
97 a patch in the checkpoint. Otherwise, the mesh does not match the
98 checkpoint, and the action set terminates the code.
99
100 In unprepareTraversal(), it hands the checkpoint's meta data to the
101 solver (@ref exahype2::Solver::fromCheckpointMetaData()) and frees the
102 reader.
103
104 """
105
106 def __init__(self, solver, reader, index_file_name, halo_width, guard, includes):
107 super().__init__(descend_invocation_order=1, parallel=False)
108 self._solver = solver
109 self._reader = reader
110 self._index_file_name = index_file_name
111 self._halo_width = halo_width
112 self._guard = guard
113 self._includes = includes
114
115 def get_body_of_operation(self, operation_name):
116 if operation_name != ActionSet.OPERATION_TOUCH_CELL_FIRST_TIME:
117 return "\n"
118 patch = self._solver._patch
119 patch_with_halo = self._solver._patch_with_halo
120 return f"""
121 constexpr int Unknowns = {patch.no_of_unknowns};
122 constexpr int DoFsPerAxis = {patch.dim[0]};
123 constexpr int Halo = {self._halo_width};
124 constexpr int EntriesPerAxisHalo = DoFsPerAxis + 2 * Halo;
125
126 int numberOfEntries = Unknowns;
127 for (int d=0; d<Dimensions; d++) {{
128 numberOfEntries *= EntriesPerAxisHalo;
129 }}
130
131 const bool found = {self._reader}.readPatch(
132 marker.x(),
133 marker.h(),
134 numberOfEntries,
135 fineGridCell{patch_with_halo.name}.value
136 );
137 if (not found) {{
138 logError(
139 "touchCellFirstTime(...)",
140 "checkpoint {self._index_file_name} holds no patch for cell " << marker.toString()
141 << ". The mesh does not match the checkpoint"
142 );
143 std::abort();
144 }}
145
146 dfor(cell, DoFsPerAxis) {{
147 const int cellSerialised = peano4::utils::dLinearised(cell, DoFsPerAxis);
148 const int cellWithHaloSerial = peano4::utils::dLinearised(cell + tarch::la::Vector<Dimensions,int>(Halo), EntriesPerAxisHalo);
149 for (int unknown=0; unknown<Unknowns; unknown++) {{
150 fineGridCell{patch.name}.value[cellSerialised*Unknowns+unknown] = fineGridCell{patch_with_halo.name}.value[cellWithHaloSerial*Unknowns+unknown];
151 }}
152 }}
153"""
154
155 def get_guard_of_operation(self, operation_name):
156 if operation_name == ActionSet.OPERATION_TOUCH_CELL_FIRST_TIME:
157 return self._guard
158 return "true"
159
161 return "\n"
162
164 return f"""
165 repositories::{self._solver.get_name_of_global_instance()}.fromCheckpointMetaData( {self._reader}.getMetaData() );
166 ::exahype2::CheckpointReader::release( "{self._index_file_name}" );
167"""
168
170 return ""
171
173 return "LoadPatchesFromCheckpoint"
174
176 return False
177
178 def get_attributes(self):
179 return ""
180
181 def get_includes(self):
182 return (
183 """
184#include <cstdlib>
185#include "exahype2/CheckpointReader.h"
186"""
187 + self._includes
188 )
189
190
192 """!
193
194 Set up a simulation from a checkpoint
195
196 Alternative to the setups over a regular grid
197 (@ref exahype2.api.fv.SetupSimulationOverRegularGrid,
198 @ref exahype2.api.rkfd4.SetupSimulationOverRegularGrid): Instead of
199 constructing a mesh and setting the initial condition, the setup reads a
200 checkpoint written by exahype2.api.fv.WriteCheckpoint or
201 exahype2.api.rkfd4.WriteCheckpoint and continues the simulation from
202 there. It is available for both schemes as exahype2.api.fv.LoadCheckpoint
203 and exahype2.api.rkfd4.LoadCheckpoint, as both use the same data layout.
204
205 The setup consists of three phases:
206
207 - It reconstructs the checkpoint's mesh. The refinement sweep repeats
208 until the mesh is stationary and the load balancing has stagnated,
209 exactly as for the regular grid. Instead of refining down to a given
210 mesh size, it refines the parents of all cells in the checkpoint
211 (@ref exahype2::CheckpointReader).
212 - Once the mesh is complete, it switches off the load balancing and
213 waits until the last splits have been carried out.
214 - A last sweep loads the data. For every cell, it reads the patch with
215 halo into the temporary solver._patch_with_halo, copies the patch into
216 solver._patch and writes the patch with halo onto the overlaps of the
217 faces (toolbox.blockstructured.api.ProjectPatchWithHaloOntoFaces).
218 The faces hence also hold the ghost data along the domain boundary and
219 the data at coarse-fine transitions as they have been at the time of
220 the checkpoint. In unprepareTraversal(), the sweep restores the
221 solver's time stamps, time step sizes and mesh sizes, plus the
222 attributes the Python API has added, e.g. the time stamps of the next
223 outputs of the plotters. Plotters which have written output at the
224 time of the checkpoint move on to their next output, so the restarted
225 simulation does not write them again
226 (@ref exahype2.api.Solver.Solver._add_checkpoint_meta_data_to_solver()).
227
228 The setup neither uses the initial condition nor the boundary conditions.
229 The checkpoint has to be written by a solver with the same unknowns,
230 auxiliary variables, patch size and halo, over the same domain. The code
231 reads the checkpoint at runtime, i.e. the files have to exist when the
232 simulation starts, but not when it is generated or built.
233
234 The time stamps of all solvers have to match, i.e. a project with
235 several solvers has to load checkpoints of all of them, written at the
236 same time.
237
238 """
239
241 self,
242 solver: Solver,
243 filename: str = "checkpoint",
244 output_path: str = ".",
245 time_stamp: float = None,
246 ):
247 """!
248
249 @param solver: exahype2.api.Solver
250 The solver whose data is loaded.
251
252 @param filename: str
253 File name of the checkpoint as passed to WriteCheckpoint. The setup
254 reads the index file output_path/filename-SolverName.peano-patch-file.
255
256 @param output_path: str
257 Directory of the checkpoint, relative to the directory the
258 simulation is started from, or absolute.
259
260 @param time_stamp: float or None
261 Time stamp of the checkpoint to load. If None, the setup loads the
262 latest checkpoint in the index file. Otherwise, it loads the
263 checkpoint whose time stamp is closest to time_stamp.
264
265 """
266 super().__init__(solver)
267 self._filename = filename
268 self._output_path = output_path
269 self._time_stamp = time_stamp
270
271 def index_file_name(self) -> str:
272 """!
273 Path of the checkpoint's index file
274 """
275 return os.path.join(
276 self._output_path,
277 self._filename + "-" + self._solver_solver.name + ".peano-patch-file",
278 )
279
280 def construct_output(self, exahype2_project, peano_project, setup_simulation):
281 """!
282
283 Add the mesh construction and the loading of the data to the setup
284 task graph
285
286 """
287 peano4.api.Logger().log(
288 "Create setup task graph which loads a checkpoint into a block-structured mesh"
289 )
290
291 for attribute in [
292 "_patch",
293 "_patch_with_halo",
294 "_patch_overlap_current_time_step",
295 ]:
296 assert hasattr(self._solver_solver, attribute), (
297 f"Solver {self._solver.name} has no attribute {attribute}. "
298 "LoadCheckpoint assumes the numerical scheme has added this field "
299 "to the solver immediately upon construction."
300 )
301
302 # The solver has to be able to restore all of its attributes
303 self._solver_solver._add_checkpoint_meta_data_to_solver()
304
305 Access = peano4.api.taskgraph.Task.DataAccess
306 Entity = peano4.api.taskgraph.Task.GridEntity
307 halo_width = (
308 self._solver_solver._patch_with_halo.dim[0] - self._solver_solver._patch.dim[0]
309 ) // 2
310 includes = (
311 self._solver_solver._get_default_includes() + self._solver_solver.user_solver_includes
312 )
313 reader = _create_reader(
314 self.index_file_name(),
315 -1.0 if self._time_stamp is None else self._time_stamp,
316 halo_width,
317 )
318
319 # Repeat while the mesh still changes, while the load balancing still
320 # wants to split, or while a split is still being carried out, as in
321 # the setup over a regular grid
322 refine_task = peano4.api.taskgraph.Task(
323 name=f"{self._solver.name}_Refine mesh from checkpoint",
324 entity=Entity.CELL,
325 task_has_to_repeat=(
326 "not peano4::grid::isGridStationary( peano4::parallel::SpacetreeSet::getInstance().getGridStatistics() )"
327 " or ( ::toolbox::loadbalancing::LoadBalancingService::getInstance().hasLoadBalancing()"
328 " and ( not ::toolbox::loadbalancing::LoadBalancingService::getInstance().getLoadBalancing()->hasStagnated()"
329 " or ::toolbox::loadbalancing::LoadBalancingService::getInstance().getLoadBalancing()->hasSplitRecently() ) )"
330 ),
331 )
332 refine_task.add_action_set(_RefineFromCheckpoint(reader, includes))
333 refine_task.add_action_set(toolbox.loadbalancing.api.actionsets.LoadBalancing())
334
335 consolidate_load_balancing_task = peano4.api.taskgraph.Task(
336 name=f"{self._solver.name}_Consolidate mesh",
337 entity=Entity.CELL,
338 task_has_to_repeat=(
339 "not peano4::grid::isGridStationary( peano4::parallel::SpacetreeSet::getInstance().getGridStatistics() )"
340 " or ( ::toolbox::loadbalancing::LoadBalancingService::getInstance().hasLoadBalancing()"
341 " and ::toolbox::loadbalancing::LoadBalancingService::getInstance().getLoadBalancing()->hasSplitRecently() )"
342 ),
343 )
344 consolidate_load_balancing_task.add_action_set(
345 toolbox.loadbalancing.api.actionsets.ToggleLoadBalancing(
346 enable_load_balancing=False, plug_into_prepare_traversal=True
347 )
348 )
349 consolidate_load_balancing_task.add_action_set(
350 toolbox.loadbalancing.api.actionsets.LoadBalancing()
351 )
352 consolidate_load_balancing_task.add_dependency(refine_task)
353
354 load_task = peano4.api.taskgraph.Task(
355 name=f"{self._solver.name}_Load checkpoint",
356 entity=Entity.CELL,
357 may_spawn_background_tasks=False,
358 )
359 load_task.add_dependency(consolidate_load_balancing_task)
360 load_task.use_cell(self._solver_solver._patch, Access.WRITE)
361 load_task.use_cell(self._solver_solver._patch_with_halo, Access.TEMPORARY)
362 load_task.use_face(self._solver_solver._patch_overlap_current_time_step, Access.WRITE)
363 load_task.add_action_set(
365 self._solver_solver,
366 reader,
367 self.index_file_name(),
368 halo_width,
369 guard=self._solver_solver.grid_selector.createCellGuard(),
370 includes=includes,
371 )
372 )
373 load_task.add_action_set(
374 toolbox.blockstructured.api.ProjectPatchWithHaloOntoFaces(
375 self._solver_solver._patch_with_halo,
376 self._solver_solver._patch_overlap_current_time_step,
377 guard=self._solver_solver.grid_selector.createCellGuard(),
378 additional_includes=includes,
379 )
380 )
381
382 setup_simulation.add_task(refine_task)
383 setup_simulation.add_task(consolidate_load_balancing_task)
384 setup_simulation.add_task(load_task)
385
386 if peano4.api.Logger().is_visualisation:
387 setup_simulation.visualise(
388 title="Setup task graph for {}".format(self._solver_solver.name)
389 )
390 if peano4.api.Logger().is_text:
391 setup_simulation.log_as_text(
392 title="Setup task graph for {}".format(self._solver_solver.name)
393 )
How a Solver drives the construction of the mesh it runs on.
Definition Solver.py:102
construct_output(self, exahype2_project, peano_project, setup_simulation)
Add the mesh construction and the loading of the data to the setup task graph.
__init__(self, Solver solver, str filename="checkpoint", str output_path=".", float time_stamp=None)
str index_file_name(self)
Path of the checkpoint's index file.
Read each cell's patch with halo from a checkpoint and restore the solver's state.
get_body_of_operation(self, operation_name)
Return actual C++ code snippets to be inserted into C++ code.
__init__(self, solver, reader, index_file_name, halo_width, guard, includes)
user_should_modify_template(self)
Is the user allowed to modify the output.
get_guard_of_operation(self, operation_name)
Return the guard of an operation.
get_attributes(self)
Return attributes as copied and pasted into the generated class.
Refine the mesh such that it matches the mesh of a checkpoint.
user_should_modify_template(self)
Is the user allowed to modify the output.
get_constructor_body(self)
Define a tailored constructor body.
get_attributes(self)
Return attributes as copied and pasted into the generated class.
get_includes(self)
Return include statements that you need.
get_body_of_operation(self, operation_name)
Return actual C++ code snippets to be inserted into C++ code.
get_body_of_createGridControlEventsForNextTraversal(self)
Return the grid control events that this action set wants to trigger.
Singleton logger for the Peano 4 Python API.
Definition Logger.py:37
Action set (reactions to events)
Definition ActionSet.py:6
One task within a peano4.api.taskgraph.Graph.
Definition Task.py:8
_create_reader(index_file_name, time_stamp, halo_width)
C++ expression which yields the exahype2::CheckpointReader of the checkpoint.
The task graph abstraction allows users to formalise their solver steps over small task graphs which ...
Definition __init__.py:1