Peano
Loading...
Searching...
No Matches
DynamicMeshRefinementAnalysis.py
Go to the documentation of this file.
1# This file is part of the Peano project. For conditions of distribution and
2# use, please see the copyright notice at www.peano-framework.org
3from peano4.solversteps.ActionSet import ActionSet
4
5
6import jinja2
7import dastgen2
8import peano4
9
10
12 """!
13
14 AMR criterion based upon the particle density
15
16 This implementation is almsot exactly the same as the toolbox variant,
17 but it does not work with a static field, but instead pipes all the
18 refinement events a global variable. Actually, it fuses two different
19 action sets of the toolbox: The actual stats over the markers which
20 count the particles and the translation fo this info into mesh refinement
21 and coarsening commands.
22
23 Different to the default toolbox variant, Swift's marker doesn't need to
24 distinguish a new and an old marker and we use the marker information
25 straightaway throughout the steps up.
26
27 Please consult the constructor, i.e. __init__(), for some information
28 on algorithm variants and the implementation.
29
30 To understand the code's behaviour, it is resonable to read through
31 @ref peano_amr_tex "Peano's generic AMR description".
32
33 """
34
35 def marker_name(name):
36 return name + "CellStatistics"
37
39 """
40
41 Create the cell marker that is used by the analysis
42
43 t.b.d.
44
45 """
46 cell_marker = peano4.datamodel.DaStGen2(
47 DynamicMeshRefinementAnalysis.marker_name(name)
48 )
49
50 cell_marker.data.add_attribute(dastgen2.attributes.Integer("NumberOfParticles"))
51 cell_marker.data.add_attribute(
52 dastgen2.attributes.Boolean("ParentOfRefinedCell")
53 )
54 cell_marker.peano4_mpi_and_storage_aspect.store_predicate = "false"
55 cell_marker.peano4_mpi_and_storage_aspect.load_predicate = "false"
56
57 return cell_marker
58
60 self,
61 particle_set,
62 min_particles_per_cell=1,
63 max_particles_per_cell=65536,
64 min_h=0.1,
65 max_h=0.01,
66 scale_marker=0.95,
67 ):
68 """!
69
70 Construct the action set
71
72 ## Arguments
73
74 particle_set: peano4.toolbox.particles.ParticleSet
75 Instance of the particle set that is to be used as trigger. Each particle in the
76 set has a search radius and this one is used to guide the AMR.
77
78 min_particles_per_cell: Integer (>=0)
79 The tree is not refined if there are less than min_particles_per_cell particles
80 within the cell. By default, this parameter is set to 1 and thus the code refines
81 always if there are more than two particles held in a cell. You can set the value
82 to 0. In this case, we refine whenever there's a particle in a cell and its search
83 radius would allow us to refine further. Set
84 it to a higher number to ensure that there's (approximately) a certain particle
85 counter per cell.
86
87 max_particles_per_cell: Integer
88 Forces the code to refine if there are more than max_particles_per_cell
89 particles held. Has to be bigger or equal to min_particles_per_cell.
90
91 Whenever the AMR criterion refines, it can happen that particles do not
92 drop down further, as their search radius is too small.
93
94 You can also set this argument to zero as well. In this case, the action
95 sets refines all the way down until the mesh size just fits the search
96 radius. It even refines a cell if there's only one particle in it.
97
98 scale_marker: Float
99 In principle, many particle codes create a mesh that is by magnitudes
100 too fine. Therefore, it makes sense to make the refinement events a
101 little bit smaller than the actual underlying cell. However, if they are
102 small, the ::peano4::grid::merge() operation might not be able to fuse
103 them, i.e. you have to be careful that you increase the tolerance there
104 in return.
105
106 """
107 if min_particles_per_cell < 0:
108 raise Exception(
109 "invalid min number of particles pre cell (has to be positive): {}".format(
110 min_particles_per_cell
111 )
112 )
113
114 if (
115 max_particles_per_cell < min_particles_per_cell
116 or max_particles_per_cell < 0
117 ):
118 raise Exception(
119 "max number of particles ({}) has to be bigger or equal to min number ({}) and it has to be positive".format(
120 max_particles_per_cell, min_particles_per_cell
121 )
122 )
123
124 self.d = {
125 "CELL_DATA_NAME": DynamicMeshRefinementAnalysis.marker_name(
126 particle_set.name
127 ),
128 "MIN_PARTICLES_PER_CELL": min_particles_per_cell,
129 "MAX_PARTICLES_PER_CELL": max_particles_per_cell,
130 "MIN_H": min_h,
131 "MAX_H": max_h,
132 "PARTICLE_SET": particle_set.name,
133 "PARTICLE": particle_set.particle_model.name,
134 "SCALE_MARKER": scale_marker,
135 }
136 pass
137
139 return False
140
141 __Template_TouchCellFirstTime = jinja2.Template(
142 """
143 fineGridCell{{CELL_DATA_NAME}}.setNumberOfParticles(0);
144 fineGridCell{{CELL_DATA_NAME}}.setParentOfRefinedCell( false );
145"""
146 )
147
148 __Template_CreateCell = jinja2.Template(
149 """
150 fineGridCell{{CELL_DATA_NAME}}.setNumberOfParticles( std::numeric_limits<int>::max() );
151 fineGridCell{{CELL_DATA_NAME}}.setParentOfRefinedCell( true );
152"""
153 )
154
155 __Template_TouchCellLastTime = jinja2.Template(
156 """
157 /*
158
159 Local particles
160 ===============
161
162 Determine local number of particles associated with the adjacent
163 vertices.
164
165 */
166 int count = 0;
167 for (int i=0; i<TwoPowerD; i++) {
168 count += fineGridVertices{{PARTICLE_SET}}(i).size();
169 }
170
171
172 /*
173
174 Determine local counter
175 =======================
176
177 We might already have received data from finer cells (if we are
178 in a refined cell), so we add the data. We might also be in a
179 newly generated cell, where adding new particles might cause an
180 overflow. So I protect the accumulation.
181
182 */
183 if ( fineGridCell{{CELL_DATA_NAME}}.getNumberOfParticles() < std::numeric_limits<int>::max() ) {
184 fineGridCell{{CELL_DATA_NAME}}.setNumberOfParticles(
185 fineGridCell{{CELL_DATA_NAME}}.getNumberOfParticles()
186 +
187 count
188 );
189 }
190
191 /*
192
193 Restrict the particle count to the next coarser level
194 =====================================================
195
196 */
197 coarseGridCell{{CELL_DATA_NAME}}.setNumberOfParticles(
198 coarseGridCell{{CELL_DATA_NAME}}.getNumberOfParticles()
199 +
200 fineGridCell{{CELL_DATA_NAME}}.getNumberOfParticles()
201 );
202
203 if ( marker.willBeRefined() ) {
204 coarseGridCell{{CELL_DATA_NAME}}.setParentOfRefinedCell( true );
205 }
206
207 /*
208
209 To understand the code's behaviour, it is resonable to read through
210 @ref peano_amr_tex "Peano's generic AMR description".
211
212 Refine
213 ======
214
215 Refine if we have not yet reached the finest mesh resolution and violate
216 the max particle count. This implies that we actually get a mesh which is
217 slightly finer then min_h or this species.
218
219 Erase
220 =====
221
222 If we want to erase a cell, we actually make the region that is to be
223 erased slightly bigger. This is in line with @ref peano_amr_tex "Peano's generic AMR description".
224 Furthermore, we mark only refined cells
225 one level above the finest mesh. These are cells which will be refined and
226 have been refined, and also carry only few particles such that we could
227 safely erase their children plus have no refined children. To find out if
228 this holds for a cell, we look at the flag getParentOfRefinedCell().
229
230 */
231 if (
232 not marker.willBeRefined()
233 and
234 fineGridCell{{CELL_DATA_NAME}}.getNumberOfParticles() > {{MAX_PARTICLES_PER_CELL}}
235 ) {
236 const double ScaleMarker = {{SCALE_MARKER}};
237 peano4::grid::GridControlEvent newEntry;
238 newEntry.setRefinementControl( peano4::grid::GridControlEvent::RefinementControl::Refine );
239 newEntry.setOffset( marker.getOffset() + marker.h() * (1.0-ScaleMarker) / 2.0 );
240 newEntry.setWidth( marker.h() * ScaleMarker );
241 newEntry.setH(
242 tarch::la::greater( marker.h()(0), {{MIN_H}} ) ? marker.h()/3.0 * 1.1 : marker.h() * 1.1
243 );
244 _localGridControlEvents.push_back(newEntry);
245 logDebug( "touchCellLastTime(...)", "add " << newEntry.toString() );
246 }
247
248 if (
249 marker.willBeRefined()
250 and
251 marker.hasBeenRefined()
252 and
253 fineGridCell{{CELL_DATA_NAME}}.getNumberOfParticles() <= {{MIN_PARTICLES_PER_CELL}}
254 and
255 not fineGridCell{{CELL_DATA_NAME}}.getParentOfRefinedCell()
256 and
257 marker.h()(0)<{{MAX_H}} // we will remove the suboctants
258 ) {
259 const double ScaleMarker = 3.0 * (1.0+{{SCALE_MARKER}});
260 peano4::grid::GridControlEvent newEntry;
261 newEntry.setRefinementControl( peano4::grid::GridControlEvent::RefinementControl::Erase );
262 newEntry.setOffset( marker.getOffset() + marker.h() * (1.0-ScaleMarker) / 2.0 );
263 newEntry.setWidth( marker.h() * ScaleMarker );
264 newEntry.setH( marker.h() * ScaleMarker );
265 _localGridControlEvents.push_back(newEntry);
266 logDebug( "touchCellLastTime(...)", "add " << newEntry.toString() );
267 }
268"""
269 )
270
271 __Template_EndTraversal = jinja2.Template(
272 """
273 static tarch::multicore::BooleanSemaphore semaphore;
274 tarch::multicore::Lock lock(semaphore);
275
276 _newGridControlEvents.insert( _newGridControlEvents.end(), _localGridControlEvents.begin(), _localGridControlEvents.end() );
277"""
278 )
279
280 def get_body_of_operation(self, operation_name):
281 result = "\n"
282 if operation_name == ActionSet.OPERATION_BEGIN_TRAVERSAL:
283 result = """
284 _localGridControlEvents.clear();
285"""
286 if operation_name == ActionSet.OPERATION_CREATE_CELL:
287 result = self.__Template_CreateCell.render(**self.d)
288 if operation_name == ActionSet.OPERATION_TOUCH_CELL_FIRST_TIME:
289 result = self.__Template_TouchCellFirstTime.render(**self.d)
290 if operation_name == ActionSet.OPERATION_TOUCH_CELL_LAST_TIME:
291 result = self.__Template_TouchCellLastTime.render(**self.d)
292 if operation_name == ActionSet.OPERATION_END_TRAVERSAL:
293 result = self.__Template_EndTraversal.render(**self.d)
294 return result
295
296 # def get_body_of_getGridControlEvents(self):
297 # return """
298 # return ::swift2::committedGridControlEvents;
299 # """
300
301 def get_attributes(self):
302 return """
303 std::list< peano4::grid::GridControlEvent > _localGridControlEvents;
304 static std::list< peano4::grid::GridControlEvent > _newGridControlEvents;
305"""
306
308 return __name__.replace(".py", "").replace(".", "_")
309
310 def get_static_initialisations(self, full_qualified_classname):
311 return (
312 """
313std::list< peano4::grid::GridControlEvent > """
314 + full_qualified_classname
315 + """::_newGridControlEvents;
316"""
317 )
318
319 def get_includes(self):
320 result = jinja2.Template(
321 """
322#include "tarch/multicore/Lock.h"
323#include "vertexdata/{{PARTICLE_SET}}.h"
324#include "globaldata/{{PARTICLE}}.h"
325#include "peano4/grid/grid.h"
326#include "swift2/GridControlEvents.h"
327
328#include <list>
329"""
330 )
331 return result.render(**self.d)
332
334 return """
335::swift2::commitGridControlEvents( _newGridControlEvents );
336_newGridControlEvents.clear();
337"""
Default superclass for any data model in Peano which is stored within the grid.
Definition DaStGen2.py:47
Action set (reactions to events)
Definition ActionSet.py:6
get_attributes(self)
Return attributes as copied and pasted into the generated class.
get_body_of_operation(self, operation_name)
Return actual C++ code snippets to be inserted into C++ code.
__init__(self, particle_set, min_particles_per_cell=1, max_particles_per_cell=65536, min_h=0.1, max_h=0.01, scale_marker=0.95)
Construct the action set.