4.1. Advanced Types

Chapter 2.1 (Base Types) introduced some of the base data types defined for use in VTK‑m. However, for simplicity Chapter Chapter 2.1 (Base Types) just briefly touched the high-level concepts of these types. In this chapter we dive into much greater depth and introduce several more types.

4.1.1. Single Number Types

As described in Chapter Chapter 2.1 (Base Types), VTK‑m provides aliases for all the base C types to ensure the representation matches the variable use. When a specific type width is not required, then the most common types to use are vtkm::FloatDefault for floating-point numbers, vtkm::Id for array and similar indices, and vtkm::IdComponent for shorter-width vector indices.

If a specific type width is desired, then one of the following is used to clearly declare the type and width.

bytes

floating point

signed integer

unsigned integer

1

vtkm::Int8

vtkm::UInt8

2

vtkm::Int16

vtkm::UInt16

4

vtkm::Float32

vtkm::Int32

vtkm::UInt32

8

vtkm::Float64

vtkm::Int64

vtkm::UInt64

These VTK‑m–defined types should be preferred over basic C types like int or float.

4.1.2. Vector Types

Visualization algorithms also often require operations on short vectors. Arrays indexed in up to three dimensions are common. Data are often defined in 2-space and 3-space, and transformations are typically done in homogeneous coordinates of length 4. To simplify these types of operations, VTK‑m provides the vtkm::Vec templated type, which is essentially a fixed length array of a given type.

template<typename T, vtkm::IdComponent Size>
class Vec : public vtkm::detail::VecBase<T, Size, Vec<T, Size>>

A short fixed-length array.

The Vec templated class holds a short array of values of a size and type specified by the template arguments.

The Vec class is most often used to represent vectors in the mathematical sense as a quantity with a magnitude and direction. Vectors are, of course, used extensively in computational geometry as well as physical simulations. The Vec class can be (and is) repurposed for more general usage of holding a fixed-length sequence of objects.

There is no real limit to the size of the sequence (other than the largest number representable by vtkm::IdComponent), but the Vec class is really designed for small sequences (seldom more than 10).

Subclassed by vtkm::VecFlat< T, false >

The default constructor of vtkm::Vec objects leaves the values uninitialized. All vectors have a constructor with one argument that is used to initialize all components. All vtkm::Vec objects also have a constructor that allows you to set the individual components (one per argument). All vtkm::Vec objects with a size that is greater than 4 are constructed at run time and support an arbitrary number of initial values. Likewise, there is a vtkm::make_Vec() convenience function that builds initialized vector types with an arbitrary number of components. Once created, you can use the bracket operator to get and set component values with the same syntax as an array.

Example 4.1 Creating vector types.
1  vtkm::Vec3f_32 A{ 1 };                      // A is (1, 1, 1)
2  A[1] = 2;                                   // A is now (1, 2, 1)
3  vtkm::Vec3f_32 B{ 1, 2, 3 };                // B is (1, 2, 3)
4  vtkm::Vec3f_32 C = vtkm::make_Vec(3, 4, 5); // C is (3, 4, 5)
5  // Longer Vecs specified with template.
6  vtkm::Vec<vtkm::Float32, 5> D{ 1 };                 // D is (1, 1, 1, 1, 1)
7  vtkm::Vec<vtkm::Float32, 5> E{ 1, 2, 3, 4, 5 };     // E is (1, 2, 3, 4, 5)
8  vtkm::Vec<vtkm::Float32, 5> F = { 6, 7, 8, 9, 10 }; // F is (6, 7, 8, 9, 10)
9  auto G = vtkm::make_Vec(1, 3, 5, 7, 9);             // G is (1, 3, 5, 7, 9)
template<typename T, typename ...Ts>
constexpr vtkm::Vec<T, vtkm::IdComponent(sizeof...(Ts) + 1)> vtkm::make_Vec(T value0, Ts&&... args)

Initializes and returns a Vec containing all the arguments.

The arguments should all be the same type or compile issues will occur.

The types vtkm::Id2, vtkm::Id3, and vtkm::Id4 are type aliases of vtkm::Vec<vtkm::Id,2>, vtkm::Vec<vtkm::Id,3>, and vtkm::Vec<vtkm::Id,4>, respectively. These are used to index arrays of 2, 3, and 4 dimensions, which is common. Likewise, vtkm::IdComponent2, vtkm::IdComponent3, and vtkm::IdComponent4 are type aliases of vtkm::Vec<vtkm::IdComponent,2>, vtkm::Vec<vtkm::IdComponent,3>, and vtkm::Vec<vtkm::IdComponent,4>, respectively.

Because declaring vtkm::Vec with all of its template parameters can be cumbersome, VTK‑m provides easy to use aliases for small vectors of base types. As introduced in Section 2.1.3 (Vector Types), the following type aliases are available.

bytes

size

floating point

signed integer

unsigned integer

1

2

vtkm::Vec2i_8

vtkm::Vec2ui_8

3

vtkm::Vec3i_8

vtkm::Vec3ui_8

4

vtkm::Vec4i_8

vtkm::Vec4ui_8

2

2

vtkm::Vec2i_16

vtkm::Vec2ui_16

3

vtkm::Vec3i_16

vtkm::Vec3ui_16

4

vtkm::Vec4i_16

vtkm::Vec4ui_16

4

2

vtkm::Vec2f_32

vtkm::Vec2i_32

vtkm::Vec2ui_32

3

vtkm::Vec3f_32

vtkm::Vec3i_32

vtkm::Vec3ui_32

4

vtkm::Vec4f_32

vtkm::Vec4i_32

vtkm::Vec4ui_32

8

2

vtkm::Vec2f_64

vtkm::Vec2i_64

vtkm::Vec2ui_64

3

vtkm::Vec3f_64

vtkm::Vec3i_64

vtkm::Vec3ui_64

4

vtkm::Vec4f_64

vtkm::Vec4i_64

vtkm::Vec4ui_64

vtkm::Vec supports component-wise arithmetic using the operators for plus (+), minus (-), multiply (*), and divide (/). It also supports scalar to vector multiplication with the multiply operator. The comparison operators equal (==) is true if every pair of corresponding components are true and not equal (!=) is true otherwise. A special vtkm::Dot() function is overloaded to provide a dot product for every type of vector.

Example 4.2 Vector operations.
 1  vtkm::Vec3f_32 A{ 1, 2, 3 };
 2  vtkm::Vec3f_32 B{ 4, 5, 6.5 };
 3  vtkm::Vec3f_32 C = A + B;                 // C is (5, 7, 9.5)
 4  vtkm::Vec3f_32 D = 2.0f * C;              // D is (10, 14, 19)
 5  vtkm::Float32 s = vtkm::Dot(A, B);        // s is 33.5
 6  bool b1 = (A == B);                       // b1 is false
 7  bool b2 = (A == vtkm::make_Vec(1, 2, 3)); // b2 is true
 8
 9  vtkm::Vec<vtkm::Float32, 5> E{ 1, 2.5, 3, 4, 5 };    // E is (1, 2, 3, 4, 5)
10  vtkm::Vec<vtkm::Float32, 5> F{ 6, 7, 8.5, 9, 10.5 }; // F is (6, 7, 8, 9, 10)
11  vtkm::Vec<vtkm::Float32, 5> G = E + F;               // G is (7, 9.5, 11.5, 13, 15.5)
12  bool b3 = (E == F);                                  // b3 is false
13  bool b4 = (G == vtkm::make_Vec(7.f, 9.5f, 11.5f, 13.f, 15.5f)); // b4 is true

These operators, of course, only work if they are also defined for the component type of the vtkm::Vec. For example, the multiply operator will work fine on objects of type vtkm::Vec<char,3>, but the multiply operator will not work on objects of type vtkm::Vec<std::string,3> because you cannot multiply objects of type std::string.

In addition to generalizing vector operations and making arbitrarily long vectors, vtkm::Vec can be repurposed for creating any sequence of homogeneous objects. Here is a simple example of using vtkm::Vec to hold the state of a polygon.

Example 4.3 Repurposing a vtkm::Vec.
1  vtkm::Vec<vtkm::Vec2f_32, 3> equilateralTriangle = { { 0.0f, 0.0f },
2                                                       { 1.0f, 0.0f },
3                                                       { 0.5f, 0.8660254f } };

4.1.2.1. Vec-like Types

The vtkm::Vec class provides a convenient structure for holding and passing small vectors of data. However, there are times when using vtkm::Vec is inconvenient or inappropriate. For example, the size of vtkm::Vec must be known at compile time, but there may be need for a vector whose size is unknown until compile time. Also, the data populating a vtkm::Vec might come from a source that makes it inconvenient or less efficient to construct a vtkm::Vec. For this reason, VTK‑m also provides several Vec-like objects that behave much like vtkm::Vec but are a different class. These Vec-like objects have the same interface as vtkm::Vec except that the NUM_COMPONENTS constant is not available on those that are sized at run time. Vec-like objects also come with a CopyInto method that will take their contents and copy them into a standard vtkm::Vec class. (The standard vtkm::Vec class also has a vtkm::Vec::CopyInto() method for consistency.)

4.1.2.1.1. C-Array Vec Wrapper

The first Vec-like object is vtkm::VecC, which exposes a C-type array as a vtkm::Vec.

template<typename T>
class VecC : public vtkm::detail::VecCBase<T, VecC<T>>

A Vec-like representation for short arrays.

The VecC class takes a short array of values and provides an interface that mimics Vec. This provides a mechanism to treat C arrays like a Vec. It is useful in situations where you want to use a Vec but the data must come from elsewhere or in certain situations where the size cannot be determined at compile time. In particular, Vec objects of different sizes can potentially all be converted to a VecC of the same type.

Note that VecC holds a reference to an outside array given to it. If that array gets destroyed (for example because the source goes out of scope), the behavior becomes undefined.

You cannot use VecC with a const type in its template argument. For example, you cannot declare VecC<const vtkm::Id>. If you want a non-mutable VecC, the VecCConst class (e.g. VecCConst<vtkm::Id>).

The constructor for vtkm::VecC takes a C array and a size of that array. There is also a constant version of vtkm::VecC named vtkm::VecCConst, which takes a constant array and cannot be mutated.

template<typename T>
class VecCConst : public vtkm::detail::VecCBase<T, VecCConst<T>>

A const version of VecC.

VecCConst is a non-mutable form of VecC. It can be used in place of VecC when a constant array is available.

A VecC can be automatically converted to a VecCConst, but not vice versa, so function arguments should use VecCConst when the data do not need to be changed.

The vtkm/Types.h header defines both vtkm::VecC and vtkm::VecCConst as well as multiple versions of vtkm::make_VecC() to easily convert a C array to either a vtkm::VecC or vtkm::VecCConst.

template<typename T>
static inline vtkm::VecC<T> vtkm::make_VecC(T *array, vtkm::IdComponent size)

Creates a VecC from an input array.

template<typename T>
static inline vtkm::VecCConst<T> vtkm::make_VecC(const T *array, vtkm::IdComponent size)

Creates a VecCConst from a constant input array.

The following example demonstrates converting values from a constant table into a vtkm::VecCConst for further consumption. The table and associated methods define how 8 points come together to form a hexahedron.

