Peano
Loading...
Searching...
No Matches
AMRMarker.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
13
14import jinja2
15
16from abc import abstractmethod
17
18import exahype2
19
20import dastgen2
22
23
24class AMRMarker(object):
25 """!
26
27 A very simple Poisson equation system solver to identify AMR transitions
28
29 Some codes need to know where AMR transitions are and want to flag the
30 areas around these transitions. This class implements a simple finite
31 differences diffusion implementation which eventually will become
32 stationary if your mesh does not change anymore. The code solves
33
34 @f$ - \Delta u = f @f$
35
36 for a fixed right-hand side f with a Jacobi solver. The solution is
37 subject to the constraints
38
39 @f$ 0 \leq u \leq 1 @f$
40
41 and Dirichlet boundary conditions. Finally, the PDE has prescribed interior
42 values of 1 for every hanging vertex. So we have 1 at AMR transitions (and
43 the boundary if that's wanted) and we see the solution u fade away once we
44 move away from the boundary, until is eventually becomes 0.
45
46 As we use a Jacobi iterative solver, using this marker within ExaHyPE is
47 equivalent to a heat equation solver which becomes stationary eventually if
48 the grid does not change. Regions with a small solution value (remember that
49 all solution values are between 0 and 1) are far away from any AMR boundary.
50 Regions with a value close to 1 are close to an AMR boundary.
51
52
53 ## Usage
54
55 Before you start, you have to reconfigure and add
56
57 --enable-fem
58
59 to your configuration call. Run make afterwards to build the FEM toolbox of
60 Peano.
61
62
63 To use the marker within your project, add a new solver to your project:
64
65 amr_label = exahype2.solvers.elliptic.AMRMarker( name="AMRMarker" )
66 project.add_solver( amr_label )
67
68 Take your ExaHyPE solver of choice and add one more auxiliary variable. This
69 variable will, from now on, hold a copy of the actual iterate value of the
70 elliptic solver.
71
72
73 Call the couple_with_FV_solver() operation on the AMRMarker so ensure that
74 the AMR marker pipes its data into the auxiliary variable. So if you solve
75 Euler with 5 unknowns, you add one auxiliary variable. The additional
76 statement
77
78 amr_label.couple_with_FV_solver( thesolver, 0 )
79
80 then makes the elliptic solver write the patch average of its marker into
81 the first (aka index 0) auxiliary quantity per volume.
82
83
84 ## Use cases
85
86 ExaHyPE codes usually use this for some damping or smearing close to the
87 AMR boundaries where instabilities due to reflecting waves can arise. There
88 might be other use cases.
89
90 In ExaHyPE, you add the AMRMarker and you project (couple) it onto an
91 auxiliary variable. When you evaluate the Poisson operator effectively
92 delivering a damping, you can now multiply the impact of this operator
93 with the auxiliary variable. This way, it is active near AMR boundaries,
94 but it disappears far away from there.
95
96
97 ## Pitfall
98
99 Ensure that you initialise all additional auxiliary variables properly in
100 ExaHyPE. If you don't initialise them, they will contain garbage will will
101 likely mess up follow-up calculations.
102
103 The same holds for the boundary data. Even though we don't exchange
104 auxiliary data between patches, you have to set boundary data for them
105 to satisfy ExaHyPE's data correctness checks.
106
107 """
108
109
110 def __init__(self, name, relaxation_coefficient = 0.6, right_hand_side = -10.0, flag_domain_boundary = True, plot = False):
111 """
112
113 name: string
114 A unique name for the solver. This one will be used for all generated
115 classes.
116
117 plot: Boolean
118 Clarifies whether a dump of the data should be enriched with grid info
119 (such as enclave status flags), too.
120
121 relaxation_coefficient: Double (0< value <1)
122 How quickly should the solution be relaxed against real solution. This
123 is the damping parameter in the Jacobi update scheme and thus has to be
124 bigger than 0 and smaller than 1. If the coefficient approaches 1, you
125 might see oscillations.
126
127 right_hand_side: Double (negative)
128 Basically describes how fast the solution is pulled down to 0 once we
129 go away from the AMR transition area.
130
131 """
132 self._name = name
133 self._relaxation_coefficient = relaxation_coefficient
134 self._flag_domain_boundary = flag_domain_boundary
135 self._right_hand_side = right_hand_side
136 self._plot = plot
137
139
141 self.create_action_sets()
142
143
144 def __str__(self):
145 return """
146Name: {}
147Type: {}
148Relaxation coefficient: {}
149""".format(
150 self._name,
151 self.__class__.__name__,
153)
154
155
156 __repr__ = __str__
157
158
159 def create_readme_descriptor(self, domain_offset, domain_size):
160 return """
161### ExaHyPE 2 solver
162
163""" + str(self)
164
165
167 """
168
169
170 """
172 self._data_model.data.add_attribute( dastgen2.attributes.Double("u") )
173 self._data_model.data.add_attribute( dastgen2.attributes.Double("residual") )
174
175 self._data_model.generator.load_store_compute_flag = "::peano4::grid::constructLoadStoreComputeFlag({},{},{})".format(
176 "true", "true", "true"
177 )
178
179 self._data_model.generator.send_condition = "true"
180 self._data_model.generator.receive_and_merge_condition = "true"
181
182 self._data_model.peano4_mpi_and_storage_aspect.merge_implementation = """
183 setResidual( getResidual() + neighbour.getResidual() );
184"""
185
186
187 @abstractmethod
189 """
190
191 Overwrite in subclasses if you wanna create different
192 action sets.
193
194 :: Call order and ownership
195
196 This operation can be called multiple times. However, only the very
197 last call matters. All previous calls are wiped out.
198
199 If you have a hierarchy of solvers, every create_data_structure()
200 should first(!) call its parent version. This way, you always ensure
201 that all data are in place before you continue to alter the more
202 specialised versions. So it is (logically) a top-down (general to
203 specialised) run through all create_data_structure() variants
204 within the inheritance tree.
205
206 """
208 self._data_model,
210 "{}".format(self._right_hand_side)
211 )
212 self._action_set_smoother.Template_CreateHangingVertex = """
213 fineGridVertex{{UNKNOWN}}.{{UNKNOWN_SETTER}}(1.0);
214 fineGridVertex{{UNKNOWN}}.{{RESIDUAL_SETTER}}(0.0);
215"""
216
217 updated_value_postprocessing = """
218 bool isBoundary = false;
219 tarch::la::Vector<Dimensions,double> domainOffset(DomainOffset);
220 tarch::la::Vector<Dimensions,double> domainSize(DomainSize);
221 for (int d=0; d<Dimensions; d++) {
222 isBoundary |= tarch::la::equals( marker.x()(d), domainOffset(d) );
223 isBoundary |= tarch::la::equals( marker.x()(d), domainOffset(d)+domainSize(d) );
224 }
225 if (isBoundary) {
226 fineGridVertex{{UNKNOWN}}.{{UNKNOWN_SETTER}}(boundaryValue);
227 }
228 if ( fineGridVertex{{UNKNOWN}}.{{UNKNOWN_GETTER}}()<0.0 ) {
229 fineGridVertex{{UNKNOWN}}.{{UNKNOWN_SETTER}}(0.0);
230 }
231"""
232 if self._flag_domain_boundary:
233 self._action_set_smoother.Template_UpdateValue += """
234const double boundaryValue = 1.0;
235""" + updated_value_postprocessing
236 else:
237 self._action_set_smoother.Template_UpdateValue += """
238const double boundaryValue = 0.0;
239""" + updated_value_postprocessing
240
241 self._action_set_smoother.Template_TouchCellFirstTime += self._volumetric_coupling_term
242 self._action_set_smoother.Template_CreatePersistentVertex = """
243 fineGridVertex{{UNKNOWN}}.{{UNKNOWN_SETTER}}(1.0);
244"""
245 self._action_set_smoother.additional_includes = """
246#include "Constants.h"
247"""
248
249 def couple_with_FV_solver(self,FV_solver,auxiliary_variable):
250 """
251
252 FV_solver: exahype2.solver.fv.Solver
253 Instance of the solver you want to couple this marker to
254
255 auxiliary_variable: Integer
256 index of the auxiliary variable that you want this class to dump its output
257 to.
258
259 """
261 double cellAverage = 0.0;
262 for(int k=0; k<TwoPowerD; k++) {{
263 cellAverage += fineGridVertices{}(k).getU();
264 }}
265 cellAverage /= TwoPowerD;
266 int index = {};
267 dfor(k,{}) {{
268 fineGridCell{}Q.value[index] = cellAverage;
269 index += {};
270 }}
271""".format(self._unknown_identifier(),FV_solver._unknowns+auxiliary_variable,FV_solver.patch_size,FV_solver.name,FV_solver._unknowns+FV_solver._auxiliary_variables)
272
273 # @todo There's a bug somewhere. I can't access unkonwns as property (it always returns patch size, while _unknowns works
274
275 self.create_action_sets()
276
277
279 return self._name+"AMRValue"
280
281
283 return "instanceOf" + self._name
284
285
286 def add_to_Peano4_datamodel( self, datamodel, verbose ):
287 """
288
289 Add all required data to the Peano4 project's datamodel
290 so it is properly built up
291
292 """
293 if verbose:
294 print( "AMR marker" )
295 print( "----------" )
296 print( str(self._name) )
297 datamodel.add_vertex(self._data_model)
298
299
301 """
302 Tell Peano what data to move around
303
304 Inform Peano4 step which data are to be moved around via the
305 use_cell and use_face commands. This operation is generic from
306 ExaHyPE's point of view, i.e. I use it for all grid sweep types.
307
308 """
309 step.use_vertex(self._data_model)
310
311
312# def _get_default_includes(self):
313# return """
314"""
315
316
317 def add_actions_to_init_grid(self, step):
318 """
327
328
329 """
330 step.add_action_set( self._action_set_smoother )
331 pass
332
333
334 def add_actions_to_create_grid(self, step, evaluate_refinement_criterion):
335 """
336
337 It is important to plug into the creation, as this is the place where
338 we get the creational events.
339
340 """
341 step.add_action_set( self._action_set_smoother )
342
343
344 def add_actions_to_plot_solution(self, step, output_path):
345 """
346
347 We plot if and only if we are asked to do so
348
349 """
350 ## Add it. I can't harm to do one more iteration, and we at least
351 ## get the hanging nodes right this way
352 step.add_action_set( self._action_set_smoother )
353 if self._plot:
354 step.add_action_set( peano4.toolbox.PlotVertexDataInPeanoBlockFormat(
355 filename=output_path + "amr-marker-" + self._name,
356 vertex_unknown=self._data_model,
357 getter="getU()",
358 description="marker-value",
359 time_stamp_evaluation="0.5*(repositories::getMinTimeStamp()+repositories::getMaxTimeStamp())",
360 additional_includes="""
361#include "repositories/SolverRepository.h"
362"""
363 ))
364
365
366 def add_actions_to_perform_time_step(self, step):
367 """
368
369 AMR
370
371 It is important that we do the inter-grid transfer operators before we
372 apply the boundary conditions.
373
374 """
375 step.add_action_set( self._action_set_smoother )
376
377
378 @abstractmethod
379 def add_entries_to_text_replacement_dictionary(self,d):
380 pass
381
382
383 def add_implementation_files_to_project(self,namespace,output, dimensions, subdirectory=""):
384 """
385
386 The ExaHyPE2 project will call this operation when it sets
387 up the overall environment.
388
389 This routine is typically not invoked by a user.
390
392
393 """
394 templatefile_prefix = os.path.dirname( os.path.realpath(__file__) ) + "/AMRMarker"
395
396 if(subdirectory):
397 subdirectory += "/"
398
399 headerDictionary = {}
400 implementationDictionary = {}
401# self._init_dictionary_with_default_parameters(headerDictionary)
402# self._init_dictionary_with_default_parameters(implementationDictionary)
403 self.add_entries_to_text_replacement_dictionary(headerDictionary)
404 self.add_entries_to_text_replacement_dictionary(implementationDictionary)
405
406 generated_solver_files = peano4.output.Jinja2TemplatedHeaderImplementationFilePair(
407 templatefile_prefix + ".template.h",
408 templatefile_prefix + ".template.cpp",
409 self._name,
410 namespace,
411 subdirectory + ".",
412 implementationDictionary,
413 True,
414 True)
415
416 output.add( generated_solver_files )
417 output.makefile.add_cpp_file( subdirectory + self._name + ".cpp", generated=True )
418
419
420# def _init_dictionary_with_default_parameters(self,d):
421# """
422#
423# This one is called by all algorithmic steps before I invoke
424# add_entries_to_text_replacement_dictionary().
425#
426# See the remarks on set_postprocess_updated_patch_kernel to understand why
427# we have to apply the (partially befilled) dictionary to create a new entry
428# for this very dictionary.##
429
441
442
443 @property
444 def name(self):
445 return self._name
446
cardinality is a string (you can thus use symbols as well as long as they will be defined at compile ...
Definition Double.py:6
A very simple Poisson equation system solver to identify AMR transitions.
Definition AMRMarker.py:24
couple_with_FV_solver(self, FV_solver, auxiliary_variable)
FV_solver: exahype2.solver.fv.Solver Instance of the solver you want to couple this marker to.
Definition AMRMarker.py:249
add_use_data_statements_to_Peano4_solver_step(self, step)
Tell Peano what data to move around.
Definition AMRMarker.py:300
create_readme_descriptor(self, domain_offset, domain_size)
Definition AMRMarker.py:159
__init__(self, name, relaxation_coefficient=0.6, right_hand_side=-10.0, flag_domain_boundary=True, plot=False)
name: string A unique name for the solver.
Definition AMRMarker.py:110
create_action_sets(self)
Overwrite in subclasses if you wanna create different action sets.
Definition AMRMarker.py:188
add_to_Peano4_datamodel(self, datamodel, verbose)
Add all required data to the Peano4 project's datamodel so it is properly built up.
Definition AMRMarker.py:286
Default superclass for any data model in Peano which is stored within the grid.
Definition DaStGen2.py:47
Represents the total output generated from the Peano4 data model plus all the operations on it.
Definition Output.py:7
name(self)
""" d["RIGHT_HAND_SIDE"] = self._right_hand_side d["RELAXATION_COEFFICIENT"] = self....
Definition AMRMarker.py:444