Views

The BUMP component provides lightweight, device-compatible, view classes that add a C++ interface for Blueprint data. Blueprint data defines several object protocols represented with arrays of various data types. Views can simplify the process of writing algorithms to support Blueprint data. Views do not own their data so they can be easily copied, making them suitable for use in device kernels.

ArrayView

Axom provides axom::ArrayView to wrap data in a non-owning data structure that can be passed to kernels. The BUMP component provides the axom::bump::utilities::make_array_view() function to help wrap arrays stored in conduit::Node to axom::ArrayView. To use the make_array_view function, one must know the type held within the Conduit node. If that is not the case, then consider using one of the dispatch ‘’nodeToArrayView’’ functions.

// Make an axom::ArrayView<float> for X coordinate components.
auto x = axom::bump::utilities::make_array_view<float>(n_mesh["coordsets/coords/values/x"]);

Coordsets

Blueprint supports multiple coordset (coordinate set) types: uniform, rectilinear, explicit. Axom provides functions to explicitly create coordset views for each of these types.

namespace views = axom::bump::views;
// Make a 2D uniform coordset view
auto view1 = views::make_uniform_coordset<2>::view(n_mesh["coordsets/coords"]);
// Make a 3D uniform coordset view
auto view2 = views::make_uniform_coordset<3>::view(n_mesh["coordsets/coords"]);
// Make a 2D rectilinear coordset view with float coordinates
auto view3 = views::make_rectilinear_coordset<float, 2>::view(n_mesh["coordsets/coords"]);
// Make a 3D rectilinear coordset view with double coordinates
auto view4 = views::make_rectilinear_coordset<double, 3>::view(n_mesh["coordsets/coords"]);
// Make a 2D explicit coordset view with float coordinates
auto view5 = views::make_explicit_coordset<float, 2>::view(n_mesh["coordsets/coords"]);
// Make a 3D explicit coordset view with double coordinates
auto view6 = views::make_explicit_coordset<double, 3>::view(n_mesh["coordsets/coords"]);

Topology Views

Topology views provide a layer on top of the Blueprint mesh topology that enables Axom algorithms to be written while not needing to care specifically about topology types and data types. Axom provides topology views for structured meshes and unstructured meshes.

Structured Mesh Views

The structured mesh topology view, axom::bump::views::StructuredTopologyView, pertains to any of the Blueprint structured topology types. The StructuredTopologyView class is a template that takes an indexing policy as a template argument. The indexing policy computes zone indices and converts to/from logical/global indices. The StridedStructuredIndexingPolicy class supports indexing for strided-structured Blueprint meshes, which are structured meshes that exist over a sub-window of the overall mesh. There are helper functions for creating structured topology views from a Conduit node.

namespace views = axom::bump::views;
conduit::Node &n_topo1 = n_mesh["topologies/mesh2d"];
conduit::Node &n_topo2 = n_mesh["topologies/mesh3d"];
conduit::Node &n_topo3 = n_mesh["topologies/mesh2dss"];
// Make a 2D structured mesh view from the topology.
auto topologyView1 = views::make_structured_topology<2>::view(n_topo1);
// Make a 3D structured mesh view from the topology.
auto topologyView2 = views::make_structured_topology<2>::view(n_topo2);
// Make a 2D strided-structured mesh view from the topology.
auto topologyView3 = views::make_strided_structured_topology<2>::view(n_topo3);

Unstructured Mesh Views

There are 3 unstructured mesh views, covering single shape meshes, mixed shape meshes, and polyhedral meshes. The axom::bump::views::UnstructuredTopologySingleShapeView class wraps a Blueprint topology that contains a single zone/shape type. The zone type is a template argument that determines the type of zone that is held within the topology.

// Make a topology view for a tetrahedral mesh with int connectivity.
namespace views = axom::bump::views;
namespace utils = axom::bump::utilities;
const conduit::Node &n_topo = n_mesh["topologies/mesh"];
const auto connView = utils::make_array_view<int>(n_topo["elements/connectivity"]);
views::UnstructuredTopologySingleShapeView<views::TetShape<int>> view(connView);