Example 4.4 Using vtkm::VecCConst with a constant array.
 1VTKM_EXEC vtkm::VecCConst<vtkm::IdComponent> HexagonIndexToIJK(vtkm::IdComponent index)
 2{
 3  static const vtkm::IdComponent HexagonIndexToIJKTable[8][3] = {
 4    { 0, 0, 0 }, { 1, 0, 0 }, { 1, 1, 0 }, { 0, 1, 0 },
 5    { 0, 0, 1 }, { 1, 0, 1 }, { 1, 1, 1 }, { 0, 1, 1 }
 6  };
 7
 8  return vtkm::make_VecC(HexagonIndexToIJKTable[index], 3);
 9}
10
11VTKM_EXEC vtkm::IdComponent HexagonIJKToIndex(vtkm::VecCConst<vtkm::IdComponent> ijk)
12{
13  static const vtkm::IdComponent HexagonIJKToIndexTable[2][2][2] = { {
14                                                                       // i=0
15                                                                       { 0, 4 }, // j=0
16                                                                       { 3, 7 }, // j=1
17                                                                     },
18                                                                     {
19                                                                       // i=1
20                                                                       { 1, 5 }, // j=0
21                                                                       { 2, 6 }, // j=1
22                                                                     } };
23
24  return HexagonIJKToIndexTable[ijk[0]][ijk[1]][ijk[2]];
25}

Common Errors

The vtkm::VecC and vtkm::VecCConst classes only hold a pointer to a buffer that contains the data. They do not manage the memory holding the data. Thus, if the pointer given to vtkm::VecC or vtkm::VecCConst becomes invalid, then using the object becomes invalid. Make sure that the scope of the vtkm::VecC or vtkm::VecCConst does not outlive the scope of the data it points to.

4.1.2.1.2. Variable-Sized Vec

The next Vec-like object is vtkm::VecVariable, which provides a Vec-like object that can be resized at run time to a maximum value. Unlike vtkm::VecC, vtkm::VecVariable holds its own memory, which makes it a bit safer to use. But also unlike vtkm::VecC, you must define the maximum size of vtkm::VecVariable at compile time. Thus, vtkm::VecVariable is really only appropriate to use when there is a predetermined limit to the vector size that is fairly small.

template<typename T, vtkm::IdComponent MaxSize>
class VecVariable

A short variable-length array with maximum length.

The VecVariable class is a Vec-like class that holds a short array of some maximum length. To avoid dynamic allocations, the maximum length is specified at compile time. Internally, VecVariable holds a Vec of the maximum length and exposes a subsection of it.

The following example uses a vtkm::VecVariable to store the trace of edges within a hexahedron. This example uses the methods defined in Example 4.5.

Example 4.5 Using vtkm::VecVariable.
 1vtkm::VecVariable<vtkm::IdComponent, 4> HexagonShortestPath(vtkm::IdComponent startPoint,
 2                                                            vtkm::IdComponent endPoint)
 3{
 4  vtkm::VecCConst<vtkm::IdComponent> startIJK = HexagonIndexToIJK(startPoint);
 5  vtkm::VecCConst<vtkm::IdComponent> endIJK = HexagonIndexToIJK(endPoint);
 6
 7  vtkm::IdComponent3 currentIJK;
 8  startIJK.CopyInto(currentIJK);
 9
10  vtkm::VecVariable<vtkm::IdComponent, 4> path;
11  path.Append(startPoint);
12  for (vtkm::IdComponent dimension = 0; dimension < 3; dimension++)
13  {
14    if (currentIJK[dimension] != endIJK[dimension])
15    {
16      currentIJK[dimension] = endIJK[dimension];
17      path.Append(HexagonIJKToIndex(currentIJK));
18    }
19  }
20
21  return path;
22}

4.1.2.1.3. Vecs from Portals

VTK‑m provides further examples of Vec-like objects as well. For example, the vtkm::VecFromPortal and vtkm::VecFromPortalPermute objects allow you to treat a subsection of an arbitrarily large array as a vtkm::Vec. These objects work by attaching to array portals, which are described in Section~ref{sec:ArrayPortals}.

template<typename PortalType>
class VecFromPortal

A short variable-length array from a window in an ArrayPortal.

The VecFromPortal class is a Vec-like class that holds an array portal and exposes a small window of that portal as if it were a Vec.

template<typename IndexVecType, typename PortalType>
class VecFromPortalPermute

A short vector from an ArrayPortal and a vector of indices.

The VecFromPortalPermute class is a Vec-like class that holds an array portal and a second Vec-like containing indices into the array. Each value of this vector is the value from the array with the respective index.

4.1.2.1.4. Point Coordinate Vec

Another example of a Vec-like object is vtkm::VecRectilinearPointCoordinates, which efficiently represents the point coordinates in an axis-aligned hexahedron. Such shapes are common in structured grids. These and other data sets are described in Chapter 2.4 (Data Sets).

4.1.3. Range

VTK‑m provides a convenience structure named vtkm::Range to help manage a range of values. The vtkm::Range struct contains two data members, vtkm::Range::Min and vtkm::Range::Max, which represent the ends of the range of numbers. vtkm::Range::Min and vtkm::Range::Max are both of type vtkm::Float64. vtkm::Range::Min and vtkm::Range::Max can be directly accessed, but vtkm::Range also comes with several helper functions to make it easier to build and use ranges. Note that all of these functions treat the minimum and maximum value as inclusive to the range.

struct Range

Represent a continuous scalar range of values.

vtkm::Range is a helper class for representing a range of floating point values from a minimum value to a maximum value. This is specified simply enough with a Min and Max value.

Range also contains several helper functions for computing and maintaining the range.

Public Functions

inline Range()

Construct a range with a given minimum and maximum.

If no minimum or maximum is given, the range will be empty.

inline bool IsNonEmpty() const

Determine if the range is valid (i.e.

has at least one valid point).

IsNonEmpty return true if the range contains some valid values between Min and Max. If Max is less than Min, then no values satisfy the range and IsNonEmpty returns false. Otherwise, return true.

IsNonEmpty assumes Min and Max are inclusive. That is, if they are equal then true is returned.

template<typename T>
inline bool Contains(const T &value) const

Determines if a value is within the range.

Contains returns true if the give value is within the range, false otherwise. Contains treats the min and max as inclusive. That is, if the value is exactly the min or max, true is returned.

inline vtkm::Float64 Length() const

Returns the length of the range.

Length computes the distance between the min and max. If the range is empty, 0 is returned.

inline vtkm::Float64 Center() const

Returns the center of the range.

Center computes the middle value of the range. If the range is empty, NaN is returned.

template<typename T>
inline void Include(const T &value)

Expand range to include a value.

This version of Include expands the range just enough to include the given value. If the range already includes this value, then nothing is done.

inline void Include(const vtkm::Range &range)

Expand range to include other range.

This version of Include expands this range just enough to include that of another range. Essentially it is the union of the two ranges.

inline vtkm::Range Union(const vtkm::Range &otherRange) const

Return the union of this and another range.

This is a nondestructive form of Include.

inline vtkm::Range Intersection(const vtkm::Range &otherRange) const

Return the intersection of this and another range.

inline vtkm::Range operator+(const vtkm::Range &otherRange) const

Operator for union

Public Members

vtkm::Float64 Min

The minumum value of the range (inclusive).

vtkm::Float64 Max

Tha maximum value of the range (inclusive).

The following example demonstrates the operation of vtkm::Range.

Example 4.6 Using vtkm::Range.
 1  vtkm::Range range;            // default constructor is empty range
 2  bool b1 = range.IsNonEmpty(); // b1 is false
 3
 4  range.Include(0.5);            // range now is [0.5 .. 0.5]
 5  bool b2 = range.IsNonEmpty();  // b2 is true
 6  bool b3 = range.Contains(0.5); // b3 is true
 7  bool b4 = range.Contains(0.6); // b4 is false
 8
 9  range.Include(2.0);            // range is now [0.5 .. 2]
10  bool b5 = range.Contains(0.5); // b3 is true
11  bool b6 = range.Contains(0.6); // b4 is true
12
13  range.Include(vtkm::Range(-1, 1)); // range is now [-1 .. 2]
14
15  range.Include(vtkm::Range(3, 4)); // range is now [-1 .. 4]
16
17  vtkm::Float64 lower = range.Min;       // lower is -1
18  vtkm::Float64 upper = range.Max;       // upper is 4
19  vtkm::Float64 length = range.Length(); // length is 5
20  vtkm::Float64 center = range.Center(); // center is 1.5

4.1.4. Bounds

VTK‑m provides a convenience structure named vtkm::Bounds to help manage an axis-aligned region in 3D space. Among other things, this structure is often useful for representing a bounding box for geometry. The vtkm::Bounds struct contains three data members, vtkm::Bounds::X, vtkm::Bounds::Y, and vtkm::Bounds::Z, which represent the range of the bounds along each respective axis. All three of these members are of type vtkm::Range, which is discussed previously in Section 4.1.3 (Range). vtkm::Bounds::X, vtkm::Bounds::Y, and vtkm::Bounds::Z can be directly accessed, but vtkm::Bounds also comes with the following helper functions to make it easier to build and use ranges.

struct Bounds

Represent an axis-aligned 3D bounds in space.

vtkm::Bounds is a helper class for representing the axis-aligned box representing some region in space. The typical use of this class is to express the containing box of some geometry. The box is specified as ranges in the x, y, and z directions.

Bounds also contains several helper functions for computing and maintaining the bounds.

Public Functions

inline Bounds()

Construct an empty bounds.

The bounds will represent no space until otherwise modified.

inline Bounds(const vtkm::Range &xRange, const vtkm::Range &yRange, const vtkm::Range &zRange)

Construct a bounds with a given range in the x, y, and z dimensions.

template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
inline Bounds(const T1 &minX, const T2 &maxX, const T3 &minY, const T4 &maxY, const T5 &minZ, const T6 &maxZ)

Construct a bounds with the minimum and maximum coordinates in the x, y, and z directions.

template<typename T>
inline explicit Bounds(const T bounds[6])

Initialize bounds with an array of 6 values in the order xmin, xmax, ymin, ymax, zmin, zmax.

template<typename T>
inline Bounds(const vtkm::Vec<T, 3> &minPoint, const vtkm::Vec<T, 3> &maxPoint)

Initialize bounds with the minimum corner point and the maximum corner point.

inline bool IsNonEmpty() const

Determine if the bounds are valid (i.e.

has at least one valid point).

IsNonEmpty returns true if the bounds contain some valid points. If the bounds are any real region, even if a single point or it expands to infinity, true is returned.

template<typename T>
inline bool Contains(const vtkm::Vec<T, 3> &point) const

Determines if a point coordinate is within the bounds.

inline vtkm::Float64 Volume() const

Returns the volume of the bounds.

Volume computes the product of the lengths of the ranges in each dimension. If the bounds are empty, 0 is returned.

inline vtkm::Float64 Area() const

Returns the area of the bounds in the X-Y-plane.

Area computes the product of the lengths of the ranges in dimensions X and Y. If the bounds are empty, 0 is returned.

inline vtkm::Vec3f_64 Center() const

Returns the center of the range.

Center computes the point at the middle of the bounds. If the bounds are empty, the results are undefined.

inline vtkm::Vec3f_64 MinCorner() const

Returns the min point of the bounds

MinCorder returns the minium point of the bounds.If the bounds are empty, the results are undefined.

inline vtkm::Vec3f_64 MaxCorner() const

