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 |
|||
2 |
|||
4 |
|||
8 |
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. TheVec
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.
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 |
|||
3 |
||||
4 |
||||
2 |
2 |
|||
3 |
||||
4 |
||||
4 |
2 |
|||
3 |
||||
4 |
||||
8 |
2 |
|||
3 |
||||
4 |
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.
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.
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 mimicsVec
. This provides a mechanism to treat C arrays like aVec
. It is useful in situations where you want to use aVec
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 aVecC
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 declareVecC<const vtkm::Id>
. If you want a non-mutableVecC
, theVecCConst
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 ofVecC
. It can be used in place ofVecC
when a constant array is available.A
VecC
can be automatically converted to aVecCConst
, but not vice versa, so function arguments should useVecCConst
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.
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 aVec
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.
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 aVec
.
-
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 aMin
andMax
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 betweenMin
andMax
. IfMax
is less thanMin
, then no values satisfy the range andIsNonEmpty
returns false. Otherwise, return true.IsNonEmpty
assumesMin
andMax
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 Range()
The following example demonstrates the operation of 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
.
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.
-
inline Bounds()
The following example demonstrates the operation of 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 aMin
andMax
value, whereMax
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 betweenMin
andMax
. IfMax
<=Min
, then no values satisfy the range andIsNonEmpty
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 RangeId()
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 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.
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.
-
RangeId2() = default
-
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 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.
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.
-
RangeId3() = default
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.
-
using NumericTag = vtkm::TypeTraitsUnknownTag
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.
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.
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 otherVec
-like object. When using this class, scalar objects are treated like aVec
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 orvtkm::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
isvtkm::VecTraitsTagSizeVariable
), thenHasMultipleComponents
might bevtkm::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
, thenNUM_COMPONENTS
is set. If set toVecTraitsTagSizeVariable
, then the number of components is not known at compile time and must be queried withGetNumberOfComponents
.
-
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>
isvtkm::Vec<T2, N>
. This replacement is not recursive. SoVecTraits<Vec<Vec<T, M>, N>::ReplaceComponentType<T2>
isvtkm::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>
isVec<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 ofNUM_COMPONENTS
for vector types that have a static size (that is,IsSizeStatic
isvtkm::VecTraitsTagSizeStatic
). But unlikeNUM_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 whenIsSizeStatic
is set tovtkm::VecTraitsTagSizeVariable
.
-
using ComponentType = T
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.
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.
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 emptystruct
that is used to hold a list of types as its template arguments. VTK-m provides templated types that allows aList
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.
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
.
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::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.
-
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
, andunsigned char
, but notchar
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.
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.)
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.
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 byList
.Becomes
std::true_type
if theT
is inList
.std::false_type
otherwise.
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
.
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
.
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.
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.
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.
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 theList
.Any type in the
List
that has a value element equal to true (the equivalent ofstd::true_type
), that item will be removed from the list. For example the following typevtkm::ListRemoveIf<vtkm::List<int, float, long long, double>, std::is_integral>
resolves to a
List
that is equivalent tovtkm::List<float, double>
becausestd::is_integral<int>
andstd::is_integral<long long>
resolve tostd::true_type
whereasstd::is_integral<float>
andstd::is_integral<double>
resolve tostd::false_type
.
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>,...>
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}).
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 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&&>()}))
-
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(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.
-
using first_type = FirstType
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.
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 ofTuple
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 likeApply
andForEach
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.
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
forvtkm::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 astd::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
.
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
forvtkm::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
forvtkm::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
.
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
.
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.
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 newvtkm::Tuple
by calling a function or functor on each of the items in the giventuple
. 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 astd::integral_constant
of the type.
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 valuesa
,b
, andc
, thenf
will be called asf(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 valuesa
,b
, andc
, thenf
will be called asf(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()
.
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.
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
-
enumerator Success
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.
1 vtkm::ErrorCode status = cellLocator.FindCell(point, cellId, parametric);
2 if (status != vtkm::ErrorCode::Success)
3 {
4 this->RaiseError(vtkm::ErrorString(status));
5 }