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
10
11#import peano4.api
14
15import copy
16import os
17
18
19class DaStGen2Artefact(object):
20 """!
21
22 Output artefact which writes one DaStGen2 data model into the project
23
24 The generators below do not write their data models straightaway, as they
25 do not know the directory of the project when they construct the output.
26 Instead, they register one artefact per data model with the output, which
27 writes the header and the implementation once the output is generated
28 into the project directory, as @ref peano4.api.output.Output "the output"
29 calls generate() on each of its artefacts.
30
31 """
32 def __init__(self, data_model, file_name_without_extension):
33 """!
34
35 @param data_model: dastgen2.DataModel
36 Data model to write. Its full qualified name has to be set already.
37
38 @param file_name_without_extension: str
39 File name relative to the project directory.
40
41 """
42 self._data_model = data_model
43 self._file_name_without_extension = file_name_without_extension
44
45
46 def generate(self, overwrite, directory):
47 file_name = os.path.join(directory, self._file_name_without_extension)
48 self._data_model.write_header_file( file_name + ".h" )
49 self._data_model.write_implementation_file( file_name + ".cpp" )
50
51
52
53class DaStGen2Generator(object):
54 """!
55
56 Simple generator mapping a DaStGen2 object onto a plain C++ class
57
58 """
59 def __init__(self,data):
60 self._data = data
61
62
64 return "peano4::stacks::STDVectorStack< " + self._data.get_full_qualified_type() + " >";
65
66
68 return "#include \"peano4/stacks/STDVectorStack.h\" \n \
69 #include \"" + self._data.namespace[-1] + "/" + self._data.name + ".h\""
70
71
72 def construct_output(self,output):
73 """!
74
75 Finally construct the output
76
77 Pass in an instance of the output object. We use this output
78 object only to register the generated C++ file with the build
79 environment.
80
81 """
82 full_qualified_name = ""
83 for i in self._data.namespace:
84 full_qualified_name += i
85 full_qualified_name += "::"
86 full_qualified_name += self._data.name
87 self._data.data.set_full_qualified_name(full_qualified_name)
88
89 output.add( DaStGen2Artefact( self._data.data, self._data.subdirectory + self._data.namespace[-1] + "/" + self._data.name ) )
90 output.makefile.add_cpp_file( self._data.subdirectory + self._data.namespace[-1] + "/" + self._data.name + ".cpp", generated=True )
91
92
93
95 """!
96
97 Simple generator mapping a DaStGen2 object onto a plain C++ class
98
99 The generator is very similar to DaStGen2Generator, but it has to take
100 extra care as we assume that some objects host smart pointers. Therefore,
101 we do two things: We dump the smart pointer version, and we create a
102 flattene version, too.
103
104 """
105 def __init__(self,data):
106 self._data = data
107
108
110 return "peano4::stacks::STDVectorStackOverObjectsWithSmartPointers< " + self._data.get_full_qualified_type() + " >";
111
112
114 return "#include \"peano4/stacks/STDVectorStackOverObjectsWithSmartPointers.h\" \n \
115 #include \"" + self._data.namespace[-1] + "/" + self._data.name + ".h\""
116
117
118 def construct_output(self,output):
119 """!
120
121 Finally construct the output
122
123 Pass in an instance of the output object. We use this output
124 object only to register the generated C++ file with the build
125 environment. This part is exactly the same as for a plain 1:1
126 translation.
127
128 Further to the default generator, this routine does a little bit
129 more:
130
131 - Make a deep copy of the data object and replace each instance of
132 a smart pointer with its plain counterpart. This new data object
133 is identified by the extension _Flattened.
134 - Make the new helper data structure include the original class with
135 the smart pointers.
136 - Declare this one as an embedded type via using.
137 - Add a new copy constructor/conversion routine which really just maps
138 the two data types onto each other by using the setters and getters.
139 - Replace the MPI aspect in the original object with an with the
140 variant for smart pointers
141
142 """
143 full_qualified_name = ""
144 for i in self._data.namespace:
145 full_qualified_name += i
146 full_qualified_name += "::"
147 full_qualified_name += self._data.name
148
149 print( "No of aspects for {}: {}".format( full_qualified_name, len(self._data.data._aspects) ))
150
151 # flattened_data_object is of type dastgen2.DataModel
152 flattened_data_object = copy.copy(self._data.data)
153 old_attributes = self._data.data._attributes
154 old_aspects = flattened_data_object._aspects
155 flattened_data_object._attributes = []
156 self._data.data._aspects = []
157 for attribute in old_attributes:
159 flattened_data_object._attributes.append( peano4.api.dastgen2.Peano4DoubleArray( name = attribute._name,
160 cardinality = attribute._cardinality,
161 ifdefs = attribute.ifdefs
162 ))
163 else:
164 flattened_data_object._attributes.append( attribute )
165
166 for aspect in old_aspects:
167 if isinstance(aspect,dastgen2.aspects.MPI):
168 self._data.data._aspects.append( dastgen2.aspects.MPIForSmartPointers(aspect._data_model) )
169 elif isinstance(aspect,peano4.api.dastgen2.MPIAndStorageAspect):
170 self._data.peano4_mpi_and_storage_aspect = aspect
171 self._data.data._aspects.append( self._data.peano4_mpi_and_storage_aspect )
172 else:
173 self._data.data._aspects.append( aspect )
174
175 extension = "_Flattened"
176 full_qualified_name_flattened = full_qualified_name + extension
177 full_qualified_file_without_extension_flattened = self._data.subdirectory + self._data.namespace[-1] + "/" + self._data.name + extension
178
179 self._data.data.set_full_qualified_name(full_qualified_name)
180 output.add( DaStGen2Artefact( self._data.data, self._data.subdirectory + self._data.namespace[-1] + "/" + self._data.name ) )
181 output.makefile.add_cpp_file( self._data.subdirectory + self._data.namespace[-1] + "/" + self._data.name + ".cpp", generated=True )
182
183 flattened_data_object.set_full_qualified_name(full_qualified_name_flattened)
184 output.add( DaStGen2Artefact( flattened_data_object, full_qualified_file_without_extension_flattened ) )
185 output.makefile.add_cpp_file( full_qualified_file_without_extension_flattened + ".cpp", generated=True )
186
187
189 """!
190
191 Default superclass for any data model in Peano which is stored within the grid
192
193 A DaStGen2 data type generator. To add fields to this object, just
194 use the DaStGen2 instance data of this field, i.e. data.add_attribute().
195
196 @image html dof-class-diagram.png
197
198 By default, we add x and h to the attributes. The DataModel object also can
199 host aspects, i.e. classes which inject technical code snippets into each
200 and every instance. By default, we add peano4.api.dastgen2.MPIAndStorageAspect
201 and dastgen2.aspect.MPI, but yuo might want to add further ones.
202
203 The actual dump into a C++ file is not done by the DaStGen2 object.
204 Instead, we hold a generator object which does this translation. In that
205 sense, the DaStGen2 object is almost an empty wrapper which tailors the
206 underlying data model, but adds no further specific behaviour.
207
208 There are two code generations: The default one, and then one that we have
209 to employ if the underlying data object hosts a smart pointer.
210
211
212 ## Attributes
213
214 data: dastgen2.DataModel
215 Add elements to this guy to enrich your data model.
216
217 peano4_mpi_and_storage_aspect: peano4.api.dastgen2.MPIAndStorageAspect
218 This aspect adds the Peano-specific MPI routines to the data type,
219 i.e. routines used for boundary and re-balancing exchange. Modify
220 this one if you want to control certain data exchange or merge
221 patterns.
222
223
224 ## Data storage
225
226 I can control when to store data through the peano4_mpi_and_storage_aspect.
227
228
229 ## MPI
230
231 If you want to add your own MPI merge implementation, you have to
232 alter the attribute peano4_mpi_and_storage_aspect.
233
234 ## Arguments
235
236 name: String
237 Name (unqualified)
238
239
240
241 """
242
243
244 readme_descriptor = """
245"""
246
247
248 readme_package_descriptor = """
249### Data structure modelling
250
251Peano models its data structures via a tool called DaStGen. The actual DaStGen
252version in use is the second generation of DaStGen which is integrated into
253LLVM, e.g. The first generation of DaStGen has been a stand-alone Java tool
254which serves as a precompiler. As DaStGen 2 is not published yet, we appreciate
255a citation of the two original DaStGen papers when you discuss the memory needs:
256
257
258 @InProceedings{Bungartz:2008:DaStGen,
259 author={Bungartz, Hans--Joachim and Eckhardt, Wolfgang and Mehl, Miriam and Weinzierl, Tobias}, "
260 editor={Bubak, Marian and van Albada, Geert Dick and Dongarra, Jack and Sloot, Peter M. A.},
261 title={DaStGen---A Data Structure Generator for Parallel C++ HPC Software},
262 booktitle={Computational Science -- ICCS 2008},
263 year=2008,
264 publisher={Springer Berlin Heidelberg},
265 address={Berlin, Heidelberg}, "
266 pages={213--222},
267 isbn={978-3-540-69389-5}
268 }
269
270
271 @article{Bungartz:2010:DaStGen,
272 title = {A precompiler to reduce the memory footprint of multiscale PDE solvers in C++},
273 journal = {Future Generation Computer Systems},"
274 volume = {26},
275 number = {1},
276 pages = {175-182},
277 year = {2010},
278 issn = {0167-739X},
279 doi = {https://doi.org/10.1016/j.future.2009.05.011},
280 url = {https://www.sciencedirect.com/science/article/pii/S0167739X09000673},
281 author = {H.-J. Bungartz and W. Eckhardt and T. Weinzierl and C. Zenger},
282 keywords = {Data compaction and compression, Code generation, Multigrid and multilevel methods},
283 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.}
284 }
285"""
286
287
288 def __init__(self, name):
289 """!
290
291 Construct a DaStGen2 object
292
293 We hold the data model and a dedicated data generator. By default, the data
294 model is augmented with geometric debug information. Every Peano data
295 object has an MPI aspect, i.e. can, in principle, be sent and received
296 through MPI.
297
298 By default, each Peano dat model also realises the MPIAndStorageAspect
299 which requires special treatment:
300
301 ## MPI and storage aspect
302
303 Normally, we just hold all the aspects in a long list and generate them one
304 by one. The MPI and storage aspect is a little bit different: If we add the
305 Peano-specific one, we still want later to modify parts of it. That is, we
306 would have to run through all the aspects one by one, pick out the MPI and
307 storage one, and then alter this one. So what we do instead is that we hold
308 it as a dedicated attribute and also add it to the list.
309
310 """
311 super(DaStGen2, self).__init__(name)
312
313 # is set by configure() lazily
314 self.generator = None
315
317
318 self.data.add_attribute( peano4.api.dastgen2.Peano4DoubleArray( "debugX", "Dimensions", ifdefs=["PeanoDebug>0"] ) )
319 self.data.add_attribute( peano4.api.dastgen2.Peano4DoubleArray( "debugH", "Dimensions", ifdefs=["PeanoDebug>0"] ) )
320
321 self.peano4_mpi_and_storage_aspect = peano4.api.dastgen2.MPIAndStorageAspect(peano4.api.datamodel.DoFAssociation.Undef)
322
323 self.data.add_aspect( self.peano4_mpi_and_storage_aspect )
324 self.data.add_aspect( dastgen2.aspects.MPI() )
325
326
327 def configure(self, namespace, association, subdirectory=""):
328 """!
329
330 Configure output
331
332 Configuring an output means setting the right output directory and
333 taking into account whether we are associated to a vertex, face or
334 cell.
335
336 I always need the MPI aspect, but I can't add the right one in the
337 constructor, as I don't know whether this DaStGen model is used for
338 vertices, faces or cells. Such context however is important to generate
339 the correct merge routines with the correct signature. Therefore, I
340 hook into this routine.
341
342 """
343 super(DaStGen2, self).configure(namespace,association,subdirectory)
344 self.peano4_mpi_and_storage_aspect.dof_association = association
345
348 else:
349 self.generator = DaStGen2Generator(self)
350
351
352 @property
357 @additional_load_and_store_arguments.setter
358 def additional_load_and_store_arguments(self,new_arguments):
359 self.peano4_mpi_and_storage_aspect.additional_load_and_store_arguments = [ (x[1],x[2]) for x in new_arguments]
360 for new_argument in new_arguments:
361 self.peano4_mpi_and_storage_aspect.includes.append( """
362#include \"""" + new_argument[1].replace("::","/") + """.h"
363""")
365
366
368 """!
369
370 Does class host a smart pointer attribute
371
372 The context is important when we pick the data generator, as objects with
373 a smart poiner have to be handled differently compared to plain objects.
374
375 """
376 for attribute in self.data._attributes:
378 return True
379 return False
380
Represents on DaStGen2 object, i.e.
Definition DataModel.py:8
Represents the MPI aspect injected into a DaStGen model.
Represents the MPI aspect injected into a DaStGen model.
Definition MPI.py:9
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.
Output artefact which writes one DaStGen2 data model into the project.
Definition DaStGen2.py:19
generate(self, overwrite, directory)
Definition DaStGen2.py:46
__init__(self, data_model, file_name_without_extension)
Definition DaStGen2.py:32
Simple generator mapping a DaStGen2 object onto a plain C++ class.
Definition DaStGen2.py:94
Simple generator mapping a DaStGen2 object onto a plain C++ class.
Definition DaStGen2.py:53
construct_output(self, output)
Finally construct the output.
Definition DaStGen2.py:72
Default superclass for any data model in Peano which is stored within the grid.
Definition DaStGen2.py:188
__init__(self, name)
Construct a DaStGen2 object.
Definition DaStGen2.py:288
hosts_smart_pointer_attribute(self)
Does class host a smart pointer attribute.
Definition DaStGen2.py:367
configure(self, namespace, association, subdirectory="")
Configure output.
Definition DaStGen2.py:327
Base class for any degree of freedom object.
Definition DoF.py:56