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
113 self._action_set_check_troubledness = VerifyTroubledness(self, use_PAC=True,
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
123 self._action_set_copy_face_data = SolveRiemannProblem(self,
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/utils/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 set_plot_description(self, description):
349 self.plot_description = description
350
351 def _generate_kernels(self, namespace, output, subdirectory, dimensions):
352 d = {}
353 self._init_dictionary_with_default_parameters(d)
354 self.add_entries_to_text_replacement_dictionary(d)
355 # d["DIMENSIONS"] = dimensions
356 # d["NUMBER_OF_DOF_3D"] = 1 if dimensions == 2 else d["NUMBER_OF_DOF"]
357 # d["NUMBER_OF_DOF_LIMITER_3D"] = 1 if dimensions == 2 else d["NUMBER_OF_DOF_LIMITER"]
358 # d["GHOST_LAYER_WIDTH_3D"] = 0 if dimensions == 2 else d["GHOST_LAYER_WIDTH"]
359 # d["FULL_QUALIFIED_SOLVER_NAME"] ="::".join(namespace) + "::" + self._name
360
361 kernels_namespace = namespace + ["kernels", self._name]
362 kernels_output_path = subdirectory + "kernels/" + self._name
363 kernels_templates_prefix = os.path.dirname(os.path.realpath(__file__)) + "/kernels/"
364
365 if not os.path.exists(kernels_output_path):
366 os.makedirs(kernels_output_path)
367
368 kernels.Limiter(d).generate_kernels(
369 kernels_namespace, output, subdirectory,
370 kernels_templates_prefix, kernels_output_path,
371 regular_solver_quadpoints = self._regular_solver._basis.quadrature_points(render=False),
372 limiter_solver_quadpoints = self._limiter_solver._basis.quadrature_points(render=False)
373 )
374
375 """
376 This tells peano to add the solver files to the project. It generates any files that are not
377 specifically cell or face data or grid actions such as the actionsets.
378 Currently it generates solver implementation and header files.
379 """
380 def add_implementation_files_to_project(self, namespace, output, dimensions, subdirectory=""):
381 """
382 The ExaHyPE2 project will call this operation when it sets
383 up the overall environment.
384
385 This routine is typically not invoked by a user.
386
387 output: peano4.output.Output
388 """
389
390 HeaderDictionary = {}
391 self._init_dictionary_with_default_parameters(HeaderDictionary)
392
393 generated_abstract_files = (
394 peano4.output.Jinja2TemplatedHeaderImplementationFilePair(
395 os.path.dirname(os.path.realpath(__file__)) + "/StaticCouplingAbstract.template.h",
396 os.path.dirname(os.path.realpath(__file__)) + "/StaticCouplingAbstract.template.cpp",
397 "Abstract" + self._name,
398 namespace,
399 subdirectory + ".",
400 HeaderDictionary,
401 True,
402 True
403 )
404 )
405
406 generated_solver_files = (
407 peano4.output.Jinja2TemplatedHeaderImplementationFilePair(
408 os.path.dirname(os.path.realpath(__file__)) + "/StaticCoupling.template.h",
409 os.path.dirname(os.path.realpath(__file__)) + "/StaticCoupling.template.cpp",
410 self._name,
411 namespace,
412 subdirectory + ".",
413 HeaderDictionary,
414 False,
415 True
416 )
417 )
418
419 output.add(generated_abstract_files)
420 output.makefile.add_cpp_file(subdirectory + "Abstract" + self._name + ".cpp", generated=True)
421 output.makefile.add_h_file(subdirectory + "Abstract" + self._name + ".h", generated=True)
422
423 output.add(generated_solver_files)
424 output.makefile.add_cpp_file(subdirectory + self._name + ".cpp", generated=True)
425 output.makefile.add_h_file(subdirectory + self._name + ".h", generated=True)
426
427 self._generate_kernels(namespace, output, subdirectory, dimensions)
428
429 @abstractmethod
430 def add_entries_to_text_replacement_dictionary(self, d):
431 pass
432
433 """
434 Generates a dictionary of "words" that will later be used in various templates to fill these out by adding
435 information from the solver or which was specified by the user.
436 """
437 def _init_dictionary_with_default_parameters(self, d):
438
439 d["SOLVER_INSTANCE"] = self.get_name_of_global_instance()
440 d["REGULAR_SOLVER_INSTANCE"] = self._regular_solver.get_name_of_global_instance()
441 d["LIMITER_SOLVER_INSTANCE"] = self._limiter_solver.get_name_of_global_instance()
442
443 d["SOLVER_NAME"] = self._name
444 d["REGULAR_SOLVER_NAME"] = self._regular_solver._name
445 d["LIMITER_SOLVER_NAME"] = self._limiter_solver._name
446
447 d["UNKNOWN_IDENTIFIER"] = self._unknown_identifier()
448 d["REGULAR_SOLVER_UNKNOWN_IDENTIFIER"] = self._regular_solver._unknown_identifier()
449 d["LIMITER_SOLVER_UNKNOWN_IDENTIFIER"] = self._limiter_solver._unknown_identifier()
450
451 d["SOLVER_INCLUDES"] = self.get_user_solver_includes()
452
453 d["REGULAR_SOLVER_ORDER"] = self._regular_solver._order
454 d["LIMITER_SOLVER_ORDER"] = self._limiter_solver._order
455
456 d["REGULAR_SOLVER_STORAGE_PRECISION"] = self._regular_solver._solution_persistent_storage_precision
457
458 d["REGULAR_SOLVER_CORRECTION_PRECISION"] = self._regular_solver._corrector_computation_precision
459 d["LIMITER_SOLVER_CORRECTION_PRECISION"] = self._limiter_solver._corrector_computation_precision
460
461 d["NUMBER_OF_DOFS_PER_CELL_2D"] = (
462 (self._regular_solver.unknowns + self._regular_solver.auxiliary_variables)
463 * (self._regular_solver.order+1) * (self._regular_solver.order+1) )
464 d["NUMBER_OF_DOFS_PER_CELL_3D"] = (
465 (self._regular_solver.unknowns + self._regular_solver.auxiliary_variables)
466 * (self._regular_solver.order+1) * (self._regular_solver.order+1) * (self._regular_solver.order+1) )
467
468 d["SOLVER_USER_DECLARATIONS"] = jinja2.Template(
469 self._solver_user_declarations, undefined=jinja2.DebugUndefined
470 ).render(**d)
471 d["SOLVER_USER_DEFINITIONS"] = jinja2.Template(
472 self._solver_user_definitions, undefined=jinja2.DebugUndefined
473 ).render(**d)
474
475 d["START_TIME_STEP_IMPLEMENTATION"] = jinja2.Template(
476 self._start_time_step_implementation, undefined=jinja2.DebugUndefined
477 ).render(**d)
478 d["FINISH_TIME_STEP_IMPLEMENTATION"] = jinja2.Template(
479 self._finish_time_step_implementation, undefined=jinja2.DebugUndefined
480 ).render(**d)
481 d["PRINT_TIME_STEP_IMPLEMENTATION"] = jinja2.Template(
482 self._print_time_step_implementation, undefined=jinja2.DebugUndefined
483 ).render(**d)
484
485 d["CONSTRUCTOR_IMPLEMENTATION"] = jinja2.Template(
486 self._constructor_implementation, undefined=jinja2.DebugUndefined
487 ).render(**d)
488
489 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)