Architecture
This section describes the internal architecture of Catalyst, including the runtime dispatch mechanism, implementation loading, and the optional asynchronous execution mode.
Overview
Catalyst is designed as a thin dispatch layer between simulation codes and in situ processing implementations. Its architecture enforces a strict separation between the API consumed by simulations and the implementations that perform actual data analysis and visualization.
┌────────────────────────────────────────────────────────┐
│ Simulation Code │
│ (NekRS, FUN3D, MINT, etc.) │
└──────────────────────┬─────────────────────────────────┘
│ conduit_node*
▼
┌────────────────────────────────────────────────────────┐
│ Adaptor │
│ Builds Conduit Blueprint mesh, calls Catalyst API │
└──────────────────────┬─────────────────────────────────┘
│ catalyst_execute()
▼
┌────────────────────────────────────────────────────────┐
│ libcatalyst (catalyst_api.c) │
│ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ Runtime Dispatch │ │
│ │ • dlopen / LoadLibrary │ │
│ │ • Function pointer table (catalyst_impl) │ │
│ └─────────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ Async Layer (optional) │ │
│ │ • Worker thread, bounded queue │ │
│ │ • Deep copy via compact_to() │ │
│ │ • MPI-synchronized skip decisions │ │
│ └─────────────────────────────────────────────────┘ │
└──────────────────────┬─────────────────────────────────┘
│ impl->execute()
▼
┌────────────────────────────────────────────────────────┐
│ Implementation Library │
│ (libcatalyst-paraview.so, libcatalyst-stub.so, etc.) │
└────────────────────────────────────────────────────────┘
Runtime Dispatch
The core of Catalyst is catalyst_api.c, which maintains a static pointer to
a catalyst_impl structure:
struct catalyst_impl
{
int version;
enum catalyst_status (*initialize)(const conduit_node*);
enum catalyst_status (*execute)(const conduit_node*);
enum catalyst_status (*finalize)(const conduit_node*);
enum catalyst_status (*about)(conduit_node*);
enum catalyst_status (*results)(conduit_node*);
conduit_uint64 conduit_is_external;
};
When catalyst_initialize() is called, Catalyst locates and loads an
implementation library using the following search order:
The name specified in
params["catalyst_load/implementation"]The
CATALYST_IMPLEMENTATION_NAMEenvironment variableIf neither is set, the built-in stub implementation is used
The implementation library is found by searching:
Paths in
params["catalyst_load/search_paths"]Paths in
CATALYST_IMPLEMENTATION_PATHSenvironment variableThe
catalyst/directory adjacent tolibcatalyst
Once loaded, the library’s exported catalyst_api_impl symbol provides the
function pointer table. Catalyst validates the version and Conduit ABI
compatibility before accepting the implementation.
This design means a simulation compiled against the stub can switch to ParaView Catalyst (or any other implementation) at runtime by simply setting environment variables, without recompiling.
Key Source Files
src/catalyst/catalyst_api.cThe dispatch layer. Loads implementations via
dlopen/LoadLibrary, maintains the globalimplpointer, and routes all API calls through the function pointer table.src/catalyst/catalyst_impl.hDefines the
catalyst_implstructure that implementations must export.src/catalyst/catalyst_stub.cppThe default (stub) implementation. Optionally dumps Conduit nodes for debugging.
src/catalyst/catalyst_api_default.cppWires the stub functions into a
catalyst_implstructure as the compile-time default.src/catalyst/catalyst_async.cppThe async execution layer. See Asynchronous Execution for details.