Returns the max point of the bounds

MaxCorder returns the minium point of the bounds.If the bounds are empty, the results are undefined.

template<typename T>
inline void Include(const vtkm::Vec<T, 3> &point)

Expand bounds to include a point.

This version of Include expands the bounds just enough to include the given point coordinates. If the bounds already include this point, then nothing is done.

inline void Include(const vtkm::Bounds &bounds)

Expand bounds to include other bounds.

This version of Include expands these bounds just enough to include that of another bounds. Essentially it is the union of the two bounds.

inline vtkm::Bounds Union(const vtkm::Bounds &otherBounds) const

Return the union of this and another bounds.

This is a nondestructive form of Include.

inline vtkm::Bounds Intersection(const vtkm::Bounds &otherBounds) const

Return the intersection of this and another range.

inline vtkm::Bounds operator+(const vtkm::Bounds &otherBounds) const

Operator for union

Public Members

vtkm::Range X

The range of values in the X direction.

The vtkm::Range struct provides the minimum and maximum along that axis.

vtkm::Range Y

The range of values in the Y direction.

The vtkm::Range struct provides the minimum and maximum along that axis.

vtkm::Range Z

The range of values in the Z direction.

The vtkm::Range struct provides the minimum and maximum along that axis.

The following example demonstrates the operation of vtkm::Bounds.

Example 4.7 Using vtkm::Bounds.
 1  vtkm::Bounds bounds;           // default constructor makes empty
 2  bool b1 = bounds.IsNonEmpty(); // b1 is false
 3
 4  bounds.Include(vtkm::make_Vec(0.5, 2.0, 0.0));            // bounds contains only
 5                                                            // the point [0.5, 2, 0]
 6  bool b2 = bounds.IsNonEmpty();                            // b2 is true
 7  bool b3 = bounds.Contains(vtkm::make_Vec(0.5, 2.0, 0.0)); // b3 is true
 8  bool b4 = bounds.Contains(vtkm::make_Vec(1, 1, 1));       // b4 is false
 9  bool b5 = bounds.Contains(vtkm::make_Vec(0, 0, 0));       // b5 is false
10
11  bounds.Include(vtkm::make_Vec(4, -1, 2)); // bounds is region [0.5 .. 4] in X,
12                                            //                  [-1 .. 2] in Y,
13                                            //              and [0 .. 2] in Z
14  bool b6 = bounds.Contains(vtkm::make_Vec(0.5, 2.0, 0.0)); // b6 is true
15  bool b7 = bounds.Contains(vtkm::make_Vec(1, 1, 1));       // b7 is true
16  bool b8 = bounds.Contains(vtkm::make_Vec(0, 0, 0));       // b8 is false
17
18  vtkm::Bounds otherBounds(vtkm::make_Vec(0, 0, 0), vtkm::make_Vec(3, 3, 3));
19  // otherBounds is region [0 .. 3] in X, Y, and Z
20  bounds.Include(otherBounds); // bounds is now region [0 .. 4] in X,
21                               //                      [-1 .. 3] in Y,
22                               //                  and [0 .. 3] in Z
23
24  vtkm::Vec3f_64 lower(bounds.X.Min, bounds.Y.Min, bounds.Z.Min);
25  // lower is [0, -1, 0]
26  vtkm::Vec3f_64 upper(bounds.X.Max, bounds.Y.Max, bounds.Z.Max);
27  // upper is [4, 3, 3]
28
29  vtkm::Vec3f_64 center = bounds.Center(); // center is [2, 1, 1.5]

4.1.5. Index Ranges

Just as it is sometimes necessary to track a range of real values, there are times when code has to specify a continuous range of values in an index sequence like an array. For this purpose, VTK‑m provides RangeId, which behaves similarly to Range except for integer values.

struct RangeId

Represent a range of vtkm::Id values.

vtkm::RangeId is a helper class for representing a range of vtkm::Id values. This is specified simply with a Min and Max value, where Max is exclusive.

RangeId also contains several helper functions for computing and maintaining the range.

Public Functions

inline RangeId()

Construct a range with no indices.

inline RangeId(vtkm::Id min, vtkm::Id max)

Construct a range with the given minimum (inclusive) and maximum (exclusive) indices.

inline bool IsNonEmpty() const

Determine if the range is valid.

IsNonEmpty return true if the range contains some valid values between Min and Max. If Max <= Min, then no values satisfy the range and IsNonEmpty returns false. Otherwise, return true.

inline bool Contains(vtkm::Id value) const

Determines if a value is within the range.

Contains returns true if the give value is within the range, false otherwise.

inline vtkm::Id Length() const

Returns the length of the range.

Length computes the distance between the min and max. If the range is empty, 0 is returned.

inline vtkm::Id Center() const

Returns the center of the range.

Center computes the middle value of the range.

inline void Include(vtkm::Id value)

Expand range to include a value.

This version of Include expands the range just enough to include the given value. If the range already includes this value, then nothing is done.

inline void Include(const vtkm::RangeId &range)

Expand range to include other range.

This version of Include expands this range just enough to include that of another range. Essentially it is the union of the two ranges.

inline vtkm::RangeId Union(const vtkm::RangeId &other) const

Return the union of this and another range.

This is a nondestructive form of Include.

inline vtkm::RangeId operator+(const vtkm::RangeId &other) const

Operator for union

Public Members

vtkm::Id Min

The minimum index of the range (inclusive).

vtkm::Id Max

The maximum index of the range (exclusive).

VTK‑m also often must operate on 2D and 3D arrays (particularly for structured cell sets). For these use cases, RangeId2 and RangeId3 are provided.

struct RangeId2

Represent 2D integer range.

vtkm::RangeId2 is a helper class for representing a 2D range of integer values. The typical use of this class is to express a box of indices in the x and y directions.

RangeId2 also contains several helper functions for computing and maintaining the range.

Public Functions

RangeId2() = default

Construct an empty 2D range.

inline RangeId2(const vtkm::RangeId &xrange, const vtkm::RangeId &yrange)

Construct a range with the given x and y directions.

inline RangeId2(vtkm::Id minX, vtkm::Id maxX, vtkm::Id minY, vtkm::Id maxY)

Construct a range with the given minimum (inclusive) and maximum (exclusive) points.

inline explicit RangeId2(const vtkm::Id range[4])

Initialize range with an array of 4 values in the order xmin, xmax, ymin, ymax.

inline RangeId2(const vtkm::Id2 &min, const vtkm::Id2 &max)

Initialize range with the minimum and the maximum corners.

inline bool IsNonEmpty() const

Determine if the range is non-empty.

IsNonEmpty returns true if the range is non-empty.

inline bool Contains(const vtkm::Id2 &val) const

Determines if an Id2 value is within the range.

inline vtkm::Id2 Center() const

Returns the center of the range.

Center computes the middle of the range.

template<typename T>
inline void Include(const vtkm::Vec<T, 2> &point)

Expand range to include a value.

This version of Include expands the range just enough to include the given value. If the range already include this value, then nothing is done.

inline void Include(const vtkm::RangeId2 &range)

Expand range to include other range.

This version of Include expands the range just enough to include the other range. Essentially it is the union of the two ranges.

inline vtkm::RangeId2 Union(const vtkm::RangeId2 &other) const

Return the union of this and another range.

This is a nondestructive form of Include.

inline vtkm::RangeId2 operator+(const vtkm::RangeId2 &other) const

Operator for union

Public Members

vtkm::RangeId X

The range of values in the X direction.

The vtkm::RangeId struct provides the minimum and maximum along that axis.

vtkm::RangeId Y

The range of values in the Y direction.

The vtkm::RangeId struct provides the minimum and maximum along that axis.

struct RangeId3

Represent 3D integer range.

vtkm::RangeId3 is a helper class for representing a 3D range of integer values. The typical use of this class is to express a box of indices in the x, y, and z directions.

RangeId3 also contains several helper functions for computing and maintaining the range.

Public Functions

RangeId3() = default

Construct an empty 3D range.

inline RangeId3(const vtkm::RangeId &xrange, const vtkm::RangeId &yrange, const vtkm::RangeId &zrange)

Construct a range with the given x, y, and z directions.

inline RangeId3(vtkm::Id minX, vtkm::Id maxX, vtkm::Id minY, vtkm::Id maxY, vtkm::Id minZ, vtkm::Id maxZ)

Construct a range with the given minimum (inclusive) and maximum (exclusive) points.

inline explicit RangeId3(const vtkm::Id range[6])

Initialize range with an array of 6 values in the order xmin, xmax, ymin, ymax, zmin, zmax.

inline RangeId3(const vtkm::Id3 &min, const vtkm::Id3 &max)

Initialize range with the minimum and the maximum corners.

inline bool IsNonEmpty() const

Determine if the range is non-empty.

IsNonEmpty returns true if the range is non-empty.

inline bool Contains(const vtkm::Id3 &val) const

Determines if an Id3 value is within the range.

inline vtkm::Id3 Center() const

Returns the center of the range.

Center computes the middle of the range.

template<typename T>
inline void Include(const vtkm::Vec<T, 3> &point)

Expand range to include a value.

This version of Include expands the range just enough to include the given value. If the range already include this value, then nothing is done.

inline void Include(const vtkm::RangeId3 &range)

Expand range to include other range.

This version of Include expands the range just enough to include the other range. Essentially it is the union of the two ranges.

inline vtkm::RangeId3 Union(const vtkm::RangeId3 &other) const

Return the union of this and another range.

This is a nondestructive form of Include.

inline vtkm::RangeId3 operator+(const vtkm::RangeId3 &other) const

Operator for union

Public Members

vtkm::RangeId X

The range of values in the X direction.

The vtkm::RangeId struct provides the minimum and maximum along that axis.

vtkm::RangeId Y

The range of values in the Y direction.

The vtkm::RangeId struct provides the minimum and maximum along that axis.

vtkm::RangeId Z

The range of values in the Z direction.

The vtkm::RangeId struct provides the minimum and maximum along that axis.

4.1.6. Traits

When using templated types, it is often necessary to get information about the type or specialize code based on general properties of the type. VTK‑m uses traits classes to publish and retrieve information about types. A traits class is simply a templated structure that provides type aliases for tag structures, empty types used for identification. The traits classes might also contain constant numbers and helpful static functions. See Effective C++ Third Edition by Scott Meyers for a description of traits classes and their uses.

4.1.6.1. Type Traits

The vtkm::TypeTraits templated class provides basic information about a core type. These type traits are available for all the basic C++ types as well as the core VTK‑m types described in Chapter 2.1 (Base Types). vtkm::TypeTraits contains the following elements.

template<typename T>
class TypeTraits

The TypeTraits class provides helpful compile-time information about the basic types used in VTKm (and a few others for convenience).

The majority of TypeTraits contents are typedefs to tags that can be used to easily override behavior of called functions.

Subclassed by vtkm::TypeTraits< const T >

Public Types

using NumericTag = vtkm::TypeTraitsUnknownTag

A tag to determine whether the type is integer or real.

This tag is either TypeTraitsRealTag or TypeTraitsIntegerTag.

using DimensionalityTag = vtkm::TypeTraitsUnknownTag

A tag to determine whether the type has multiple components.

This tag is either TypeTraitsScalarTag or TypeTraitsVectorTag. Scalars can also be treated as vectors with VecTraits.

