Peano
Loading...
Searching...
No Matches
DaStGen2.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 .DaStGenToLegacyTool import DaStGenToLegacyTool
4from .DoF import DoF
5
6import dastgen2
7
9
10import copy
11
12
13
14class DaStGen2Generator(object):
15 """!
16
17 Simple generator mapping a DaStGen2 object onto a plain C++ class
18
19 """
20 def __init__(self,data):
21 self._data = data
22
23
25 return "peano4::stacks::STDVectorStack< " + self._data.get_full_qualified_type() + " >";
26
27
29 return "#include \"peano4/stacks/STDVectorStack.h\" \n \
30 #include \"" + self._data.namespace[-1] + "/" + self._data.name + ".h\""
31
32
33 def construct_output(self,output):
34 """!
35
36 Finally construct the output
37
38 Pass in an instance of the output object. We use this output
39 object only to register the generated C++ file with the build
40 environment.
41
42 """
43 full_qualified_name = ""
44 for i in self._data.namespace:
45 full_qualified_name += i
46 full_qualified_name += "::"
47 full_qualified_name += self._data.name
48 self._data.data.set_full_qualified_name(full_qualified_name)
49
50 self._data.data.write_header_file( self._data.subdirectory + self._data.namespace[-1] + "/" + self._data.name + ".h" )
51 self._data.data.write_implementation_file( self._data.subdirectory + self._data.namespace[-1] + "/" + self._data.name + ".cpp" )
52 output.makefile.add_cpp_file( self._data.subdirectory + self._data.namespace[-1] + "/" + self._data.name + ".cpp", generated=True )
53
54
55
57 """!
58
59 Simple generator mapping a DaStGen2 object onto a plain C++ class
60
61 The generator is very similar to DaStGen2Generator, but it has to take
62 extra care as we assume that some objects host smart pointers. Therefore,
63 we do two things: We dump the smart pointer version, and we create a
64 flattene version, too.
65
66 """
67 def __init__(self,data):
68 self._data = data
69
70
72 return "peano4::stacks::STDVectorStackOverObjectsWithSmartPointers< " + self._data.get_full_qualified_type() + " >";
73
74
76 return "#include \"peano4/stacks/STDVectorStackOverObjectsWithSmartPointers.h\" \n \
77 #include \"" + self._data.namespace[-1] + "/" + self._data.name + ".h\""
78
79
80 def construct_output(self,output):
81 """!
82
83 Finally construct the output
84
85 Pass in an instance of the output object. We use this output
86 object only to register the generated C++ file with the build
87 environment. This part is exactly the same as for a plain 1:1
88 translation.
89
90 Further to the default generator, this routine does a little bit
91 more:
92
93 - Make a deep copy of the data object and replace each instance of
94 a smart pointer with its plain counterpart. This new data object
95 is identified by the extension _Flattened.
96 - Make the new helper data structure include the original class with
97 the smart pointers.
98 - Declare this one as an embedded type via using.
99 - Add a new copy constructor/conversion routine which really just maps
100 the two data types onto each other by using the setters and getters.
101
102 """
103 full_qualified_name = ""
104 for i in self._data.namespace:
105 full_qualified_name += i
106 full_qualified_name += "::"
107 full_qualified_name += self._data.name
108
109
110 flattened_data_object = copy.copy(self._data.data)
111 old_attributes = flattened_data_object._attributes
112 flattened_data_object._attributes = []
113 copy_statements = ""
114 for attribute in old_attributes:
115 if isinstance(attribute,peano4.dastgen2.Peano4SmartPointerDoubleArray):
116 flattened_data_object._attributes.append( peano4.dastgen2.Peano4DoubleArray( name = attribute._name,
117 cardinality = attribute._cardinality,
118 ifdefs = attribute.ifdefs
119 ))
120 else:
121 flattened_data_object._attributes.append( attribute )
122 if attribute.ifdefs==[]:
123 copy_statements += """
124result.set{}( static_cast<decltype(result.get{}())>( copy.get{}() ) );
125""".format(attribute.get_accessor_name(),
126 attribute.get_accessor_name(),
127 attribute.get_accessor_name()
128 )
129 else:
130 copy_statements += """
131{}
132result.set{}( static_cast<decltype(result.get{}())>( copy.get{}() ) );
133#endif
134""".format(dastgen2.Utils.construct_ifdef_string(attribute.ifdefs),
135 attribute.get_accessor_name(),
136 attribute.get_accessor_name(),
137 attribute.get_accessor_name(),
138 )
139
140
141 extension = "_Flattened"
142 full_qualified_name_flattened = full_qualified_name + extension
143 full_qualified_file_without_extension_flattened = self._data.subdirectory + self._data.namespace[-1] + "/" + self._data.name + extension
144
145
146 self._data.data.additional_includes += """
147#include "{}_Flattened.h"
148""".format(self._data.name)
149
150
151# flattened_data_object.additional_includes += """
152
154
155
156 self._data.data.public_fields = """
157 using FlattenedType = {}_Flattened;
158
159 static {} flatten(const {}& copy) {{
160 {} result;
161
162 {}
163
164 return result;
165 }}
166 static {} unflatten(const {}& copy) {{
167 {} result;
168
169 {}
170
171 return result;
172 }}
173""".format(self._data.name,
174#flatten
175 self._data.name + extension,
176 self._data.name,
177 self._data.name + extension,
178 copy_statements,
179# unflatten
180 self._data.name,
181 self._data.name + extension,
182 self._data.name,
183 copy_statements,
184 )
185
186 self._data.data.set_full_qualified_name(full_qualified_name)
187 self._data.data.write_header_file( self._data.subdirectory + self._data.namespace[-1] + "/" + self._data.name + ".h" )
188 self._data.data.write_implementation_file( self._data.subdirectory + self._data.namespace[-1] + "/" + self._data.name + ".cpp" )
189 output.makefile.add_cpp_file( self._data.subdirectory + self._data.namespace[-1] + "/" + self._data.name + ".cpp", generated=True )
190
191 flattened_data_object.set_full_qualified_name(full_qualified_name_flattened)
192 flattened_data_object.write_header_file( full_qualified_file_without_extension_flattened + ".h" )
193 flattened_data_object.write_implementation_file( full_qualified_file_without_extension_flattened + ".cpp" )
194 output.makefile.add_cpp_file( full_qualified_file_without_extension_flattened + ".cpp", generated=True )
195
196
198 """!
199
200 Default superclass for any data model in Peano which is stored within the grid
201
202 A DaStGen2 data type generator. To add fields to this object, just
203 use the DaStGen2 instance data of this field, i.e. data.add_attribute().
204
205
206 ## Attributes
207
208 data: dastgen2.DataModel
209 Add elements to this guy to enrich your data model.
210
211 peano4_mpi_and_storage_aspect: peano4.dastgen2.MPIAndStorageAspect
212 This aspect adds the Peano-specific MPI routines to the data type,
213 i.e. routines used for boundary and re-balancing exchange. Modify
214 this one if you want to control certain data exchange or merge
215 patterns.
216
217
218 ## Data storage
219
220 I can control when to store data through the peano4_mpi_and_storage_aspect.
221
222
223 ## MPI
224
225 If you want to add your own MPI merge implementation, you have to
226 alter the attribute peano4_mpi_and_storage_aspect.
227
228 ## Arguments
229
230 name: String
231 Name (unqualified)
232
233
234
235 """
236
237
238 readme_descriptor = """
239"""
240
241
242 readme_package_descriptor = """
243### Data structure modelling
244
245Peano models its data structures via a tool called DaStGen. The actual DaStGen
246version in use is the second generation of DaStGen which is integrated into
247LLVM, e.g. The first generation of DaStGen has been a stand-alone Java tool
248which serves as a precompiler. As DaStGen 2 is not published yet, we appreciate
249a citation of the two original DaStGen papers when you discuss the memory needs:
250
251
252 @InProceedings{Bungartz:2008:DaStGen,
253 author={Bungartz, Hans--Joachim and Eckhardt, Wolfgang and Mehl, Miriam and Weinzierl, Tobias}, "
254 editor={Bubak, Marian and van Albada, Geert Dick and Dongarra, Jack and Sloot, Peter M. A.},
255 title={DaStGen---A Data Structure Generator for Parallel C++ HPC Software},
256 booktitle={Computational Science -- ICCS 2008},
257 year=2008,
258 publisher={Springer Berlin Heidelberg},
259 address={Berlin, Heidelberg}, "
260 pages={213--222},
261 isbn={978-3-540-69389-5}
262 }
263
264
265 @article{Bungartz:2010:DaStGen,
266 title = {A precompiler to reduce the memory footprint of multiscale PDE solvers in C++},
267 journal = {Future Generation Computer Systems},"
268 volume = {26},
269 number = {1},
270 pages = {175-182},
271 year = {2010},
272 issn = {0167-739X},
273 doi = {https://doi.org/10.1016/j.future.2009.05.011},
274 url = {https://www.sciencedirect.com/science/article/pii/S0167739X09000673},
275 author = {H.-J. Bungartz and W. Eckhardt and T. Weinzierl and C. Zenger},
276 keywords = {Data compaction and compression, Code generation, Multigrid and multilevel methods},
277 abstract = {A PDE solver's value is increasingly co-determined by its memory footprint, as the increase of computational multicore power overtakes the memory access speed, and as memory restricts the maximum experiment size. Tailoring a code to require less memory is technical challenging, error-prone, and hardware-dependent. Object-oriented code typically consumes much memory, though developers favour such high-level languages offering meaningful models and good maintainability. We augment the language C++ with new keywords branding records to be memory-critical. Our precompiler DaStGen then transforms this augmented specification into plain C++ optimised for low memory requirements. Hereby, it encodes multiple attributes with fixed range within one variable, and it reduces the number of bits per floating point value. The tool also generates one user-defined MPI data type per class and, thus, facilitates the construction of parallel codes with small messages.}
278 }
279"""
280
281
282 def __init__(self, name):
283 """!
284
285 Construct a DaStGen2 object
286
287 We hold the data model and a dedicated data generator. By default, the data
288 model is augmented with geometric debug information. Every Peano data
289 object has an MPI aspect, i.e. can, in principle, be sent and received
290 through MPI.
291
292 """
293 super(DaStGen2, self).__init__(name)
294
295 # is set by configure() lazily
296 self.generator = None
297
299
300 self.data.add_attribute( peano4.dastgen2.Peano4DoubleArray( "debugX", "Dimensions", ifdefs=["PeanoDebug>0"] ) )
301 self.data.add_attribute( peano4.dastgen2.Peano4DoubleArray( "debugH", "Dimensions", ifdefs=["PeanoDebug>0"] ) )
302
303 self.peano4_mpi_and_storage_aspect = peano4.dastgen2.MPIAndStorageAspect(peano4.datamodel.DoFAssociation.Undef)
304
305 self.data.add_aspect( self.peano4_mpi_and_storage_aspect )
306
307
308 def configure(self, namespace, association, subdirectory=""):
309 """!
310
311 Configure output
312
313 Configuring an output means setting the right output directory and
314 taking into account whether we are associated to a vertex, face or
315 cell.
316
317 I always need the MPI aspect, but I can't add the right one in the
318 constructor, as I don't know whether this DaStGen model is used for
319 vertices, faces or cells. Such context however is important to generate
320 the correct merge routines with the correct signature. Therefore, I
321 hook into this routine.
322
323 """
324 super(DaStGen2, self).configure(namespace,association,subdirectory)
325 self.peano4_mpi_and_storage_aspect.dof_association = association
326
329 else:
330 self.generator = DaStGen2Generator(self)
331
332
333 @property
338 @additional_load_and_store_arguments.setter
339 def additional_load_and_store_arguments(self,new_arguments):
340 self.peano4_mpi_and_storage_aspect.additional_load_and_store_arguments = [ (x[1],x[2]) for x in new_arguments]
341 for new_argument in new_arguments:
342 self.peano4_mpi_and_storage_aspect.includes.append( """
343#include \"""" + new_argument[1].replace("::","/") + """.h"
344""")
346
347
349 """!
350
351 Does class host a smart pointer attribute
352
353 The context is important when we pick the data generator, as objects with
354 a smart poiner have to be handled differently compared to plain objects.
355
356 """
357 for attribute in self.data._attributes:
358 if isinstance(attribute,peano4.dastgen2.Peano4SmartPointerDoubleArray):
359 return True
360 return False
361
Represents on DaStGen2 object, i.e.
Definition DataModel.py:7
Represents Peano's MPI and storage aspect injected into a DaStGen model.
Specialisation of array using Peano's tarch.
Specialisation of array using Peano's tarch with a smart pointer.
Simple generator mapping a DaStGen2 object onto a plain C++ class.
Definition DaStGen2.py:56
construct_output(self, output)
Finally construct the output.
Definition DaStGen2.py:80
Simple generator mapping a DaStGen2 object onto a plain C++ class.
Definition DaStGen2.py:14
construct_output(self, output)
Finally construct the output.
Definition DaStGen2.py:33
Default superclass for any data model in Peano which is stored within the grid.
Definition DaStGen2.py:197
hosts_smart_pointer_attribute(self)
Does class host a smart pointer attribute.
Definition DaStGen2.py:348
__init__(self, name)
Construct a DaStGen2 object.
Definition DaStGen2.py:282
configure(self, namespace, association, subdirectory="")
Configure output.
Definition DaStGen2.py:308
_additional_load_and_store_arguments
Definition DoF.py:96
construct_ifdef_string(symbol_list)
Return empty string if symbol_list is empty.
Definition Utils.py:22