Peano
|
As several code types are built on top of the same Peano infrastructure, we can always combine them or alter the underlying Peano representation by adding additional mesh traversals for example.
Peano's Python API is a mere wrapper around the Peano C++ core, i.e. it provides a high-level abstraction of Peano's action sets, the data held by a Peano application, its Makefile, and so forth. Popular Peano extensions then create a layer on top of this API which eventually yields a Peano project. Obviously, once you have lowered the abstraction level into a Peano project, you can still alter this whole application model. Indeed, you can now add technical details that have previously been hidden, or you can combine different projects.
We distinguish various different terms in the context of coupling:
Before we continue, we emphasise that we rely heavily on terms like observer and also make use of the notion of action sets. Each mesh sweep is tied to one observer, which in turn is represented by a peano4.solversteps.Step object.
Skip this part if you work with only one extension and want to add additional helper grid sweeps, e.g. If you have two extensions - such as ExaHyPE and MGHyPE or Swift - which both create Peano projects, you end up with a high-level code which resembles:
Solvers for each project need to be added (possibly, several):
An empty global Peano project is created, followed by subsequently adding the projects from the above two extensions into the global one:
Once merged (which was done by the new add_subproject
method above), source files (such as repositories/StepRepository.h
) are generated by calling peano4_project.generate()
or peano4_project.build(make_clean_first=True, number_of_parallel_builds=args.j)
methods. The files are written each correspondingly to their extension project in their own subdirectory
which was passed as a parameter in their extension Project
class constructor. Thus, there'll be two instances for every source file, such as (using the example of StepRepository.h
):
The generated main header and source files will be located in the common application folder (corresponding to peano4_project.directory
, above the subprojects' subdirectories) and have the names peano4_project.project_name + "-main.h"
and peano4_project.project_name + "-main.cpp"
respectively. Initially, it is created using the template from extension set as "master"
(in our example, this is the first extension indicated by the master=True
parameter). A template from any extension contains definitions for the selectNextAlgorithmicStep()
and step()
functions. The generated instances of these functions in the source file have to be modified to include the steps from the second extension (non-master
extension). The choice of master
and non-master
is somewhat arbitrary; the goal is to manually insert all the steps from the non-master
extension into the master
extension, so perhaps it makes sense to choose the more complex one as master
which has more steps. Thus, your task becomes copying the steps from the template of the non-master
extension and inserting them one by one in the appropriate positions between the steps of the master
extension (in the generated source file). Keep in mind that the template file may contain template expressions which are translated in C++ expression in the generated source file, so it is suggested to switch temporarily the master
extension to generate a source file from the other extension to copy the steps from there instead from the template. Now, the main source file is adapted and includes all the steps from both extension projects in the right order.
Once lowered, you can also add new algorithmic steps as they are required for separate coupling sweeps, e.g. From hereon, the (merged) Peano 4 project is the work data set, as any change in the original project (such as an exahype2.Project instance) does not propagate through anymore.
Once merged, it is reasonably to doublecheck the generated file
in each extension subdirectory. Each of them defines observers from their corresponding extension project, but StepRepository
notably hosts an enum called Steps
which accommodates identifiers for the steps from their corresponding project.
Peano usually expects that the high-level extension ensures that no two algorithmic steps use the same name for two different observers. Our approach in merging two projects guarantees unique names by using namespaces passed as parameters when creating extension projects. Therefore, steps with the same name from solvers of different extension projects are differentiated as simple as
and projectB.namespace + "::Step1</tt>, where <tt>"Step1"</tt> is the step name
in both solvers.
@section autotoc_md1253 Add additional mesh sweeps manually
Once you have the low-level Peano project, you can add an arbitrary number of
additional algorithmic steps. Each step models a new mesh sweep and
gives you a brand new observer object:
@icode
additional_step = peano4.solversteps.Step( name = "AdditionalStep",
add_user_defined_actions=False,
)
peano4_project.solversteps.add_step( additional_step )
@endicode
Passing in True gives you a C++ template which you can befill with
semantics. Consult the @ref page_architecture_home "architecture" and
@ref peano_action_sets "action set" descriptions. Per step added, you should find a new class in observers.
Unify the data usage
Though the repository now contains both solver's data structures and observers, the observers are not yet compatible with each other: Each observer needs to be told via use_face(), use_cell() and use_vertex() which data entities are out there. If we construct two separate solvers, solver A knows nothing of the data declared in solver B and vice versa. If we introduce additional mesh sweeps, these mesh sweeps do not know anything of each other either.
The merge() operation for the projects automatically ensures that all data are correct: It runs, for example, through all use_vertex() data of the first observer of solver A and adds those guys to all steps in solver B. There are some assumptions here to make this work:
Additional external mesh sweeps are slightly more complicated. Here, we have to add all the use statements manually. Fortunately, some extensions such as ExaHyPE offer routines to register external, additional mesh sweeps, and you should use those.
Create a merged main file
Once you have created your fused project with additional mesh traversals, you can alter your main routine and invoke the steps from the new, joint project.
The toggling is straightforward and simple. However, you might have objects with states in your code, such as global solver objects. Some of these toggle their state after and before each mesh sweep, and then they make their behaviour depend upon the actual state. Some extensions therefore define routines such as
which you can use in the code to ensure that solvers do not misbehave.
Lowering two codes into a Peano project (additively)