Peano
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 
4 import dastgen2
5 import peano4
6 import exahype2
7 
8 import jinja2
9 import os
10 
11 import kernels
12 
13 from abc import abstractmethod
14 
15 from exahype2.solvers.PDETerms import PDETerms
16 
17 from .actionsets import ( SpreadLimiterStatus, SolveRiemannProblem, VerifyTroubledness)
18 
19 class StaticCoupling(object):
20  # initialization stores the key information about the solver and initializes a number of variables for later usage
21  def __init__(
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 = name
32 
33  # respectively solver to be used in stable regions and solver to be used in unstable regions
34  self._regular_solver_regular_solver = regularSolver
35  self._limiter_solver_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  """
41  self._solver_user_declarations_solver_user_declarations = ""
42  self._solver_user_definitions_solver_user_definitions = ""
43 
44  self.user_action_set_includesuser_action_set_includes = ""
45  self.user_solver_includesuser_solver_includes = ""
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  """
52  self._start_time_step_implementation_start_time_step_implementation = ""
53  self._finish_time_step_implementation_finish_time_step_implementation = ""
54  self._print_time_step_implementation_print_time_step_implementation = ""
55 
56  self._constructor_implementation_constructor_implementation = ""
57 
58  self._physical_admissibility_criterion_physical_admissibility_criterion = limiting_criterion_implementation
59  if ( self._physical_admissibility_criterion_physical_admissibility_criterion==PDETerms.None_Implementation
60  or self._physical_admissibility_criterion_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
65  self.create_data_structurescreate_data_structures()
66  self.create_action_setscreate_action_sets()
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_cell_label = exahype2.grid.create_cell_label(self._name_name)
88  self._face_label_face_label = exahype2.grid.create_face_label(self._name_name)
89  self._cell_label_cell_label.data.add_attribute(dastgen2.attributes.Enumeration( name="Troubled_Marker", variants=Variants, initval="Troubled_Marker::REGULAR" ) )
90  self._face_label_face_label.data.add_attribute(dastgen2.attributes.Enumeration( name="Troubled_Marker", variants=Variants, initval="Troubled_Marker::REGULAR" ) )
91 
92  self._face_label_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_regular_solver.get_name_of_global_instance() + """.getAdmissibleTimeStepSize(),
96  repositories::""" + self._limiter_solver_limiter_solver.get_name_of_global_instance() + """.getAdmissibleTimeStepSize());
97 """
98 
99  self._limiter_solver_limiter_solver._compute_time_step_size = compute_time_step_size
100  self._regular_solver_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_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_instanceget_name_of_global_instance() + ".getSolverState()==" + self._name_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_action_set_copy_face_data = SolveRiemannProblem(self,
124  guard = ("not marker.willBeRefined() and not marker.hasBeenRefined()"
125  + " and repositories::" + self.get_name_of_global_instanceget_name_of_global_instance() + ".getSolverState()==" + self._name_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_instanceget_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_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_action_set_copy_face_data.descend_invocation_order = 10
145 
146  self._regular_solver_regular_solver._action_set_prediction.guard += (
147  " and fineGridCell" + self._name_name + "CellLabel.getTroubled_Marker()==celldata::" + self._name_name + "CellLabel::Troubled_Marker::REGULAR"
148  )
149 
150  self._regular_solver_regular_solver._action_set_correction.guard += (
151  " and fineGridCell" + self._name_name + "CellLabel.getTroubled_Marker()==celldata::" + self._name_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_limiter_solver._action_set_prediction.guard += (
159  " and fineGridCell" + self._name_name + "CellLabel.getTroubled_Marker()==celldata::" + self._name_name + "CellLabel::Troubled_Marker::TROUBLED"
160  )
161 
162  self._limiter_solver_limiter_solver._action_set_correction.guard += (
163  " and fineGridCell" + self._name_name + "CellLabel.getTroubled_Marker()==celldata::" + self._name_name + "CellLabel::Troubled_Marker::TROUBLED"
164  )
165 
166  self._limiter_solver_limiter_solver._action_set_correction.face_guard += (
167  " and fineGridFace" + self._name_name + "FaceLabel.getTroubled_Marker()>=facedata::" + self._name_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 
178  return self.user_action_set_includesuser_action_set_includes
179 
181  return self.user_solver_includesuser_solver_includes
182 
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_includesuser_action_set_includes += value
189 
190 
192  return (
193  "not marker.willBeRefined() "
194  + "and repositories::"
195  + self.get_name_of_global_instanceget_name_of_global_instance()
196  + ".getSolverState()!="
197  + self._name_name
198  + "::SolverState::GridConstruction"
199  )
200 
202  return (
203  "not marker.willBeRefined() "
204  + "and repositories::"
205  + self.get_name_of_global_instanceget_name_of_global_instance()
206  + ".getSolverState()!="
207  + self._name_name
208  + "::SolverState::GridConstruction"
209  )
210 
212  return (
213  "not marker.willBeRefined() "
214  + "and repositories::"
215  + self.get_name_of_global_instanceget_name_of_global_instance()
216  + ".getSolverState()!="
217  + self._name_name
218  + "::SolverState::GridConstruction"
219  )
220 
222  return (
223  "not marker.hasBeenRefined() "
224  + "and repositories::"
225  + self.get_name_of_global_instanceget_name_of_global_instance()
226  + ".getSolverState()!="
227  + self._name_name
228  + "::SolverState::GridConstruction "
229  + "and repositories::"
230  + self.get_name_of_global_instanceget_name_of_global_instance()
231  + ".getSolverState()!="
232  + self._name_name
233  + "::SolverState::GridInitialisation"
234  )
235 
237  return (
238  "not marker.willBeRefined() "
239  + "and repositories::"
240  + self.get_name_of_global_instanceget_name_of_global_instance()
241  + ".getSolverState()!="
242  + self._name_name
243  + "::SolverState::GridConstruction"
244  )
245 
247  return (
248  "not marker.hasBeenRefined() "
249  + "and repositories::"
250  + self.get_name_of_global_instanceget_name_of_global_instance()
251  + ".getSolverState()!="
252  + self._name_name
253  + "::SolverState::GridConstruction "
254  + "and repositories::"
255  + self.get_name_of_global_instanceget_name_of_global_instance()
256  + ".getSolverState()!="
257  + self._name_name
258  + "::SolverState::GridInitialisation"
259  )
260 
262  return (
263  self._store_face_data_default_guard_store_face_data_default_guard()
264  + " and not repositories::"
265  + self.get_name_of_global_instanceget_name_of_global_instance()
266  + ".PeriodicBC[marker.getSelectedFaceNumber()%DIMENSIONS]"
267  + " and not marker.hasBeenRefined() and fineGridFace"
268  + self._name_name
269  + "FaceLabel.getBoundary()"
270  )
271 
273  return (
274  "not marker.willBeRefined()"
275  + "and repositories::"
276  + self.get_name_of_global_instanceget_name_of_global_instance()
277  + ".getSolverState()!="
278  + self._name_name
279  + "::SolverState::GridConstruction "
280  )
281 
283  return (
284  "repositories::"
285  + self.get_name_of_global_instanceget_name_of_global_instance()
286  + ".getSolverState()!="
287  + self._name_name
288  + "::SolverState::GridInitialisation"
289  )
290 
292  return "true"
293 
295  return self._name_name + "Q"
296 
298  return "InstanceOf" + self._name_name
299 
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  """
320 Name: """ + self._name_name + """
321 Type: """ + self.__class__.__name__
322  )
323  return result
324 
325  def add_to_Peano4_datamodel(self, datamodel):
326  datamodel.add_cell(self._cell_label_cell_label)
327  datamodel.add_face(self._face_label_face_label)
328 
330  step.use_cell(self._cell_label_cell_label)
331  step.use_face(self._face_label_face_label)
332 
333  def add_actions_to_init_grid(self, step):
334  step.add_action_set(self._action_set_check_troubledness_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
345  # step.add_action_set(self._action_set_spread_limiter_status)
346  step.add_action_set(self._action_set_copy_face_data_action_set_copy_face_data)
347 
348  def set_plot_description(self, description):
349  self.plot_descriptionplot_description = description
350 
351  def _generate_kernels(self, namespace, output, subdirectory, dimensions):
352  d = {}
353  self._init_dictionary_with_default_parameters_init_dictionary_with_default_parameters(d)
354  self.add_entries_to_text_replacement_dictionaryadd_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_name]
362  kernels_output_path = subdirectory + "kernels/" + self._name_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_regular_solver._basis.quadrature_points(render=False),
372  limiter_solver_quadpoints = self._limiter_solver_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_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_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_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_name + ".cpp", generated=True)
421  output.makefile.add_h_file(subdirectory + "Abstract" + self._name_name + ".h", generated=True)
422 
423  output.add(generated_solver_files)
424  output.makefile.add_cpp_file(subdirectory + self._name_name + ".cpp", generated=True)
425  output.makefile.add_h_file(subdirectory + self._name_name + ".h", generated=True)
426 
427  self._generate_kernels_generate_kernels(namespace, output, subdirectory, dimensions)
428 
429  @abstractmethod
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  """
438 
439  d["SOLVER_INSTANCE"] = self.get_name_of_global_instanceget_name_of_global_instance()
440  d["REGULAR_SOLVER_INSTANCE"] = self._regular_solver_regular_solver.get_name_of_global_instance()
441  d["LIMITER_SOLVER_INSTANCE"] = self._limiter_solver_limiter_solver.get_name_of_global_instance()
442 
443  d["SOLVER_NAME"] = self._name_name
444  d["REGULAR_SOLVER_NAME"] = self._regular_solver_regular_solver._name
445  d["LIMITER_SOLVER_NAME"] = self._limiter_solver_limiter_solver._name
446 
447  d["UNKNOWN_IDENTIFIER"] = self._unknown_identifier_unknown_identifier()
448  d["REGULAR_SOLVER_UNKNOWN_IDENTIFIER"] = self._regular_solver_regular_solver._unknown_identifier()
449  d["LIMITER_SOLVER_UNKNOWN_IDENTIFIER"] = self._limiter_solver_limiter_solver._unknown_identifier()
450 
451  d["SOLVER_INCLUDES"] = self.get_user_solver_includesget_user_solver_includes()
452 
453  d["REGULAR_SOLVER_ORDER"] = self._regular_solver_regular_solver._order
454  d["LIMITER_SOLVER_ORDER"] = self._limiter_solver_limiter_solver._order
455 
456  d["REGULAR_SOLVER_STORAGE_PRECISION"] = self._regular_solver_regular_solver._solution_persistent_storage_precision
457 
458  d["REGULAR_SOLVER_CORRECTION_PRECISION"] = self._regular_solver_regular_solver._corrector_computation_precision
459  d["LIMITER_SOLVER_CORRECTION_PRECISION"] = self._limiter_solver_limiter_solver._corrector_computation_precision
460 
461  d["NUMBER_OF_DOFS_PER_CELL_2D"] = (
462  (self._regular_solver_regular_solver.unknowns + self._regular_solver_regular_solver.auxiliary_variables)
463  * (self._regular_solver_regular_solver.order+1) * (self._regular_solver_regular_solver.order+1) )
464  d["NUMBER_OF_DOFS_PER_CELL_3D"] = (
465  (self._regular_solver_regular_solver.unknowns + self._regular_solver_regular_solver.auxiliary_variables)
466  * (self._regular_solver_regular_solver.order+1) * (self._regular_solver_regular_solver.order+1) * (self._regular_solver_regular_solver.order+1) )
467 
468  d["SOLVER_USER_DECLARATIONS"] = jinja2.Template(
469  self._solver_user_declarations_solver_user_declarations, undefined=jinja2.DebugUndefined
470  ).render(**d)
471  d["SOLVER_USER_DEFINITIONS"] = jinja2.Template(
472  self._solver_user_definitions_solver_user_definitions, undefined=jinja2.DebugUndefined
473  ).render(**d)
474 
475  d["START_TIME_STEP_IMPLEMENTATION"] = jinja2.Template(
476  self._start_time_step_implementation_start_time_step_implementation, undefined=jinja2.DebugUndefined
477  ).render(**d)
478  d["FINISH_TIME_STEP_IMPLEMENTATION"] = jinja2.Template(
479  self._finish_time_step_implementation_finish_time_step_implementation, undefined=jinja2.DebugUndefined
480  ).render(**d)
481  d["PRINT_TIME_STEP_IMPLEMENTATION"] = jinja2.Template(
482  self._print_time_step_implementation_print_time_step_implementation, undefined=jinja2.DebugUndefined
483  ).render(**d)
484 
485  d["CONSTRUCTOR_IMPLEMENTATION"] = jinja2.Template(
486  self._constructor_implementation_constructor_implementation, undefined=jinja2.DebugUndefined
487  ).render(**d)
488 
489  d["ADMISSIBILITY_IMPLEMENTATION"] = self._physical_admissibility_criterion_physical_admissibility_criterion
def __init__(self, name, regularSolver, limitingSolver, limiting_criterion_implementation=PDETerms.User_Defined_Implementation)
def add_actions_to_plot_solution(self, step, output_path)
def create_data_structures(self)
This will serve as a face marker to communicate with neighbouring cells whether a given cell is troub...
def add_user_action_set_includes(self, value)
Add further includes to this property, if your action sets require some additional routines from othe...
def add_to_Peano4_datamodel(self, datamodel)
def add_implementation_files_to_project(self, namespace, output, dimensions, subdirectory="")
The ExaHyPE2 project will call this operation when it sets up the overall environment.
def _generate_kernels(self, namespace, output, subdirectory, dimensions)
def add_use_data_statements_to_Peano4_solver_step(self, step)
def create_readme_descriptor(self, domain_offset, domain_size)
def set_plot_description(self, description)
def add_actions_to_create_grid(self, step, evaluate_refinement_criterion)