SpECTRE
v2023.01.13
|
This tutorial will illustrate what is needed to compile the minimal SpECTRE executable that will simply print some useful information about the executable and then exit.
Specifically, this tutorial will introduce:
add_spectre_parallel_executable
, a CMake function that will add a build target for a SpECTRE executableMetavariables
, a C++ struct that is used to specify the metaprogram that is converted into a C++ executable.Main
, the main parallel component that acts as the main function of a C++ executable.In this tutorial, SPECTRE_ROOT
refers to the directory in which SpECTRE was cloned, and SPECTRE_BUILD_DIR
refers to the directory in which you built SpECTRE.
The first step is to select (or create) a directory (within SPECTRE_ROOT/src
) that will hold the files from which the executable will be created. For this tutorial we created the directory ParallelTutorial
in src/Executables/Examples
. If you create a new directory for the executable, you will need to edit the CMakeLists.txt
file in its parent directory and add (replacing ParallelTutorial
with the appropriate directory name)
The second step is to edit (or create) the CMakeLists.txt
file in the executable directory and add a call to add_spectre_parallel_executable
such as:
The (SpECTRE defined) CMake
function add_spectre_executable
takes five arguments:
MinimalExample
) that will be created, which will also be the name of the corresponding build target.MinimalExecutable
) of the two user-provided files that declare (MinimalExecutableFwd.hpp
) and define (MinimalExecutable.hpp
) a C++ struct (or struct template) that will describe the metaprogram that is converted into a C++ executable. We will refer to this struct (template) as the metavariables struct (template), and the files declaring and defining the metavariables struct (template) as the metavariables files.SPECTRE_ROOT/src
to the directory holding the metavariables files (in the given example Executables/Examples/ParallelTutorial
)Metavariables
) that will be used to create the executable. This is either the name of the metavariables struct in the metavariables files, or a specific instantiation of the metavariables struct template in the metavariables files.CMake
list LIBS_TO_LINK
where Informer
and Utilities
are two SpECTRE libraries)The header files from which an executable is generated must declare and define a metavariables struct that can be thought of as a compile-time input file that defines what the executable will do.
The first metavariables file (MinimalExecutableFwd.hpp
) is simply a forward declaration of the metavariables struct:
(Note that #pragma once
tells the compiler to only include the file once per compilation, and the /// \cond
and /// \endcond
around the code tells doxygen not to generate documentation from the wrapped region)
The second metavariables file (MinimalExecutable.hpp
) holds the definition of the metavariables struct.
The metavariables struct must define a static constexpr std::array<Parallel::Phase, N> default_phase_order
that is used to define the default order in which phases are executed. In this example the executable will execute the Initialization
phase followed by the Exit
phase. (Parallel::CProxy_GlobalCache
is an unused proxy to the GlobalCache
that is explained below)
The metavariables struct must define a type alias component_list
that is a tmpl::list
(a typelist defined in Utilities/TMPL.hpp
) of the parallel components used by the executable. In this example no parallel components are used.
The metavariables struct must define help
, a static constexpr Options::String
that will be printed as part of the help message of the executable. (Options::String
is defined in Options/Options.hpp
.)
In addition to defining the metavaribles struct, the metavariables file must define the two vectors of functions charm_init_node_funcs
and charm_init_proc_funcs
that are executed at startup by Charm++ on each node and processing element (PE) the executable runs on. In this example, the vectors are empty.
Let $EXECUTABLE
be the name of the executable (the first argument passed to the add_spectre_executable
CMake
function, so in this example MinimalExample
). Then the executable can be built by running the following command in $SPECTRE_BUILD_DIR
:
which will produce the executable of the same name in $SPECTRE_BUILD_DIR/bin
.
To run a SpECTRE executable, run the command:
where <options>
must include any required command-line options. In the simple example for this tutorial, no command-line options are required.
On a laptop, we get the following output:
which includes information that will be printed by every SpECTRE executable on startup and exit. First, there is information provided by Charm++
that will depend upon how Charm++
was built. Next you will see information provided by SpECTRE which includes:
On exit, the executable will print that it is Done!
, followed by how the long the executable took to run as timed by the Charm++
wall-clock timer, and the date and time at completion, followed by any information the Charm++
provides upon exiting the program.
Every SpECTRE executable comes with a set of command-line options that can be used to obtain useful information about the executable (and for executables expecting an input file, whether or not the input file can be parsed successfully).
To get a list of available options for a SpECTRE executable, run either of the following commands:
In the middle of the Charm++
startup information will now appear a long list of Charm++
related command-line options which we will ignore for this tutorial. After the SpECTRE startup information, there is now a list of available command-line options:
which we will describe in detail below. This is followed by a description of the expected input-file options, which in this example will simply print the help
string from the metavariables struct, and the statement that there are no options expected:
We will cover input file options in a future tutorial.
As the minimal executable in this tutorial expects no input-file options, running the command:
will print out No options to check!
and exit the program. See a future tutorial for an example of checking input-file options.
In order to aid in reproducibility, all SpECTRE executables contain a copy of $SPECTRE_ROOT
. To obtain the source tree as an archive file, run the command:
which will produce the archive file SpECTRE.tar.gz
which can be expanded with the command:
In addition to dumping the entire source tree there are the following options:
--dump-paths
will print out various paths from when the executable was compiled--dump-environment
will print the results of printenv
(i.e. all of the environment variables) from when the executable was compiled--dump-build-info
will print the contents of SpECTRE's BuildInfo.txt
which will contain the versions of libraries that SpECTRE linked against, as well as various CMake
variablesAlso note that the option --dump-only
can be used to have the SpECTRE executable terminate immediately after dumping the information.
Every Charm++ executable needs a mainchare. All SpECTRE executables use Main
(found in src/Parallel/Main.hpp
) as the mainchare. When a SpECTRE executable is run, the constructor of Main
that is executed takes the command line options as an argument (as type CkArgMsg*
). This constructor performs the following operations:
GlobalCache
(a nodegroup chare) that holds objects created from input file options that are stored once per Charm++ node, as well as proxies to all other parallel components.GlobalCache
as well as any items they request that can be created from input file options.GlobalCache
.Once the list of parallel components is sent to the GlobalCache
on each node, the Main
member function allocate_array_components_and_execute_initial_phase
will be executed. This will allocate the elements of the array parallel components by calling the allocate_array
member function of each component. Then the start_phase
member function is called on each component, which will execute the phase action list for the Initialization
phase for each component. Charm++ will execute each phase until it detects that nothing is happening (quiescence detection). As this represents a global synchronization point, the number of phases should be minimized in order to exploit the power of SpECTRE. After each phase, the execute_next_phase
member function of Main
will be called. This member function first determines what the next phase is. If the next phase is Exit
, then some useful information is printed and the program exits gracefully. Otherwise the execute_next_phase
member function of each parallel component is called.