Peano
Loading...
Searching...
No Matches
__init__.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
3"""!
4
5The task graph abstraction allows users to formalise their solver steps over small task graphs which are then lowered into a sequence of Peano mesh traversals.
6
7
8@tableofcontents
9
10
11## Example
12
13An ExaHyPE solver's generator, i.e. the part that translates the pyysical model into a numerical workflow, describes each algorithmic phase (setup, time stepping, plotting)
14as a @ref peano4.api.taskgraph.Graph of @ref peano4.api.taskgraph.Task instances.
15Each task defines computations over a mesh entity (vertex, face, cell, or global), subject to dependencies between the tasks.
16A simple task graph reads as follows:
17
181. Run over all cells and compute A.
192. Run over all faces and compute B, meanwhile do a global calculation. Both steps require A to have finished.
203. Run over all vertices once B has completed.
214. Wait for the third step and the global calculation and run over all cells again.
22
23The solvers use this formalism to set up graphs similar to this one:
24
25@image html task-graph-example.png
26
27This is obviously strongly simplified.
28A proper yet still simplistic example can be found in @ref exahype2.api.fv.SetupSimulationOverRegularGrid.
29The core interesting stuff looks similar to
30
31~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
32refine_task = peano4.api.taskgraph.Task(name=f"{self._solver.name}_Refine mesh",
33 entity=peano4.api.taskgraph.Task.GridEntity.CELL,
34 task_has_to_repeat=...
35 )
36consolidate_load_balancing_task = peano4.api.taskgraph.Task(name=f"{self._solver.name}_Consolidate mesh",
37 entity=peano4.api.taskgraph.Task.GridEntity.CELL,
38 task_has_to_repeat=...
39 )
40
41refine_task.add_action_set( ... )
42consolidate_load_balancing_task.add_action_set(toolbox.loadbalancing.api.actionsets.LoadBalancing())
43
44initial_condition_task = peano4.api.taskgraph.Task(name=f"{self._solver.name} Initial condition", entity=peano4.api.taskgraph.Task.GridEntity.CELL)
45project_on_faces_task = peano4.api.taskgraph.Task(name=f"{self._solver.name} Project on faces", entity=peano4.api.taskgraph.Task.GridEntity.CELL)
46
47consolidate_load_balancing_task.add_dependency(refine_task)
48initial_condition_task.add_dependency(consolidate_load_balancing_task)
49project_on_faces_task.add_dependency(initial_condition_task)
50
51initial_condition_task.add_action_set(
52 InitialCondition(self._solver, guard=self._solver.grid_selector.createCellGuard())
53)
54project_on_faces_task.add_action_set(
55 ProjectPatchOntoFaces(
56 self._solver._patch,
57 self._solver._patch_overlap_update,
58 guard=self._solver.grid_selector.createCellGuard(),
59 includes=self._solver._get_default_includes() + self._solver.user_solver_includes,
60 )
61)
62project_on_faces_task.add_action_set(
63 RollOverUpdatedFace(
64 self._solver._patch_overlap_current_time_step,
65 self._solver._patch_overlap_update,
66 guard=self._solver.grid_selector.createFaceGuard(),
67 includes=self._solver._get_default_includes() + self._solver.user_solver_includes,
68 )
69 )
70
71setup_simulation.add_task(refine_task)
72setup_simulation.add_task(consolidate_load_balancing_task)
73setup_simulation.add_task(initial_condition_task)
74setup_simulation.add_task(project_on_faces_task)
75
76initial_condition_task.use_cell(self._solver._patch, peano4.api.taskgraph.Task.DataAccess.WRITE)
77project_on_faces_task.use_cell(self._solver._patch, peano4.api.taskgraph.Task.DataAccess.READ_AND_WRITE)
78project_on_faces_task.use_face(self._solver._patch_overlap_update, peano4.api.taskgraph.Task.DataAccess.TEMPORARY)
79project_on_faces_task.use_face(self._solver._patch_overlap_current_time_step, peano4.api.taskgraph.Task.DataAccess.WRITE)
80
81setup_simulation.visualise(title="Setup task graph for {}".format(self._solver.name))
82setup_simulation.log_as_text(title="Setup task graph for {}".format(self._solver.name))
83~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
84
85
86The typical steps are always the same:
87
881. Create the tasks.
892. Give them a name, specify if they can repeat (off by default) and specify over which mesh entity they operate.
903. Add action sets to the tasks. Action sets are the actual code that is triggered by a task (and executed during a mesh traversal corresponding to this task later).
914. Add dependencies between the tasks.
925. Add task to task graph.
93
94
95Note the nice feature at the end of the script: The API comes along
96with a routine to visualise the arising task graph. This is the same
97feature used for the example image above.
98
99## Mapping the task graph onto Peano
100
101The idea behind the task graph feature of Peano is that there are different
102compilers which take the task graph and lower it onto grid traversals.
103The term "lower" is taken from the xDSL compiler project and highlights that
104we go from more abstract definitions close to the actual implementation.
105
106There are different compilers available, each producing a different type of
107a task graph implementation. You find them all in @ref peano4.api.taskgraph.compiler.
108The simples one if @ref @ref peano4.api.taskgraph.compiler.Sequential, which
109maps the task graph onto a total order preservering the dependencies. Each task
110of the rearranged total order (each step) is then mapped onto one mesh traversal.
111This is the simplest way to execute a task graph, through obviously might not
112be the most efficient one.
113
114Besides the lowering onto Peano mesh traversals, the compilers also yield
115brief functions which we can call from the main() function later to step
116through all the mesh traversals which make up one task graph realisation.
117
118
119## Graph properties
120
121<div style="background-color: #f0c ; padding: 10px; border: 1px solid green;">
122The task graph implicitly models dependencies over touch-first events. This is,
123if a task A is formalised over faces and B depends on cells, then the task graph
124compiler might later conclude that A and B can be done in one mesh sweep, as
125all touchFaceFirstTime() complete before any touchCellFirstTime() is called on
126adjacent faces. These dependencies are not validated. Task A might as well host
127an action set which does something in touchFaceLastTime() which feeds into B.
128It is the user's responsibility to ensure that the tasks are formalised correctly.
129</div>
130
131
132### Task dependencies
133
134Each task can depend on an arbitrary number of predecessor tasks. There is
135no feature to model outgoing dependencies. They are implicitly given by other
136tasks referencing predecessors.
137
138The task graph does not have to have a unique root task. It can comprise
139multiple ready tasks and can have multiple terminal tasks.
140
141### Tasks and action sets
142
143Each task can hold an arbitrary number of Peano 4 action sets (@ref peano4.api.solversteps.ActionSet).
144Each action set can plug into all kinds of events. This seems to be a contradiction:
145The task is tied to a particular mesh entity, while the action set can define actions for multiple mesh entities.
146The task association defines dependencies, the action set what is done.
147If task A depends on B and B is tied to vertices, any operation over a cell in
148A will be executed after all operations over the cell's adjacent vertices in B
149have completed.
150The action sets of A still might also do something on cells and faces as well,
151but this is not subject to the dependency handling.
152
153### Task repetition
154
155By default, tasks in the task graph do not repeat. This means that they are
156executed once. But users can attach a boolean expression to a task which is
157evaluated at the end of the task's execution. If it evaluates to true, then the task is repeated. This is useful for tasks that need to be executed multiple times until a certain condition is met.
158Unfortunately, a task that can repeat can never be merged with any successor,
159so these repeating tasks kind of veto any optimisation.
160
161### Task tags
162
163Each task can carry arbitrarily many tags. They are plain strings, stored
164in the set tags of @ref peano4.api.taskgraph.Task.Task, so one task can be
165tagged by several independent parties at the same time. Tags are global:
166Nobody constructs a tag object.
167
168~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
169task = peano4.api.taskgraph.Task(name="Update cell",
170 entity=peano4.api.taskgraph.Task.GridEntity.CELL,
171 tags={"MYTAG"})
172task.tags.add(exahype2.api.Solver.SolutionUpdateTaskTag)
173task.tags.add("MYOTHERTAG")
174~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
175
176Tags allow you to pick out tasks from a graph which someone else has
177built: If you know that there is a task tagged with MYTAG, then
178@ref peano4.api.taskgraph.Graph.find_tasks() returns all tasks which carry
179this tag, and you can add new tasks behind them through
180@ref peano4.api.taskgraph.Graph.insert_after().
181
182The tags carry no intrinsic semantics from the task graph's point of view,
183i.e. the task graph compilers ignore them. It is up to the user to define
184their meaning.
185
186
187
188@see @ref peano4.api.taskgraph.Task
189@see @ref peano4.api.taskgraph.Graph
190@see @ref peano4.api.taskgraph.compiler
191@see @ref peano4.api.taskgraph.create_runner
192
193"""
194
195from .Task import Task
196from .Graph import Graph, wait_for_visualisations
197from .Runner import create_runner
198from . import compiler