Peano
Loading...
Searching...
No Matches
StaticCoupling.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
3
4import dastgen2
5import peano4
6import exahype2
7
8import jinja2
9import os
10
11import kernels
12
13from abc import abstractmethod
14
15from exahype2.solvers.PDETerms import PDETerms
16
17from .actionsets import ( SpreadLimiterStatus, SolveRiemannProblem, VerifyTroubledness)
18
19class StaticCoupling(object):
20 # initialization stores the key information about the solver and initializes a number of variables for later usage
22 self,
23 name,
24 regularSolver,
25 limitingSolver,
26 limiting_criterion_implementation = PDETerms.User_Defined_Implementation
27 ):
28
29
30 # name of the limiting solver
31 self._name = name
32
33 # respectively solver to be used in stable regions and solver to be used in unstable regions
34 self._regular_solver = regularSolver
35 self._limiter_solver = limitingSolver
36
37 """
38 These will be used by children of this class to fill them with the declaration and definition of the
39 above mandatory and optional functions.
40 """
43
46
47 """
48 Used by child classes, will contain code to be executed at the start and end respectively of the
49 time step. Typically specifies some timestep variable and advances the overall timestamp of the
50 entire solver.
51 """
55
57
58 self._physical_admissibility_criterion = limiting_criterion_implementation
59 if ( self._physical_admissibility_criterion==PDETerms.None_Implementation
60 or self._physical_admissibility_criterion==PDETerms.Empty_Implementation):
61 raise Exception("Limiting criterion cannot be none")
62
63
64 # create initial structures and action_sets, these are re-generated essentially anytime something about the solver is modified
67
68 """
69 Creates all the structures which are attached on the peano grid either in a cell or on the faces.
70 These are defined as peano patches which have given sizes to contain persistent data as well as
71 conditions for when they should be merged, sent, received, stored, loaded, etc.
72 """
73
74 @abstractmethod
76
77 """
78 This will serve as a face marker to communicate with neighbouring cells whether
79 a given cell is troubled, is neighbouring a troubled cell, or is fine.
80 Cells that are troubled or neighbouring a troubled cell must rollback their solution
81 to the previous one and perform one timestep using a more robust FV scheme.
82 Therefore these and their neighbours must convert the DG representation of their
83 previous solution to an FV representation and project it to their faces so that these
84 can be exchanged with their neighbours.
85 """
86 Variants = ["REGULAR","REGULAR_TO_LIMITER","LIMITER_TO_REGULAR","TROUBLED"]
87 self._cell_label = exahype2.grid.create_cell_label(self._name)
88 self._face_label = exahype2.grid.create_face_label(self._name)
89 self._cell_label.data.add_attribute(dastgen2.attributes.Enumeration( name="Troubled_Marker", variants=Variants, initval="Troubled_Marker::REGULAR" ) )
90 self._face_label.data.add_attribute(dastgen2.attributes.Enumeration( name="Troubled_Marker", variants=Variants, initval="Troubled_Marker::REGULAR" ) )
91
92 self._face_label.peano4_mpi_and_storage_aspect.merge_implementation += "\n _Troubled_Marker = std::max(_Troubled_Marker, neighbour.getTroubled_Marker());"
93
94 compute_time_step_size = """
95 double timeStepSize = std::min( repositories::""" + self._regular_solver.get_name_of_global_instance() + """.getAdmissibleTimeStepSize(),
96 repositories::""" + self._limiter_solver.get_name_of_global_instance() + """.getAdmissibleTimeStepSize());
97"""
98
99 self._limiter_solver._compute_time_step_size = compute_time_step_size
100 self._regular_solver._compute_time_step_size = compute_time_step_size
101
102 """
103 Creates the action sets, these are actions tied to the grid that are executed at given points of
104 grid generation, construction or steps of the ader-dg solver. Peano handles grid structures that
105 contain data as well as operations that are executed on that data. These are the latter.
106 The guard here are the conditions for the execution of the operation, as in they are only executed
107 if the guard evaluates to true.
108 """
109
110 @abstractmethod
112
114 guard = ("not marker.willBeRefined() and not marker.hasBeenRefined() and" +
115 " repositories::" + self.get_name_of_global_instance() + ".getSolverState()==" + self._name + "::SolverState::GridInitialisation"
116 ))
117
118 # self._action_set_spread_limiter_status = SpreadLimiterStatus(self,
119 # guard = ("not marker.willBeRefined() and not marker.hasBeenRefined() and" +
120 # " repositories::" + self.get_name_of_global_instance() + ".getSolverState()==" + self._name + "::SolverState::LimiterStatusSpreadingToNeighbours"
121 # ))
122
124 guard = ("not marker.willBeRefined() and not marker.hasBeenRefined()"
125 + " and repositories::" + self.get_name_of_global_instance() + ".getSolverState()==" + self._name + "::SolverState::TimeStepping"
126 # + " and fineGridCell" + self._name + "CellLabel.getTroubled_Marker()==celldata::" + self._name + "CellLabel::Troubled_Marker::REGULAR"
127 + " and " + "repositories::" + self.get_name_of_global_instance() + ".isFirstGridSweepOfTimeStep()"),
128 )
129
130 """
131 checking troubledness needs to happen in the initialization after the regular solver
132 has computed its initial condition.
133 spreading limiter status happens once in its own dedicated step after initialization
134 but before either solvers are allowed to start computing, and once in the first
135 timestep before any other operations are performed
136 copying and converting the data from regular to limiter and from limiter to regular
137 happens before they are used in the first grid traversal, so either at the very
138 beginning of the first grid traversal or at the end of the second, so that
139 regular-to-limiter and limiter-to-regular cells both have access to either version
140 and can therefore project both variants of their faces
141 """
142 self._action_set_check_troubledness.descend_invocation_order = 1000
143 # self._action_set_spread_limiter_status.descend_invocation_order = 0
144 self._action_set_copy_face_data.descend_invocation_order = 10
145
146 self._regular_solver._action_set_prediction.guard += (
147 " and fineGridCell" + self._name + "CellLabel.getTroubled_Marker()==celldata::" + self._name + "CellLabel::Troubled_Marker::REGULAR"
148 )
149
150 self._regular_solver._action_set_correction.guard += (
151 " and fineGridCell" + self._name + "CellLabel.getTroubled_Marker()==celldata::" + self._name + "CellLabel::Troubled_Marker::REGULAR"
152 )
153
154 # self._regular_solver._action_set_correction.riemann_guard += (
155 # " and fineGridFace" + self._name + "FaceLabel.getTroubled_Marker()<=facedata::" + self._name + "FaceLabel::Troubled_Marker::LIMITER_TO_REGULAR"
156 # )
157
158 self._limiter_solver._action_set_prediction.guard += (
159 " and fineGridCell" + self._name + "CellLabel.getTroubled_Marker()==celldata::" + self._name + "CellLabel::Troubled_Marker::TROUBLED"
160 )
161
162 self._limiter_solver._action_set_correction.guard += (
163 " and fineGridCell" + self._name + "CellLabel.getTroubled_Marker()==celldata::" + self._name + "CellLabel::Troubled_Marker::TROUBLED"
164 )
165
166 self._limiter_solver._action_set_correction.face_guard += (
167 " and fineGridFace" + self._name + "FaceLabel.getTroubled_Marker()>=facedata::" + self._name + "FaceLabel::Troubled_Marker::LIMITER_TO_REGULAR"
168 )
169
170
171
172 def create_readme_descriptor(self, domain_offset, domain_size):
173 return (
174 """ ExaHyPE 2 Limiting solver"""
175 )
176
177 def get_user_action_set_includes(self):
178 return self.user_action_set_includes
179
180 def get_user_solver_includes(self):
181 return self.user_solver_includes
182
183 def add_user_action_set_includes(self, value):
184 """
185 Add further includes to this property, if your action sets require some additional
186 routines from other header files.
187 """
188 self.user_action_set_includes += value
189
190
191 def _store_cell_data_default_guard(self):
192 return (
193 "not marker.willBeRefined() "
194 + "and repositories::"
195 + self.get_name_of_global_instance()
196 + ".getSolverState()!="
197 + self._name
198 + "::SolverState::GridConstruction"
199 )
200
201 def _provide_cell_data_to_compute_kernels_default_guard(self):
202 return (
203 "not marker.willBeRefined() "
204 + "and repositories::"
205 + self.get_name_of_global_instance()
206 + ".getSolverState()!="
207 + self._name
208 + "::SolverState::GridConstruction"
209 )
210
211 def _provide_face_data_to_compute_kernels_default_guard(self):
212 return (
213 "not marker.willBeRefined() "
214 + "and repositories::"
215 + self.get_name_of_global_instance()
216 + ".getSolverState()!="
217 + self._name
218 + "::SolverState::GridConstruction"
219 )
220
221 def _load_cell_data_default_guard(self):
222 return (
223 "not marker.hasBeenRefined() "
224 + "and repositories::"
225 + self.get_name_of_global_instance()
226 + ".getSolverState()!="
227 + self._name
228 + "::SolverState::GridConstruction "
229 + "and repositories::"
230 + self.get_name_of_global_instance()
231 + ".getSolverState()!="
232 + self._name
233 + "::SolverState::GridInitialisation"
234 )
235
236 def _store_face_data_default_guard(self):
237 return (
238 "not marker.willBeRefined() "
239 + "and repositories::"
240 + self.get_name_of_global_instance()
241 + ".getSolverState()!="
242 + self._name
243 + "::SolverState::GridConstruction"
244 )
245
246 def _load_face_data_default_guard(self):
247 return (
248 "not marker.hasBeenRefined() "
249 + "and repositories::"
250 + self.get_name_of_global_instance()
251 + ".getSolverState()!="
252 + self._name
253 + "::SolverState::GridConstruction "
254 + "and repositories::"
255 + self.get_name_of_global_instance()
256 + ".getSolverState()!="
257 + self._name
258 + "::SolverState::GridInitialisation"
259 )
260
261 def _store_boundary_data_default_guard(self):
262 return (
263 self._store_face_data_default_guard()
264 + " and not repositories::"
265 + self.get_name_of_global_instance()
266 + ".PeriodicBC[marker.getSelectedFaceNumber()%DIMENSIONS]"
267 + " and not marker.hasBeenRefined() and fineGridFace"
268 + self._name
269 + "FaceLabel.getBoundary()"
270 )
271
272 def _clear_face_data_default_guard(self):
273 return (
274 "not marker.willBeRefined()"
275 + "and repositories::"
276 + self.get_name_of_global_instance()
277 + ".getSolverState()!="
278 + self._name
279 + "::SolverState::GridConstruction "
280 )
281
282 def _interpolate_face_data_default_guard(self):
283 return (
284 "repositories::"
285 + self.get_name_of_global_instance()
286 + ".getSolverState()!="
287 + self._name
288 + "::SolverState::GridInitialisation"
289 )
290
291 def _restrict_face_data_default_guard(self):
292 return "true"
293
294 def _unknown_identifier(self):
295 return self._name + "Q"
296
297 def get_name_of_global_instance(self):
298 return "InstanceOf" + self._name
299
300 def _get_default_includes(self):
301 return """
302#include "tarch/la/Vector.h"
303
304#include "peano4/Globals.h"
305#include "peano4/utils/Loop.h"
306
307#include "repositories/SolverRepository.h"
308"""
309
310
311 """
312 The following functions will be called by the peano4 project,
313 they tell peano which of our generated data it should attach
314 to each grid element and use.
315 """
316
317 def __str__(self):
318 result = (
319 """
320Name: """ + self._name + """
321Type: """ + self.__class__.__name__
322 )
323 return result
324
325 def add_to_Peano4_datamodel(self, datamodel):
326 datamodel.add_cell(self._cell_label)
327 datamodel.add_face(self._face_label)
328
329 def add_use_data_statements_to_Peano4_solver_step(self, step):
330 step.use_cell(self._cell_label)
331 step.use_face(self._face_label)
332
333 def add_actions_to_init_grid(self, step):
334 step.add_action_set(self._action_set_check_troubledness)
335 pass
336
337 def add_actions_to_create_grid(self, step, evaluate_refinement_criterion):
338 pass
339
340 def add_actions_to_plot_solution(self, step, output_path):
341 pass
342
343 # these actions are executed during each time step
344 def add_actions_to_perform_time_step(self, step):
345 # step.add_action_set(self._action_set_spread_limiter_status)
346 step.add_action_set(self._action_set_copy_face_data)
347
348 def _generate_kernels(self, namespace, output, subdirectory, dimensions):
349 d = {}
350 self._init_dictionary_with_default_parameters(d)
351 self.add_entries_to_text_replacement_dictionary(d)
352 # d["DIMENSIONS"] = dimensions
353 # d["NUMBER_OF_DOF_3D"] = 1 if dimensions == 2 else d["NUMBER_OF_DOF"]
354 # d["NUMBER_OF_DOF_LIMITER_3D"] = 1 if dimensions == 2 else d["NUMBER_OF_DOF_LIMITER"]
355 # d["GHOST_LAYER_WIDTH_3D"] = 0 if dimensions == 2 else d["GHOST_LAYER_WIDTH"]
356 # d["FULL_QUALIFIED_SOLVER_NAME"] ="::".join(namespace) + "::" + self._name
357
358 kernels_namespace = namespace + ["kernels", self._name]
359 kernels_output_path = subdirectory + "kernels/" + self._name
360 kernels_templates_prefix = os.path.dirname(os.path.realpath(__file__)) + "/kernels/"
361
362 if not os.path.exists(kernels_output_path):
363 os.makedirs(kernels_output_path)
364
365 kernels.Limiter(d).generate_kernels(
366 kernels_namespace, output, subdirectory,
367 kernels_templates_prefix, kernels_output_path,
368 regular_solver_quadpoints = self._regular_solver._basis.quadrature_points(render=False),
369 limiter_solver_quadpoints = self._limiter_solver._basis.quadrature_points(render=False)
370 )
371
372 """
373 This tells peano to add the solver files to the project. It generates any files that are not
374 specifically cell or face data or grid actions such as the actionsets.
375 Currently it generates solver implementation and header files.
376 """
377 def add_implementation_files_to_project(self, namespace, output, dimensions, subdirectory=""):
378 """
379 The ExaHyPE2 project will call this operation when it sets
380 up the overall environment.
381
382 This routine is typically not invoked by a user.
383
384 output: peano4.output.Output
385 """
386
387 HeaderDictionary = {}
388 self._init_dictionary_with_default_parameters(HeaderDictionary)
389
390 generated_abstract_files = (
391 peano4.output.Jinja2TemplatedHeaderImplementationFilePair(
392 os.path.dirname(os.path.realpath(__file__)) + "/StaticCouplingAbstract.template.h",
393 os.path.dirname(os.path.realpath(__file__)) + "/StaticCouplingAbstract.template.cpp",
394 "Abstract" + self._name,
395 namespace,
396 subdirectory + ".",
397 HeaderDictionary,
398 True,
399 True
400 )
401 )
402
403 generated_solver_files = (
404 peano4.output.Jinja2TemplatedHeaderImplementationFilePair(
405 os.path.dirname(os.path.realpath(__file__)) + "/StaticCoupling.template.h",
406 os.path.dirname(os.path.realpath(__file__)) + "/StaticCoupling.template.cpp",
407 self._name,
408 namespace,
409 subdirectory + ".",
410 HeaderDictionary,
411 False,
412 True
413 )
414 )
415
416 output.add(generated_abstract_files)
417 output.makefile.add_cpp_file(subdirectory + "Abstract" + self._name + ".cpp", generated=True)
418 output.makefile.add_h_file(subdirectory + "Abstract" + self._name + ".h", generated=True)
419
420 output.add(generated_solver_files)
421 output.makefile.add_cpp_file(subdirectory + self._name + ".cpp", generated=True)
422 output.makefile.add_h_file(subdirectory + self._name + ".h", generated=True)
423
424 self._generate_kernels(namespace, output, subdirectory, dimensions)
425
426 @abstractmethod
427 def add_entries_to_text_replacement_dictionary(self, d):
428 pass
429
430 """
431 Generates a dictionary of "words" that will later be used in various templates to fill these out by adding
432 information from the solver or which was specified by the user.
433 """
434 def _init_dictionary_with_default_parameters(self, d):
435
436 d["SOLVER_INSTANCE"] = self.get_name_of_global_instance()
437 d["REGULAR_SOLVER_INSTANCE"] = self._regular_solver.get_name_of_global_instance()
438 d["LIMITER_SOLVER_INSTANCE"] = self._limiter_solver.get_name_of_global_instance()
439
440 d["SOLVER_NAME"] = self._name
441 d["REGULAR_SOLVER_NAME"] = self._regular_solver._name
442 d["LIMITER_SOLVER_NAME"] = self._limiter_solver._name
443
444 d["UNKNOWN_IDENTIFIER"] = self._unknown_identifier()
445 d["REGULAR_SOLVER_UNKNOWN_IDENTIFIER"] = self._regular_solver._unknown_identifier()
446 d["LIMITER_SOLVER_UNKNOWN_IDENTIFIER"] = self._limiter_solver._unknown_identifier()
447
448 d["SOLVER_INCLUDES"] = self.get_user_solver_includes()
449
450 d["REGULAR_SOLVER_ORDER"] = self._regular_solver._order
451 d["LIMITER_SOLVER_ORDER"] = self._limiter_solver._order
452
453 d["REGULAR_SOLVER_STORAGE_PRECISION"] = self._regular_solver._solution_persistent_storage_precision
454
455 d["REGULAR_SOLVER_CORRECTION_PRECISION"] = self._regular_solver._corrector_computation_precision
456 d["LIMITER_SOLVER_CORRECTION_PRECISION"] = self._limiter_solver._corrector_computation_precision
457
458 d["NUMBER_OF_DOFS_PER_CELL_2D"] = (
459 (self._regular_solver.unknowns + self._regular_solver.auxiliary_variables)
460 * (self._regular_solver.order+1) * (self._regular_solver.order+1) )
461 d["NUMBER_OF_DOFS_PER_CELL_3D"] = (
462 (self._regular_solver.unknowns + self._regular_solver.auxiliary_variables)
463 * (self._regular_solver.order+1) * (self._regular_solver.order+1) * (self._regular_solver.order+1) )
464
465 d["SOLVER_USER_DECLARATIONS"] = jinja2.Template(
466 self._solver_user_declarations, undefined=jinja2.DebugUndefined
467 ).render(**d)
468 d["SOLVER_USER_DEFINITIONS"] = jinja2.Template(
469 self._solver_user_definitions, undefined=jinja2.DebugUndefined
470 ).render(**d)
471
472 d["START_TIME_STEP_IMPLEMENTATION"] = jinja2.Template(
473 self._start_time_step_implementation, undefined=jinja2.DebugUndefined
474 ).render(**d)
475 d["FINISH_TIME_STEP_IMPLEMENTATION"] = jinja2.Template(
476 self._finish_time_step_implementation, undefined=jinja2.DebugUndefined
477 ).render(**d)
478 d["PRINT_TIME_STEP_IMPLEMENTATION"] = jinja2.Template(
479 self._print_time_step_implementation, undefined=jinja2.DebugUndefined
480 ).render(**d)
481
482 d["CONSTRUCTOR_IMPLEMENTATION"] = jinja2.Template(
483 self._constructor_implementation, undefined=jinja2.DebugUndefined
484 ).render(**d)
485
486 d["ADMISSIBILITY_IMPLEMENTATION"] = self._physical_admissibility_criterion
create_readme_descriptor(self, domain_offset, domain_size)
create_data_structures(self)
This will serve as a face marker to communicate with neighbouring cells whether a given cell is troub...
__init__(self, name, regularSolver, limitingSolver, limiting_criterion_implementation=PDETerms.User_Defined_Implementation)