Catalyst for Simulation Developers

This section describes how simulation (and other computational codes) can use Catalyst.

Building with Catalyst

To use the Catalyst API in any code, the code must be built against an implementation of the Catalyst API. While one can use any implementation of the Catalyst API, the stub implementation is probably the easiest to build against since it doesn’t have any external dependencies besides compiler tools.

There are two ways codes can build with Catalyst: using CMake, or using any build tool like make.

Using CMake

If your code already uses CMake as the build system generator, then to use Catalyst APIs, you simply need to find the Catalyst install using find_package and the link against the catalyst::catalyst target. This is done as follows:

 1# Find the Catalyst install.
 2#
 3# The version is optional but recommended since it lets you choose
 4# the compatibility version. The only supported value currently is 2.0
 5#
 6# REQUIRED ensures that CMake raises errors if Catalyst is not found
 7# properly.
 8
 9find_package(catalyst 2.0 REQUIRED)
10
11
12# Your simulation will have an executable (or a library) that
13# houses the main-loop in which you'll make the Catalyst API falls.
14# You need to link that executable (or the library) target with Catalyst.
15# This is done as follows (where simulation_target must be replaced by the
16# name of the correct executable (or library) target.
17
18target_link_library(simulation_target
19  PRIVATE catalyst::catalyst)

Now, when you run cmake on your simulation code, a new cache variable catalyst_DIR can be set to the directory containing the file catalyst-config.cmake to help CMake find where you built Catalyst. That file can be found in either the Catalyst build directory or the Catalyst install directory.

Using make (or similar)

If not using CMake as the build system generator for your simulation code, it is still easy to make it aware of Catalyst. You simply need to pass the include path i.e. the location where the Catalyst headers are available, and the location and library to link against.

In a typical Catalyst install at location, CATALYST_INSTALL_PREFIX, these are:

  • Include path: <CATALYST_INSTALL_PREFIX>/include/catalyst-2.0

  • Library path: <CATALYST_INSTALL_PREFIX>/lib

  • Library: <CATALYST_INSTALL_PREFIX>/lib/libcatalyst.so

Using gcc, for example, this translates to the following command-line:

gcc test_driver.c -I<CATALYST_INSTALL_PREFIX>/include/catalyst-2.0 <CATALYST_INSTALL_PREFIX>/lib/libcatalyst.so.3

Catalyst API

Catalyst API is used by simulations to invoke Catalyst for co-processing. To use the Catalyst API, one must include the catalyst.h header file.

catalyst_initialize

enum catalyst_status catalyst_initialize(const conduit_node* params);

This function must be called once to initialize Catalyst. Metadata that can be used to configure the initialize is provided using a params pointer.

The catalyst will attempt to load the implementation named using params["catalyst_load/implementation"]. If not specified, but the CATALYST_IMPLEMENTATION_NAME environment variable is, it will be used. If no implementation is named, a default implementation using the stub functions will be used.

If an implementation is named, it will be loaded at runtime using dlopen (or the platform equivalent) by searching the nodes specified under the params["catalyst_load/search_paths"] node. Next, the paths specified by the CATALYST_IMPLEMENTATION_PATHS (using ; as a separator on Windows and : otherwise) will be searched. Finally, the catalyst directory beside libcatalyst will be searched. Once found, it will be loaded and inspected for compatibility. If it is compatible, the implementation will be loaded and made available. The return code indicates the error received, if any.

The search priority of the CATALYST_IMPLEMENTATION_ environment variables may be made first by setting teh CATALYST_IMPLEMENTATION_PREFER_ENV environment variable to a non-empty value.

catalyst_finalize

enum catalyst_status catalyst_finalize(const conduit_node* params);

This function must be called once to finalize Catalyst. Metadata is passed using params pointer.

catalyst_execute

enum catalyst_status catalyst_execute(const conduit_node* params);

This function is called for every time step as the simulation advances. This is the call in which the analysis may execute. params provides metadata as well as the data generated by the simulation for that time-step.

catalyst_about

enum catalyst_status catalyst_about(conduit_node* params);

This function fills up the params instance with metadata about the Catalyst library being used.

catalyst_results

enum catalyst_status catalyst_results(conduit_node* params);

This function fills up the params instance with updated parameters values from the Catalyst implementation side.

All the above functions use a params object which is a conduit_node. It is simply a hierarchical mechanism for describing data and/or metadata including simulation meshes and fields. Essentially, think of it as a map where keys are strings called paths and values are either data or pointers to data. What these keys can be and what they mean is totally up to the Catalyst API implementation being used.

To create and populate the conduit_node instance, you use the Conduit C API. e.g.

conduit_node* node = conduit_node_create();
conduit_node_set_path_int(node, "sim/timestep", 0);
conduit_node_set_path_double(node, "sim/time", 1.212);
...
conduit_node_destroy(node);

Refer to Conduit documentation for details of the C API. [TODO: there are no docs for Conduit C API upstream].