Peano
Loading...
Searching...
No Matches
Step.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
4
5from peano4.api.solversteps.StepToActionSets import StepToActionSets
6from peano4.api.solversteps.StepToObserver import StepToObserver
7from peano4.api.solversteps.SynchroniseActionSets import SynchroniseActionSets, get_task_groups
8
9
10class Step:
11 """!
12
13 One step
14
15 Most generic version of a solver step. A solverstep describes what Peano 4
16 should do when it runs over the grid. As users have to specify which pieces
17 of data from the data model are used by the solver step, it can handle all
18 the user data stack flow.
19
20 This class also is responsible to generate all function signatures of all
21 the steps, observers and action sets. In the Peano terminology, a step
22 corresponds to an observer. For any given step, we run through the mesh
23 and pass the traversal automaton an observer which accepts events (aka
24 state transition observations).
25
26 It is the observer's job to then distribute these observations, broken
27 down into grid actions such as "touch vertex first time", among the action
28 sets that are tied to this observer. In Python you can have one action set
29 and associate it with several observers. In the C++ code, we will flatten
30 such a relation, i.e. create the corresponding action set multiple times.
31
32 @see @ref peano4.api.solversteps.ActionSet.ActionSet
33
34 name: String
35 This name is used to create the underlying action set later on
36 """
37
38 def __init__(self,
39 name,
40 add_user_defined_actions=True,
41 ):
42 """
43 By default, the step generates at least one action set for the user.
44 However, you can disable this behaviour by passing False to
45 add_user_defined_actions. Alternatively, use remove_all_action_sets()
46 on the step.
47 """
48 self.name = name
49 self.cell_data = []
50 self.face_data = []
51 self.vertex_data = []
52 # Optional side-channel, empty unless a caller populates it: maps a
53 # submodel already in cell_data/face_data/vertex_data to the
54 # peano4.api.taskgraph.Task.DataAccess qualifier it was declared
55 # with on the originating Task. use_cell()/use_face()/use_vertex()
56 # below deliberately do not touch these - they exist purely so
57 # peano4.api.taskgraph.compiler.Sequential.translate() can carry a
58 # Task's qualifiers over onto the Step it compiles into, for
59 # reporting (@see peano4.api.taskgraph.compiler.ReportCompiledStepSequence)
60 # to display; nothing about how this Step's own generated Observer
61 # behaves depends on them.
65 if add_user_defined_actions:
67 else:
68 self.action_sets = []
71
72 def get_observer_class_name(self) -> str:
73 """!
74
75 Class name of the observer this step is translated into. This is
76 the step's name, cut down to 64 characters plus a consecutive number
77 if it is longer (@see peano4.api.output.Helper.shortened_class_name()),
78 as the class name also is the observer's file name. Everybody
79 referring to the observer class, such as the generated runners, has
80 to use this getter rather than the step's name.
81
82 """
83 # Imported here, as peano4.api.output in turn imports this package
84 from peano4.api.output.Helper import shortened_class_name
85
86 return shortened_class_name(self.name, max_length=64)
87
89 """
90 Each step holds a set of actions. They describe what the step actually
91 should do whenever it loads a vertex, runs into a cell, and so forth. By
92 default, the step holds one user-defined actions which means
93 that a stub is generated where users can insert their functionality. You
94 can remove this one (or any other one added so far) with this routine.
95 """
96 self.action_sets = []
97
98 def __sort(self):
99 """!
100
101 Simple bubble sort the action sets, such that their descend_invocation_order
102 is preserved.
103
104 @see @ref peano4.api.solversteps.ActionSet.ActionSet.descend_invocation_order
105
106 """
107 for i in range(0, len(self.action_sets)):
108 for j in range(i + 1, len(self.action_sets)):
109 if (
110 self.action_sets[i].descend_invocation_order
111 > self.action_sets[j].descend_invocation_order
112 ):
113 tmp = self.action_sets[i]
114 self.action_sets[i] = self.action_sets[j]
115 self.action_sets[j] = tmp
116
117 def add_action_set(self, action_set):
118 """!
119
120 Add a new action set to this mesh traversal step
121
122 Each step holds a set of action_sets. They describe what the step actually
123 should do whenever it loads a vertex, runs into a cell, and so forth. By
124 default, the step holds one user-defined action_set (UserActionSet) which means
125 that a stub is generated where users can insert their functionality. It is
126 important in which order you add your action_sets: The whole tree traversal
127 is a top-down/depth-first tree traversal. So all the enter, create, ...
128 operations of a action_set are invoked exactly in the order you add them to
129 the step. All the delete, leave, ... operations are invokved in reversed
130 order.
131
132 I used to have a flag append_at_end with the default True, but this one is
133 now replaced, as each action set knows its priority.
134 """
135 self.action_sets.append(action_set)
136 self.__sort()
137
138 def set_project(self, project):
139 """!
140
141 Tie step to project
142
143 You don't have to call this. It is automatically called once you add a step
144 to the project's steps.
145 """
146 self.project = project
147 self.namespace = project.namespace
148 self.subdirectory = project.subdirectory
149
150 def use_cell(self, submodel):
151 self.cell_data.append(submodel)
152
153 def use_face(self, submodel):
154 self.face_data.append(submodel)
155
156 def use_vertex(self, submodel):
157 self.vertex_data.append(submodel)
158
160 """!
161
162 Return max descend_invocation_order over all action sets associated with this step.
163
164 @see @ref peano4.api.solversteps.ActionSet.ActionSet.descend_invocation_order
165
166 """
167 self.__sort()
168 if len(self.action_sets) == 0:
169 return 0
170 return self.action_sets[-1].descend_invocation_order
171
173 """!
174
175 Return minimum descend_invocation_order over all action sets associated with this step.
176
177 @see @ref peano4.api.solversteps.ActionSet.ActionSet.descend_invocation_order
178
179 """
180 self.__sort()
181 if len(self.action_sets) == 0:
182 return 0
183 return self.action_sets[0].descend_invocation_order
184
186 result = ["marker", "const peano4::datamanagement::VertexMarker&"]
187 for i in self.vertex_data:
188 result += ["fineGridVertex" + i.name, i.get_full_qualified_type() + "&"]
189 for i in self.vertex_data:
190 result += ["coarseGridVertices" + i.name, i.get_enumeration_type() + ""]
191 for i in self.face_data:
192 result += ["coarseGridFaces" + i.name, i.get_enumeration_type() + ""]
193 for i in self.cell_data:
194 result += ["coarseGridCell" + i.name, i.get_full_qualified_type() + "&"]
195 return result
196
198 result = ["marker", "const peano4::datamanagement::FaceMarker&"]
199 for i in self.vertex_data:
200 result += ["fineGridVertices" + i.name, i.get_enumeration_type() + ""]
201 for i in self.face_data:
202 result += ["fineGridFace" + i.name, i.get_full_qualified_type() + "&"]
203 for i in self.vertex_data:
204 result += ["coarseGridVertices" + i.name, i.get_enumeration_type() + ""]
205 for i in self.face_data:
206 result += ["coarseGridFaces" + i.name, i.get_enumeration_type() + ""]
207 for i in self.cell_data:
208 result += ["coarseGridCell" + i.name, i.get_full_qualified_type() + "&"]
209 return result
210
212 result = ["marker", "const peano4::datamanagement::CellMarker&"]
213 for i in self.vertex_data:
214 result += ["fineGridVertices" + i.name, i.get_enumeration_type() + ""]
215 for i in self.face_data:
216 result += ["fineGridFaces" + i.name, i.get_enumeration_type() + ""]
217 for i in self.cell_data:
218 result += ["fineGridCell" + i.name, i.get_full_qualified_type() + "&"]
219 for i in self.vertex_data:
220 result += ["coarseGridVertices" + i.name, i.get_enumeration_type() + ""]
221 for i in self.face_data:
222 result += ["coarseGridFaces" + i.name, i.get_enumeration_type() + ""]
223 for i in self.cell_data:
224 result += ["coarseGridCell" + i.name, i.get_full_qualified_type() + "&"]
225 return result
226
228 result = ["marker", "const peano4::datamanagement::CellMarker&"]
229 for i in self.vertex_data:
230 result += ["fineGridVertices" + i.name, i.get_enumeration_type() + ""]
231 for i in self.face_data:
232 result += ["fineGridFaces" + i.name, i.get_enumeration_type() + ""]
233 for i in self.cell_data:
234 result += ["fineGridCell" + i.name, i.get_full_qualified_type() + "&"]
235
236 for i in self.vertex_data:
237 result += ["coarseGridVertices" + i.name, i.get_enumeration_type() + ""]
238 for i in self.face_data:
239 result += ["coarseGridFaces" + i.name, i.get_enumeration_type() + ""]
240 for i in self.cell_data:
241 result += ["coarseGridCell" + i.name, i.get_full_qualified_type() + "&"]
242
243 return result
244
245 def construct_output(self, output):
246 """
247 Each solver step basically gives us two big files/classes: A class which
248 handles the actual data movements, i.e. is an implementation of the tree
249 visitor pattern over the Peano4 tree. The other type is an interface which
250 provides plugin points into the created data transitions from a user's
251 perspective.
252
253 Markers of type
254 @ref peano4.api.solversteps.SynchroniseActionSets.SynchroniseActionSets
255 yield no C++ code. They only separate the task groups which we hand
256 over to the observer
257 (@ref peano4.api.solversteps.SynchroniseActionSets.get_task_groups()).
258 """
259
260 included_action_sets = []
261 index_of_action_set = {}
262 for action_set in self.action_sets:
263 if isinstance(action_set, SynchroniseActionSets):
264 continue
265 full_qualified_action_set_name = self.action_set_generator.construct_output(
266 output, action_set
267 )
268 index_of_action_set[id(action_set)] = len(included_action_sets)
269 included_action_sets.append(full_qualified_action_set_name)
270
271 task_groups = [
272 [index_of_action_set[id(action_set)] for action_set in group]
273 for group in get_task_groups(self.action_sets)
274 ]
275 self.observer_generator.construct_output(output, included_action_sets, task_groups)
276
277 def copy_action_sets_from_other_step(self, other_step):
278 self.action_sets += other_step.action_sets
Take an action set and construct an observer from it.
__sort(self)
Simple bubble sort the action sets, such that their descend_invocation_order is preserved.
Definition Step.py:98
construct_output(self, output)
Each solver step basically gives us two big files/classes: A class which handles the actual data move...
Definition Step.py:245
add_action_set(self, action_set)
Add a new action set to this mesh traversal step.
Definition Step.py:117
use_vertex(self, submodel)
Definition Step.py:156
remove_all_actions(self)
Each step holds a set of actions.
Definition Step.py:88
use_face(self, submodel)
Definition Step.py:153
set_project(self, project)
Tie step to project.
Definition Step.py:138
__init__(self, name, add_user_defined_actions=True)
By default, the step generates at least one action set for the user.
Definition Step.py:41
highest_descend_invocation_order(self)
Return max descend_invocation_order over all action sets associated with this step.
Definition Step.py:159
copy_action_sets_from_other_step(self, other_step)
Definition Step.py:277
lowest_descend_invocation_order(self)
Return minimum descend_invocation_order over all action sets associated with this step.
Definition Step.py:172
str get_observer_class_name(self)
Class name of the observer this step is translated into.
Definition Step.py:72
use_cell(self, submodel)
Definition Step.py:150
Marker which ends a group of action sets that run in parallel.