1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
|
// SPDX-FileCopyrightText: Copyright (c) Kitware Inc.
// SPDX-License-Identifier: BSD-3-Clause
#ifndef CatalystAdaptor_h
#define CatalystAdaptor_h
#include "FEDataStructures.h"
#include <catalyst.hpp>
#include <iostream>
#include <string>
/**
* The namespace hold wrappers for the three main functions of the catalyst API
* - catalyst_initialize
* - catalyst_execute
* - catalyst_finalize
* Although not required it often helps with regards to complexity to collect
* catalyst calls under a class /namespace.
*/
namespace CatalystAdaptor
{
/**
* In this example, we show how we can use Catalysts's C++
* wrapper around conduit's C API to create Conduit nodes.
* This is not required. A C++ adaptor can just as
* conveniently use the Conduit C API to setup the
* `conduit_node`. However, this example shows that one can
* indeed use Catalyst's C++ API, if the developer so chooses.
*/
void Initialize(int argc, char* argv[])
{
// Populate the catalyst_initialize argument based on the "initialize" protocol [1].
// [1] https://docs.paraview.org/en/latest/Catalyst/blueprints.html#protocol-initialize
conduit_cpp::Node node;
// Using the arguments given to the driver set the filename for the catalyst
// script and pass the rest of the arguments as arguments of the script
// itself. To retrieve these arguments from the script use the `get_args()`
// method of the paraview catalyst module [2]
// [2] https://www.paraview.org/paraview-docs/latest/python/paraview.catalyst.html
node["catalyst/scripts/script/filename"].set_string(argv[1]);
for (int cc = 2; cc < argc; ++cc)
{
conduit_cpp::Node list_entry = node["catalyst/scripts/script/args"].append();
list_entry.set(argv[cc]);
}
// For this example we hardcode the implementation name to "paraview" and
// define the "PARAVIEW_IMPL_DIR" during compilation time (see the
// accompanying CMakeLists.txt). We could however defined them via
// environmental variables see [1].
node["catalyst_load/implementation"] = "paraview";
node["catalyst_load/search_paths/paraview"] = PARAVIEW_IMPL_DIR;
catalyst_status err = catalyst_initialize(conduit_cpp::c_node(&node));
if (err != catalyst_status_ok)
{
std::cerr << "Failed to initialize Catalyst: " << err << std::endl;
}
}
void Execute(int cycle, double time, Grid& grid, Attributes& attribs)
{
// Populate the catalyst_execute argument based on the "execute" protocol [3].
// [3] https://docs.paraview.org/en/latest/Catalyst/blueprints.html#protocol-execute
conduit_cpp::Node exec_params;
// State: Information about the current iteration. All parameters are
// optional for catalyst but downstream filters may need them to execute
// correctly.
// add time/cycle information
auto state = exec_params["catalyst/state"];
state["timestep"].set(cycle);
state["time"].set(time);
state["multiblock"].set(1);
// Channels: Named data-sources that link the data of the simulation to the
// analysis pipeline in other words we map the simulation datastructures to
// the ones expected by ParaView. In this example we use the Mesh Blueprint
// to describe data see also bellow.
// Add channels.
// We only have 1 channel here. Let's name it 'grid'.
auto channel = exec_params["catalyst/channels/grid"];
// Since this example is using Conduit Mesh Blueprint to define the mesh,
// we set the channel's type to "mesh".
channel["type"].set("mesh");
// now create the mesh.
auto mesh = channel["data"];
// populate the data node following the Mesh Blueprint [4]
// [4] https://llnl-conduit.readthedocs.io/en/latest/blueprint_mesh.html
// start with coordsets (of course, the sequence is not important, just make
// it easier to think in this order).
mesh["coordsets/coords/type"].set("explicit");
// .set_external passes just the pointer to the analysis pipeline allowing thus for zero-copy
// data conversion see https://llnl-conduit.readthedocs.io/en/latest/tutorial_cpp_ownership.html
mesh["coordsets/coords/values/x"].set_external(
grid.GetPointsArray(), grid.GetNumberOfPoints(), /*offset=*/0, /*stride=*/3 * sizeof(double));
mesh["coordsets/coords/values/y"].set_external(grid.GetPointsArray(), grid.GetNumberOfPoints(),
/*offset=*/sizeof(double), /*stride=*/3 * sizeof(double));
mesh["coordsets/coords/values/z"].set_external(grid.GetPointsArray(), grid.GetNumberOfPoints(),
/*offset=*/2 * sizeof(double), /*stride=*/3 * sizeof(double));
// Next, add topology
mesh["topologies/mesh/type"].set("unstructured");
mesh["topologies/mesh/coordset"].set("coords");
mesh["topologies/mesh/elements/shape"].set("hex");
mesh["topologies/mesh/elements/connectivity"].set_external(
grid.GetCellPoints(0), grid.GetNumberOfCells() * 8);
// Finally, add fields.
// First component of the path is the name of the field . The rest are described
// in https://llnl-conduit.readthedocs.io/en/latest/blueprint_mesh.html#fields
// under the Material-Independent Fields section.
auto fields = mesh["fields"];
fields["velocity/association"].set("vertex");
fields["velocity/topology"].set("mesh");
fields["velocity/volume_dependent"].set("false");
// velocity is stored in non-interlaced form (unlike points).
fields["velocity/values/x"].set_external(
attribs.GetVelocityArray(), grid.GetNumberOfPoints(), /*offset=*/0);
fields["velocity/values/y"].set_external(attribs.GetVelocityArray(), grid.GetNumberOfPoints(),
/*offset=*/grid.GetNumberOfPoints() * sizeof(double));
fields["velocity/values/z"].set_external(attribs.GetVelocityArray(), grid.GetNumberOfPoints(),
/*offset=*/grid.GetNumberOfPoints() * sizeof(double) * 2);
// pressure is cell-data.
fields["pressure/association"].set("element");
fields["pressure/topology"].set("mesh");
fields["pressure/volume_dependent"].set("false");
fields["pressure/values"].set_external(attribs.GetPressureArray(), grid.GetNumberOfCells());
catalyst_status err = catalyst_execute(conduit_cpp::c_node(&exec_params));
if (err != catalyst_status_ok)
{
std::cerr << "Failed to execute Catalyst: " << err << std::endl;
}
}
// Although no arguments are passed for catalyst_finalize it is required in
// order to release any resources the ParaViewCatalyst implementation has
// allocated.
void Finalize()
{
conduit_cpp::Node node;
catalyst_status err = catalyst_finalize(conduit_cpp::c_node(&node));
if (err != catalyst_status_ok)
{
std::cerr << "Failed to finalize Catalyst: " << err << std::endl;
}
}
}
#endif
|