Working with vtkDataArrays: 2019 Edition

As discussed at last week’s hackathon, VTK is moving in the direction of deprecating the GetVoidPointer/ vtkTemplateMacro method of working with data arrays. Efforts are underway to update many existing filters and algorithms to use newer techniques, namely vtkArrayDispatch and vtkDataArrayRange.

Two key pieces of feedback emerged from the hackathon regarding these utilities:

  1. There’s not enough documentation.
  2. There’s too much documentation.

As a result, Allie has been updating the documentation, hoping to produce a Goldilocks-like compromise that will ease the community’s transition towards using these tools. Meanwhile, Rob has been working hard to convert VTK filters to demonstrate how existing code can be ported to use the new approach. This post provides a high level overview of these techniques and links to additional resources where developers can learn more about them.

Dispatchers and Ranges: What do they do?

The vtkArrayDispatch.h header provides a number of “dispatchers” that can be used to safely cast a vtkDataArray object to a type that provides a more efficient API. This effectively replaces vtkTemplateMacro with a more idiomatic C++ approach that supports all vtkDataArray subclasses, including the in-situ arrays that do not use the same memory layout as the standard VTK arrays. The dispatchers inspect an array’s derived type and execute an algorithm with the downcasted array, allowing more performant APIs to be used. The dispatchers are more flexible than vtkTemplateMacro: They can dispatch multiple arrays at once, and can be restricted to only check for a few array types to reduce compile time / binary size.

The vtkDataArrayRange.h header provides two utilities that simplify writing algorithms with vtkDataArrays: TupleRange and ValueRange. These are STL-range-like objects that abstract the details of accessing/modifying data from any vtkDataArray. They provide a consistent API that allows a developer to write an algorithm once, and then reuse the implementation with any vtkDataArray-derived object with the best possible performance. For example, a range constructed from vtkFloatArray will use a non-virtual inline API that optimizes to raw memory accesses. However, using a vtkDataArray to create the range uses a the slower virtual double-precision API, suitable as a fallback path for less common array types. These ranges also allow optimized access to the data stored by the more esoteric in-situ arrays, such as vtkScaledSOADataArrays.

How are they used?

To use these tools, an algorithm is implemented in a functor (ie. a struct with a definition of operator()) that accepts the arrays as templated arguments. The arrays are used to construct either TupleRanges or ValueRanges using the methods vtk::DataArrayTupleRange or vtk::DataArrayValueRange, respectively. The ranges are used to perform all array accesses required by the algorithm.

To use the functor, a dispatcher is selected from the options provided in vtkArrayDispatch.h and configured with any desired constraints. The dispatcher’s Execute method attempts to match the input arrays against the constraints, and if successful, casts the arrays to their derived types and executes the functor with them.

If the input arrays don’t satisfy the constraints, Execute returns false, and the functor can then be called directly with the vtkDataArray pointers. This allows common usecases to have fast paths, while still supporting uncommon usecases with a slower fallback path.

For example, the following functor and dispatch implement an algorithm that scales an array by a per-tuple factor and writes the result into another array. A fast-path is used when the arrays all hold floats or doubles, but falls back to the slower vtkDataArray interface for other types.

Further Reading

For those in the “too much documentation!” camp, concise, example-based documentation is provided in the VTK sources:

For those who carry the “not enough documentation!” banner, these references may be of interest:

To see how these tools are used in practice and find examples of how to update existing algorithms to use them, check out some of Rob Maynard’s recent PRs on Gitlab:

5 Responses to Working with vtkDataArrays: 2019 Edition

  1. Pingback: andrew.amaclean

  2. Pingback: Marcus D. Hanwell

Questions or comments are always welcome!