Public Static Functions

static inline T ZeroInitialization()

A static function that returns 0 (or the closest equivalent to it) for the given type.

The vtkm::TypeTraits::NumericTag will be an alias for one of the following tags.

struct TypeTraitsRealTag

Tag used to identify types that store real (floating-point) numbers.

A TypeTraits class will typedef this class to NumericTag if it stores real numbers (or vectors of real numbers).

struct TypeTraitsIntegerTag

Tag used to identify types that store integer numbers.

A TypeTraits class will typedef this class to NumericTag if it stores integer numbers (or vectors of integers).

The vtkm::TypeTraits::DimensionalityTag will be an alias for one of the following tags.

struct TypeTraitsScalarTag

Tag used to identify 0 dimensional types (scalars).

Scalars can also be treated like vectors when used with VecTraits. A TypeTraits class will typedef this class to DimensionalityTag.

struct TypeTraitsVectorTag

Tag used to identify 1 dimensional types (vectors).

A TypeTraits class will typedef this class to DimensionalityTag.

If for some reason one of these tags do not apply, vtkm::TypeTraitsUnknownTag will be used.

struct TypeTraitsUnknownTag

Tag used to identify types that aren’t Real, Integer, Scalar or Vector.

The definition of vtkm::TypeTraits for vtkm::Float32 could like something like this.

Example 4.8 Example definition of vtkm::TypeTraits<vtkm::Float32>.
 1namespace vtkm {
 2
 3template<>
 4struct TypeTraits<vtkm::Float32>
 5{
 6  using NumericTag = vtkm::TypeTraitsRealTag;
 7  using DimensionalityTag = vtkm::TypeTraitsScalarTag;
 8
 9  VTKM_EXEC_CONT
10  static vtkm::Float32 ZeroInitialization() { return vtkm::Float32(0); }
11};
12
13}

Here is a simple example of using vtkm::TypeTraits to implement a generic function that behaves like the remainder operator (%) for all types including floating points and vectors.

Example 4.9 Using vtkm::TypeTraits for a generic remainder.
 1#include <vtkm/TypeTraits.h>
 2
 3#include <vtkm/Math.h>
 4
 5template<typename T>
 6T AnyRemainder(const T& numerator, const T& denominator);
 7
 8namespace detail
 9{
10
11template<typename T>
12T AnyRemainderImpl(const T& numerator,
13                   const T& denominator,
14                   vtkm::TypeTraitsIntegerTag,
15                   vtkm::TypeTraitsScalarTag)
16{
17  return numerator % denominator;
18}
19
20template<typename T>
21T AnyRemainderImpl(const T& numerator,
22                   const T& denominator,
23                   vtkm::TypeTraitsRealTag,
24                   vtkm::TypeTraitsScalarTag)
25{
26  // The VTK-m math library contains a Remainder function that operates on
27  // floating point numbers.
28  return vtkm::Remainder(numerator, denominator);
29}
30
31template<typename T, typename NumericTag>
32T AnyRemainderImpl(const T& numerator,
33                   const T& denominator,
34                   NumericTag,
35                   vtkm::TypeTraitsVectorTag)
36{
37  T result;
38  for (int componentIndex = 0; componentIndex < T::NUM_COMPONENTS; componentIndex++)
39  {
40    result[componentIndex] =
41      AnyRemainder(numerator[componentIndex], denominator[componentIndex]);
42  }
43  return result;
44}
45
46} // namespace detail
47
48template<typename T>
49T AnyRemainder(const T& numerator, const T& denominator)
50{
51  return detail::AnyRemainderImpl(numerator,
52                                  denominator,
53                                  typename vtkm::TypeTraits<T>::NumericTag(),
54                                  typename vtkm::TypeTraits<T>::DimensionalityTag());
55}

4.1.6.2. Vector Traits

The templated vtkm::Vec class contains several items for introspection (such as the component type and its size). However, there are other types that behave similarly to vtkm::Vec objects but have different ways to perform this introspection.

For example, VTK‑m contains Vec-like objects that essentially behave the same but might have different features. Also, there may be reason to interchangeably use basic scalar values, like an integer or floating point number, with vectors. To provide a consistent interface to access these multiple types that represents vectors, the vtkm::VecTraits templated class provides information and accessors to vector types.It contains the following elements.

template<class T>
struct VecTraits

Traits that can be queried to treat any type as a Vec.

The VecTraits class gives several static members that define how to use a given type as a vector. This is useful for templated functions and methods that have a parameter that could be either a standard scalar type or a Vec or some other Vec-like object. When using this class, scalar objects are treated like a Vec of size 1.

The default implementation of this template treats the type as a scalar. Types that actually behave like vectors should specialize this template to provide the proper information.

Subclassed by vtkm::VecTraits< T & >, vtkm::VecTraits< T * >, vtkm::VecTraits< const T & >, vtkm::VecTraits< const T >, vtkm::internal::SafeVecTraits< T >

Public Types

using ComponentType = T

Type of the components in the vector.

If the type is really a scalar, then the component type is the same as the scalar type.

using BaseComponentType = T

Base component type in the vector.

Similar to ComponentType except that for nested vectors (e.g. Vec<Vec<T, M>, N>), it returns the base scalar type at the end of the composition (T in this example).

using HasMultipleComponents = vtkm::VecTraitsTagSingleComponent

A tag specifying whether this vector has multiple components (i.e.

is a “real” vector).

This type is set to either vtkm::VecTraitsTagSingleComponent if the vector length is size 1 or vtkm::VecTraitsTagMultipleComponents otherwise. This tag can be useful for creating specialized functions when a vector is really just a scalar. If the vector type is of variable size (that is, IsSizeStatic is vtkm::VecTraitsTagSizeVariable), then HasMultipleComponents might be vtkm::VecTraitsTagMultipleComponents even when at run time there is only one component.

using IsSizeStatic = vtkm::VecTraitsTagSizeStatic

A tag specifying whether the size of this vector is known at compile time.

If set to VecTraitsTagSizeStatic, then NUM_COMPONENTS is set. If set to VecTraitsTagSizeVariable, then the number of components is not known at compile time and must be queried with GetNumberOfComponents.

template<typename NewComponentType>
using ReplaceComponentType = NewComponentType

Get a vector of the same type but with a different component.

This type resolves to another vector with a different component type. For example, vtkm::VecTraits<vtkm::Vec<T, N>>::ReplaceComponentType<T2> is vtkm::Vec<T2, N>. This replacement is not recursive. So VecTraits<Vec<Vec<T, M>, N>::ReplaceComponentType<T2> is vtkm::Vec<T2, N>.

template<typename NewComponentType>
using ReplaceBaseComponentType = NewComponentType

Get a vector of the same type but with a different base component.

This type resolves to another vector with a different base component type. The replacement is recursive for nested types. For example, VecTraits<Vec<Vec<T, M>, N>::ReplaceBaseComponentType<T2> is Vec<Vec<T2, M>, N>.

Public Static Functions

static inline constexpr vtkm::IdComponent GetNumberOfComponents(const T&)

Returns the number of components in the given vector.

The result of GetNumberOfComponents() is the same value of NUM_COMPONENTS for vector types that have a static size (that is, IsSizeStatic is vtkm::VecTraitsTagSizeStatic). But unlike NUM_COMPONENTS, GetNumberOfComponents() works for vectors of any type.

static inline const ComponentType &GetComponent(const T &vector, vtkm::IdComponent)

Returns the value in a given component of the vector.

static inline ComponentType &GetComponent(T &vector, vtkm::IdComponent)

Returns the value in a given component of the vector.

static inline void SetComponent(T &vector, vtkm::IdComponent, ComponentType value)

Changes the value in a given component of the vector.

template<vtkm::IdComponent destSize>
static inline void CopyInto(const T &src, vtkm::Vec<ComponentType, destSize> &dest)

Copies the components in the given vector into a given Vec object.

Public Static Attributes

static constexpr vtkm::IdComponent NUM_COMPONENTS = 1

Number of components in the vector.

This is only defined for vectors of a static size. That is, NUM_COMPONENTS is not available when IsSizeStatic is set to vtkm::VecTraitsTagSizeVariable.

The vtkm::VecTraits::HasMultipleComponents could be one of the following tags.

struct VecTraitsTagMultipleComponents

A tag for vectors that are “true” vectors (i.e.

have more than one component).

struct VecTraitsTagSingleComponent

A tag for vectors that are really just scalars (i.e.

have only one component)

The vtkm::VecTraits::IsSizeStatic could be one of the following tags.

struct VecTraitsTagSizeStatic

A tag for vectors where the number of components are known at compile time.

struct VecTraitsTagSizeVariable

A tag for vectors where the number of components are not determined until run time.

The definition of vtkm::VecTraits for vtkm::Id3 could look something like this.

Example 4.10 Example definition of vtkm::VecTraits<vtkm::Id3>.
 1namespace vtkm {
 2
 3template<>
 4struct VecTraits<vtkm::Id3>
 5{
 6  using ComponentType = vtkm::Id;
 7  using BaseComponentType = vtkm::Id;
 8  static const int NUM_COMPONENTS = 3;
 9  using IsSizeStatic = vtkm::VecTraitsTagSizeStatic;
10  using HasMultipleComponents = vtkm::VecTraitsTagMultipleComponents;
11
12  VTKM_EXEC_CONT
13  static vtkm::IdComponent GetNumberOfComponents(const vtkm::Id3&)
14  {
15    return NUM_COMPONENTS;
16  }
17
18  VTKM_EXEC_CONT
19  static const vtkm::Id& GetComponent(const vtkm::Id3& vector, int component)
20  {
21    return vector[component];
22  }
23  VTKM_EXEC_CONT
24  static vtkm::Id& GetComponent(vtkm::Id3& vector, int component)
25  {
26    return vector[component];
27  }
28
29  VTKM_EXEC_CONT
30  static void SetComponent(vtkm::Id3& vector, int component, vtkm::Id value)
31  {
32    vector[component] = value;
33  }
34
35  template<typename NewComponentType>
36  using ReplaceComponentType = vtkm::Vec<NewComponentType, 3>;
37
38  template<typename NewComponentType>
39  using ReplaceBaseComponentType = vtkm::Vec<NewComponentType, 3>;
40
41  template<vtkm::IdComponent DestSize>
42  VTKM_EXEC_CONT static void CopyInto(const vtkm::Id3& src,
43                                      vtkm::Vec<vtkm::Id, DestSize>& dest)
44  {
45    for (vtkm::IdComponent index = 0; (index < NUM_COMPONENTS) && (index < DestSize);
46         index++)
47    {
48      dest[index] = src[index];
49    }
50  }
51};
52
53} // namespace vtkm

The real power of vector traits is that they simplify creating generic operations on any type that can look like a vector. This includes operations on scalar values as if they were vectors of size one. The following code uses vector traits to simplify the implementation of less functors that define an ordering that can be used for sorting and other operations.

