16from abc
import abstractmethod
27 A very simple Poisson equation system solver to identify AMR transitions
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
34 @f$ - \Delta u = f @f$
36 for a fixed right-hand side f with a Jacobi solver. The solution is
37 subject to the constraints
39 @f$ 0 \leq u \leq 1 @f$
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.
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.
55 Before you start, you have to reconfigure and add
59 to your configuration call. Run make afterwards to build the FEM toolbox of
63 To use the marker within your project, add a new solver to your project:
65 amr_label = exahype2.solvers.elliptic.AMRMarker( name="AMRMarker" )
66 project.add_solver( amr_label )
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
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
78 amr_label.couple_with_FV_solver( thesolver, 0 )
80 then makes the elliptic solver write the patch average of its marker into
81 the first (aka index 0) auxiliary quantity per volume.
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.
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.
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.
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.
110 def __init__(self, name, relaxation_coefficient = 0.6, right_hand_side = -10.0, flag_domain_boundary = True, plot = False):
114 A unique name for the solver. This one will be used for all generated
118 Clarifies whether a dump of the data should be enriched with grid info
119 (such as enclave status flags), too.
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.
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.
148Relaxation coefficient: {}
151 self.__class__.__name__,
175 self.
_data_model.generator.load_store_compute_flag =
"::peano4::grid::constructLoadStoreComputeFlag({},{},{})".format(
176 "true",
"true",
"true"
180 self.
_data_model.generator.receive_and_merge_condition =
"true"
182 self.
_data_model.peano4_mpi_and_storage_aspect.merge_implementation =
"""
183 setResidual( getResidual() + neighbour.getResidual() );
191 Overwrite in subclasses if you wanna create different
194 :: Call order and ownership
196 This operation can be called multiple times. However, only the very
197 last call matters. All previous calls are wiped out.
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.
213 fineGridVertex{{UNKNOWN}}.{{UNKNOWN_SETTER}}(1.0);
214 fineGridVertex{{UNKNOWN}}.{{RESIDUAL_SETTER}}(0.0);
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) );
226 fineGridVertex{{UNKNOWN}}.{{UNKNOWN_SETTER}}(boundaryValue);
228 if ( fineGridVertex{{UNKNOWN}}.{{UNKNOWN_GETTER}}()<0.0 ) {
229 fineGridVertex{{UNKNOWN}}.{{UNKNOWN_SETTER}}(0.0);
234const double boundaryValue = 1.0;
235""" + updated_value_postprocessing
238const double boundaryValue = 0.0;
239""" + updated_value_postprocessing
243 fineGridVertex{{UNKNOWN}}.{{UNKNOWN_SETTER}}(1.0);
246#include "Constants.h"
252 FV_solver: exahype2.solver.fv.Solver
253 Instance of the solver you want to couple this marker to
255 auxiliary_variable: Integer
256 index of the auxiliary variable that you want this class to dump its output
261 double cellAverage = 0.0;
262 for(int k=0; k<TwoPowerD; k++) {{
263 cellAverage += fineGridVertices{}(k).getU();
265 cellAverage /= TwoPowerD;
268 fineGridCell{}Q.value[index] = cellAverage;
271""".format(self.
_unknown_identifier(),FV_solver._unknowns+auxiliary_variable,FV_solver.patch_size,FV_solver.name,FV_solver._unknowns+FV_solver._auxiliary_variables)
279 return self.
_name+
"AMRValue"
283 return "instanceOf" + self.
_name
289 Add all required data to the Peano4 project's datamodel
290 so it is properly built up
294 print(
"AMR marker" )
295 print(
"----------" )
296 print( str(self.
_name) )
302 Tell Peano what data to move around
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.
317 def add_actions_to_init_grid(self, step):
330 step.add_action_set( self._action_set_smoother )
334 def add_actions_to_create_grid(self, step, evaluate_refinement_criterion):
337 It
is important to plug into the creation,
as this
is the place where
338 we get the creational events.
341 step.add_action_set( self._action_set_smoother )
344 def add_actions_to_plot_solution(self, step, output_path):
347 We plot
if and only
if we are asked to do so
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 )
354 step.add_action_set( peano4.toolbox.PlotVertexDataInPeanoBlockFormat(
355 filename=output_path + "amr-marker-" + self._name,
356 vertex_unknown=self._data_model,
358 description="marker-value",
359 time_stamp_evaluation="0.5*(repositories::getMinTimeStamp()+repositories::getMaxTimeStamp())",
360 additional_includes="""
366 def add_actions_to_perform_time_step(self, step):
371 It
is important that we do the inter-grid transfer operators before we
372 apply the boundary conditions.
375 step.add_action_set( self._action_set_smoother )
379 def add_entries_to_text_replacement_dictionary(self,d):
383 def add_implementation_files_to_project(self,namespace,output, dimensions, subdirectory=""):
386 The ExaHyPE2 project will call this operation when it sets
387 up the overall environment.
389 This routine
is typically
not invoked by a user.
394 templatefile_prefix = os.path.dirname( os.path.realpath(__file__) ) + "/AMRMarker"
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)
406 generated_solver_files = peano4.output.Jinja2TemplatedHeaderImplementationFilePair(
407 templatefile_prefix + ".template.h",
408 templatefile_prefix + ".template.cpp",
412 implementationDictionary,
416 output.add( generated_solver_files )
417 output.makefile.add_cpp_file( subdirectory + self._name + ".cpp", generated=True )
420# def _init_dictionary_with_default_parameters(self,d):
cardinality is a string (you can thus use symbols as well as long as they will be defined at compile ...
A very simple Poisson equation system solver to identify AMR transitions.
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.
add_use_data_statements_to_Peano4_solver_step(self, step)
Tell Peano what data to move around.
create_readme_descriptor(self, domain_offset, domain_size)
__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.
create_action_sets(self)
Overwrite in subclasses if you wanna create different action sets.
add_to_Peano4_datamodel(self, datamodel, verbose)
Add all required data to the Peano4 project's datamodel so it is properly built up.
get_name_of_global_instance(self)
create_data_structures(self)
_unknown_identifier(self)
_volumetric_coupling_term
Default superclass for any data model in Peano which is stored within the grid.
Represents the total output generated from the Peano4 data model plus all the operations on it.
name(self)
""" d["RIGHT_HAND_SIDE"] = self._right_hand_side d["RELAXATION_COEFFICIENT"] = self....