Peano
Loading...
Searching...
No Matches
ReconstructPatchAndApplyFunctor.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 enum import IntEnum
4
5from peano4.solversteps.ActionSet import ActionSet
6
8 """
9 All arrays are held on the call stack. Might not work with PGI compilers or
10 Clang, but it does work with GCC and Intel. This mode is the preferred one,
11 as all memory frees are implicitly done.
12 """
13 CallStack = 0,
14 """
15 Create data on the heap. Done via a plain new. You have to delete the
16 reconstructed data yourself.
17 """
18 Heap = 1,
19 HeapWithoutDelete = 2,
20 """
21 Use tarch::allocateMemory()
22 """
23 HeapThroughTarch = 3,
24 HeapThroughTarchWithoutDelete = 4,
25 """
26 Use tarch::allocateMemory()
27 """
28 ManagedSharedAcceleratorDeviceMemoryThroughTarch = 5,
29 ManagedSharedAcceleratorDeviceMemoryThroughTarchWithoutDelete = 6
30
31
33 """!
34
35 This class assumes that you have NxNxN patch within your block. It also assumes that
36 you have an 2MxNxN patch on your faces. M<N. The code interprets these face-associated
37 data as overlap with the patch, hooks into touchCellLastTime, and projects the cell's
38 patch data onto the overlap (simple copy). See ProjectPatchOntoFaces for details.
39
40 If the face patches are auxiliary patches holding copies from the cell patches, then
41 we can reconstruct N+2M x N+2M x N+2M patches per cell whenever we hit a cell: We
42 create a new temporary array, and copy data from both the cell patch and the faces
43 into this array (gather operation). After that, we can launch the passed functor
44 giving it access to the temporary, large array plus the original patch data.
45
46 If you want to swap the functor, please replace self.functor_implementation,
47 and ensure that all external references (text replacements) are already
48 resolved. Consult _add_action_set_entries_to_dictionary() for details.
49
50 """
51
52 def __init__(self,
53 patch,
54 patch_overlap,
55 functor_implementation,
56 reconstructed_array_memory_location=ReconstructedArrayMemoryLocation.Heap,
57 guard="true",
58 add_assertions_to_halo_exchange = True
59 ):
60 """!
61
62 patch: peano4.datamodel.Patch
63 Patch which is to be used
64
65 patch_overlap: peano4.datamodel.Patch
66 Consult remark above about how the dimensions of this overlap
67 patch have to match
68
69 ## Functor_implementation
70
71 The functor implementation is a plain C/C++
72
73 - If you want to use brackets in your implementation, please use double brackets {{ }} as
74 the template system otherwise gets confused.
75 - The following C++ variables are defined:
76
77 oldQWithHalo
78 newQ
79
80 Both are plain double pointers.
81
82 ## Data validation
83
84 I use quite a lot of validitiy checks for the copied data via comparison to its self. This
85 way, I can at least spot nans. I use the dictionary entries ASSERTION_WITH_X_ARGUMENTS to
86 realise this, and they are, by default, set to Peano's assertion macros. You can redefine
87 them.
88
89 """
90 super(ReconstructPatchAndApplyFunctor,self).__init__(descend_invocation_order=1,parallel=False)
91
92 assert isinstance(reconstructed_array_memory_location,ReconstructedArrayMemoryLocation), "type of argument is {}".format( type(reconstructed_array_memory_location) )
93
94 if patch_overlap.dim[0] % 2 != 0:
95 print( "Error: Patch associated to face has to have even number of cells. Otherwise, it is not a symmetric overlap." )
96 assert( patch_overlap.dim[0] % 2 == 0 )
97 if patch.dim[0] != patch.dim[1]:
98 print( "Error: Can only handle square patches." )
99 assert( patch.dim[0] == patch.dim[1] )
100 if patch_overlap.dim[1] != patch.dim[0]:
101 print( "Error: Patch of overlap and patch of cell have to match" )
102 assert( patch_overlap.dim[1] == patch.dim[0] )
103
104 self.guard = guard
105 self.no_of_unknowns = int(patch.no_of_unknowns)
106 self.dofs_per_axis = int(patch.dim[0])
107 self.total_overlap = int(patch_overlap.dim[0])
108 self.overlap_name = patch_overlap.name
109 self.patch_name = patch.name
110
111 self.functor_implementation = functor_implementation
112 self.add_assertions_to_halo_exchange = add_assertions_to_halo_exchange
113 self.reconstructed_array_memory_location = reconstructed_array_memory_location
114
115
117 """!
118
119 Befill dictionary
120
121 If you inherit from this class and specialise this routine, you can add
122 more entries to the dictionary. This is important if you change the
123 actual compute kernels (templates) and use futher unknowns in there. If
124 you specialise the function, i.e. overwrite it in a subclass, please
125 ensure that you use the superclass still.
126
127 Please note that we do not replace entries in the functor implementation:
128 The overall code created by this action set consists of different parts
129 realised as different templates. The templates are subject to a text
130 replacement system and then are concatenated. One of the things that is
131 replaced within the templates is the actual functor implementation
132 (CELL_FUNCTOR_IMPLEMENTATION). If this one contains again free parameters,
133 it is your responsibility to first resolve those parameters, and then to
134 reset the functor in this routine.
135
136 If you want to replace the functor, you can hence either first call this
137 routine and then change d["CELL_FUNCTOR_IMPLEMENTATION"] or you set
138 self.functor_implementation and then you call this routine, i.e. the
139 superclass.
140
141 """
142 d[ "GUARD" ] = self.guard
143
144 assert isinstance(self.no_of_unknowns,int)
145 assert isinstance(self.dofs_per_axis,int)
146 assert isinstance(self.total_overlap,int)
147
148 d[ "UNKNOWNS" ] = str(self.no_of_unknowns)
149 d[ "DOFS_PER_AXIS" ] = str(self.dofs_per_axis)
150 d[ "OVERLAP" ] = str(int(self.total_overlap/2))
151 d[ "NUMBER_OF_DOUBLE_VALUES_IN_ORIGINAL_PATCH_2D" ] = str(self.no_of_unknowns * self.dofs_per_axis * self.dofs_per_axis)
152 d[ "NUMBER_OF_DOUBLE_VALUES_IN_ORIGINAL_PATCH_3D" ] = str(self.no_of_unknowns * self.dofs_per_axis * self.dofs_per_axis * self.dofs_per_axis)
153 d[ "NUMBER_OF_DOUBLE_VALUES_IN_RECONSTRUCTED_PATCH_2D" ] = str(self.no_of_unknowns * (self.total_overlap + self.dofs_per_axis) * (self.total_overlap + self.dofs_per_axis))
154 d[ "NUMBER_OF_DOUBLE_VALUES_IN_RECONSTRUCTED_PATCH_3D" ] = str(self.no_of_unknowns * (self.total_overlap + self.dofs_per_axis) * (self.total_overlap + self.dofs_per_axis) * (self.total_overlap + self.dofs_per_axis))
155 d[ "FACES_ACCESSOR" ] = "fineGridFaces" + self.overlap_name
156 d[ "CELL_ACCESSOR" ] = "fineGridCell" + self.patch_name
157
158 d[ "ASSERTION_WITH_1_ARGUMENTS" ] = "assertion1"
159 d[ "ASSERTION_WITH_2_ARGUMENTS" ] = "assertion2"
160 d[ "ASSERTION_WITH_3_ARGUMENTS" ] = "assertion3"
161 d[ "ASSERTION_WITH_4_ARGUMENTS" ] = "assertion4"
162 d[ "ASSERTION_WITH_5_ARGUMENTS" ] = "assertion5"
163 d[ "ASSERTION_WITH_6_ARGUMENTS" ] = "assertion6"
164 d[ "ASSERTION_WITH_7_ARGUMENTS" ] = "assertion7"
165
166 d[ "CELL_FUNCTOR_IMPLEMENTATION" ] = self.functor_implementation
167
169 d[ "ASSERTION_PREFIX_FOR_HALO" ] = "false"
170 else:
171 d[ "ASSERTION_PREFIX_FOR_HALO" ] = "true"
172
173 if self.reconstructed_array_memory_location==ReconstructedArrayMemoryLocation.Heap or self.reconstructed_array_memory_location==ReconstructedArrayMemoryLocation.HeapWithoutDelete:
174 d[ "CREATE_RECONSTRUCTED_PATCH" ] = """
175 #if Dimensions==2
176 double* oldQWithHalo = new double[""" + d[ "NUMBER_OF_DOUBLE_VALUES_IN_RECONSTRUCTED_PATCH_2D" ] + """];
177 #elif Dimensions==3
178 double* oldQWithHalo = new double[""" + d[ "NUMBER_OF_DOUBLE_VALUES_IN_RECONSTRUCTED_PATCH_3D" ] + """];
179 #endif
180"""
181 elif self.reconstructed_array_memory_location==ReconstructedArrayMemoryLocation.CallStack:
182 d[ "CREATE_RECONSTRUCTED_PATCH" ] = """
183 #if Dimensions==2
184 double oldQWithHalo[""" + d[ "NUMBER_OF_DOUBLE_VALUES_IN_RECONSTRUCTED_PATCH_2D" ] + """];
185 #elif Dimensions==3
186 double oldQWithHalo[""" + d[ "NUMBER_OF_DOUBLE_VALUES_IN_RECONSTRUCTED_PATCH_3D" ] + """];
187 #endif
188"""
189 elif self.reconstructed_array_memory_location==ReconstructedArrayMemoryLocation.HeapThroughTarch or self.reconstructed_array_memory_location==ReconstructedArrayMemoryLocation.HeapThroughTarchWithoutDelete:
190 d[ "CREATE_RECONSTRUCTED_PATCH" ] = """
191 #if Dimensions==2
192 double* oldQWithHalo = ::tarch::allocateMemory<double>(""" + d[ "NUMBER_OF_DOUBLE_VALUES_IN_RECONSTRUCTED_PATCH_2D" ] + """, ::tarch::MemoryLocation::ManagedSharedAcceleratorDeviceMemory);
193 #elif Dimensions==3
194 double* oldQWithHalo = ::tarch::allocateMemory<double>(""" + d[ "NUMBER_OF_DOUBLE_VALUES_IN_RECONSTRUCTED_PATCH_3D" ] + """, ::tarch::MemoryLocation::ManagedSharedAcceleratorDeviceMemory);
195 #endif
196"""
197 elif self.reconstructed_array_memory_location==ReconstructedArrayMemoryLocation.ManagedSharedAcceleratorDeviceMemoryThroughTarch or self.reconstructed_array_memory_location==ReconstructedArrayMemoryLocation.ManagedSharedAcceleratorDeviceMemoryThroughTarchWithoutDelete:
198 d[ "CREATE_RECONSTRUCTED_PATCH" ] = """
199 #if Dimensions==2
200 double* oldQWithHalo = ::tarch::allocateMemory<double>(""" + d[ "NUMBER_OF_DOUBLE_VALUES_IN_RECONSTRUCTED_PATCH_2D" ] + """, ::tarch::MemoryLocation::ManagedSharedAcceleratorDeviceMemory);
201 #elif Dimensions==3
202 double* oldQWithHalo = ::tarch::allocateMemory<double>(""" + d[ "NUMBER_OF_DOUBLE_VALUES_IN_RECONSTRUCTED_PATCH_3D" ] + """, ::tarch::MemoryLocation::ManagedSharedAcceleratorDeviceMemory);
203 #endif
204"""
205 else:
206 raise Exception( "Error: memory allocation mode {} for patch reconstruction not known".format(self.reconstructed_array_memory_location) )
207
208 if self.reconstructed_array_memory_location==ReconstructedArrayMemoryLocation.Heap:
209 d[ "DESTROY_RECONSTRUCTED_PATCH" ] = """
210 delete[] oldQWithHalo;
211"""
212 elif self.reconstructed_array_memory_location==ReconstructedArrayMemoryLocation.HeapThroughTarch:
213 d[ "DESTROY_RECONSTRUCTED_PATCH" ] = """
214 ::tarch::freeMemory(oldQWithHalo, tarch::MemoryLocation::Heap );
215"""
216 elif self.reconstructed_array_memory_location==ReconstructedArrayMemoryLocation.ManagedSharedAcceleratorDeviceMemoryThroughTarch:
217 d[ "DESTROY_RECONSTRUCTED_PATCH" ] = """
218 ::tarch::freeMemory(oldQWithHalo, tarch::MemoryLocation::ManagedSharedAcceleratorDeviceMemory );
219"""
220 else:
221 d[ "DESTROY_RECONSTRUCTED_PATCH" ] = ""
222
224 return """ _treeNumber = treeNumber;
225"""
226
227
229 return __name__.replace(".py", "").replace(".", "_")
230
231
233 return False
234
235
236 _Template_TouchCellFirstTime_Preamble = """
237 auto serialisePatchIndex = [](tarch::la::Vector<Dimensions,int> overlapCell, int normal) {{
238 int base = 1;
239 int result = 0;
240 for (int d=0; d<Dimensions; d++) {{
241 result += overlapCell(d) * base;
242 if (d==normal) {{
243 base *= {OVERLAP}*2;
244 }}
245 else {{
246 base *= {DOFS_PER_AXIS};
247 }}
248 }}
249 return result;
250 }};
251
252 if ({GUARD}) {{
253 logTraceInWith1Argument( "touchCellFirstTime(...)", marker.toString() );
254
255 {CREATE_RECONSTRUCTED_PATCH}
256"""
257
258
259 _Template_TouchCellFirstTime_Fill_Patch = """
260 //
261 // Loop over original patch (k) and copy stuff over.
262 //
263 dfor(sourceCell,{DOFS_PER_AXIS}) {{
264 tarch::la::Vector<Dimensions,int> destinationCell = sourceCell + tarch::la::Vector<Dimensions,int>({OVERLAP});
265 int sourceCellSerialised = peano4::utils::dLinearised(sourceCell,{DOFS_PER_AXIS});
266 int destinationCellSerialised = peano4::utils::dLinearised(destinationCell,{DOFS_PER_AXIS} + 2*{OVERLAP});
267 for (int j=0; j<{UNKNOWNS}; j++) {{
268 oldQWithHalo[destinationCellSerialised*{UNKNOWNS}+j] = {CELL_ACCESSOR}.value[ sourceCellSerialised*{UNKNOWNS}+j ];
269 {ASSERTION_WITH_4_ARGUMENTS}( oldQWithHalo[destinationCellSerialised*{UNKNOWNS}+j]==oldQWithHalo[destinationCellSerialised*{UNKNOWNS}+j], sourceCell, j, _treeNumber, marker.toString() );
270 }}
271 }}
272"""
273
274
275 _Template_TouchCellFirstTime_Fill_Halos = """
276 //
277 // Bring in the auxiliary patches, i.e. befill halo
278 //
279 for(int d=0; d<Dimensions; d++) {{
280 logTraceInWith1Argument( "touchCellFirstTime(...)::loopOverFace", d );
281 //
282 // d-loop over all dimensions except d. The vector k's entry d is set
283 // to 0. We start with the left/bottom face, i.e. the one closer to the
284 // coordinate system's origin.
285 //
286 dfore(k,{DOFS_PER_AXIS},d,0) {{
287 for (int i=0; i<{OVERLAP}; i++) {{
288 tarch::la::Vector<Dimensions,int> destinationCell = k + tarch::la::Vector<Dimensions,int>({OVERLAP});
289 tarch::la::Vector<Dimensions,int> sourceCell = k;
290 destinationCell(d) = i;
291 sourceCell(d) = i;
292
293 int destinationCellSerialised = peano4::utils::dLinearised(destinationCell,{DOFS_PER_AXIS} + 2*{OVERLAP});
294 int sourceCellSerialised = serialisePatchIndex(sourceCell,d);
295
296 for (int j=0; j<{UNKNOWNS}; j++) {{
297 oldQWithHalo[ destinationCellSerialised*{UNKNOWNS}+j ] = {FACES_ACCESSOR}(d).value[ sourceCellSerialised*{UNKNOWNS}+j ];
298 {ASSERTION_WITH_7_ARGUMENTS}(
299 {ASSERTION_PREFIX_FOR_HALO} or
300 oldQWithHalo[ destinationCellSerialised*{UNKNOWNS}+j ]==oldQWithHalo[ destinationCellSerialised*{UNKNOWNS}+j ],
301 sourceCell, destinationCell, j, d, marker.toString(), _treeNumber, marker.toString()
302 );
303 }}
304
305 destinationCell(d) = i+{DOFS_PER_AXIS}+{OVERLAP};
306 sourceCell(d) = i+{OVERLAP};
307
308 destinationCellSerialised = peano4::utils::dLinearised(destinationCell,{DOFS_PER_AXIS} + 2*{OVERLAP});
309 sourceCellSerialised = serialisePatchIndex(sourceCell,d);
310 for (int j=0; j<{UNKNOWNS}; j++) {{
311 oldQWithHalo[ destinationCellSerialised*{UNKNOWNS}+j ] = {FACES_ACCESSOR}(d+Dimensions).value[ sourceCellSerialised*{UNKNOWNS}+j ];
312 {ASSERTION_WITH_7_ARGUMENTS}(
313 {ASSERTION_PREFIX_FOR_HALO} or
314 oldQWithHalo[ destinationCellSerialised*{UNKNOWNS}+j ]==oldQWithHalo[ destinationCellSerialised*{UNKNOWNS}+j ],
315 sourceCell, destinationCell, j, d, marker.toString(), _treeNumber, marker.toString()
316 );
317 }}
318 }}
319 }}
320 logTraceOut( "touchCellFirstTime(...)::loopOverFace" );
321 }}
322"""
323
324
325 _Template_TouchCellFirstTime_Core = """
326 double* newQ = {CELL_ACCESSOR}.value;
327 {CELL_FUNCTOR_IMPLEMENTATION}
328
329 {DESTROY_RECONSTRUCTED_PATCH}
330"""
331
332
333 _Template_TouchCellFirstTime_Epilogue = """
334 logTraceOut( "touchCellFirstTime(...)" );
335 }}
336"""
337
338
339 def get_body_of_operation(self,operation_name):
340 result = "\n"
341 if operation_name==ActionSet.OPERATION_TOUCH_CELL_FIRST_TIME:
342 d = {}
344 result = self._Template_TouchCellFirstTime_Preamble.format(**d)
345 result += self._Template_TouchCellFirstTime_Fill_Patch.format(**d)
346 result += self._Template_TouchCellFirstTime_Fill_Halos.format(**d)
347 result += self._Template_TouchCellFirstTime_Core.format(**d)
348 result += self._Template_TouchCellFirstTime_Epilogue.format(**d)
349 pass
350 return result
351
352
353 def get_attributes(self):
354 return """int _treeNumber;
355"""
356
357
358 def get_includes(self):
359 return """
360#include <functional>
361#include "peano4/utils/Loop.h"
362#include "tarch/multicore/Core.h"
363"""
#define assert(...)
Definition LinuxAMD.h:28
Action set (reactions to events)
Definition ActionSet.py:6
__init__(self, patch, patch_overlap, functor_implementation, reconstructed_array_memory_location=ReconstructedArrayMemoryLocation.Heap, guard="true", add_assertions_to_halo_exchange=True)
patch: peano4.datamodel.Patch Patch which is to be used
get_body_of_operation(self, operation_name)
Return actual C++ code snippets to be inserted into C++ code.