Example 4.11 Using vtkm::VecTraits for less functors.
 1#include <vtkm/VecTraits.h>
 2
 3// This functor provides a total ordering of vectors. Every compared vector
 4// will be either less, greater, or equal (assuming all the vector components
 5// also have a total ordering).
 6template<typename T>
 7struct LessTotalOrder
 8{
 9  VTKM_EXEC_CONT
10  bool operator()(const T& left, const T& right)
11  {
12    for (int index = 0; index < vtkm::VecTraits<T>::NUM_COMPONENTS; index++)
13    {
14      using ComponentType = typename vtkm::VecTraits<T>::ComponentType;
15      const ComponentType& leftValue = vtkm::VecTraits<T>::GetComponent(left, index);
16      const ComponentType& rightValue = vtkm::VecTraits<T>::GetComponent(right, index);
17      if (leftValue < rightValue)
18      {
19        return true;
20      }
21      if (rightValue < leftValue)
22      {
23        return false;
24      }
25    }
26    // If we are here, the vectors are equal (or at least equivalent).
27    return false;
28  }
29};
30
31// This functor provides a partial ordering of vectors. It returns true if and
32// only if all components satisfy the less operation. It is possible for
33// vectors to be neither less, greater, nor equal, but the transitive closure
34// is still valid.
35template<typename T>
36struct LessPartialOrder
37{
38  VTKM_EXEC_CONT
39  bool operator()(const T& left, const T& right)
40  {
41    for (int index = 0; index < vtkm::VecTraits<T>::NUM_COMPONENTS; index++)
42    {
43      using ComponentType = typename vtkm::VecTraits<T>::ComponentType;
44      const ComponentType& leftValue = vtkm::VecTraits<T>::GetComponent(left, index);
45      const ComponentType& rightValue = vtkm::VecTraits<T>::GetComponent(right, index);
46      if (!(leftValue < rightValue))
47      {
48        return false;
49      }
50    }
51    // If we are here, all components satisfy less than relation.
52    return true;
53  }
54};

4.1.7. List Templates

VTK‑m internally uses template metaprogramming, which utilizes C++ templates to run source-generating programs, to customize code to various data and compute platforms. One basic structure often uses with template metaprogramming is a list of class names (also sometimes called a tuple or vector, although both of those names have different meanings in VTK‑m).

Many VTK‑m users only need predefined lists, such as the type lists specified in Section 4.1.7.2 (Type Lists). Those users can skip most of the details of this section. However, it is sometimes useful to modify lists, create new lists, or operate on lists, and these usages are documented here.

4.1.7.1. Building Lists

A basic list is defined with the vtkm::List template.

template<typename ...Ts>
struct List

A template used to hold a list of types.

List is an empty struct that is used to hold a list of types as its template arguments. VTK-m provides templated types that allows a List to be manipulated and used in numerous ways.

It is common (but not necessary) to use the using keyword to define an alias for a list with a particular meaning.

Example 4.12 Creating lists of types.
 1#include <vtkm/List.h>
 2
 3// Placeholder classes representing things that might be in a template
 4// metaprogram list.
 5class Foo;
 6class Bar;
 7class Baz;
 8class Qux;
 9class Xyzzy;
10
11// The names of the following tags are indicative of the lists they contain.
12
13using FooList = vtkm::List<Foo>;
14
15using FooBarList = vtkm::List<Foo, Bar>;
16
17using BazQuxXyzzyList = vtkm::List<Baz, Qux, Xyzzy>;
18
19using QuxBazBarFooList = vtkm::List<Qux, Baz, Bar, Foo>;

VTK‑m defines some special and convenience versions of vtkm::List.

using vtkm::ListEmpty = vtkm::List<>

A convenience type for an empty list.

using vtkm::ListUniversal = vtkm::List<detail::UniversalTypeTag>

A special type for a list that represents holding all potential values.

Note: This list cannot be used with ForEach and some list transforms for obvious reasons.

4.1.7.2. Type Lists

One of the major use cases for template metaprogramming lists in VTK‑m is to identify a set of potential data types for arrays. The vtkm/TypeList.h header contains predefined lists for known VTK‑m types. The following lists are provided.

using vtkm::TypeListId = vtkm::List<vtkm::Id>

A list containing the type vtkm::Id.

using vtkm::TypeListId2 = vtkm::List<vtkm::Id2>

A list containing the type vtkm::Id2.

using vtkm::TypeListId3 = vtkm::List<vtkm::Id3>

A list containing the type vtkm::Id3.

using vtkm::TypeListId4 = vtkm::List<vtkm::Id4>

A list containing the type vtkm::Id4.

using vtkm::TypeListIdComponent = vtkm::List<vtkm::IdComponent>

A list containing the type vtkm::IdComponent.

using vtkm::TypeListIndex = vtkm::List<vtkm::Id, vtkm::Id2, vtkm::Id3>

A list containing types used to index arrays.

Contains vtkm::Id, vtkm::Id2, and vtkm::Id3.

using vtkm::TypeListFieldScalar = vtkm::List<vtkm::Float32, vtkm::Float64>

A list containing types used for scalar fields.

Specifically, contains floating point numbers of different widths (i.e. vtkm::Float32 and vtkm::Float64).

using vtkm::TypeListFieldVec2 = vtkm::List<vtkm::Vec2f_32, vtkm::Vec2f_64>

A list containing types for values for fields with two dimensional vectors.

using vtkm::TypeListFieldVec3 = vtkm::List<vtkm::Vec3f_32, vtkm::Vec3f_64>

A list containing types for values for fields with three dimensional vectors.

using vtkm::TypeListFieldVec4 = vtkm::List<vtkm::Vec4f_32, vtkm::Vec4f_64>

A list containing types for values for fields with four dimensional vectors.

using vtkm::TypeListFloatVec = vtkm::List<vtkm::Vec2f_32, vtkm::Vec2f_64, vtkm::Vec3f_32, vtkm::Vec3f_64, vtkm::Vec4f_32, vtkm::Vec4f_64>

A list containing common types for floating-point vectors.

Specifically contains floating point vectors of size 2, 3, and 4 with floating point components. Scalars are not included.

using vtkm::TypeListField = vtkm::List<vtkm::Float32, vtkm::Float64, vtkm::Vec2f_32, vtkm::Vec2f_64, vtkm::Vec3f_32, vtkm::Vec3f_64, vtkm::Vec4f_32, vtkm::Vec4f_64>

A list containing common types for values in fields.

Specifically contains floating point scalars and vectors of size 2, 3, and 4 with floating point components.

using vtkm::TypeListScalarAll = vtkm::List<vtkm::Int8, vtkm::UInt8, vtkm::Int16, vtkm::UInt16, vtkm::Int32, vtkm::UInt32, vtkm::Int64, vtkm::UInt64, vtkm::Float32, vtkm::Float64>

A list of all scalars defined in vtkm/Types.h.

A scalar is a type that holds a single number. This should containing all true variations of scalars, but there might be some arithmetic C types not included. For example, this list contains signed char, and unsigned char, but not char as one of those types will behave the same as it. Two of the three types behave the same, but be aware that template resolution will treat them differently.

using vtkm::TypeListBaseC = vtkm::ListAppend<vtkm::TypeListScalarAll, vtkm::List<bool, char, signed long, unsigned long>>
using vtkm::TypeListVecCommon = vtkm::List<vtkm::Vec2ui_8, vtkm::Vec2i_32, vtkm::Vec2i_64, vtkm::Vec2f_32, vtkm::Vec2f_64, vtkm::Vec3ui_8, vtkm::Vec3i_32, vtkm::Vec3i_64, vtkm::Vec3f_32, vtkm::Vec3f_64, vtkm::Vec4ui_8, vtkm::Vec4i_32, vtkm::Vec4i_64, vtkm::Vec4f_32, vtkm::Vec4f_64>

A list of the most commonly use Vec classes.

Specifically, these are vectors of size 2, 3, or 4 containing either unsigned bytes, signed integers of 32 or 64 bits, or floating point values of 32 or 64 bits.

using vtkm::TypeListVecAll = vtkm::ListAppend<vtkm::TypeListVecCommon, vtkm::internal::TypeListVecUncommon>

A list of all vector classes with standard types as components and lengths between 2 and 4.

using vtkm::TypeListAll = vtkm::ListAppend<vtkm::TypeListScalarAll, vtkm::TypeListVecAll>

A list of all basic types listed in vtkm/Types.h.

Does not include all possible VTK-m types like arbitrarily typed and sized Vecs (only up to length 4) or math types like matrices.

using vtkm::TypeListCommon = vtkm::List<vtkm::UInt8, vtkm::Int32, vtkm::Int64, vtkm::Float32, vtkm::Float64, vtkm::Vec3f_32, vtkm::Vec3f_64>

A list of the most commonly used types across multiple domains.

Includes integers, floating points, and 3 dimensional vectors of floating points.

If these lists are not sufficient, it is possible to build new type lists using the existing type lists and the list bases from Section 4.1.7.1 (Building Lists) as demonstrated in the following example.

Example 4.13 Defining new type lists.
1// A list of 2D vector types.
2using Vec2List = vtkm::List<vtkm::Vec2f_32, vtkm::Vec2f_64>;
3
4// An application that uses 2D geometry might commonly encounter this list of
5// types.
6using MyCommonTypes = vtkm::ListAppend<Vec2List, vtkm::TypeListCommon>;

The vtkm/cont/DefaultTypes.h header defines a macro named VTKM_DEFAULT_TYPE_LIST that defines a default list of types to use when, for example, determining the type of a field array. This macro can change depending on VTK‑m compile options.

4.1.7.3. Querying Lists

vtkm/List.h contains some templated classes to help get information about a list type. This are particularly useful for lists that are provided as templated parameters for which you do not know the exact type.

4.1.7.3.1. Is a List

The VTKM_IS_LIST does a compile-time check to make sure a particular type is actually a vtkm::List of types. If the compile-time check fails, then a build error will occur. This is a good way to verify that a templated class or method that expects a list actually gets a list.

VTKM_IS_LIST(type)

Checks that the argument is a proper list.

This is a handy concept check for functions and classes to make sure that a template argument is actually a device adapter tag. (You can get weird errors elsewhere in the code when a mistake is made.)