There are multiple shape types defined in axom/bump/views/Shapes.hpp that can be used with the UnstructuredTopologySingleShapeView class: TriShape, QuadShape, TetShape, PyramidShape, WedgeShape, and HexShape.

Blueprint supports mixed topologies that contain multiple shape types. These topologies are handled using the axom::bump::views::UnstructuredTopologyMixedShapeView. Additional array views are needed to supply the sizes, offsets, and shapes arrays.

// A shape map helps map values from the values used in the Blueprint topology to
// the shape ids used in Axom.
namespace views = axom::bump::views;
namespace utils = axom::bump::utilities;

const conduit::Node &n_topo = n_mesh["topologies/mesh"];
const int allocatorID = axom::execution_space<ExecSpace>::allocatorID();
axom::Array<int> ids, values;
auto shapeMap = views::buildShapeMap(n_topo, ids, values, allocatorID);

views::UnstructuredTopologyMixedShapeView<int> view(
  utils::make_array_view(n_topo["elements/connectivity"),
  utils::make_array_view(n_topo["elements/sizes"),
  utils::make_array_view(n_topo["elements/offsets"),
  utils::make_array_view(n_topo["elements/shapes"),
  shapeMap);

The final unstructured topology view is axom::bump::views::UnstructuredTopologyPolyhedralView and it provides a view interface to polyhedral meshes.

    auto topoView =
      TopologyView(utils::make_array_view<ConnectivityType>(n_topo["subelements/connectivity"]),
                   utils::make_array_view<ConnectivityType>(n_topo["subelements/sizes"]),
                   utils::make_array_view<ConnectivityType>(n_topo["subelements/offsets"]),
                   utils::make_array_view<ConnectivityType>(n_topo["elements/connectivity"]),
                   utils::make_array_view<ConnectivityType>(n_topo["elements/sizes"]),
                   utils::make_array_view<ConnectivityType>(n_topo["elements/offsets"]));

Once a suitable topology view type has wrapped a Blueprint topology, it can be used in device kernels to obtain zone information.

auto topologyView = ...
axom::for_all<ExecSpace>(topologyView.numberOfZones(), AXOM_LAMBDA(axom::IndexType zoneIndex)
{
  // Get the current zone.
  const auto zone = topologyView.zone(zoneIndex);

  // Iterate over this zone's nodes.
  for(const auto &nodeId : zone.getIds())
  {
    // Do something.
  }
});

Matsets

The BUMP component provides material views to wrap Blueprint matsets behind an interface that supports queries of the matset data without having to care much about its internal representation. Blueprint provides 4 flavors of matset, each with a different representation. The axom::bump::views::UnibufferMaterialView class wraps unibuffer matsets, which consist of several arrays that define materials for each zone in the associated topology. The view’s methods allow algorithms to query the list of materials for each zone.

      using MatsetView = axom::bump::views::UnibufferMaterialView<int, float, 3>;
      MatsetView matsetView;
      matsetView.set(utils::make_array_view<int>(deviceMesh["matsets/mat/material_ids"]),
                     utils::make_array_view<float>(deviceMesh["matsets/mat/volume_fractions"]),
                     utils::make_array_view<int>(deviceMesh["matsets/mat/sizes"]),
                     utils::make_array_view<int>(deviceMesh["matsets/mat/offsets"]),
                     utils::make_array_view<int>(deviceMesh["matsets/mat/indices"]));

Dispatch

There are several helper functions that wrap a Conduit node in a specific view type and dispatch the view to a user-supplied lambda for further processing. The lambda function will typically be instantiated multiple times to handle various data types and object types (e.g. coordsets). Generic lambdas can be used to process multiple views and it is possible to nest dispatch functions to handle added complexity.

Array Data

Blueprint data can readily be wrapped in axom::ArrayView using the axom::bump::utilities::make_array_view() function. There are dispatch functions for conduit::Node data arrays that automate the wrapping to axom::ArrayView and passing the views to a user-supplied lambda.

To generically wrap any type of datatype supported by Conduit, the axom::bump::views::nodeToArrayView() function can be used. This template function takes a variable number of conduit::Node arguments and a generic lambda function that accepts the view arguments. The lambda gets instantiated for every supported Conduit data type.

conduit::Node n; // Assume it contains data values
axom::bump::views::nodeToArrayView(n["foo"], n["bar"], [&](auto fooView, auto barView)
{
  // Use fooView and barView axom::ArrayView objects to access data.
  // They can have different types.
});

Using axom::bump::views::nodeToArrayView with multiple data values can instantiate the supplied lambda many times so be careful. It is more common when wrapping multiple nodes that they are the same type. The axom::bump::views::nodeToArrayViewSame function ensures that the lambdas get instantiated with views that wrap the Conduit nodes in array views that of the same type.

conduit::Node n; // Assume it contains data values
axom::bump::views::nodeToArrayViewSame(n["foo"], n["bar"], [&](auto fooView, auto barView)
{
  // Use fooView and barView axom::ArrayView objects to access data.
  // They have the same types.
});

When dealing with mesh data structures, it is common to have data that are using only integer types or only floating-point types. Axom provides functions that limit the lambda instantiation to only those selected types using the following functions:

  • axom::bump::views::indexNodeToArrayView()

  • axom::bump::views::indexNodeToArrayViewSame()

  • axom::bump::views::floatNodeToArrayView()

  • axom::bump::views::floatNodeToArrayViewSame()

The “Index” functions limit lambda instantiation to common index types signed/unsigned 32/64-bit integers. The “Float” functions instantiate lambdas with float32 and float64 types.

Coordsets

The axom::bump::views::dispatch_coordset() function can wrap Blueprint coordsets in an appropriate view and pass it to a lambda function.

const conduit::Node &n_coordset = n_mesh["coordsets/coords"];
axom::bump::views::dispatch_coordset(n_coordset, [&](auto coordsetView) {
  // Get the C++ type of the coordset.
  using CoordsetView = decltype(coordsetView);
  // Implement algorithm using coordsetView.
});

Topologies

Dispatch functions for topologies enable creation of algorithms that can operate on multiple topology types through a topology view. These dispatch functions can be called for specific topology types such as unstructured topologies or they can be called to implement algorithms that can operate on any topology.

namespace views = axom::bump::views;
const conduit::Node &n_topo = n_mesh["topologies/mesh"];
// Handle rectilinear topology type.
views::dispatch_rectilinear_topology(n_topo, [&](auto topologyView) {
});
// Handle structured topology types
views::dispatch_structured_topology(n_topo, [&](auto topologyView) {
});
// Handle unstructured topology types
views::dispatch_unstructured_topology(n_topo, [&](auto topologyView) {
});
// Handle any topology type.
views::dispatch_topology(n_topo, [&](auto topologyView) {
});

Nesting dispatch functions permits the calling code to handle both coordset views and topology views using a compact amount of code. For portability, the actual algorithm should be placed in a function or class member method when instantiated from the anonymous lambda function from the dispatch functions.

struct Algorithm
{
  void execute(const conduit::Node &n_mesh)
  {
    namespace views = axom::bump::views;
    // Handle product of coordset types and topology types.
    views::dispatch_coordset(n_mesh["coordsets/coords"], [&](auto coordsetView)
    {
      views::dispatch_topologies(n_mesh["topologies/mesh"], [&](auto topologyView)
      {
        implementation(coordsetView, topologyView);
      });
    });
  }

  template <typename CoordsetView, typename TopologyView>
  void implementation(CoordsetView coordsetView, TopologyView topologyView) const
  {
    // Algorithm that involves coordsetView and topologyView.
  }
};