Catalyst 2 – Language wrappings

November 7, 2023

Simulations written in Python or Fortran can now utilize Catalyst 2.0 !

Catalyst 2.0 offers significant advantages over the original implementation including simpler integration to simulations thanks to a small yet powerful API as well as easier deployment due to its ABI-stable design which allows dynamically swapping backends at load-time when launching the simulation. All these benefits are now accessible through Python and Fortran thanks to the new language wrappings.

Background

One of the challenges of using the first ParaView Catalyst release was the process of building and deploying it in simulations.  The process required using a ParaView and VTK software development kit (SDK) which was often a convoluted process since it evolved by building a number of dependencies across a variety of systems.

Catalyst 2.0 and the Catalyst API were designed from the ground up to ease the deployment and integration of Catalyst with simulation codes. Thus, it was written in C which enabled providing a mechanism for ABI (Application Binary Interface) compatible implementations. The interoperability of C allowed us to wrap the Catalyst API in Fortran and Python at the adapter level.

In practice, this means that Catalyst 2.0 can now be used within simulations written in either C, C++, Fortran, or Python. The API uses the same naming conventions so transitioning between the wrappers is straightforward. When it comes to Conduit, the library used to pass arguments between Catalyst and the simulation, we reused the available Fortran and Python wrappings and contributed improvements upstream to make the integration easier.

Snippets

The new wrappings have also been exposed in ParaView through the ParaView-Catalyst implementation along with examples of how to use them. Here are some equivalent snippets:

C++

In C++ Conduit nodes are exposed as classes, this has the advantage of compact code and automatic type deduction. The Catalyst library is accessed via its C interface using a C++ convenience API:

#include <catalyst.hpp>
…

int update_timestep(int cycle, double time)
{
  conduit_cpp::Node exec_params;
  // add time/cycle information - catalyst-specific variable
  auto state = exec_params["catalyst/state"];
  state["timestep"].set(cycle);
  state["time"].set(time);

  // Add channel
  auto channel = exec_params["catalyst/channels/grid"];

  channel["type"].set("mesh");
  // Use Conduit Mesh Blueprint to define the mesh,
  // we set the channel's type to "mesh".
  auto mesh = channel["data"];
  mesh["coordsets/coords/type"].set("uniform");
  …
  return catalyst_execute(conduit_cpp::c_node(&exec_params));
}

C

In C we use the C API of Conduit. Here the types need to be explicitly defined. It is a C API, so resource management is manual; don’t forget to destroy the nodes at the end!

#include <catalyst.h>
…

int update_timestep(int cycle, double time)
{
  conduit_node *exec_params = conduit_node_create();
  // add time/cycle information - Catalyst-specific variables
  conduit_node_set_path_int64(catalyst_exec_params,     
    "catalyst/state/timestep", cycle);
  conduit_node_set_path_float64(catalyst_exec_params,    
    "catalyst/state/time", time);

  // Add channel
  conduit_node_set_path_char8_str(catalyst_exec_params,   
    "catalyst/channels/grid", "mesh");

  // Use Conduit Mesh Blueprint to define the mesh,
  conduit_node *mesh = conduit_node_create();
  conduit_node_set_path_char8_str(mesh, "topologies/mesh/type",  
    "uniform");
  …

  conduit_node_set_path_external_node(catalyst_exec_params, 
    "catalyst/channels/grid/data", mesh);

  int status = catalyst_execute(catalyst_exec_params);

  conduit_node_destroy(catalyst_exec_params);
  conduit_node_destroy(mesh);

  return status;
}

Fortran

The Fortran API is similar to C. Types must be explicitly defined and nodes must be destroyed explicitly.

use catalyst_api
use catalyst_conduit

subroutine catalyst_adaptor_execute(cycle,time)
  integer, intent(in) :: time
  real(kind=8), intent(in) :: time
  integer(kind(catalyst_status)) :: err

  catalyst_exec_params = catalyst_conduit_node_create()
  ! add time/cycle information - Catalyst-specific variables
  call catalyst_conduit_node_set_path_int32(catalyst_exec_params,   
    "catalyst/state/timestep", step)
  call catalyst_conduit_node_set_path_float64(catalyst_exec_params, 
    "catalyst/state/time", time)

  ! Add channel 
  channel = catalyst_conduit_node_fetch(catalyst_exec_params,   
    "catalyst/channels/grid")

  ! Use Conduit Mesh Blueprint to define the mesh
  mesh = catalyst_conduit_node_fetch(channel, "data")
  call catalyst_conduit_node_set_path_char8_str(mesh, 
    "coordsets/coords/type", "uniform")
  …
  err = c_catalyst_execute(catalyst_exec_params)
  if (err /= catalyst_status_ok) then
    write (stderr, *) "ERROR: Failed to execute Catalyst: ", err
  end if
  call catalyst_conduit_node_destroy(catalyst_exec_params)
end subroutine

Python

In Python, the API of the Conduit nodes closely resembles the one from dictionaries. Errors in any of the Catalyst calls are exposed as CatalystError exceptions.

import catalyst
import catalyst_conduit

def update_timestep(cycle,time):
  node = catalyst_conduit.Node()

  # add time/cycle information - catalyst-specific variables
  node['catalyst/state/timestep'] = cycle
  node['catalyst/state/time'] = time

  # Add channel
  node['catalyst/channels/input/type'] = 'mesh'

  # Use Conduit Mesh Blueprint to define the mesh
  mesh = node['catalyst/channels/grid/data']
  mesh['coordsets/coords/type'] = 'uniform'
  …
  # any errors will be thrown as a CatalystError exception
  catalyst.execute(node)

Note that even though we drew examples from the ParaView-Catalyst implementation the wrappers are implementation agnostic and can be used across any Catalyst 2.0 implementation. 

Next Step

To learn more about Catalyst head to the library documentation. To get started with the ParaView-Catalyst implementation check the corresponding section in ParaView documentation. Complete examples of the wrappings can be found in the ParaView examples directory. If you encounter any issues or have questions regarding the use of the Catalyst wrappings or Catalyst in general you can reach out in the in-situ support section of the ParaView discourse page. 

Acknowledgements

This research was supported by the Exascale Computing Project (17-SC-20-SC), a joint project of the U.S. Department of Energy’s Office of Science and National Nuclear Security Administration, responsible for delivering a capable exascale ecosystem, including software, applications, and hardware technology, to support the nation’s exascale computing imperative.

Leave a Reply