Example 4.14 Checking that a template parameter is a valid vtkm::List.
 1template<typename List>
 2class MyImportantClass
 3{
 4  VTKM_IS_LIST(List);
 5  // Implementation...
 6};
 7
 8void DoImportantStuff()
 9{
10  MyImportantClass<vtkm::List<vtkm::Id>> important1; // This compiles fine
11  MyImportantClass<vtkm::Id> important2;  // COMPILE ERROR: vtkm::Id is not a list

4.1.7.3.2. List Size

The size of a list can be determined by using the vtkm::ListSize template. The type of the template will resolve to a std::integral_constant<vtkm::IdComponent,N> where N is the number of types in the list. vtkm::ListSize does not work with vtkm::ListUniversal.

template<typename List>
using vtkm::ListSize = typename detail::ListSizeImpl<List>::type

Becomes an std::integral_constant containing the number of types in a list.

Example 4.15 Getting the size of a vtkm::List.
1  using MyList = vtkm::List<vtkm::Int8, vtkm::Int32, vtkm::Int64>;
2
3  constexpr vtkm::IdComponent myListSize = vtkm::ListSize<MyList>::value;
4  // myListSize is 3

4.1.7.3.3. List Contains

The vtkm::ListHas template can be used to determine if a vtkm::List contains a particular type. vtkm::ListHas takes two template parameters. The first parameter is a form of vtkm::List. The second parameter is any type to check to see if it is in the list. If the type is in the list, then vtkm::ListHas resolves to std::true_type. Otherwise it resolves to std::false_type. vtkm::ListHas always returns true for vtkm::ListUniversal.

template<typename List, typename T>
using vtkm::ListHas = typename detail::ListHasImpl<List, T>::type

Checks to see if the given T is in the list pointed to by List.

Becomes std::true_type if the T is in List. std::false_type otherwise.

Example 4.16 Determining if a vtkm::List contains a particular type.
1  using MyList = vtkm::List<vtkm::Int8, vtkm::Int16, vtkm::Int32, vtkm::Int64>;
2
3  constexpr bool hasInt = vtkm::ListHas<MyList, int>::value;
4  // hasInt is true
5
6  constexpr bool hasFloat = vtkm::ListHas<MyList, float>::value;
7  // hasFloat is false

4.1.7.3.4. List Indices

The vtkm::ListIndexOf template can be used to get the index of a particular type in a vtkm::List. vtkm::ListIndexOf takes two template parameters. The first parameter is a form of vtkm::List. The second parameter is any type to check to see if it is in the list. The type of the template will resolve to a std::integral_constant<vtkm::IdComponent,N> where N is the index of the type. If the requested type is not in the list, then vtkm::ListIndexOf becomes std::integral_constant<vtkm::IdComponent,-1>.

template<typename List, typename T>
using vtkm::ListIndexOf = typename detail::ListIndexOfImpl<List, T>::type

Finds the index of a given type.

Becomes a std::integral_constant for the index of the given type. If the given type is not in the list, the value is set to -1.

Conversely, the vtkm::ListAt template can be used to get the type for a particular index. The two template parameters for vtkm::ListAt are the vtkm::List and an index for the list.

template<typename List, vtkm::IdComponent Index>
using vtkm::ListAt = typename detail::ListAtImpl<List, Index>::type

Finds the type at the given index.

This becomes the type of the list at the given index.

Neither vtkm::ListIndexOf nor vtkm::ListAt works with vtkm::ListUniversal.

Example 4.17 Using indices with vtkm::List.
 1  using MyList = vtkm::List<vtkm::Int8, vtkm::Int32, vtkm::Int64>;
 2
 3  constexpr vtkm::IdComponent indexOfInt8 = vtkm::ListIndexOf<MyList, vtkm::Int8>::value;
 4  // indexOfInt8 is 0
 5  constexpr vtkm::IdComponent indexOfInt32 =
 6    vtkm::ListIndexOf<MyList, vtkm::Int32>::value;
 7  // indexOfInt32 is 1
 8  constexpr vtkm::IdComponent indexOfInt64 =
 9    vtkm::ListIndexOf<MyList, vtkm::Int64>::value;
10  // indexOfInt64 is 2
11  constexpr vtkm::IdComponent indexOfFloat32 =
12    vtkm::ListIndexOf<MyList, vtkm::Float32>::value;
13  // indexOfFloat32 is -1 (not in list)
14
15  using T0 = vtkm::ListAt<MyList, 0>; // T0 is vtkm::Int8
16  using T1 = vtkm::ListAt<MyList, 1>; // T1 is vtkm::Int32
17  using T2 = vtkm::ListAt<MyList, 2>; // T2 is vtkm::Int64

4.1.7.4. Operating on Lists

In addition to providing the base templates for defining and querying lists, vtkm/List.h also contains several features for operating on lists.

4.1.7.4.1. Appending Lists

The vtkm::ListAppend template joins together 2 or more vtkm::List types. The items are concatenated in the order provided to vtkm::ListAppend. vtkm::ListAppend does not work with vtkm::ListUniversal.

template<typename ...Lists>
using vtkm::ListAppend = typename detail::ListAppendImpl<Lists...>::type

Concatinates a set of lists into a single list.

Note that this does not work correctly with vtkm::ListUniversal.

Example 4.18 Appending vtkm::List types.
 1using BigTypes = vtkm::List<vtkm::Int64, vtkm::Float64>;
 2using MediumTypes = vtkm::List<vtkm::Int32, vtkm::Float32>;
 3using SmallTypes = vtkm::List<vtkm::Int8>;
 4
 5using SmallAndBigTypes = vtkm::ListAppend<SmallTypes, BigTypes>;
 6// SmallAndBigTypes is vtkm::List<vtkm::Int8, vtkm::Int64, vtkm::Float64>
 7
 8using AllMyTypes = vtkm::ListAppend<BigTypes, MediumTypes, SmallTypes>;
 9// AllMyTypes is
10// vtkm::List<vtkm::Int64, vtkm::Float64, vtkm::Int32, vtkm::Float32, vtkm::Int8>

4.1.7.4.2. Intersecting Lists

The vtkm::ListIntersect template takes two vtkm::List types and becomes a vtkm::List containing all types in both lists. If one of the lists is vtkm::ListUniversal, the contents of the other list used.

template<typename List1, typename List2>
using vtkm::ListIntersect = typename detail::ListIntersectImpl<List1, List2>::type

Constructs a list containing types present in all lists.

Example 4.19 Intersecting vtkm::List types.
1using SignedInts = vtkm::List<vtkm::Int8, vtkm::Int16, vtkm::Int32, vtkm::Int64>;
2using WordTypes = vtkm::List<vtkm::Int32, vtkm::UInt32, vtkm::Int64, vtkm::UInt64>;
3
4using SignedWords = vtkm::ListIntersect<SignedInts, WordTypes>;
5// SignedWords is vtkm::List<vtkm::Int32, vtkm::Int64>

4.1.7.4.3. Resolve a Template with all Types in a List

The vtkm::ListApply template transfers all of the types in a vtkm::List to another template. The first template argument of vtkm::ListApply is the vtkm::List to apply. The second template argument is another template to apply to. vtkm::ListApply becomes an instance of the passed template with all the types in the vtkm::List. vtkm::ListApply can be used to convert a vtkm::List to some other template. vtkm::ListApply cannot be used with vtkm::ListUniversal.

template<typename List, template<typename...> class Target>
using vtkm::ListApply = typename detail::ListApplyImpl<List, Target>::type

Applies the list of types to a template.

Given a ListTag and a templated class, returns the class instantiated with the types represented by the ListTag.

Example 4.20 Applying a vtkm::List to another template.
1using MyList = vtkm::List<vtkm::Id, vtkm::Id3, vtkm::Vec3f>;
2
3using MyTuple = vtkm::ListApply<MyList, std::tuple>;
4// MyTuple is std::tuple<vtkm::Id, vtkm::Id3, vtkm::Vec3f>

4.1.7.4.4. Transform Each Type in a List

The vtkm::ListTransform template applies each item in a vtkm::List to another template and constructs a list from all these applications. The first template argument of vtkm::ListTransform is the vtkm::List to apply. The second template argument is another template to apply to. vtkm::ListTransform becomes an instance of a new vtkm::List containing the passed template each type. vtkm::ListTransform cannot be used with vtkm::ListUniversal.

template<typename List, template<typename> class Transform>
using vtkm::ListTransform = typename detail::ListTransformImpl<List, Transform>::type

Constructs a list containing all types in a source list applied to a transform template.

Example 4.21 Transforming a vtkm::List using a custom template.
1using MyList = vtkm::List<vtkm::Int32, vtkm::Float32>;
2
3template<typename T>
4using MakeVec = vtkm::Vec<T, 3>;
5
6using MyVecList = vtkm::ListTransform<MyList, MakeVec>;
7// MyVecList is vtkm::List<vtkm::Vec<vtkm::Int32, 3>, vtkm::Vec<vtkm::Float32, 3>>

4.1.7.4.5. Conditionally Removing Items from a List

The vtkm::ListRemoveIf template removes items from a vtkm::List given a predicate. The first template argument of vtkm::ListRemoveIf is the vtkm::List. The second argument is another template that is used as a predicate to determine if the type should be removed or not. The predicate should become a type with a value member that is a static true or false value. Any type in the list that the predicate evaluates to true is removed. vtkm::ListRemoveIf cannot be used with vtkm::ListUniversal.

template<typename List, template<typename> class Predicate>
using vtkm::ListRemoveIf = typename detail::ListRemoveIfImpl<List, Predicate>::type

Takes an existing List and a predicate template that is applied to each type in the List.

Any type in the List that has a value element equal to true (the equivalent of std::true_type), that item will be removed from the list. For example the following type

vtkm::ListRemoveIf<vtkm::List<int, float, long long, double>, std::is_integral>

resolves to a List that is equivalent to vtkm::List<float, double> because std::is_integral<int> and std::is_integral<long long> resolve to std::true_type whereas std::is_integral<float> and std::is_integral<double> resolve to std::false_type.

Example 4.22 Removing items from a vtkm::List.
1using MyList =
2  vtkm::List<vtkm::Int64, vtkm::Float64, vtkm::Int32, vtkm::Float32, vtkm::Int8>;
3
4using FilteredList = vtkm::ListRemoveIf<MyList, std::is_integral>;
5// FilteredList is vtkm::List<vtkm::Float64, vtkm::Float32>

4.1.7.4.6. Combine all Pairs of Two Lists

The vtkm::ListCross takes two lists and performs a cross product of them. It does this by creating a new vtkm::List that contains nested vtkm::List types, each of length 2 and containing all possible pairs of items in the first list with items in the second list. vtkm::ListCross is often used in conjunction with another list processing command, such as vtkm::ListTransform to build templated types of many combinations. vtkm::ListCross cannot be used with vtkm::ListUniversal.

template<typename List1, typename List2>
using vtkm::ListCross = typename detail::ListCrossImpl<List1, List2>::type

Generates a list that is the cross product of two input lists.

The resulting list has the form of vtkm::List<vtkm::List<A1,B1>, vtkm::List<A1,B2>,...>

Example 4.23 Creating the cross product of 2 vtkm::List types.
 1using BaseTypes = vtkm::List<vtkm::Int8, vtkm::Int32, vtkm::Int64>;
 2using BoolCases = vtkm::List<std::false_type, std::true_type>;
 3
 4using CrossTypes = vtkm::ListCross<BaseTypes, BoolCases>;
 5// CrossTypes is
 6//   vtkm::List<vtkm::List<vtkm::Int8, std::false_type>,
 7//              vtkm::List<vtkm::Int8, std::true_type>,
 8//              vtkm::List<vtkm::Int32, std::false_type>,
 9//              vtkm::List<vtkm::Int32, std::true_type>,
10//              vtkm::List<vtkm::Int64, std::false_type>,
11//              vtkm::List<vtkm::Int64, std::true_type>>
12
13template<typename TypeAndIsVec>
14using ListPairToType =
15  typename std::conditional<vtkm::ListAt<TypeAndIsVec, 1>::value,
16                            vtkm::Vec<vtkm::ListAt<TypeAndIsVec, 0>, 3>,
17                            vtkm::ListAt<TypeAndIsVec, 0>>::type;
18
19using AllTypes = vtkm::ListTransform<CrossTypes, ListPairToType>;
20// AllTypes is
21//   vtkm::List<vtkm::Int8,
22//              vtkm::Vec<vtkm::Int8, 3>,
23//              vtkm::Int32,
24//              vtkm::Vec<vtkm::Int32, 3>,
25//              vtkm::Int64,
26//              vtkm::Vec<vtkm::Int64, 3>>

4.1.7.4.7. Call a Function For Each Type in a List

The vtkm::ListForEach function takes a functor object and a vtkm::List. It then calls the functor object with the default object of each type in the list. This is most typically used with C++ run-time type information to convert a run-time polymorphic object to a statically typed (and possibly inlined) call.

template<typename Functor, typename ...Ts, typename ...Args>
void vtkm::ListForEach(Functor &&f, vtkm::List<Ts...>, Args&&... args)

For each typename represented by the list, call the functor with a default instance of that type.

The following example shows a rudimentary version of converting a dynamically-typed array to a statically-typed array similar to what is done in VTK‑m classes like vtkm::cont::UnknownArrayHandle (which is documented in Chapter~ref{chap:UnknownArrayHandle}).

Example 4.24 Converting dynamic types to static types with vtkm::ListForEach.
 1struct MyArrayBase
 2{
 3  // A virtual destructor makes sure C++ RTTI will be generated. It also helps
 4  // ensure subclass destructors are called.
 5  virtual ~MyArrayBase() {}
 6};
 7
 8template<typename T>
 9struct MyArrayImpl : public MyArrayBase
10{
11  std::vector<T> Array;
12};
13
14template<typename T>
15void PrefixSum(std::vector<T>& array)
16{
17  T sum(typename vtkm::VecTraits<T>::ComponentType(0));
18  for (typename std::vector<T>::iterator iter = array.begin(); iter != array.end();
19       iter++)
20  {
21    sum = sum + *iter;
22    *iter = sum;
23  }
24}
25
26struct PrefixSumFunctor
27{
28  MyArrayBase* ArrayPointer;
29
30  PrefixSumFunctor(MyArrayBase* arrayPointer)
31    : ArrayPointer(arrayPointer)
32  {
33  }
34
35  template<typename T>
36  void operator()(T)
37  {
38    using ConcreteArrayType = MyArrayImpl<T>;
39    ConcreteArrayType* concreteArray =
40      dynamic_cast<ConcreteArrayType*>(this->ArrayPointer);
41    if (concreteArray != NULL)
42    {
43      PrefixSum(concreteArray->Array);
44    }
45  }
46};
47
48void DoPrefixSum(MyArrayBase* array)
49{
50  PrefixSumFunctor functor = PrefixSumFunctor(array);
51  vtkm::ListForEach(functor, vtkm::TypeListCommon());
52}

4.1.8. Pair

VTK‑m defines a vtkm::Pair templated object that behaves just like std::pair from the standard template library. The difference is that vtkm::Pair will work in both the execution and control environments, whereas the STL std::pair does not always work in the execution environment.

template<typename T1, typename T2>
struct Pair

A vtkm::Pair is essentially the same as an STL pair object except that the methods (constructors and operators) are defined to work in both the control and execution environments (whereas std::pair is likely to work only in the control environment).

Public Types

using FirstType = T1

The type of the first object.

using SecondType = T2

The type of the second object.

using first_type = FirstType

The same as FirstType, but follows the naming convention of std::pair.

using second_type = SecondType

The same as SecondType, but follows the naming convention of std::pair.

Public Functions

Pair() = default
inline Pair(const FirstType &firstSrc, const SecondType &secondSrc)
inline Pair(FirstType &&firstSrc, SecondType &&secondSrc) noexcept(noexcept(FirstType{std::declval<FirstType&&>()}, SecondType{std::declval<SecondType&&>()}))
Pair(const Pair&) = default
Pair(Pair&&) = default
template<typename U1, typename U2>
inline Pair(const vtkm::Pair<U1, U2> &src)
template<typename U1, typename U2>
inline Pair(vtkm::Pair<U1, U2> &&src) noexcept(noexcept(U1{std::declval<U1&&>()}, U2{std::declval<U2&&>()}))
template<typename U1, typename U2>
inline Pair(const std::pair<U1, U2> &src)
template<typename U1, typename U2>
inline Pair(std::pair<U1, U2> &&src) noexcept(noexcept(U1{std::declval<U1&&>()}, U2{std::declval<U2&&>()}))
vtkm::Pair<FirstType, SecondType> &operator=(const vtkm::Pair<FirstType, SecondType> &src) = default
vtkm::Pair<FirstType, SecondType> &operator=(vtkm::Pair<FirstType, SecondType> &&src) = default
inline bool operator==(const vtkm::Pair<FirstType, SecondType> &other) const
inline bool operator!=(const vtkm::Pair<FirstType, SecondType> &other) const
inline bool operator<(const vtkm::Pair<FirstType, SecondType> &other) const

Tests ordering on the first object, and then on the second object if the first are equal.

inline bool operator>(const vtkm::Pair<FirstType, SecondType> &other) const

Tests ordering on the first object, and then on the second object if the first are equal.

inline bool operator<=(const vtkm::Pair<FirstType, SecondType> &other) const

Tests ordering on the first object, and then on the second object if the first are equal.

inline bool operator>=(const vtkm::Pair<FirstType, SecondType> &other) const

Tests ordering on the first object, and then on the second object if the first are equal.

Public Members

FirstType first

The pair’s first object.

Note that this field breaks VTK-m’s naming conventions to make vtkm::Pair more compatible with std::pair.

SecondType second

The pair’s second object.

Note that this field breaks VTK-m’s naming conventions to make vtkm::Pair more compatible with std::pair.

The VTK‑m version of vtkm::Pair supports the same types, fields, and operations as the STL version. VTK‑m also provides a vtkm::make_Pair() function for convenience.

template<typename T1, typename T2>
vtkm::Pair<typename std::decay<T1>::type, typename std::decay<T2>::type> vtkm::make_Pair(T1 &&v1, T2 &&v2)

4.1.9. Tuple

VTK‑m defines a vtkm::Tuple templated object that behaves like std::tuple from the standard template library. The main difference is that vtkm::Tuple will work in both the execution and control environments, whereas the STL std::tuple does not always work in the execution environment.

template<typename ...Ts>
class Tuple

VTK-m replacement for std::tuple.

This function serves the same function as std::tuple and behaves similarly. However, this version of Tuple works on devices that VTK-m supports. There are also some implementation details that makes compiling faster for VTK-m use. We also provide some methods like Apply and ForEach that are helpful for several VTK-m operations.

4.1.9.1. Defining and Constructing

vtkm::Tuple takes any number of template parameters that define the objects stored the tuple.

Example 4.25 Defining a vtkm::Tuple.
1  vtkm::Tuple<vtkm::Id, vtkm::Vec3f, vtkm::cont::ArrayHandle<vtkm::Int32>> myTuple;

You can construct a vtkm::Tuple with arguments that will be used to initialize the respective objects. As a convenience, you can use vtkm::MakeTuple() to construct a vtkm::Tuple of types based on the arguments.

template<typename ...Ts>
auto vtkm::MakeTuple(Ts&&... args) -> vtkm::Tuple<typename std::decay<Ts>::type...>

Creates a new vtkm::Tuple with the given types.

template<typename ...Ts>
auto vtkm::make_tuple(Ts&&... args) -> decltype(vtkm::MakeTuple(std::forward<Ts>(args)...))

Compatible with std::make_tuple for vtkm::Tuple.

Example 4.26 Initializing values in a vtkm::Tuple.
1  // Initialize a tuple with 0, [0, 1, 2], and an existing ArrayHandle.
2  vtkm::Tuple<vtkm::Id, vtkm::Vec3f, vtkm::cont::ArrayHandle<vtkm::Float32>> myTuple1(
3    0, vtkm::Vec3f(0, 1, 2), array);
4
5  // Another way to create the same tuple.
6  auto myTuple2 = vtkm::MakeTuple(vtkm::Id(0), vtkm::Vec3f(0, 1, 2), array);

4.1.9.2. Querying

The size of a vtkm::Tuple can be determined by using the vtkm::TupleSize template, which resolves to an std::integral_constant. The types at particular indices can be determined with vtkm::TupleElement.

template<typename TupleType>
using vtkm::TupleSize = std::integral_constant<vtkm::IdComponent, TupleType::Size>

Get the size of a tuple.

Given a vtkm::Tuple type, becomes a std::integral_constant of the type.

template<vtkm::IdComponent Index, typename TupleType>
using vtkm::TupleElement = typename detail::TupleElementImpl<Index, TupleType>::type

Becomes the type of the given index for the given vtkm::Tuple.

Example 4.27 Querying vtkm::Tuple types.
1  using TupleType = vtkm::Tuple<vtkm::Id, vtkm::Float32, vtkm::Float64>;
2
3  // Becomes 3
4  constexpr vtkm::IdComponent size = vtkm::TupleSize<TupleType>::value;
5
6  using FirstType = vtkm::TupleElement<0, TupleType>;  // vtkm::Id
7  using SecondType = vtkm::TupleElement<1, TupleType>; // vtkm::Float32
8  using ThirdType = vtkm::TupleElement<2, TupleType>;  // vtkm::Float64

The function vtkm::Get() can be used to retrieve an element from the vtkm::Tuple. vtkm::Get() returns a reference to the element, so you can set a vtkm::Tuple element by setting the return value of vtkm::Get().

template<vtkm::IdComponent Index, typename ...Ts>
auto vtkm::Get(const vtkm::Tuple<Ts...> &tuple)

Retrieve the object from a vtkm::Tuple at the given index.

template<vtkm::IdComponent Index, typename ...Ts>
auto vtkm::Get(vtkm::Tuple<Ts...> &tuple)

Retrieve the object from a vtkm::Tuple at the given index.

template<std::size_t Index, typename ...Ts>
auto vtkm::get(const vtkm::Tuple<Ts...> &tuple) -> decltype(vtkm::Get<static_cast<vtkm::IdComponent>(Index)>(tuple))

Compatible with std::get for vtkm::Tuple.

template<std::size_t Index, typename ...Ts>
auto vtkm::get(vtkm::Tuple<Ts...> &tuple) -> decltype(vtkm::Get<static_cast<vtkm::IdComponent>(Index)>(tuple))

Compatible with std::get for vtkm::Tuple.

Example 4.28 Retrieving values from a vtkm::Tuple.
1  auto myTuple = vtkm::MakeTuple(vtkm::Id3(0, 1, 2), vtkm::Vec3f(3, 4, 5));
2
3  // Gets the value [0, 1, 2]
4  vtkm::Id3 x = vtkm::Get<0>(myTuple);
5
6  // Changes the second object in myTuple to [6, 7, 8]
7  vtkm::Get<1>(myTuple) = vtkm::Vec3f(6, 7, 8);

4.1.9.3. For Each Tuple Value

The vtkm::ForEach() function takes a tuple and a function or functor and calls the function for each of the items in the tuple. Nothing is returned from vtkm::ForEach(), and any return value from the function is ignored.

template<typename ...Ts, typename Function>
void vtkm::ForEach(const vtkm::Tuple<Ts...> &tuple, Function &&f)

Call a function with each value of the given tuple.

The function calls will be done in the order of the values in the vtkm::Tuple.

template<typename ...Ts, typename Function>
void vtkm::ForEach(vtkm::Tuple<Ts...> &tuple, Function &&f)

Call a function with each value of the given tuple.

The function calls will be done in the order of the values in the vtkm::Tuple.

vtkm::ForEach() can be used to check the validity of each item in a vtkm::Tuple.

Example 4.29 Using vtkm::Tuple::ForEach() to check the contents.
 1void CheckPositive(vtkm::Float64 x)
 2{
 3  if (x < 0)
 4  {
 5    throw vtkm::cont::ErrorBadValue("Values need to be positive.");
 6  }
 7}
 8
 9// ...
10
11  vtkm::Tuple<vtkm::Float64, vtkm::Float64, vtkm::Float64> tuple(
12    CreateValue(0), CreateValue(1), CreateValue(2));
13
14  // Will throw an error if any of the values are negative.
15  vtkm::ForEach(tuple, CheckPositive);

vtkm::ForEach() can also be used to aggregate values in a vtkm::Tuple.

Example 4.30 Using vtkm::Tuple::ForEach() to aggregate.
 1struct SumFunctor
 2{
 3  vtkm::Float64 Sum = 0;
 4
 5  template<typename T>
 6  void operator()(const T& x)
 7  {
 8    this->Sum = this->Sum + static_cast<vtkm::Float64>(x);
 9  }
10};
11
12// ...
13
14  vtkm::Tuple<vtkm::Float32, vtkm::Float64, vtkm::Id> tuple(
15    CreateValue(0), CreateValue(1), CreateValue(2));
16
17  SumFunctor sum;
18  vtkm::ForEach(tuple, sum);
19  vtkm::Float64 average = sum.Sum / 3;

The previous examples used an explicit struct as the functor for clarity. However, it is often less verbose to use a C++ lambda function.

Example 4.31 Using vtkm::Tuple::ForEach() to aggregate.
1  vtkm::Tuple<vtkm::Float32, vtkm::Float64, vtkm::Id> tuple(
2    CreateValue(0), CreateValue(1), CreateValue(2));
3
4  vtkm::Float64 sum = 0;
5  auto sumFunctor = [&sum](auto x) { sum += static_cast<vtkm::Float64>(x); };
6
7  vtkm::ForEach(tuple, sumFunctor);
8  vtkm::Float64 average = sum / 3;

4.1.9.4. Transform Each Tuple Value

The vtkm::Transform() function builds a new vtkm::Tuple by calling a function or functor on each of the items in an existing vtkm::Tuple. The return value is placed in the corresponding part of the resulting vtkm::Tuple, and the type is automatically created from the return type of the function.

template<typename TupleType, typename Function>
auto vtkm::Transform(const TupleType &&tuple, Function &&f) -> decltype(Apply(tuple, detail::TupleTransformFunctor(), std::forward<Function>(f)))

Construct a new vtkm::Tuple by applying a function to each value.

The vtkm::Transform function builds a new vtkm::Tuple by calling a function or functor on each of the items in the given tuple. The return value is placed in the corresponding part of the resulting Tuple, and the type is automatically created from the return type of the function.

template<typename TupleType, typename Function>
auto vtkm::Transform(TupleType &&tuple, Function &&f) -> decltype(Apply(tuple, detail::TupleTransformFunctor(), std::forward<Function>(f)))

Get the size of a tuple.

Given a vtkm::Tuple type, becomes a std::integral_constant of the type.

Example 4.32 Transforming a vtkm::Tuple.
 1struct GetReadPortalFunctor
 2{
 3  template<typename Array>
 4  typename Array::ReadPortalType operator()(const Array& array) const
 5  {
 6    VTKM_IS_ARRAY_HANDLE(Array);
 7    return array.ReadPortal();
 8  }
 9};
10
11// ...
12
13  auto arrayTuple = vtkm::MakeTuple(array1, array2, array3);
14
15  auto portalTuple = vtkm::Transform(arrayTuple, GetReadPortalFunctor{});

4.1.9.5. Apply

The vtkm::Apply() function calls a function or functor using the objects in a vtkm::Tuple as the arguments. If the function returns a value, that value is returned from vtkm::Apply().

template<typename ...Ts, typename Function, typename ...Args>
auto vtkm::Apply(const vtkm::Tuple<Ts...> &tuple, Function &&f, Args&&... args) -> decltype(tuple.Apply(std::forward<Function>(f), std::forward<Args>(args)...))

Call a function with the values of a vtkm::Tuple as arguments.

If a vtkm::Tuple<A, B, C> is given with values a, b, and c, then f will be called as f(a, b, c).

Additional arguments can optionally be given to vtkm::Apply(). These arguments will be added to the beginning of the arguments to the function.

The returned value of the function (if any) will be returned from vtkm::Apply().

template<typename ...Ts, typename Function, typename ...Args>
auto vtkm::Apply(vtkm::Tuple<Ts...> &tuple, Function &&f, Args&&... args) -> decltype(tuple.Apply(std::forward<Function>(f), std::forward<Args>(args)...))

Call a function with the values of a vtkm::Tuple as arguments.

If a vtkm::Tuple<A, B, C> is given with values a, b, and c, then f will be called as f(a, b, c).

Additional arguments can optionally be given to vtkm::Apply(). These arguments will be added to the beginning of the arguments to the function.

The returned value of the function (if any) will be returned from vtkm::Apply().

Example 4.33 Applying a vtkm::Tuple as arguments to a function.
 1struct AddArraysFunctor
 2{
 3  template<typename Array1, typename Array2, typename Array3>
 4  vtkm::Id operator()(Array1 inArray1, Array2 inArray2, Array3 outArray) const
 5  {
 6    VTKM_IS_ARRAY_HANDLE(Array1);
 7    VTKM_IS_ARRAY_HANDLE(Array2);
 8    VTKM_IS_ARRAY_HANDLE(Array3);
 9
10    vtkm::Id length = inArray1.GetNumberOfValues();
11    VTKM_ASSERT(inArray2.GetNumberOfValues() == length);
12    outArray.Allocate(length);
13
14    auto inPortal1 = inArray1.ReadPortal();
15    auto inPortal2 = inArray2.ReadPortal();
16    auto outPortal = outArray.WritePortal();
17    for (vtkm::Id index = 0; index < length; ++index)
18    {
19      outPortal.Set(index, inPortal1.Get(index) + inPortal2.Get(index));
20    }
21
22    return length;
23  }
24};
25
26// ...
27
28  auto arrayTuple = vtkm::MakeTuple(array1, array2, array3);
29
30  vtkm::Id arrayLength = vtkm::Apply(arrayTuple, AddArraysFunctor{});

If additional arguments are given to vtkm::Apply(), they are also passed to the function (before the objects in the vtkm::Tuple). This is helpful for passing state to the function.

Example 4.34 Using extra arguments with vtkm::Tuple::Apply().
 1struct ScanArrayLengthFunctor
 2{
 3  template<vtkm::IdComponent N, typename Array, typename... Remaining>
 4  vtkm::Vec<vtkm::Id, N + 1 + vtkm::IdComponent(sizeof...(Remaining))> operator()(
 5    const vtkm::Vec<vtkm::Id, N>& partialResult,
 6    const Array& nextArray,
 7    const Remaining&... remainingArrays) const
 8  {
 9    vtkm::Vec<vtkm::Id, N + 1> nextResult;
10    std::copy(&partialResult[0], &partialResult[0] + N, &nextResult[0]);
11    nextResult[N] = nextResult[N - 1] + nextArray.GetNumberOfValues();
12    return (*this)(nextResult, remainingArrays...);
13  }
14
15  template<vtkm::IdComponent N>
16  vtkm::Vec<vtkm::Id, N> operator()(const vtkm::Vec<vtkm::Id, N>& result) const
17  {
18    return result;
19  }
20};
21
22// ...
23
24  auto arrayTuple = vtkm::MakeTuple(array1, array2, array3);
25
26  vtkm::Vec<vtkm::Id, 4> sizeScan =
27    vtkm::Apply(arrayTuple, ScanArrayLengthFunctor{}, vtkm::Vec<vtkm::Id, 1>{ 0 });

4.1.10. Error Codes

For operations that occur in the control environment, VTK‑m uses exceptions to report errors as described in Chapter 2.9 (Error Handling). However, when operating in the execution environment, it is not feasible to throw exceptions. Thus, for operations designed for the execution environment, the status of an operation that can fail is returned as an vtkm::ErrorCode, which is an enum.

enum class vtkm::ErrorCode

Identifies whether an operation was successful or what type of error it had.

Most errors in VTK-m are reported by throwing an exception. However, there are some places, most notably the execution environment, where it is not possible to throw an exception. For those cases, it is typical for a function to return an ErrorCode identifier. The calling code can check to see if the operation was a success or what kind of error was encountered otherwise.

Use the vtkm::ErrorString() function to get a descriptive string of the error type.

Values:

enumerator Success

A successful operation.

This code is returned when the operation was successful. Calling code should check the error code against this identifier when checking the status.

enumerator InvalidShapeId

A unknown shape identifier was encountered.

All cell shapes must be listed in vtkm::CellShapeIdEnum.

enumerator InvalidNumberOfPoints

The wrong number of points was provided for a given cell type.

For example, if a triangle has 4 points associated with it, you are likely to get this error.

enumerator InvalidCellMetric

A cell metric was requested for a cell that does not support that metric.

enumerator WrongShapeIdForTagType

This is an internal error from the lightweight cell library.

enumerator InvalidPointId

A bad point identifier was detected while operating on a cell.

enumerator InvalidEdgeId

A bad edge identifier was detected while operating on a cell.

enumerator InvalidFaceId

A bad face identifier was detected while operating on a cell.

enumerator SolutionDidNotConverge

An iterative operation did not find an appropriate solution.

This error code might be returned with some results of an iterative solution. However, solution did not appear to resolve, so the results might not be accurate.

enumerator MatrixFactorizationFailed

A solution was not found for a linear system.

Some VTK-m computations use linear algebra to solve a system of equations. If the equations does not give a valid result, this error can be returned.

enumerator DegenerateCellDetected

An operation detected a degenerate cell.

A degenerate cell has two or more vertices combined into one, which changes the structure of the cell. For example, if 2 vertices of a tetrahedron are at the same point, the cell degenerates to a triangle. Degenerate cells have the potential to interfere with some computations on cells.

enumerator MalformedCellDetected

An operation detected on a malformed cell.

Most cell shapes have some assumptions about their geometry (e.g. not self intersecting). If an operation detects an expected behavior is violated, this error is returned. (Note that vtkm::DegenerateCellDetected has its own error coe.)

enumerator OperationOnEmptyCell

An operation was attempted on a cell with an empty shape.

There is a special “empty” cell shape type (vtkm::CellShapeTagEmpty) that can be used as a placeholder for a cell with no information. Math operations such as interpolation cannot be performed on empty cells, and attempting to do so will result in this error.

enumerator CellNotFound

A cell matching some given criteria could not be found.

This error code is most often used in a cell locator where no cell in the given region could be found.

enumerator UnknownError

If a function or method returns an vtkm::ErrorCode, it is a good practice to check to make sure that the returned value is vtkm::ErrorCode::Success. If it is not, you can use the vtkm::ErrorString() function to convert the vtkm::ErrorCode to a descriptive C string. The easiest thing to do from within a worklet is to call the worklet’s RaiseError method.

inline const char *vtkm::ErrorString(vtkm::ErrorCode code) noexcept

Convert a vtkm::ErrorCode into a human-readable string.

This method is useful when reporting the results of a function that failed.

Example 4.35 Checking an vtkm::ErrorCode and reporting errors in a worklet.
1    vtkm::ErrorCode status = cellLocator.FindCell(point, cellId, parametric);
2    if (status != vtkm::ErrorCode::Success)
3    {
4      this->RaiseError(vtkm::ErrorString(status));
5    }