Peano
Loading...
Searching...
No Matches
CellCenteredFiniteDifferences.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
6import peano4.datamodel
11
12import jinja2
13
14from abc import abstractmethod
15from enum import Enum
16
17import exahype2
19
20from exahype2.solvers.PDETerms import PDETerms
21
22from exahype2.solvers.ButcherTableau import RungeKutta_steps
23from exahype2.solvers.Storage import Storage
24
25
26
28 """
29 Abstract solver for patch-based finite diffences
30
31 All solvers in ExaHyPE are cell-centered discretisations.
32
33
34 ## Adaptive mesh refinement
35
36 We have, at the moment, no hard-coded AMR operator set available unless
37 you work with an overlap of one. In this case, you find operators in the
38 toolbox. Very few pre-manufactured operators there are ready to go for
39 higher overlaps (the injection operator is an example). In general, you
40 will have to inject your own transfer operators.
41
42 It depends on the flavour that you want to use for your interpolation and
43 restriction. A simple interpolation for an overlap of three and a patch_size
44 of five would be
45
46 self._interpolation = "tensor_product< " + self._name + ">"
47 self.add_solver_constants( "static constexpr double NormalInterpolationMatrix1d[] = {0.0, 1.0, 0.0};" )
48 self.add_solver_constants( " ""static constexpr double TangentialInterpolationMatrix1d[] = {
49 1.0,0.0,0.0,0.0,0.0,
50 1.0,0.0,0.0,0.0,0.0,
51 1.0,0.0,0.0,0.0,0.0,
52 0.0,1.0,0.0,0.0,0.0,
53 0.0,1.0,0.0,0.0,0.0,
54
55 0.0,1.0,0.0,0.0,0.0,
56 0.0,0.0,1.0,0.0,0.0,
57 0.0,0.0,1.0,0.0,0.0,
58 0.0,0.0,1.0,0.0,0.0,
59 0.0,0.0,0.0,1.0,0.0,
60
61 0.0,0.0,0.0,1.0,0.0,
62 0.0,0.0,0.0,1.0,0.0,
63 0.0,0.0,0.0,0.0,1.0,
64 0.0,0.0,0.0,0.0,1.0,
65 0.0,0.0,0.0,0.0,1.0
66 };" "" )
67 """
69 self,
70 name,
71 patch_size,
72 overlap,
73 rk_order,
74 unknowns,
75 auxiliary_variables,
76 min_meshcell_h,
77 max_meshcell_h,
78 plot_grid_properties,
79 kernel_namespace,
80 baseline_action_set_descend_invocation_order=0,
81 ):
82 """
83 name: string
84 A unique name for the solver. This one will be used for all generated
85 classes. Also the C++ object instance later on will incorporate this
86 name.
87
88 patch_size: int
89 Size of the patch in one dimension. All stuff here's dimension-generic.
90
91 overlap: int
92 That's the size of the halo layer which is half of the overlap with a
93 neighbour. A value of 1 means that a patch_size x patch_size patch in
94 2d is surrounded by one additional cell layer. The overlap has to be
95 bigger or equal to one. It has to be smaller or equal to patch_size.
96
97 unknowns: int
98 Number of unknowns per Finite Volume voxel.
99
100 auxiliary_variables: int
101 Number of auxiliary variables per Finite Volume voxel. Eventually, both
102 unknowns and auxiliary_variables are merged into one big vector if we
103 work with AoS. But the solver has to be able to distinguish them, as
104 only the unknowns are subject to a hyperbolic formulation.
105
106 min_meshcell_h: double
107 This size refers to the individual Finite Volume.
108
109 max_meshcell_h: double
110 This size refers to the individual Finite Volume.
111
112 plot_grid_properties: Boolean
113 Clarifies whether a dump of the data should be enriched with grid info
114 (such as enclave status flags), too.
115 """
116 self._name = name
117
118 self._min_meshcell_h = min_meshcell_h
119 self._max_meshcell_h = max_meshcell_h
120 self._plot_grid_properties = plot_grid_properties
121
122 self._patch_size = patch_size
123 self._overlap = overlap
124 self._rk_order = rk_order
125
126 """
127 self._unknowns and self._auxiliary_variables respectively hold the number of unknowns and
128 auxiliary variables in the equation to be computed. Unknowns are variables that change over
129 time whereas auxiliary variables can be space-dependent but don't vary over time.
130 These can be specified either as simple ints or by a dictionary
131 (e.g.) unknowns = {'a': 1, 'b': 1, 'c': 3}
132 in which the user specifies the multiplicity of the variable (the velocity has one component
133 per dimension for example.)
134 If they are specified by a dictionary then the code generates a "VariableShortcuts" file which
135 allows the user to specifiy a variable by name and automatically maps this to the right position
136 in an array for better legibility. Otherwise they must manually remember the position of each
137 variable manually.
138
139 use_var_shortcut is used to know whether or not the user passed their variables via a dict
140 variable_names and variable_pos are used internally to remember the names and respective
141 positions of variables if set by a dictionary.
142 """
143 self._use_var_shortcut = False
145 self._variable_pos = [0]
146
147 if type(unknowns) is dict:
148 self._unknowns = sum(unknowns.values())
149 self._variable_names += list(unknowns.keys())
150 for var in list(unknowns.values()):
151 self._variable_pos.append(var + self._variable_pos[-1])
152 self._use_var_shortcut = True
153 elif type(unknowns) is int:
154 self._unknowns = unknowns
155 else:
156 raise Exception(
157 "not a valid type for parameter unknowns, needs to be int or dictionary"
158 )
159
160 if type(auxiliary_variables) is dict:
161 self._auxiliary_variables = sum(auxiliary_variables.values())
162 self._variable_names += list(auxiliary_variables.keys())
163 for var in list(auxiliary_variables.values()):
164 self._variable_pos.append(var + self._variable_pos[-1])
165 self._use_var_shortcut = True
166 elif type(auxiliary_variables) is int:
167 self._auxiliary_variables = auxiliary_variables
168 else:
169 raise Exception(
170 "not a valid type for parameter auxiliary_variables, needs to be int or dictionary"
171 )
172
176
177 self._kernel_namespace = kernel_namespace
178
179 if min_meshcell_h > max_meshcell_h:
180 print(
181 "Error: min_meshcell_h ("
182 + str(min_meshcell_h)
183 + ") is bigger than max_meshcell_h ("
184 + str(max_meshcell_h)
185 + ")"
186 )
187
189 peano4.toolbox.blockstructured.ReconstructedArrayMemoryLocation.CallStack
190 )
191
193
195
197
200 self._action_set_AMR = None
207 None
208 )
211
212 self._compute_time_step_size = "#error Not yet defined"
213 self._compute_new_time_step_size = "#error Not yet defined"
216
217 self._compute_kernel_call = "#error Not yet defined"
218
219 self._reconstruction_kernel_call = "#error Not yet defined"
220 self._primary_variables_indices = "#error Not yet defined"
221 self._auxiliary_variables_indices = "#error Not yet defined"
222
228
232
236
237 self._interpolation = "#error Not yet defined"
238 self._restriction = "#error Not yet defined"
239
240 self._baseline_action_set_descend_invocation_order = baseline_action_set_descend_invocation_order
241
242 self.switch_storage_scheme(Storage.SmartPointers, Storage.SmartPointers)
243
244
245 def __str__(self):
246 result = (
247 """
248Name: """
249 + self._name
250 + """
251Type: """
252 + self.__class__.__name__
253 + """
254Patch size: """
255 + str(self._patch_size)
256 + """
257Runge-Kutta order: """
258 + str(self._rk_order)
259 + """
260Overlap: """
261 + str(self._overlap)
262 + """
263Unknowns: """
264 + str(self._unknowns)
265 + """
266Auxiliary variables: """
267 + str(self._auxiliary_variables)
268 + """
269h_meshcell_min: """
270 + str(self._min_meshcell_h)
271 + """
272h_meshcell_max: """
273 + str(self._max_meshcell_h)
274 + """
275"""
276 )
277 return result
278
279 __repr__ = __str__
280
282 coarsest_tree_level = 0
283 while (
284 domain_size * 3 ** (-coarsest_tree_level) / self._patch_size
285 > self._max_meshcell_h
286 ):
287 coarsest_tree_level += 1
288 return coarsest_tree_level
289
291 finest_tree_level = 0
292 while (
293 domain_size * 3 ** (-finest_tree_level) / self._patch_size
294 > self._min_meshcell_h
295 ):
296 finest_tree_level += 1
297 return finest_tree_level
298
299 # self._overlap = overlap
300 # self._unknowns = unknowns
301 # self._auxiliary_variables = auxiliary_variables
302
303 def get_coarsest_number_of_patches(self, domain_size):
304 return 3 ** self.get_min_number_of_spacetree_levels(domain_size)
305
306 def get_finest_number_of_patches(self, domain_size):
307 return 3 ** self.get_max_number_of_spacetree_levels(domain_size)
308
310 return self.get_coarsest_number_of_patches(domain_size) * self._patch_size
311
313 return self.get_finest_number_of_patches(domain_size) * self._patch_size
314
316 return domain_size / self.get_coarsest_number_of_compute_grid_cells(domain_size)
317
318 def get_finest_compute_grid_cell_size(self, domain_size):
319 return domain_size / self.get_finest_number_of_compute_grid_cells(domain_size)
320
321 def create_readme_descriptor(self, domain_offset, domain_size):
322 return (
323 """
324### ExaHyPE 2 solver
325
326"""
327 + str(self)
328 + """
329
330Real type of this solver: """
331 + str(type(self))
332 + """
333
334We assume that you use a domain size of (0,"""
335 + str(domain_size)
336 + """)^d. Peano 4 will cut this domain equidistantly
337and recursively into three parts along each coordinate axis. This yields a spacetree.
338
339The spacetree will at least have """
340 + str(self.get_min_number_of_spacetree_levels(domain_size))
341 + """ levels.
342The spacetree will at most have """
343 + str(self.get_max_number_of_spacetree_levels(domain_size))
344 + """ levels.
345
346The spacetree will thus span at least """
347 + str(self.get_coarsest_number_of_patches(domain_size))
348 + """ octants/cells (see clarification below) per coordinate axis. This means a """
349 + str(self.get_coarsest_number_of_patches(domain_size))
350 + """^d grid of octants.
351The spacetree will thus span at most """
352 + str(self.get_finest_number_of_patches(domain_size))
353 + """ octants/cells (see clarification below) per coordinate axis. This means a """
354 + str(self.get_finest_number_of_patches(domain_size))
355 + """^d grid of octants.
356
357ExaHyPE 2 embeds """
358 + str(self._patch_size)
359 + """^d patches of compute cells into the finest tree level.
360In the text above, we refer to the elements of this level of the tree as octants.
361The octants are squares/cubes and many papers refer to them as cells, but they are not
362the actual compute data structure. The compute data structure is the cells that
363are embedded into these finest level spacetree cells. We therefore prefer the
364term octant for the latter, whereas we use the term (compute) cell for the
365entities that are actually used for the computations, i.e. hold degrees of
366freedom, and are actually visible within Paraview, e.g.
367
368The coarsest possible mesh will consist of """
369 + str(self.get_coarsest_number_of_compute_grid_cells(domain_size))
370 + """ compute cells per coordinate axis.
371The finest possible mesh will consist of """
372 + str(self.get_finest_number_of_compute_grid_cells(domain_size))
373 + """ compute cells per coordinate axis.
374
375The coarsest mesh width of """
376 + str(self.get_coarsest_compute_grid_cell_size(domain_size))
377 + """ is thus just smaller than the maximum mesh size """
378 + str(self._max_meshcell_h)
379 + """.
380The finest mesh width of """
381 + str(self.get_finest_compute_grid_cell_size(domain_size))
382 + """ is thus just smaller than the minimum mesh size """
383 + str(self._min_meshcell_h)
384 + """.
385
386"""
387 )
388
389 @property
391 """
392
393 Add further includes to this property, if your action sets require some additional
394 routines from other header files.
395
396 """
397 return self._user_action_set_includes
398
399 @property
401 """
402
403 Add further includes to this property, if your solver requires some additional
404 routines from other header files.
405
406 """
407 return self._user_solver_includes
408
410 """!
411
412 Return number of steps required to realise the Runge-Kutta scheme
413
414 Delegate to ButcherTableau.RungeKutta_steps, which tells us for a given
415 polynomial order _rk_order how many Runge Kutta steps we have to
416 employ.
417
418 """
419 return RungeKutta_steps(self._rk_order)
420
422 """
423
424 Add further includes to this property, if your action sets require some additional
425 routines from other header files.
426
427 """
428 self._user_action_set_includes += value
429
430 def add_user_solver_includes(self, value):
431 """
432
433 Add further includes to this property, if your solver requires some additional
434 routines from other header files.
435
436 """
437 self._user_solver_includes += value
438
439 @abstractmethod
441 """
442
443 Recall in subclasses if you wanna change the number of unknowns
444 or auxiliary variables. See class description's subsection on
445 data flow.
446
447 :: Call order and ownership
448
449 This operation can be called multiple times. However, only the very
450 last call matters. All previous calls are wiped out.
451
452 If you have a hierarchy of solvers, every create_data_structure()
453 should first(!) call its parent version. This way, you always ensure
454 that all data are in place before you continue to alter the more
455 specialised versions. So it is (logically) a top-down (general to
456 specialised) run through all create_data_structure() variants
457 within the inheritance tree.
458
459
460 :: Arguments
461
462 _patch: Patch (NxNxN)
463 Actual patch data. We use Finite Volumes, so this is
464 always the current snapshot, i.e. the valid data at one point.
465
466 _patch_overlap_old, _patch_overlap_new: Patch (2xNxN)
467 This is a copy/excerpt from the two adjacent finite volume
468 snapshots plus the old data as backup. If I want to implement
469 local timestepping, I don't have to backup the whole patch
470 (see _patch), but I need a backup of the face data to be able
471 to interpolate in time.
472
473 _patch_overlap_update: Patch (2xNxN)
474 This is hte new update. After the time step, I roll this
475 information over into _patch_overlap_new, while I backup the
476 previous _patch_overlap_new into _patch_overlap_old. If I
477 worked with regular meshes only, I would not need this update
478 field and could work directly with _patch_overlap_new. However,
479 AMR requires me to accumulate data within new while I need
480 the new and old data temporarily. Therefore, I employ this
481 accumulation/roll-over data which usually is not stored
482 persistently.
483
484 """
486 (self._patch_size, self._patch_size, self._patch_size),
488 self._unknown_identifier(),
489 )
491 (
493 self._patch_size,
494 self._patch_size,
495 ),
496 self._unknowns,
497 self._unknown_identifier() + "RhsEstimates",
498 )
500 (2 * self._overlap, self._patch_size, self._patch_size),
502 self._unknown_identifier() + "Old",
503 )
505 (2 * self._overlap, self._patch_size, self._patch_size),
507 self._unknown_identifier() + "New",
508 )
510 (2 * self._overlap, self._patch_size, self._patch_size),
512 self._unknown_identifier() + "Update",
513 )
514
515 if self._cell_data_storage == Storage.CallStack:
517 self._patch, "double"
518 )
520 self._patch_estimates, "double"
521 )
522 elif self._cell_data_storage == Storage.Heap:
524 self._patch, "double"
525 )
527 self._patch_estimates, "double"
528 )
529 elif self._cell_data_storage == Storage.SmartPointers:
531 self._patch, "double"
532 )
533 self._patch_estimates.generator = (
535 self._patch_estimates, "double"
536 )
537 )
538
539 if self._face_data_storage == Storage.CallStack:
541 self._patch_overlap_old, "double"
542 )
544 self._patch_overlap_new, "double"
545 )
547 self._patch_overlap_update, "double"
548 )
549 elif self._face_data_storage == Storage.Heap:
550 self._patch_overlap_old.generator = (
552 self._patch_overlap_old, "double"
553 )
554 )
555 self._patch_overlap_new.generator = (
557 self._patch_overlap_new, "double"
558 )
559 )
560 self._patch_overlap_update.generator = (
562 self._patch_overlap_update, "double"
563 )
564 )
565 elif self._face_data_storage == Storage.SmartPointers:
566 self._patch_overlap_old.generator = (
568 self._patch_overlap_old, "double"
569 )
570 )
571 self._patch_overlap_new.generator = (
573 self._patch_overlap_new, "double"
574 )
575 )
576 self._patch_overlap_update.generator = (
578 self._patch_overlap_update, "double"
579 )
580 )
581 else:
582 assert False, "storage variant {} not supported".format(
584 )
585
586 self._patch_overlap_old.generator.merge_method_definition = (
587 peano4.toolbox.blockstructured.get_face_merge_implementation(
589 )
590 )
591 self._patch_overlap_new.generator.merge_method_definition = (
592 peano4.toolbox.blockstructured.get_face_merge_implementation(
594 )
595 )
596 self._patch.generator.merge_method_definition = (
597 peano4.toolbox.blockstructured.get_cell_merge_implementation(self._patch)
598 )
599
600 self._patch_overlap_old.generator.includes += """
601#include "peano4/utils/Loop.h"
602#include "repositories/SolverRepository.h"
603"""
604 self._patch_overlap_new.generator.includes += """
605#include "peano4/utils/Loop.h"
606#include "repositories/SolverRepository.h"
607"""
608
609 self._patch.generator.load_store_compute_flag = "::peano4::grid::constructLoadStoreComputeFlag({},{},{})".format(
613 )
614
615 self._patch_estimates.generator.load_store_compute_flag = "::peano4::grid::constructLoadStoreComputeFlag({},{},{})".format(
619 )
620
621 self._patch_overlap_old.generator.send_condition = "false"
622 self._patch_overlap_old.generator.receive_and_merge_condition = "false"
623
624 self._patch_overlap_new.generator.send_condition = "false"
625 self._patch_overlap_new.generator.receive_and_merge_condition = "false"
626
627 self._patch_overlap_update.generator.send_condition = "false"
628 self._patch_overlap_update.generator.receive_and_merge_condition = "false"
629
630 self._patch_overlap_old.generator.load_store_compute_flag = "::peano4::grid::constructLoadStoreComputeFlag({},{},{})".format(
634 )
635
636 self._patch_overlap_new.generator.load_store_compute_flag = "::peano4::grid::constructLoadStoreComputeFlag({},{},{})".format(
640 )
641
642 self._patch_overlap_update.generator.load_store_compute_flag = "::peano4::grid::constructLoadStoreComputeFlag({},{},{})".format(
644 "false",
645 "false"
646 )
647
648 self._patch.generator.includes += """
649#include "../repositories/SolverRepository.h"
650"""
651 self._patch_estimates.generator.includes += """
652#include "../repositories/SolverRepository.h"
653"""
654 self._patch_overlap_old.generator.includes += """
655#include "../repositories/SolverRepository.h"
656"""
657 self._patch_overlap_new.generator.includes += """
658#include "../repositories/SolverRepository.h"
659"""
660 self._patch_overlap_update.generator.includes += """
661#include "../repositories/SolverRepository.h"
662"""
663
664 self._cell_label = exahype2.grid.create_cell_label(self._name)
665 self._face_label = exahype2.grid.create_face_label(self._name)
666
667 @abstractmethod
669 """!
670
671 Create required action sets
672
673 Overwrite in subclasses if you wanna create different
674 action sets.
675
676 ## Call order and ownership
677
678 This operation can be called multiple times. However, only the very
679 last call matters. All previous calls are wiped out.
680
681 If you have a hierarchy of solvers, every create_data_structure()
682 should first(!) call its parent version. This way, you always ensure
683 that all data are in place before you continue to alter the more
684 specialised versions. So it is (logically) a top-down (general to
685 specialised) run through all create_data_structure() variants
686 within the inheritance tree.
687
688 :: Recreation vs backup (state discussion)
689
690 We faced some issues with action sets that should not be
691 overwritten. For example, the postprocessing should not be overwritten
692 as users might want to set it and then later on reset the number of
693 unknowns, e.g. In this case, you would loose your postprocessing if
694 create_action_sets() recreated them. So I decided to make an exception
695 here: the postprocessing step is never overwritten by the standard
696 classes.
697
698 There are further action sets which have a state, which users might
699 want to alter. The most prominent one is the AMR routines, where users
700 often alter the interpolation and restriction scheme. Here, things are
701 tricky: If we keep the default one, the action set would not pick up
702 if you changed the number of unknowns, e.g. However, if we recreated
703 the action set, we'd miss out on any changed interpolation/restriction
704 scheme. Therefore, I have to hold the interpolation and restriction
705 scheme seperatae.
706
707 ## Injecting your own guards
708
709 If you inject your own guards, you should combine them with a storage
710 predicate, i.e. _store_cell_data_default_guard() and
711 _load_cell_data_default_guard(). The action sets themselves will not
712 combine the guard with further boolean expressions. Also, you have to
713 study carefully if a predicate accepts a unique guard or a set of
714 guards.
715
716
717 ## Priorities
718
719 All action sets are given the right (default) priorities in this step.
720 You can alter them in subclasses, but it might be more appropriate to
721 set the priorities of your own action sets relative to the existing
722 ones using self._baseline_action_set_descend_invocation_order.
723
724 """
727 self, self._store_cell_data_default_guard(), "true"
728 )
729 )
732 self, self._store_cell_data_default_guard(), "false"
733 )
734 )
736 solver=self,
738 build_up_new_refinement_instructions=True,
739 implement_previous_refinement_instructions=True,
740 called_by_grid_construction=False,
741 )
744 solver=self,
746 build_up_new_refinement_instructions=False,
747 implement_previous_refinement_instructions=True,
748 called_by_grid_construction=False,
749 )
750 )
753 solver=self,
755 build_up_new_refinement_instructions=True,
756 implement_previous_refinement_instructions=True,
757 called_by_grid_construction=True,
758 )
759 )
763 )
764 )
767 )
771 )
772 )
777 False,
780 )
781 )
783 solver=self,
784 interpolation=self._interpolation,
785 restriction=self._restriction,
786 )
787
790 solver=self, guard=self._store_cell_data_default_guard()
791 )
792 )
793
794 # This one is different: it is the hook-in point for other solvers, so we create it
795 # only once if it does not exist
796 if self._action_set_postprocess_solution == None:
799 )
800 if self._action_set_preprocess_solution == None:
803 )
804
807
808 self._action_set_initial_conditions.descend_invocation_order = (
810 )
811 self._action_set_initial_conditions_for_grid_construction.descend_invocation_order = (
813 )
816 )
817 self._action_set_copy_new_faces_onto_old_faces.descend_invocation_order = (
819 )
820 self._action_set_roll_over_update_of_faces.descend_invocation_order = (
822 )
823 self._action_set_update_face_label.descend_invocation_order = (
825 )
826 self._action_set_update_cell_label.descend_invocation_order = (
828 )
829 self._action_set_handle_boundary.descend_invocation_order = (
831 )
832 self._action_set_compute_final_linear_combination.descend_invocation_order = (
834 )
835 self._action_set_project_patch_onto_faces.descend_invocation_order = (
837 )
838 self._action_set_AMR.descend_invocation_order = self._baseline_action_set_descend_invocation_order + 6
839 self._action_set_postprocess_solution.descend_invocation_order = (
841 ) # will be in touch last
842 self._action_set_preprocess_solution.descend_invocation_order = (
844 )
845
847
848
850 return (
851 "not marker.willBeRefined() "
852 + "and repositories::"
854 + ".getSolverState()!="
855 + self._name
856 + "::SolverState::GridConstruction"
857 )
858
860 return (
861 "not marker.willBeRefined() "
862 + "and repositories::"
864 + ".getSolverState()!="
865 + self._name
866 + "::SolverState::GridConstruction"
867 )
868
870 """!
871
872 Extend the guard via ands only. Never use an or, as subclasses might
873 extend it as well, and they will append further ends.
874
875 """
876 return (
877 "not marker.willBeRefined() "
878 + "and repositories::"
880 + ".getSolverState()!="
881 + self._name
882 + "::SolverState::GridConstruction"
883 )
884
886 """!
887
888 Extend the guard via ands only. Never use an or, as subclasses might
889 extend it as well, and they will append further ends.
890
891 """
892 return (
893 "not marker.hasBeenRefined() "
894 + "and repositories::"
896 + ".getSolverState()!="
897 + self._name
898 + "::SolverState::GridConstruction "
899 + "and repositories::"
901 + ".getSolverState()!="
902 + self._name
903 + "::SolverState::GridInitialisation"
904 )
905
907 """!
908
909 Extend the guard via ands only. Never use an or, as subclasses might
910 extend it as well, and they will append further ends.
911
912 """
913 return (
914 "not marker.willBeRefined() "
915 + "and repositories::"
917 + ".getSolverState()!="
918 + self._name
919 + "::SolverState::GridConstruction"
920 )
921
923 """!
924
925 Extend the guard via ands only. Never use an or, as subclasses might
926 extend it as well, and they will append further ends.
927
928 """
929 return (
930 "not marker.hasBeenRefined() "
931 + "and repositories::"
933 + ".getSolverState()!="
934 + self._name
935 + "::SolverState::GridConstruction "
936 + "and repositories::"
938 + ".getSolverState()!="
939 + self._name
940 + "::SolverState::GridInitialisation"
941 )
942
944 return self._name + "Q"
945
947 return "instanceOf" + self._name
948
949 def add_to_Peano4_datamodel(self, datamodel, verbose):
950 """!
951
952 Add all required data to the Peano4 project's datamodel
953 so it is properly built up
954
955 """
956 if verbose:
957 print("Patch data")
958 print("----------")
959 print(str(self._patch))
960 print("Patch overlap data")
961 print("----------")
962 print(str(self._patch_overlap_old))
963 print("Patch overlap data")
964 print("----------")
965 print(str(self._patch_overlap_new))
966 datamodel.add_cell(self._cell_label)
967 datamodel.add_cell(self._patch)
968 datamodel.add_cell(self._patch_estimates)
969 datamodel.add_face(self._patch_overlap_old)
970 datamodel.add_face(self._patch_overlap_new)
971 datamodel.add_face(self._patch_overlap_update)
972 datamodel.add_face(self._face_label)
973
975 """
976 Tell Peano what data to move around
977
978 Inform Peano4 step which data are to be moved around via the
979 use_cell and use_face commands. This operation is generic from
980 ExaHyPE's point of view, i.e. I use it for all grid sweep types.
981
982 """
983 step.use_cell(self._patch)
984 step.use_cell(self._patch_estimates)
985 step.use_cell(self._cell_label)
986 step.use_face(self._patch_overlap_old)
987 step.use_face(self._patch_overlap_new)
988 step.use_face(self._patch_overlap_update)
989 step.use_face(self._face_label)
990
992 return """
993#include "tarch/la/Vector.h"
994
995#include "peano4/utils/Globals.h"
996#include "peano4/utils/Loop.h"
997
998#include "repositories/SolverRepository.h"
999"""
1000
1001 def add_actions_to_init_grid(self, step, restart_from_checkpoint=False):
1002 """!
1003
1004 Add your actions to init grid
1005
1006 The AMR stuff has to be the very first thing. Actually, the AMR routines'
1007 interpolation doesn't play any role here. But the restriction indeed is
1008 very important, as we have to get the face data for BCs et al. The action
1009 set order is inverted while we ascend within the tree again. Therefore, we
1010 add the AMR action set first which means it will be called last when we go
1011 from fine to coarse levels within the tree.
1012
1013 The projection onto the faces is a postprocessing step. This is different
1014 to DG, where we need face data for the current time step's solution. Here,
1015 we ensure that all halos are valid for the subsequent time step again.
1016
1017 ## Ordering
1018
1019 The order of the action sets is preserved throughout the steps down within
1020 the tree hierarchy. It is inverted throughout the backrolling.
1021
1022 This is what we want to achieve:
1023
1024 - Project solution onto faces. This happens in touchCellLastTime(). See
1025 exahype2.solvers.rkfd.actionsets.ProjectPatchOntoFaces for comments.
1026 The project will end up in QUpdate.
1027 - Roll updates over on the faces from QUpdate into Q_new. This is done
1028 by RollOverUpdateFace, which requires in turn that the getUpdated()
1029 flag is set. As the roll-over plugs into touchFaceLastTime(), it will
1030 always be called after the projection, since the latter is a cell
1031 operation.
1032 - Copy new face data Q_new into old face data Q_old, as this is the
1033 initial sweep, i.e. the old face data otherwise might hold rubbish.
1034 This is a backup operation realised through the action set
1035 BackupPatchOverlap. This one plugs into touchFaceLastTime() too.
1036 Therefore, it is important that its priority is smaller than the one
1037 of the roll-over, since we invert the call order for the touch-last
1038 events.
1039 - Restrict the data to the coarser level if we are on a hanging face.
1040
1041
1042 """
1043 assert (
1044 self._action_set_copy_new_faces_onto_old_faces.descend_invocation_order
1045 < self._action_set_roll_over_update_of_faces.descend_invocation_order
1046 )
1047
1048 if restart_from_checkpoint:
1051 self, self._store_cell_data_default_guard(), "true", restart_from_checkpoint=True
1052 )
1053 )
1054
1055 step.add_action_set(self._action_set_preprocess_solution)
1056 step.add_action_set(
1058 )
1059 step.add_action_set(self._action_set_copy_new_faces_onto_old_faces)
1060 step.add_action_set(self._action_set_roll_over_update_of_faces)
1061 step.add_action_set(self._action_set_initial_conditions)
1062 step.add_action_set(self._action_set_project_patch_onto_faces)
1063 step.add_action_set(self._action_set_update_face_label)
1064 step.add_action_set(self._action_set_update_cell_label)
1065 step.add_action_set(self._action_set_AMR)
1066 step.add_action_set(self._action_set_postprocess_solution)
1067
1068 def add_actions_to_create_grid(self, step, evaluate_refinement_criterion):
1069 """
1070
1071 The boundary information is set only once. It is therefore important that
1072 we ues the face label and initialise it properly.
1073
1074 """
1076 step.add_action_set(self._action_set_update_face_label)
1077 step.add_action_set(self._action_set_update_cell_label)
1078 if evaluate_refinement_criterion:
1079 step.add_action_set(self._action_set_AMR_throughout_grid_construction)
1080 else:
1081 step.add_action_set(self._action_set_AMR_commit_without_further_analysis)
1082
1083 @property
1085 self,
1086 ):
1087 return self._plot_description
1088
1089 @plot_description.setter
1090 def plot_description(self, description):
1091 """
1092
1093 Use this one to set a description within the output patch file that tells
1094 the vis solver what the semantics of the entries are. Typicallly, I use
1095 a comma-separated list here.
1096
1097 """
1098 self._plot_description = description
1099
1100 def add_actions_to_plot_solution(self, step, output_path, restart_from_checkpoint=False):
1101 """!
1102
1103 Add action sets to plotting grid sweep
1104
1105 Consult the discussion in add_actions_to_init_grid() around the order
1106 of the individual action sets.
1107
1108
1109 ## Adaptive mesh refinement
1110
1111 It is important that we have the coupling/dynamic AMR part in here, as
1112 there might be pending AMR refinement requests that now are realised.
1113 For the same reason, we need the update of the face label and the update
1114 of the cell label in here: The AMR might just propagate over into the
1115 plotting, i.e. we might create new grid entities throughout the plot.
1116 These entities (faces and cells) have to be initialised properly.
1117 Otherwise, their un-initialised data will propagate through to the next
1118 time step.
1119
1120 To make the restriction work, we have to project the solutions onto the
1121 faces.
1122
1123
1124 ## Roll over face data
1125
1126 Das ist ein Kaese, weil das nur einspringt, wenn project wahr ist
1127
1128
1129 """
1130 d = {}
1133
1134 step.add_action_set(
1136 )
1137 # step.add_action_set( self._action_set_roll_over_update_of_faces )
1138 step.add_action_set(self._action_set_update_face_label)
1139 step.add_action_set(self._action_set_update_cell_label)
1140 # step.add_action_set( self._action_set_project_patch_onto_faces )
1141
1143 filename=output_path + "solution-" + self._name,
1144 patch=self._patch,
1145 dataset_name=self._unknown_identifier(),
1146 description=self._plot_description,
1147 guard="repositories::plotFilter.plotPatch(marker) and "
1149 additional_includes="""
1150#include "exahype2/PlotFilter.h"
1151#include "../repositories/SolverRepository.h"
1152""",
1153 precision="PlotterPrecision",
1154 time_stamp_evaluation="0.5*(repositories::getMinTimeStamp()+repositories::getMaxTimeStamp())",
1155 select_dofs=self.select_dofs_to_print,
1156 restart_preprocess=restart_from_checkpoint
1157 )
1158 plot_patches_action_set.descend_invocation_order = self._baseline_action_set_descend_invocation_order
1159 step.add_action_set(plot_patches_action_set)
1160
1161 if self._plot_grid_properties:
1162 plot_grid_action_set = peano4.toolbox.PlotGridInPeanoBlockFormat(
1163 filename=output_path + "grid-" + self._name,
1164 cell_unknown=None,
1165 additional_includes="""
1166#include "exahype2/PlotFilter.h"
1167#include "../repositories/SolverRepository.h"
1168""",
1169 )
1170 plot_grid_action_set.descend_invocation_order = self._baseline_action_set_descend_invocation_order
1171 step.add_action_set(plot_grid_action_set)
1172
1173 pass
1174
1175 def add_actions_to_checkpoint_solution(self, step, output_path, restart_from_checkpoint=False):
1176 """!
1177
1178 Add action sets to checkpoint grid sweep
1179
1180 Consult the discussion in add_actions_to_init_grid() around the order
1181 of the individual action sets.
1182
1183
1184 ## Adaptive mesh refinement
1185
1186 It is important that we have the coupling/dynamic AMR part in here, as
1187 there might be pending AMR refinement requests that now are realised.
1188 For the same reason, we need the update of the face label and the update
1189 of the cell label in here: The AMR might just propagate over into the
1190 plotting, i.e. we might create new grid entities throughout the plot.
1191 These entities (faces and cells) have to be initialised properly.
1192 Otherwise, their un-initialised data will propagate through to the next
1193 time step.
1194
1195 To make the restriction work, we have to project the solutions onto the
1196 faces.
1197
1198
1199 ## Roll over face data
1200
1201 Das ist ein Kaese, weil das nur einspringt, wenn project wahr ist
1202
1203
1204 """
1205 d = {}
1208
1209 step.add_action_set(
1211 )
1212 # step.add_action_set( self._action_set_roll_over_update_of_faces )
1213 step.add_action_set(self._action_set_update_face_label)
1214 step.add_action_set(self._action_set_update_cell_label)
1215 # step.add_action_set( self._action_set_project_patch_onto_faces )
1216
1218 filename=output_path + "checkpoint-" + self._name,
1219 patch=self._patch,
1220 dataset_name=self._unknown_identifier(),
1221 description=self._plot_description,
1222 guard=self._load_cell_data_default_guard(),
1223 additional_includes="""
1224#include "../repositories/SolverRepository.h"
1225""",
1226 precision="PlotterPrecision",
1227 time_stamp_evaluation="0.5*(repositories::getMinTimeStamp()+repositories::getMaxTimeStamp())",
1228 select_dofs=None,
1229 restart_preprocess=restart_from_checkpoint
1230 )
1231 checkpoint_patches_action_set.descend_invocation_order = self._baseline_action_set_descend_invocation_order
1232 step.add_action_set(checkpoint_patches_action_set)
1233
1235 """
1236
1237 AMR
1238
1239 It is important that we do the inter-grid transfer operators before we
1240 apply the boundary conditions.
1241
1242 """
1243 d = {}
1246
1247 step.add_action_set(self._action_set_preprocess_solution)
1248 step.add_action_set(
1250 )
1251 step.add_action_set(self._action_set_roll_over_update_of_faces)
1252 step.add_action_set(self._action_set_update_face_label)
1253 step.add_action_set(self._action_set_update_cell_label)
1254 step.add_action_set(self._action_set_handle_boundary)
1255 step.add_action_set(self._action_set_update_cell)
1256 step.add_action_set(self._action_set_project_patch_onto_faces)
1257 step.add_action_set(self._action_set_compute_final_linear_combination)
1258 step.add_action_set(self._action_set_AMR)
1259 step.add_action_set(self._action_set_postprocess_solution)
1260
1261 @abstractmethod
1265 def add_implementation_files_to_project(self, namespace, output, dimensions, subdirectory=""):
1266 """
1267
1268 The ExaHyPE2 project will call this operation when it sets
1269 up the overall environment.
1270
1271 This routine is typically not invoked by a user.
1272
1273 output: peano4.output.Output
1274
1275 """
1276 templatefile_prefix = os.path.dirname(os.path.realpath(__file__)) + "/"
1277
1278 if self._solver_template_file_class_name is None:
1279 templatefile_prefix += self.__class__.__name__
1280 else:
1281 templatefile_prefix += self._solver_template_file_class_name
1282
1283 if(subdirectory):
1284 subdirectory += "/"
1285
1286 abstractHeaderDictionary = {}
1287 implementationDictionary = {}
1288 self._init_dictionary_with_default_parameters(abstractHeaderDictionary)
1289 self._init_dictionary_with_default_parameters(implementationDictionary)
1290 self.add_entries_to_text_replacement_dictionary(abstractHeaderDictionary)
1291 self.add_entries_to_text_replacement_dictionary(implementationDictionary)
1292
1293 generated_abstract_header_file = (
1295 templatefile_prefix + "Abstract.template.h",
1296 templatefile_prefix + "Abstract.template.cpp",
1297 "Abstract" + self._name,
1298 namespace,
1299 subdirectory + ".",
1300 abstractHeaderDictionary,
1301 True,
1302 True,
1303 )
1304 )
1305 generated_solver_files = (
1307 templatefile_prefix + ".template.h",
1308 templatefile_prefix + ".template.cpp",
1309 self._name,
1310 namespace,
1311 subdirectory + ".",
1312 implementationDictionary,
1313 False,
1314 True,
1315 )
1316 )
1317
1318 output.add(generated_abstract_header_file)
1319 output.add(generated_solver_files)
1320 output.makefile.add_h_file(subdirectory + "Abstract" + self._name + ".h", generated=True)
1321 output.makefile.add_h_file(subdirectory + self._name + ".h", generated=True)
1322 output.makefile.add_cpp_file(subdirectory + "Abstract" + self._name + ".cpp", generated=True)
1323 output.makefile.add_cpp_file(subdirectory + self._name + ".cpp", generated=True)
1324
1325 if self._use_var_shortcut:
1326 generated_shortcut_file = peano4.output.Jinja2TemplatedHeaderFile(
1327 os.path.dirname(os.path.realpath(__file__))
1328 + "/"
1329 + "../VariableShortcuts.template.h",
1330 "VariableShortcuts",
1331 namespace,
1332 subdirectory + ".",
1333 implementationDictionary,
1334 True,
1335 True,
1336 )
1337 output.add(generated_shortcut_file)
1338 output.makefile.add_h_file(subdirectory + "VariableShortcuts.h", generated=True)
1339
1340 def set_solver_constants(self, datastring):
1341 self._solver_constants = datastring
1342
1343 def add_solver_constants(self, datastring):
1344 self._solver_constants += datastring
1345
1347 """
1348 This one is called by all algorithmic steps before I invoke
1349 add_entries_to_text_replacement_dictionary().
1350
1351 See the remarks on set_postprocess_updated_patch_kernel to understand why
1352 we have to apply the (partially befilled) dictionary to create a new entry
1353 for this very dictionary.
1354 """
1355 d["NUMBER_OF_GRID_CELLS_PER_PATCH_PER_AXIS"] = self._patch.dim[0]
1356 d["OVERLAP"] = self._overlap
1357 d["HALO_SIZE"] = int(self._patch_overlap_old.dim[0] / 2)
1358 d["RK_ORDER"] = self._rk_order
1359 d["RK_STEPS"] = self.number_of_Runge_Kutta_steps()
1360 d["SOLVER_INSTANCE"] = self.get_name_of_global_instance()
1361 d["SOLVER_NAME"] = self._name
1362 d["UNKNOWN_IDENTIFIER"] = self._unknown_identifier()
1363 d["NUMBER_OF_UNKNOWNS"] = self._unknowns
1364 d["NUMBER_OF_AUXILIARY_VARIABLES"] = self._auxiliary_variables
1365 d["SOLVER_NUMBER"] = 22
1366
1367 d["ASSERTION_WITH_1_ARGUMENTS"] = "nonCriticalAssertion1"
1368 d["ASSERTION_WITH_2_ARGUMENTS"] = "nonCriticalAssertion2"
1369 d["ASSERTION_WITH_3_ARGUMENTS"] = "nonCriticalAssertion3"
1370 d["ASSERTION_WITH_4_ARGUMENTS"] = "nonCriticalAssertion4"
1371 d["ASSERTION_WITH_5_ARGUMENTS"] = "nonCriticalAssertion5"
1372 d["ASSERTION_WITH_6_ARGUMENTS"] = "nonCriticalAssertion6"
1373
1374 if self._min_meshcell_h > self._max_meshcell_h:
1375 raise Exception("min/max h are inconsistent")
1376 d["MAX_GRID_CELL_H"] = self._max_meshcell_h
1377 d["MIN_GRID_CELL_H"] = self._min_meshcell_h
1378
1379 d["SOLVER_CONSTANTS"] = self._solver_constants
1380
1381 d["SOLVER_INCLUDES"] = self.user_solver_includes
1382
1383 d[
1384 "BOUNDARY_CONDITIONS_IMPLEMENTATION"
1386 d[
1387 "REFINEMENT_CRITERION_IMPLEMENTATION"
1389 d["INITIAL_CONDITIONS_IMPLEMENTATION"] = self._initial_conditions_implementation
1390
1391 d["COMPUTE_KERNEL_CALL"] = jinja2.Template(
1392 self._compute_kernel_call, undefined=jinja2.DebugUndefined
1393 ).render(**d)
1394
1395 d["RECONSTRUCTION_KERNEL_CALL"] = jinja2.Template(self._reconstruction_kernel_call, undefined=jinja2.DebugUndefined).render(**d)
1396 d["PRIMARY_VARS_INDICES"] = self._primary_variables_indices
1397 d["AUXILIARY_VARS_INDICES"] = self._auxiliary_variables_indices
1398
1399 d["ABSTRACT_SOLVER_USER_DECLARATIONS"] = jinja2.Template(
1400 self._abstract_solver_user_declarations, undefined=jinja2.DebugUndefined
1401 ).render(**d)
1402 d["ABSTRACT_SOLVER_USER_DEFINITIONS"] = jinja2.Template(
1403 self._abstract_solver_user_definitions, undefined=jinja2.DebugUndefined
1404 ).render(**d)
1405 d["SOLVER_USER_DECLARATIONS"] = jinja2.Template(
1406 self._solver_user_declarations, undefined=jinja2.DebugUndefined
1407 ).render(**d)
1408 d["SOLVER_USER_DEFINITIONS"] = jinja2.Template(
1409 self._solver_user_definitions, undefined=jinja2.DebugUndefined
1410 ).render(**d)
1411 d["START_TIME_STEP_IMPLEMENTATION"] = jinja2.Template(
1412 self._start_time_step_implementation, undefined=jinja2.DebugUndefined
1413 ).render(**d)
1414 d["FINISH_TIME_STEP_IMPLEMENTATION"] = jinja2.Template(
1415 self._finish_time_step_implementation, undefined=jinja2.DebugUndefined
1416 ).render(**d)
1417 d["CONSTRUCTOR_IMPLEMENTATION"] = jinja2.Template(
1418 self._constructor_implementation, undefined=jinja2.DebugUndefined
1419 ).render(**d)
1420
1421 d["PREPROCESS_RECONSTRUCTED_PATCH"] = jinja2.Template(
1422 self._preprocess_reconstructed_patch, undefined=jinja2.DebugUndefined
1423 ).render(**d)
1424 d["POSTPROCESS_UPDATED_PATCH"] = jinja2.Template(
1425 self._postprocess_updated_patch, undefined=jinja2.DebugUndefined
1426 ).render(**d)
1427
1428 d["COMPUTE_TIME_STEP_SIZE"] = jinja2.Template(
1429 self._compute_time_step_size, undefined=jinja2.DebugUndefined
1430 ).render(**d)
1431 d["COMPUTE_NEW_TIME_STEP_SIZE"] = jinja2.Template(
1432 self._compute_new_time_step_size, undefined=jinja2.DebugUndefined
1433 ).render(**d)
1434 d["COMPUTE_MAX_EIGENVALUE"] = self._compute_eigenvalue
1435
1436 d["KERNEL_NAMESPACE"] = self._kernel_namespace
1437
1438 d["USE_VARIABLE_SHORTCUT"] = self._use_var_shortcut
1439 d["VARIABLE_NAMES"] = self._variable_names
1440 d["VARIABLE_POSITIONS"] = self._variable_pos
1441
1442 @property
1443 def unknowns(self):
1444 return self._unknowns
1445
1446 @property
1447 def patch_size(self):
1448 return self._patch_size
1449
1450 @property
1452 return self._auxiliary_variables
1453
1454 @patch_size.setter
1455 def patch_size(self, value):
1456 self._patch_size = value
1458 self.create_action_sets()
1459
1460 @unknowns.setter
1461 def unknowns(self, value):
1462 self._unknowns = value
1464 self.create_action_sets()
1465
1466 @auxiliary_variables.setter
1467 def auxiliary_variables(self, value):
1468 self._auxiliary_variables = value
1470 self.create_action_sets()
1471
1472 @property
1476 @preprocess_reconstructed_patch.setter
1478 """!
1479
1480 Please consult exahype2.solvers.fv.FV.preprocess_reconstructed_patch() for
1481 a documentation on this routine.
1482
1483 """
1486 self.create_action_sets()
1487
1488 @property
1489 def name(self):
1490 return self._name
1491
1492 @property
1496 @postprocess_updated_patch.setter
1497 def postprocess_updated_patch(self, kernel):
1498 """
1499
1500 Define a postprocessing routine over the data
1501
1502 The postprocessing kernel often looks similar to the following code:
1503
1504 {
1505 int index = 0;
1506 dfor( volume, {{NUMBER_OF_GRID_CELLS_PER_PATCH_PER_AXIS}} ) {
1507 enforceCCZ4constraints( newQ+index );
1508 index += {{NUMBER_OF_UNKNOWNS}} + {{NUMBER_OF_AUXILIARY_VARIABLES}};
1509 }
1510 }
1511
1512
1513 Within this kernel, you have at least the following variables available:
1514
1515 - newQ This is a pointer to the whole data structure (one large
1516 array).
1517 The patch is not supplemented by a halo layer.
1518 - oldQWithHalo This is a pointer to the data snapshot before the
1519 actual update. This data is combined with the halo layer, i.e. if you
1520 work with 7x7 patches and a halo of 2, the pointer points to a 11x11
1521 patch.
1522 - marker
1523
1524 Furthermore, you can use all the symbols (via Jinja2 syntax) from
1525 _init_dictionary_with_default_parameters().
1526
1527 kernel: String
1528 C++ code that holds the postprocessing kernel
1529
1530 """
1531 self._postprocess_updated_patch = kernel
1533 self.create_action_sets()
1534
1535 @property
1536 def overlap(self):
1537 return self._overlap
1538
1539 @overlap.setter
1540 def overlap(self, value):
1541 if value < 1:
1542 raise Exception(
1543 "Halo (overlap) size has to be bigger than zero but was {}".format(
1544 value
1545 )
1546 )
1547 self._overlap = value
1549 self.create_action_sets()
1550
1551 @property
1552 def interpolation(self):
1553 return self._interpolation
1554
1555 @interpolation.setter
1556 def interpolation(self, value):
1557 """
1558
1559 Set the interpolation scheme. If you rely on a built-in operation, then this
1560 call is all you have to do. Some ExaHyPE solvers however require each solver
1561 to provide special matrices/operators for some interpolation/restriction
1562 variants. If this is the case, you still have to add these matrices manually
1563 to your solver.
1564
1565 """
1566 self._interpolation = value
1567
1569 self.create_action_sets()
1570
1571 @property
1572 def restriction(self):
1573 """
1574
1575 Set the restriction scheme. If you rely on a built-in operation, then this
1576 call is all you have to do. Some ExaHyPE solvers however require each solver
1577 to provide special matrices/operators for some interpolation/restriction
1578 variants. If this is the case, you still have to add these matrices manually
1579 to your solver.
1580
1581 """
1582 return self._restriction
1583
1584 @restriction.setter
1585 def restriction(self, value):
1586 self._restriction = value
1587
1589 self.create_action_sets()
1590
1592 self,
1593 cell_data_storage: Storage,
1594 face_data_storage: Storage,
1595 ):
1596 """
1597
1598 By default, we hold all data on the call stacks. You can explicitly switch
1599 to storage on the heap via smart pointers.
1600
1601 @see create_data_structures()
1602
1603 """
1604 assert isinstance(cell_data_storage, Storage)
1605 assert isinstance(face_data_storage, Storage)
1606
1607 self._cell_data_storage = cell_data_storage
1608 self._face_data_storage = face_data_storage
1609
1611 self.create_action_sets()
Update the cell label within a sweep.
Definition CellLabel.py:9
add_actions_to_create_grid(self, step, evaluate_refinement_criterion)
The boundary information is set only once.
add_user_solver_includes(self, value)
Add further includes to this property, if your solver requires some additional routines from other he...
user_action_set_includes(self)
Add further includes to this property, if your action sets require some additional routines from othe...
add_implementation_files_to_project(self, namespace, output, dimensions, subdirectory="")
The ExaHyPE2 project will call this operation when it sets up the overall environment.
add_to_Peano4_datamodel(self, datamodel, verbose)
Add all required data to the Peano4 project's datamodel so it is properly built up.
add_actions_to_checkpoint_solution(self, step, output_path, restart_from_checkpoint=False)
Add action sets to checkpoint grid sweep.
switch_storage_scheme(self, Storage cell_data_storage, Storage face_data_storage)
By default, we hold all data on the call stacks.
__init__(self, name, patch_size, overlap, rk_order, unknowns, auxiliary_variables, min_meshcell_h, max_meshcell_h, plot_grid_properties, kernel_namespace, baseline_action_set_descend_invocation_order=0)
name: string A unique name for the solver.
number_of_Runge_Kutta_steps(self)
Return number of steps required to realise the Runge-Kutta scheme.
add_actions_to_init_grid(self, step, restart_from_checkpoint=False)
Add your actions to init grid.
user_solver_includes(self)
Add further includes to this property, if your solver requires some additional routines from other he...
_init_dictionary_with_default_parameters(self, d)
This one is called by all algorithmic steps before I invoke add_entries_to_text_replacement_dictionar...
create_data_structures(self)
Recall in subclasses if you wanna change the number of unknowns or auxiliary variables.
add_user_action_set_includes(self, value)
Add further includes to this property, if your action sets require some additional routines from othe...
add_actions_to_plot_solution(self, step, output_path, restart_from_checkpoint=False)
Add action sets to plotting grid sweep.
The handling of (dynamically) adaptive meshes for finite differences.
Definition DynamicAMR.py:11
The global periodic boundary conditions are set in the Constants.h.
PostprocessSolution differs from other action sets, as I only create it once.
PreprocessSolution differs from other action sets, as I only create it once.
Project patch data onto faces, so the faces hold valid data which can feed into the subsequent Runge-...
Very simple converter which maps the patch 1:1 onto a double array.
Patch implementation of a degree of freedom.
Definition Patch.py:7
This class plugs into the first access to a face and copies the data over.