Peano
Loading...
Searching...
No Matches
ActionSet.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
3import os
4import re
5
6from .Helper import write_file, shortened_class_name
7
8from .Overwrite import Overwrite
9
11
12class ActionSet(object):
13 """!
14
15 Code generator for one action set
16
17 Do not confuse this with @ref peano4.api.solversteps.ActionSet.ActionSet,
18 which is the interface you actually implement (you subclass it and override
19 get_guard_of_operation(), get_body_of_operation(), get_attributes(),
20 get_includes(), ... to say
21 *what* the action set does). Users typically never interact with this
22 class. They work against the ActionSet in solversteps.
23
24 This class here is the corresponding writer: given one
25 such solversteps.ActionSet instance (held as self.implementation), it
26 emits the actual C++ .h/.cpp pair - the include guard, the class
27 declaration inside the right namespace, a static tarch::logging::Log
28 _log, the constructor/destructor, createGridControlEventsForNextTraversal(),
29 prepareTraversal()/unprepareTraversal(), and one method per grid event
30 (touchCellFirstTime, createPersistentVertex, ...) - calling back into
31 the get_implementation_of_*() routines - which combine your
32 get_guard_of_operation() and get_body_of_*() overrides - to fill in each
33 method body.
34 @ref peano4.api.solversteps.ActionSet.ActionSet is the data model, this class is the writer.
35
36 # Where is is used
37
38 The class is instantiated in exactly one place: construct_output() of @ref
39 peano4.api.solversteps.StepToActionSets.StepToActionSets, which is called
40 once per action set attached to a @ref peano4.api.solversteps.Step.Step,
41 from Step.construct_output(), as it loops over self.action_sets. That
42 call site decides two things this class here itself does not know about:
43
44 - Which operations to generate.
45 - What the total number of vertices, cells, ... is and what they are called.
46 - Where the file goes and what it is called - if
47 action_set.user_should_modify_template() is True, it is named after the
48 action set itself and placed under actions/ (meant for you to hand-edit,
49 regenerated only if missing); if False, it is placed under observers/
50 and named "{step.name}2{action_set.get_action_set_name()}{index}" -
51 regenerated unconditionally every run.
52
53 # In short
54
55 - This is the generator which takes one @ref peano4.api.solversteps.StepToActionSets.StepToActionSets and maps it onto a header/implementation file pair.
56 - The outcome either ends up in actions/ (if user_should_modify_template() is True) or in observers/ (if False).
57 - The outcome typically is named Observer2ActionSetName.
58
59 ## Important links
60
61 - @ref page_peano_action_sets
62 - @ref peano4.api.taskgraph
63
64 """
65
66 def __init__(self,classname,namespace,subdirectory,implementation = None):
67 """!
68
69 implementation Should be of type peano4.api.solversteps.ActionSet or
70 None. If it is None, then the generated stuff will be a
71 sole interface.
72
73 """
74 # The class name is also the file name, which might become too long
75 self.classname = shortened_class_name(classname)
76 self.namespace = namespace
77 self.subdirectory = subdirectory
78 self.operations = [
79 (peano4.api.solversteps.ActionSet.OPERATION_BEGIN_TRAVERSAL,"void"),
80 (peano4.api.solversteps.ActionSet.OPERATION_END_TRAVERSAL,"void")
81 ]
82 self.include_files = []
83 self.typedefs = []
84 self.implementation = implementation
85
86 def add_operation(self,name,signature):
87 """
88 signature is a long tuple. The first entry is the name of the routine,
89 the second entry is the result type. From thereon, one entry gives the
90 name of an attribute, the second one the type.
91 """
92 self.operations.append(signature)
93
94 def __generate_includes(self, outputfile):
95 for i in self.include_files: outputfile.write( '#include "{}"\n'.format(i) )
96
97 def __get_operation_arguments(self,operation):
98 result = "(\n "
99 i = 2
100 while i<len(operation):
101 result += operation[i+1]
102 result += " "
103 result += operation[i]
104 i+=2
105 if i<len(operation):
106 result += ",\n "
107
108 result += ")"
109 return result
110
111 def __generate_operation(self,outputfile,operation):
112 """
113 outputfile points to file, operation to an operation object as added by the solver step
114 """
115 if self.implementation == None:
116 outputfile.write( " virtual " )
117 else:
118 outputfile.write( " " )
119 outputfile.write( operation[1] )
120 outputfile.write( " ")
121 outputfile.write( operation[0] )
122 outputfile.write( self.__get_operation_arguments(operation) )
123 if self.implementation == None:
124 outputfile.write( " = 0")
125 outputfile.write( ";\n\n")
126
128 full_qualified_classname = ""
129 for i in self.namespace:
130 full_qualified_classname += i
131 full_qualified_classname += "::"
132 full_qualified_classname += self.classname
133 return full_qualified_classname
134
135 def __generate_header(self,overwrite,directory):
136 filename = directory + "/" + self.subdirectory + "/" + self.classname + ".h";
137 default_overwrite = True
138 if self.implementation.user_should_modify_template():
139 default_overwrite = False
140
141 if write_file(overwrite,default_overwrite,filename):
142 import inspect, os
143 print( "{} written by {}".format(filename, os.path.basename(inspect.getfile(self.__class__))))
144
145 with open( filename, "w" ) as outputfile:
146 full_qualified_classname = self.__get_full_qualified_class_name()
147 include_guard = "_{}_H_".format(full_qualified_classname.replace( "::", "_" ).upper())
148
149 outputfile.write( "#ifndef {}\n#define {}\n\n\n".format(include_guard, include_guard))
150
151 outputfile.write( """
152#include "peano4/utils/Globals.h"
153#include "peano4/datamanagement/VertexEnumerator.h"
154#include "peano4/datamanagement/VertexMarker.h"
155#include "peano4/datamanagement/FaceEnumerator.h"
156#include "peano4/datamanagement/FaceMarker.h"
157#include "peano4/datamanagement/CellMarker.h"
158#include "peano4/grid/GridControlEvent.h"
159#include "tarch/la/Vector.h"
160
161#include <vector>
162
163
164""" )
165
166 outputfile.write( self.implementation.get_includes() )
167 outputfile.write( "\n\n" )
168
169 self.__generate_includes(outputfile)
170
171 for i in self.namespace: outputfile.write( "namespace " + i + " {\n" )
172 outputfile.write(" class {};\n".format(self.classname))
173 for i in self.namespace: outputfile.write( "}\n" )
174
175 outputfile.write( "class " + full_qualified_classname + "{\n" )
176 outputfile.write( " private:\n" )
177 outputfile.write( " static tarch::logging::Log _log;\n" )
178 outputfile.write( self.implementation.get_attributes() )
179
180 outputfile.write( " public:\n" )
181 outputfile.write( """
182 /**
183 * Create action instance for one tree for one grid sweep
184 *
185 * <h2> Thread safety </h2>
186 *
187 * The creation of individual trees usually happens through peano4::parallel::SpacetreeSet::createObserverCloneIfRequired().
188 * This routine is called lazily when we start to traverse a subtree.
189 * Therefore, the creation of actions is not thread-safe.
190 *
191 *
192 * @param treeNumber Number of the spacetree for which we create the tree instance. Is
193 * smaller 0 if this is the prototype action used on a rank from which
194 * the real actions are constructed from.
195 */
196""" )
197 outputfile.write( " " + self.classname + "(int treeNumber);\n\n" )
198 outputfile.write( " ~" + self.classname + "();\n\n" )
199 outputfile.write( """
200 std::vector< peano4::grid::GridControlEvent > createGridControlEventsForNextTraversal() const;
201 static void prepareTraversal();
202 static void unprepareTraversal();
203""" )
204
205 for i in self.operations: self.__generate_operation(outputfile,i)
206 outputfile.write( "};\n\n\n" )
207 outputfile.write( "#endif\n\n" )
208
210 return self.subdirectory + "/" + self.classname + ".cpp"
211
212 def __generate_implementation(self,overwrite,directory):
213 filename = directory + "/" + self.get_cpp_file_name()
214 default_overwrite = True
215 if self.implementation.user_should_modify_template():
216 default_overwrite = False
217 if write_file(overwrite,default_overwrite,filename):
218 import inspect, os
219 print( "{} written by {}".format(filename, os.path.basename(inspect.getfile(self.__class__))))
220 outputfile = open( filename, "w" )
221
222 #full_qualified_classname = self.__get_full_qualified_class_name()
223
224 outputfile.write( "#include \"" + self.classname + ".h\"\n\n\n" )
225
226 outputfile.write( "tarch::logging::Log " + self.__get_full_qualified_class_name() + "::_log( \""+ self.__get_full_qualified_class_name() + "\");\n\n\n" )
227
228 outputfile.write( self.implementation.get_static_initialisations(self.__get_full_qualified_class_name()) )
229 outputfile.write( "\n\n\n" )
230
231 outputfile.write( self.__get_full_qualified_class_name() + "::" + self.classname + "(int treeNumber) {\n" )
232 outputfile.write( self.implementation.get_constructor_body() )
233 outputfile.write( "}\n\n\n" )
234
235 outputfile.write( self.__get_full_qualified_class_name() + "::~" + self.classname + "() {\n" )
236 outputfile.write( self.implementation.get_destructor_body() )
237 outputfile.write( "}\n\n\n" )
238
239 outputfile.write( "std::vector< peano4::grid::GridControlEvent > " + self.__get_full_qualified_class_name() + "::createGridControlEventsForNextTraversal() const {\n" )
240 outputfile.write( self.implementation.get_implementation_of_createGridControlEventsForNextTraversal() )
241 outputfile.write( "}\n\n\n" )
242
243 outputfile.write( "void " + self.__get_full_qualified_class_name() + "::prepareTraversal() {\n" )
244 outputfile.write( self.implementation.get_implementation_of_prepareTraversal() )
245 outputfile.write( "}\n\n\n" )
246
247 outputfile.write( "void " + self.__get_full_qualified_class_name() + "::unprepareTraversal() {\n" )
248 outputfile.write( self.implementation.get_implementation_of_unprepareTraversal() )
249 outputfile.write( "}\n\n\n" )
250
251 for operation in self.operations:
252 outputfile.write( operation[1] )
253 outputfile.write( " " )
254 outputfile.write( self.__get_full_qualified_class_name() + "::" + operation[0] )
255 outputfile.write( self.__get_operation_arguments(operation) )
256 outputfile.write( " {\n" )
257 outputfile.write( self.implementation.get_implementation_of_operation( operation[0] ) )
258 outputfile.write( "\n" )
259 outputfile.write( "}\n\n\n" )
260
261 def generate(self,overwrite,directory):
262 if not os.path.exists( directory + "/" + self.subdirectory ):
263 os.mkdir(directory + "/" + self.subdirectory)
264 self.__generate_header(overwrite,directory)
265 self.__generate_implementation(overwrite,directory)
Code generator for one action set.
Definition ActionSet.py:12
__generate_operation(self, outputfile, operation)
outputfile points to file, operation to an operation object as added by the solver step
Definition ActionSet.py:111
add_operation(self, name, signature)
signature is a long tuple.
Definition ActionSet.py:86
__init__(self, classname, namespace, subdirectory, implementation=None)
implementation Should be of type peano4.api.solversteps.ActionSet or None.
Definition ActionSet.py:66
__generate_header(self, overwrite, directory)
Definition ActionSet.py:135
__generate_implementation(self, overwrite, directory)
Definition ActionSet.py:212
generate(self, overwrite, directory)
Definition ActionSet.py:261
__generate_includes(self, outputfile)
Definition ActionSet.py:94
__get_operation_arguments(self, operation)
Definition ActionSet.py:97
Action set (reactions to events)
Definition ActionSet.py:6