Peano
Loading...
Searching...
No Matches
ReconstructPatchWithHalo.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.api.solversteps.ActionSet import ActionSet
4
5
7 """!
8
9 Reconstruct a cell patch together with its halo into a separate,
10 already-declared reconstructed_patch cell submodel.
11
12 This class assumes that you have an NxNxN patch within your block. It also
13 assumes that you have a 2MxNxN patch on your faces, M<N. The code
14 interprets these face-associated data as overlap with the patch, hooks
15 into touchCellFirstTime, and gathers the cell patch and its face-associated
16 overlaps into reconstructed_patch - a real, separately-declared cell
17 submodel of shape (N+2M)x(N+2M)x(N+2M) (@see ProjectPatchOntoFaces for the
18 counterpart that fills the face-associated overlap patches in the first
19 place).
20
21 reconstructed_patch is not a scratch array this class allocates and frees
22 itself - it is a proper Peano-managed cell submodel handed in directly by
23 the caller (declared on the surrounding Task/Step the same way patch and
24 patch_overlap are), so this class never has to choose where or how to
25 allocate memory for it: it simply writes into reconstructed_patch's own
26 accessor.
27
28 @see ReconstructPatchAndApplyFunctor, which extends this with an
29 additional functor invoked once the reconstruction is done.
30
31 """
32
33 def __init__(self,
34 patch,
35 patch_overlap,
36 reconstructed_patch,
37 guard="true",
38 add_assertions_to_halo_exchange = True,
39 additional_includes = ""
40 ):
41 """!
42
43 patch: peano4.api.datamodel.Patch
44 Patch which is to be used
45
46 patch_overlap: peano4.api.datamodel.Patch
47 Consult remark above about how the dimensions of this overlap
48 patch have to match
49
50 reconstructed_patch: peano4.api.datamodel.Patch
51 Where to write the reconstructed patch-plus-halo to - has to already be
52 declared (use_cell()) on the surrounding Task/Step, just like patch and
53 patch_overlap, and its dimensions have to be patch's plus twice
54 patch_overlap's overlap width, per axis.
55
56 additional_includes: str
57 Further includes this action set's generated code needs - e.g. a
58 solver's own default and user includes.
59
60 ## Data validation
61
62 I use quite a lot of validitiy checks for the copied data via comparison to its self. This
63 way, I can at least spot nans. I use the dictionary entries ASSERTION_WITH_X_ARGUMENTS to
64 realise this, and they are, by default, set to Peano's assertion macros. You can redefine
65 them.
66
67 """
68 super(ReconstructPatchWithHalo,self).__init__(descend_invocation_order=1,parallel=False)
69
70 if patch_overlap.dim[0] % 2 != 0:
71 print( "Error: Patch associated to face has to have even number of cells. Otherwise, it is not a symmetric overlap." )
72 assert( patch_overlap.dim[0] % 2 == 0 )
73 if patch.dim[0] != patch.dim[1]:
74 print( "Error: Can only handle square patches." )
75 assert( patch.dim[0] == patch.dim[1] )
76 if patch_overlap.dim[1] != patch.dim[0]:
77 print( "Error: Patch of overlap and patch of cell have to match" )
78 assert( patch_overlap.dim[1] == patch.dim[0] )
79 if reconstructed_patch.dim[0] != patch.dim[0] + patch_overlap.dim[0]:
80 print( "Error: reconstructed_patch has to be patch's plus patch_overlap's full width per axis." )
81 assert( reconstructed_patch.dim[0] == patch.dim[0] + patch_overlap.dim[0] )
82
83 self.guard = guard
84 self.no_of_unknowns = int(patch.no_of_unknowns)
85 self.dofs_per_axis = int(patch.dim[0])
86 self.total_overlap = int(patch_overlap.dim[0])
87 self.overlap_name = patch_overlap.name
88 self.patch_name = patch.name
89 self.reconstructed_patch_name = reconstructed_patch.name
90
91 self.add_assertions_to_halo_exchange = add_assertions_to_halo_exchange
92 self.additional_includes = additional_includes
93
94
96 """!
97
98 Befill dictionary
99
100 If you inherit from this class and specialise this routine, you can add
101 more entries to the dictionary. This is important if you change the
102 actual compute kernels (templates) and use futher unknowns in there. If
103 you specialise the function, i.e. overwrite it in a subclass, please
104 ensure that you use the superclass still.
105
106 """
107 d[ "GUARD" ] = self.guard
108
109 assert isinstance(self.no_of_unknowns,int)
110 assert isinstance(self.dofs_per_axis,int)
111 assert isinstance(self.total_overlap,int)
112
113 d[ "UNKNOWNS" ] = str(self.no_of_unknowns)
114 d[ "DOFS_PER_AXIS" ] = str(self.dofs_per_axis)
115 d[ "OVERLAP" ] = str(int(self.total_overlap/2))
116 d[ "NUMBER_OF_DOUBLE_VALUES_IN_ORIGINAL_PATCH_2D" ] = str(self.no_of_unknowns * self.dofs_per_axis * self.dofs_per_axis)
117 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)
118 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))
119 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))
120 d[ "FACES_ACCESSOR" ] = "fineGridFaces" + self.overlap_name
121 d[ "CELL_ACCESSOR" ] = "fineGridCell" + self.patch_name
122 d[ "RECONSTRUCTED_PATCH_ACCESSOR" ] = "fineGridCell" + self.reconstructed_patch_name
123
124 d[ "ASSERTION_WITH_1_ARGUMENTS" ] = "assertion1"
125 d[ "ASSERTION_WITH_2_ARGUMENTS" ] = "assertion2"
126 d[ "ASSERTION_WITH_3_ARGUMENTS" ] = "assertion3"
127 d[ "ASSERTION_WITH_4_ARGUMENTS" ] = "assertion4"
128 d[ "ASSERTION_WITH_5_ARGUMENTS" ] = "assertion5"
129 d[ "ASSERTION_WITH_6_ARGUMENTS" ] = "assertion6"
130 d[ "ASSERTION_WITH_7_ARGUMENTS" ] = "assertion7"
131
133 d[ "ASSERTION_PREFIX_FOR_HALO" ] = "false"
134 else:
135 d[ "ASSERTION_PREFIX_FOR_HALO" ] = "true"
136
137
139 return ""
140
141
143 return __name__.replace(".py", "").replace(".", "_")
144
145
147 return False
148
149
150 _Template_TouchCellFirstTime_Preamble = """
151 auto serialisePatchIndex = [](tarch::la::Vector<Dimensions,int> overlapCell, int normal) {{
152 int base = 1;
153 int result = 0;
154 for (int d=0; d<Dimensions; d++) {{
155 result += overlapCell(d) * base;
156 if (d==normal) {{
157 base *= {OVERLAP}*2;
158 }}
159 else {{
160 base *= {DOFS_PER_AXIS};
161 }}
162 }}
163 return result;
164 }};
165
166 logTraceInWith1Argument( "touchCellFirstTime(...)", marker.toString() );
167
168 double* oldQWithHalo = {RECONSTRUCTED_PATCH_ACCESSOR}.value;
169"""
170
171
172 _Template_TouchCellFirstTime_Fill_Patch = """
173 //
174 // Loop over original patch (k) and copy stuff over.
175 //
176 dfor(sourceCell,{DOFS_PER_AXIS}) {{
177 tarch::la::Vector<Dimensions,int> destinationCell = sourceCell + tarch::la::Vector<Dimensions,int>({OVERLAP});
178 int sourceCellSerialised = peano4::utils::dLinearised(sourceCell,{DOFS_PER_AXIS});
179 int destinationCellSerialised = peano4::utils::dLinearised(destinationCell,{DOFS_PER_AXIS} + 2*{OVERLAP});
180 for (int j=0; j<{UNKNOWNS}; j++) {{
181 oldQWithHalo[destinationCellSerialised*{UNKNOWNS}+j] = {CELL_ACCESSOR}.value[ sourceCellSerialised*{UNKNOWNS}+j ];
182 {ASSERTION_WITH_4_ARGUMENTS}( oldQWithHalo[destinationCellSerialised*{UNKNOWNS}+j]==oldQWithHalo[destinationCellSerialised*{UNKNOWNS}+j], sourceCell, j, "Unknown Tree Number", marker.toString() );
183 }}
184 }}
185"""
186
187
188 _Template_TouchCellFirstTime_Fill_Halos = """
189 //
190 // Bring in the auxiliary patches, i.e. befill halo
191 //
192 for(int d=0; d<Dimensions; d++) {{
193 logTraceInWith1Argument( "touchCellFirstTime(...)::loopOverFace", d );
194 //
195 // d-loop over all dimensions except d. The vector k's entry d is set
196 // to 0. We start with the left/bottom face, i.e. the one closer to the
197 // coordinate system's origin.
198 //
199 dfore(k,{DOFS_PER_AXIS},d,0) {{
200 for (int i=0; i<{OVERLAP}; i++) {{
201 tarch::la::Vector<Dimensions,int> destinationCell = k + tarch::la::Vector<Dimensions,int>({OVERLAP});
202 tarch::la::Vector<Dimensions,int> sourceCell = k;
203 destinationCell(d) = i;
204 sourceCell(d) = i;
205
206 int destinationCellSerialised = peano4::utils::dLinearised(destinationCell,{DOFS_PER_AXIS} + 2*{OVERLAP});
207 int sourceCellSerialised = serialisePatchIndex(sourceCell,d);
208
209 for (int j=0; j<{UNKNOWNS}; j++) {{
210 oldQWithHalo[ destinationCellSerialised*{UNKNOWNS}+j ] = {FACES_ACCESSOR}(d).value[ sourceCellSerialised*{UNKNOWNS}+j ];
211 {ASSERTION_WITH_7_ARGUMENTS}(
212 {ASSERTION_PREFIX_FOR_HALO} or
213 oldQWithHalo[ destinationCellSerialised*{UNKNOWNS}+j ]==oldQWithHalo[ destinationCellSerialised*{UNKNOWNS}+j ],
214 sourceCell, destinationCell, j, d, marker.toString(), "Unknown Tree Number", marker.toString()
215 );
216 }}
217
218 destinationCell(d) = i+{DOFS_PER_AXIS}+{OVERLAP};
219 sourceCell(d) = i+{OVERLAP};
220
221 destinationCellSerialised = peano4::utils::dLinearised(destinationCell,{DOFS_PER_AXIS} + 2*{OVERLAP});
222 sourceCellSerialised = serialisePatchIndex(sourceCell,d);
223 for (int j=0; j<{UNKNOWNS}; j++) {{
224 oldQWithHalo[ destinationCellSerialised*{UNKNOWNS}+j ] = {FACES_ACCESSOR}(d+Dimensions).value[ sourceCellSerialised*{UNKNOWNS}+j ];
225 {ASSERTION_WITH_7_ARGUMENTS}(
226 {ASSERTION_PREFIX_FOR_HALO} or
227 oldQWithHalo[ destinationCellSerialised*{UNKNOWNS}+j ]==oldQWithHalo[ destinationCellSerialised*{UNKNOWNS}+j ],
228 sourceCell, destinationCell, j, d, marker.toString(), "Unknown Tree Number", marker.toString()
229 );
230 }}
231 }}
232 }}
233 logTraceOut( "touchCellFirstTime(...)::loopOverFace" );
234 }}
235"""
236
237
238 _Template_TouchCellFirstTime_Epilogue = """
239 logTraceOut( "touchCellFirstTime(...)" );
240"""
241
242
243 def get_body_of_operation(self,operation_name):
244 result = "\n"
245 if operation_name==ActionSet.OPERATION_TOUCH_CELL_FIRST_TIME:
246 d = {}
248 result = self._Template_TouchCellFirstTime_Preamble.format(**d)
249 result += self._Template_TouchCellFirstTime_Fill_Patch.format(**d)
250 result += self._Template_TouchCellFirstTime_Fill_Halos.format(**d)
251 result += self._Template_TouchCellFirstTime_Epilogue.format(**d)
252 pass
253 return result
254
255
256 def get_guard_of_operation(self,operation_name):
257 if operation_name==ActionSet.OPERATION_TOUCH_CELL_FIRST_TIME:
258 return self.guard
259 return "true"
260
261
262 def get_attributes(self):
263 return ""
264
265
266 def get_includes(self):
267 return """
268#include <functional>
269#include "peano4/utils/Loop.h"
270#include "tarch/multicore/Core.h"
271""" + self.additional_includes
#define assert(...)
Definition LinuxAMD.h:28
Reconstruct a cell patch together with its halo into a separate, already-declared reconstructed_patch...
get_guard_of_operation(self, operation_name)
Return the guard of an operation.
get_body_of_operation(self, operation_name)
Return actual C++ code snippets to be inserted into C++ code.
get_attributes(self)
Return attributes as copied and pasted into the generated class.
get_constructor_body(self)
Define a tailored constructor body.
user_should_modify_template(self)
Is the user allowed to modify the output.
__init__(self, patch, patch_overlap, reconstructed_patch, guard="true", add_assertions_to_halo_exchange=True, additional_includes="")
patch: peano4.api.datamodel.Patch Patch which is to be used
get_includes(self)
Return include statements that you need.
Action set (reactions to events)
Definition ActionSet.py:6