4.9. Fancy Array Handles
One of the features of using vtkm::cont::ArrayHandle is that it hides the implementation and layout of the array behind a generic interface.
This gives us the opportunity to replace a simple C array with some custom definition of the data and the code using the vtkm::cont::ArrayHandle is none the wiser.
This gives us the opportunity to implement fancy arrays that do more than simply look up a value in an array. For example, arrays can be augmented on the fly by mutating their indices or values. Or values could be computed directly from the index so that no storage is required for the array at all. VTK‑m provides many of the fancy arrays, which we explore in this section.
Did You Know?
One of the advantages of VTK‑m’s implementation of fancy arrays is that they can define whole arrays without actually storing and values.
For example, vtkm::cont::ArrayHandleConstant, vtkm::cont::ArrayHandleIndex, and vtkm::cont::ArrayHandleCounting do not store data in any array in memory.
Rather, they construct the value for an index at runtime.
Likewise, arrays like vtkm::cont::ArrayHandlePermutation construct new arrays from the values of other arrays without having to create a copy of the data.
Did You Know?
This chapter documents several array handle types that modify other array handles. Chapter 4.8 (Memory Layout of Array Handles) has several similar examples of modifying basic arrays to represent data in different layouts. The difference is that the fancy array handles in this chapter decorate other array handles of any type whereas those in Chapter 4.8 only decorate basic array handles. If you do not find the fancy array handle you are looking for here, you might try that chapter.
4.9.1. Constant Arrays
A constant array is a fancy array handle that has the same value in all of its entries. The constant array provides this array without actually using any memory.
Specifying a constant array in VTK‑m is straightforward.
VTK‑m has a class named vtkm::cont::ArrayHandleConstant.
vtkm::cont::ArrayHandleConstant is a templated class with a single template argument that is the type of value for each element in the array.
The constructor for vtkm::cont::ArrayHandleConstant takes the value to provide by the array and the number of values the array should present.
The following example is a simple demonstration of the constant array handle.
-
template<typename T>
class ArrayHandleConstant : public vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagConstant> An array handle with a constant value.
ArrayHandleConstantis an implicit array handle with a constant value. A constant array handle is constructed by giving a value and an array length. The resulting array is of the given size with each entry the same value given in the constructor. The array is defined implicitly, so there it takes (almost) no memory.
1 // Create an array of 50 entries, all containing the number 3. This could be
2 // used, for example, to represent the sizes of all the polygons in a set
3 // where we know all the polygons are triangles.
4 vtkm::cont::ArrayHandleConstant<vtkm::Id> constantArray(3, 50);
The vtkm/cont/ArrayHandleConstant.h header also contains the templated convenience function vtkm::cont::make_ArrayHandleConstant() that takes a value and a size for the array.
This function can sometimes be used to avoid having to declare the full array type.
-
template<typename T>
vtkm::cont::ArrayHandleConstant<T> vtkm::cont::make_ArrayHandleConstant(T value, vtkm::Id numberOfValues) make_ArrayHandleConstantis convenience function to generate an ArrayHandleImplicit.
1 // Create an array of 50 entries, all containing the number 3.
2 vtkm::cont::make_ArrayHandleConstant(3, 50)
4.9.2. Viewing a Subset of an Array
An array handle view is a fancy array handle that returns a subset of an already existing array handle. The array handle view uses the same memory as the existing array handle the view was created from. This means that changes to the data in the array handle view will also change the data in the original array handle.
-
template<typename ArrayHandleType>
class ArrayHandleView : public vtkm::cont::ArrayHandle<ArrayHandleType::ValueType, StorageTagView<ArrayHandleType::StorageTag>> Provided a windowed view into a
vtkm::cont::ArrayHandle.ArrayHandleViewis a fancy array that wraps around anotherArrayHandleand reindexes it to provide access to a specified region of values in the array. This view is specified using the offset to the first index and the length of the entries to view.Public Functions
-
inline ArrayHandleView(const ArrayHandleType &array, vtkm::Id startIndex, vtkm::Id numValues)
Create an
ArrayHandleViewover a provided source array.- Parameters:
array – The source array to create a view from.
startIndex – The offset in
arrayto start the view.numValues – The number of values in the view.
-
inline ArrayHandleType GetSourceArray() const
Retrieve the full array being viewed.
-
inline ArrayHandleView(const ArrayHandleType &array, vtkm::Id startIndex, vtkm::Id numValues)
To use the vtkm::cont::ArrayHandleView you must supply an vtkm::cont::ArrayHandle to the vtkm::cont::ArrayHandleView class constructor.
vtkm::cont::ArrayHandleView is a templated class with a single template argument that is the vtkm::cont::ArrayHandle type of the array that the view is being created from.
The constructor for vtkm::cont::ArrayHandleView takes a target array, starting index, and length.
The following example shows a simple usage of the array handle view.
1 vtkm::cont::ArrayHandle<vtkm::Id> sourceArray;
2 vtkm::cont::ArrayCopy(vtkm::cont::ArrayHandleIndex(10), sourceArray);
3 // sourceArray has [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
4
5 vtkm::cont::ArrayHandleView<vtkm::cont::ArrayHandle<vtkm::Id>> viewArray(
6 sourceArray, 3, 5);
7 // viewArray has [3, 4, 5, 6, 7]
The vtkm/cont/ArrayHandleView.h header contains a templated convenience function vtkm::cont::make_ArrayHandleView() that takes a target array, index, and length.
-
template<typename ArrayHandleType>
ArrayHandleView<ArrayHandleType> vtkm::cont::make_ArrayHandleView(const ArrayHandleType &array, vtkm::Id startIndex, vtkm::Id numValues) Construct a
vtkm::cont::ArrayHandleViewfrom a source array.
1 vtkm::cont::make_ArrayHandleView(sourceArray, 3, 5)
4.9.3. Counting Arrays
A counting array is a fancy array handle that provides a sequence of numbers. These fancy arrays can represent the data without actually using any memory.
VTK‑m provides two versions of a counting array.
The first version is an index array that provides a specialized but common form of a counting array called an index array.
An index array has values of type vtkm::Id that start at 0 and count up by 1 (i.e., \(0, 1, 2, 3,\ldots\)).
The index array mirrors the array’s index.
-
class ArrayHandleIndex : public vtkm::cont::ArrayHandle<vtkm::Id, StorageTagIndex>
An implicit array handle containing the its own indices.
ArrayHandleIndexis an implicit array handle containing the values 0, 1, 2, 3,… to a specified size. Every value in the array is the same as the index to that value.
Specifying an index array in VTK‑m is done with a class named vtkm::cont::ArrayHandleIndex.
The constructor for vtkm::cont::ArrayHandleIndex takes the size of the array to create.
The following example is a simple demonstration of the index array handle.
1 // Create an array containing [0, 1, 2, 3, ..., 49].
2 vtkm::cont::ArrayHandleIndex indexArray(50);
A vtkm::cont::make_ArrayHandleIndex() convenience function is also available.
-
inline vtkm::cont::ArrayHandleIndex vtkm::cont::make_ArrayHandleIndex(vtkm::Id length)
A convenience function for creating an ArrayHandleIndex.
It takes the size of the array and generates an array holding vtkm::Id from [0, size - 1]
The vtkm::cont::ArrayHandleCounting class provides a more general form of counting.
vtkm::cont::ArrayHandleCounting is a templated class with a single template argument that is the type of value for each element in the array.
The constructor for vtkm::cont::ArrayHandleCounting takes three arguments: the start value (used at index 0), the step from one value to the next, and the length of the array.
The following example is a simple demonstration of the counting array handle.
-
template<typename CountingValueType>
class ArrayHandleCounting : public vtkm::cont::ArrayHandle<CountingValueType, vtkm::cont::StorageTagCounting> ArrayHandleCounting is a specialization of ArrayHandle.
By default it contains a increment value, that is increment for each step between zero and the passed in length
1 // Create an array containing [-1.0, -0.9, -0.8, ..., 0.9, 1.0]
2 vtkm::cont::ArrayHandleCounting<vtkm::Float32> sampleArray(-1.0f, 0.1f, 21);
Did You Know?
In addition to being simpler to declare, vtkm::cont::ArrayHandleIndex is slightly faster than vtkm::cont::ArrayHandleCounting.
Thus, when applicable, you should prefer using vtkm::cont::ArrayHandleIndex.
The vtkm/cont/ArrayHandleCounting.h header also contains the templated convenience function vtkm::cont::make_ArrayHandleCounting that also takes the start value, step, and length as arguments.
This function can sometimes be used to avoid having to declare the full array type.
-
template<typename CountingValueType>
vtkm::cont::ArrayHandleCounting<CountingValueType> vtkm::cont::make_ArrayHandleCounting(CountingValueType start, CountingValueType step, vtkm::Id length) A convenience function for creating an ArrayHandleCounting.
It takes the value to start counting from and and the number of times to increment.
1 // Create an array containing [-1.0, -0.9, -0.8, ..., 0.9, 1.0]
2 vtkm::cont::make_ArrayHandleCounting(-1.0f, 0.1f, 21)
There are no fundamental limits on how vtkm::cont::ArrayHandleCounting counts.
For example, it is possible to count backwards.
1 // Create an array containing [49, 48, 47, 46, ..., 0].
2 vtkm::cont::ArrayHandleCounting<vtkm::Id> backwardIndexArray(49, -1, 50);
It is also possible to use vtkm::cont::ArrayHandleCounting to make sequences of vtkm::Vec values with piece-wise counting in each of the components.
1 // Create an array containg [(0,-3,75), (1,2,25), (3,7,-25)]
2 vtkm::cont::make_ArrayHandleCounting(
3 vtkm::make_Vec(0, -3, 75), vtkm::make_Vec(1, 5, -50), 3)
4.9.4. Cast Arrays
A cast array is a fancy array that changes the type of the elements in an array. The cast array provides this re-typed array without actually copying or generating any data. Instead, casts are performed as the array is accessed.
VTK‑m has a class named vtkm::cont::ArrayHandleCast to perform this implicit casting.
vtkm::cont::ArrayHandleCast is a templated class with two template arguments.
The first argument is the type to cast values to.
The second argument is the type of the original vtkm::cont::ArrayHandle.
The constructor to vtkm::cont::ArrayHandleCast takes the vtkm::cont::ArrayHandle to modify by casting.
-
template<typename T, typename ArrayHandleType>
class ArrayHandleCast : public vtkm::cont::ArrayHandle<T, StorageTagCast<ArrayHandleType::ValueType, ArrayHandleType::StorageTag>> Cast the values of an array to the specified type, on demand.
ArrayHandleCast is a specialization of ArrayHandleTransform. Given an ArrayHandle and a type, it creates a new handle that returns the elements of the array cast to the specified type.
Public Functions
-
inline ArrayHandleCast(const vtkm::cont::ArrayHandle<typename ArrayHandleType::ValueType, typename ArrayHandleType::StorageTag> &handle)
Construct an
ArrayHandleCastfrom a source array handle.
-
inline ArrayHandleType GetSourceArray() const
Returns the
ArrayHandlethat is being transformed.
-
inline ArrayHandleCast(const vtkm::cont::ArrayHandle<typename ArrayHandleType::ValueType, typename ArrayHandleType::StorageTag> &handle)
1template<typename T>
2VTKM_CONT void Foo(const std::vector<T>& inputData)
3{
4 vtkm::cont::ArrayHandle<T> originalArray =
5 vtkm::cont::make_ArrayHandle(inputData, vtkm::CopyFlag::On);
6
7 vtkm::cont::ArrayHandleCast<vtkm::Float64, vtkm::cont::ArrayHandle<T>> castArray(
8 originalArray);
The vtkm/cont/ArrayHandleCast.h header also contains the templated convenience function vtkm::cont::make_ArrayHandleCast() that constructs the cast array.
The first argument is the original vtkm::cont::ArrayHandle original array to cast.
The optional second argument is of the type to cast to (or you can optionally specify the cast-to type as a template argument.
-
template<typename T, typename ArrayType>
detail::MakeArrayHandleCastImpl<T, typename ArrayType::ValueType, ArrayType>::ReturnType vtkm::cont::make_ArrayHandleCast(const ArrayType &array, const T& = T()) make_ArrayHandleCastis convenience function to generate an ArrayHandleCast.
1 vtkm::cont::make_ArrayHandleCast<vtkm::Float64>(originalArray)
4.9.5. Discard Arrays
It is sometimes the case where you will want to run an operation in VTK‑m that fills values in two (or more) arrays, but you only want the values that are stored in one of the arrays. It is possible to allocate space for both arrays and then throw away the values that you do not want, but that is a waste of memory. It is also possible to rewrite the functionality to output only what you want, but that is a poor use of developer time.
To solve this problem easily, VTK‑m provides vtkm::cont::ArrayHandleDiscard.
This array behaves similar to a regular vtkm::cont::ArrayHandle in that it can be “allocated” and has size, but any values that are written to it are immediately discarded.
vtkm::cont::ArrayHandleDiscard takes up no memory.
-
template<typename ValueType_>
class ArrayHandleDiscard : public vtkm::cont::ArrayHandle<ValueType, StorageTag> ArrayHandleDiscard is a write-only array that discards all data written to it.
This can be used to save memory when a filter provides optional outputs that are not needed.
1template<typename InputArrayType, typename OutputArrayType1, typename OutputArrayType2>
2VTKM_CONT void DoFoo(InputArrayType input,
3 OutputArrayType1 output1,
4 OutputArrayType2 output2);
5
6template<typename InputArrayType>
7VTKM_CONT inline vtkm::cont::ArrayHandle<vtkm::FloatDefault> DoBar(InputArrayType input)
8{
9 VTKM_IS_ARRAY_HANDLE(InputArrayType);
10
11 vtkm::cont::ArrayHandle<vtkm::FloatDefault> keepOutput;
12
13 vtkm::cont::ArrayHandleDiscard<vtkm::FloatDefault> discardOutput;
14
15 DoFoo(input, keepOutput, discardOutput);
16
17 return keepOutput;
18}
4.9.6. Permuted Arrays
A permutation array is a fancy array handle that reorders the elements in an array. Elements in the array can be skipped over or replicated. The permutation array provides this reordered array without actually coping any data. Instead, indices are adjusted as the array is accessed.
Specifying a permutation array in VTK‑m is straightforward.
VTK‑m has a class named vtkm::cont::ArrayHandlePermutation that takes two arrays: an array of values and an array of indices that maps an index in the permutation to an index of the original values.
The index array is specified first.
The following example is a simple demonstration of the permutation array handle.
-
template<typename IndexArrayHandleType, typename ValueArrayHandleType>
class ArrayHandlePermutation : public vtkm::cont::ArrayHandle<ValueArrayHandleType::ValueType, vtkm::cont::StorageTagPermutation<IndexArrayHandleType::StorageTag, ValueArrayHandleType::StorageTag>> Implicitly permutes the values in an array.
ArrayHandlePermutation is a specialization of ArrayHandle. It takes two delegate array handles: an array of indices and an array of values. The array handle created contains the values given permuted by the indices given. So for a given index i, ArrayHandlePermutation looks up the i-th value in the index array to get permuted index j and then gets the j-th value in the value array. This index permutation is done on the fly rather than creating a copy of the array.
An ArrayHandlePermutation can be used for either input or output. However, if used for output the array must be pre-allocated. That is, the indices must already be established and the values must have an allocation large enough to accommodate the indices. An output ArrayHandlePermutation will only have values changed. The indices are never changed.
When using ArrayHandlePermutation great care should be taken to make sure that every index in the index array points to a valid position in the value array. Otherwise, access validations will occur. Also, be wary of duplicate indices that point to the same location in the value array. For input arrays, this is fine. However, this could result in unexpected results for using as output and is almost certainly wrong for using as in-place.
Public Functions
-
inline ArrayHandlePermutation(const IndexArrayHandleType &indexArray, const ValueArrayHandleType &valueArray)
Construct a permuation array with index and value arrays.
-
inline IndexArrayHandleType GetIndexArray() const
Return the array used for indices.
The index array provides how indices get permuted. When a value is retrieved from an
ArrayHandlePermutation, an index is retrived from this index array, and this new index is used to retrieve a value from the value array.
-
inline ValueArrayHandleType GetValueArray() const
Return the array used for values.
The index array provides how indices get permuted. When a value is retrieved from an
ArrayHandlePermutation, an index is retrived from this index array, and this new index is used to retrieve a value from the value array.
-
inline ArrayHandlePermutation(const IndexArrayHandleType &indexArray, const ValueArrayHandleType &valueArray)
1 using IdArrayType = vtkm::cont::ArrayHandle<vtkm::Id>;
2 using IdPortalType = IdArrayType::WritePortalType;
3
4 using ValueArrayType = vtkm::cont::ArrayHandle<vtkm::Float64>;
5 using ValuePortalType = ValueArrayType::WritePortalType;
6
7 // Create array with values [0.0, 0.1, 0.2, 0.3]
8 ValueArrayType valueArray;
9 valueArray.Allocate(4);
10 ValuePortalType valuePortal = valueArray.WritePortal();
11 valuePortal.Set(0, 0.0);
12 valuePortal.Set(1, 0.1);
13 valuePortal.Set(2, 0.2);
14 valuePortal.Set(3, 0.3);
15
16 // Use ArrayHandlePermutation to make an array = [0.3, 0.0, 0.1].
17 IdArrayType idArray1;
18 idArray1.Allocate(3);
19 IdPortalType idPortal1 = idArray1.WritePortal();
20 idPortal1.Set(0, 3);
21 idPortal1.Set(1, 0);
22 idPortal1.Set(2, 1);
23 vtkm::cont::ArrayHandlePermutation<IdArrayType, ValueArrayType> permutedArray1(
24 idArray1, valueArray);
25
26 // Use ArrayHandlePermutation to make an array = [0.1, 0.2, 0.2, 0.3, 0.0]
27 IdArrayType idArray2;
28 idArray2.Allocate(5);
29 IdPortalType idPortal2 = idArray2.WritePortal();
30 idPortal2.Set(0, 1);
31 idPortal2.Set(1, 2);
32 idPortal2.Set(2, 2);
33 idPortal2.Set(3, 3);
34 idPortal2.Set(4, 0);
35 vtkm::cont::ArrayHandlePermutation<IdArrayType, ValueArrayType> permutedArray2(
36 idArray2, valueArray);
The vtkm/cont/ArrayHandlePermutation.h header also contains the templated convenience function vtkm::cont::make_ArrayHandlePermutation() that takes instances of the index and value array handles and returns a permutation array.
This function can sometimes be used to avoid having to declare the full array type.
-
template<typename IndexArrayHandleType, typename ValueArrayHandleType>
vtkm::cont::ArrayHandlePermutation<IndexArrayHandleType, ValueArrayHandleType> vtkm::cont::make_ArrayHandlePermutation(IndexArrayHandleType indexArray, ValueArrayHandleType valueArray) make_ArrayHandleTransform is convenience function to generate an ArrayHandleTransform.
It takes in an ArrayHandle and a functor to apply to each element of the Handle.
1 vtkm::cont::make_ArrayHandlePermutation(idArray, valueArray)
Common Errors
When using an vtkm::cont::ArrayHandlePermutation, take care that all the provided indices in the index array point to valid locations in the values array.
Bad indices can cause reading from or writing to invalid memory locations, which can be difficult to debug.
Also, be wary about having duplicate indices, which means that multiple array entries point to the same memory location.
This will work fine when using the array as input, but will cause a dangerous race condition if used as an output.
Did You Know?
You can write to a vtkm::cont::ArrayHandlePermutation by, for example, using it as an output array.
Writes to the vtkm::cont::ArrayHandlePermutation will go to the respective location in the source array.
However, vtkm::cont::ArrayHandlePermutation cannot be resized.
4.9.7. Zipped Arrays
A zip array is a fancy array handle that combines two arrays of the same size to pair up the corresponding values.
Each element in the zipped array is a vtkm::Pair containing the values of the two respective arrays.
These pairs are not stored in their own memory space.
Rather, the pairs are generated as the array is used.
Writing a pair to the zipped array writes the values in the two source arrays.
Specifying a zipped array in VTK‑m is straightforward.
VTK‑m has a class named vtkm::cont::ArrayHandleZip that takes the two arrays providing values for the first and second entries in the pairs.
The following example is a simple demonstration of creating a zip array handle.
-
template<typename FirstHandleType, typename SecondHandleType>
class ArrayHandleZip : public vtkm::cont::ArrayHandle<ValueType, Tag> ArrayHandleZip is a specialization of ArrayHandle.
It takes two delegate array handle and makes a new handle that access the corresponding entries in these arrays as a pair.
Public Functions
-
inline ArrayHandleZip(const FirstHandleType &firstArray, const SecondHandleType &secondArray)
Create
ArrayHandleZipwith two arrays.
-
inline FirstHandleType GetFirstArray() const
Returns the the array for the first part of the zip pair.
-
inline SecondHandleType GetSecondArray() const
Returns the the array for the second part of the zip pair.
-
inline ArrayHandleZip(const FirstHandleType &firstArray, const SecondHandleType &secondArray)
1 using ArrayType1 = vtkm::cont::ArrayHandle<vtkm::Id>;
2 using PortalType1 = ArrayType1::WritePortalType;
3
4 using ArrayType2 = vtkm::cont::ArrayHandle<vtkm::Float64>;
5 using PortalType2 = ArrayType2::WritePortalType;
6
7 // Create an array of vtkm::Id with values [3, 0, 1]
8 ArrayType1 array1;
9 array1.Allocate(3);
10 PortalType1 portal1 = array1.WritePortal();
11 portal1.Set(0, 3);
12 portal1.Set(1, 0);
13 portal1.Set(2, 1);
14
15 // Create a second array of vtkm::Float32 with values [0.0, 0.1, 0.2]
16 ArrayType2 array2;
17 array2.Allocate(3);
18 PortalType2 portal2 = array2.WritePortal();
19 portal2.Set(0, 0.0);
20 portal2.Set(1, 0.1);
21 portal2.Set(2, 0.2);
22
23 // Zip the two arrays together to create an array of
24 // vtkm::Pair<vtkm::Id, vtkm::Float64> with values [(3,0.0), (0,0.1), (1,0.2)]
25 vtkm::cont::ArrayHandleZip<ArrayType1, ArrayType2> zipArray(array1, array2);
The vtkm/cont/ArrayHandleZip.h header also contains the templated convenience function vtkm::cont::make_ArrayHandleZip() that takes instances of the two array handles and returns a zip array.
This function can sometimes be used to avoid having to declare the full array type.
-
template<typename FirstHandleType, typename SecondHandleType>
vtkm::cont::ArrayHandleZip<FirstHandleType, SecondHandleType> vtkm::cont::make_ArrayHandleZip(const FirstHandleType &first, const SecondHandleType &second) A convenience function for creating an ArrayHandleZip.
It takes the two arrays to be zipped together.
1 vtkm::cont::make_ArrayHandleZip(array1, array2)
4.9.8. Coordinate System Arrays
Many of the data structures we use in VTK‑m are described in a 3D coordinate system.
Although, as we will see in Chapter 2.4 (Data Sets), we can use any vtkm::cont::ArrayHandle to store point coordinates, including a raw array of 3D vectors, there are some common patterns for point coordinates that we can use specialized arrays to better represent the data.
There are two fancy array handles that each handle a special form of coordinate system.
The first such array handle is vtkm::cont::ArrayHandleUniformPointCoordinates, which represents a uniform sampling of space.
The constructor for vtkm::cont::ArrayHandleUniformPointCoordinates takes three arguments.
The first argument is a vtkm::Id3 that specifies the number of samples in the \(x\), \(y\), and \(z\) directions.
The second argument, which is optional, specifies the origin (the location of the first point at the lower left corner).
If not specified, the origin is set to \([0,0,0]\).
The third argument, which is also optional, specifies the distance between samples in the \(x\), \(y\), and \(z\) directions.
If not specified, the spacing is set to 1 in each direction.
-
class ArrayHandleUniformPointCoordinates : public vtkm::cont::ArrayHandle<vtkm::Vec3f, vtkm::cont::StorageTagUniformPoints>
ArrayHandleUniformPointCoordinates is a specialization of ArrayHandle.
It contains the information necessary to compute the point coordinates in a uniform orthogonal grid (extent, origin, and spacing) and implicitly computes these coordinates in its array portal.
Public Functions
-
ArrayHandleUniformPointCoordinates(vtkm::Id3 dimensions, ValueType origin = ValueType(0.0f, 0.0f, 0.0f), ValueType spacing = ValueType(1.0f, 1.0f, 1.0f))
Create an
ArrayHandleUniformPointCoordinateswith the given specifications.
-
ArrayHandleUniformPointCoordinates(vtkm::Id3 dimensions, ValueType origin = ValueType(0.0f, 0.0f, 0.0f), ValueType spacing = ValueType(1.0f, 1.0f, 1.0f))
1 // Create a set of point coordinates for a uniform grid in the space between
2 // -5 and 5 in the x direction and -3 and 3 in the y and z directions. The
3 // uniform sampling is spaced in 0.08 unit increments in the x direction (for
4 // 126 samples), 0.08 unit increments in the y direction (for 76 samples) and
5 // 0.24 unit increments in the z direction (for 26 samples). That makes
6 // 248,976 values in the array total.
7 vtkm::cont::ArrayHandleUniformPointCoordinates uniformCoordinates(
8 vtkm::Id3(126, 76, 26),
9 vtkm::Vec3f{ -5.0f, -3.0f, -3.0f },
10 vtkm::Vec3f{ 0.08f, 0.08f, 0.24f });
The second fancy array handle for special coordinate systems is vtkm::cont::ArrayHandleCartesianProduct, which represents a rectilinear sampling of space where the samples are axis aligned but have variable spacing.
Sets of coordinates of this type are most efficiently represented by having a separate array for each component of the axis, and then for each \([i,j,k]\) index of the array take the value for each component from each array using the respective index.
This is equivalent to performing a Cartesian product on the arrays.
-
template<typename FirstHandleType, typename SecondHandleType, typename ThirdHandleType>
class ArrayHandleCartesianProduct : public vtkm::cont::ArrayHandle<ValueType, Tag> ArrayHandleCartesianProduct is a specialization of ArrayHandle.
It takes two delegate array handle and makes a new handle that access the corresponding entries in these arrays as a pair.
Public Functions
-
inline ArrayHandleCartesianProduct(const FirstHandleType &firstArray, const SecondHandleType &secondArray, const ThirdHandleType &thirdArray)
Construct an
ArrayHandleCartesianProductgiven arrays for the coordinates in the x, y, and z diretions.
-
inline ~ArrayHandleCartesianProduct()
Implemented so that it is defined exclusively in the control environment.
If there is a separate device for the execution environment (for example, with CUDA), then the automatically generated destructor could be created for all devices, and it would not be valid for all devices.
-
inline FirstHandleType GetFirstArray() const
Get the array for the coordinates in the x direction.
-
inline SecondHandleType GetSecondArray() const
Get the array for the coordinates in the y direction.
-
inline ThirdHandleType GetThirdArray() const
Get the array for the coordinates in the z direction.
-
inline ArrayHandleCartesianProduct(const FirstHandleType &firstArray, const SecondHandleType &secondArray, const ThirdHandleType &thirdArray)
vtkm::cont::ArrayHandleCartesianProduct is a templated class.
It has three template parameters, which are the types of the arrays used for the \(x\), \(y\), and \(z\) axes.
The constructor for vtkm::cont::ArrayHandleCartesianProduct takes the three arrays.
1 using AxisArrayType = vtkm::cont::ArrayHandle<vtkm::Float32>;
2 using AxisPortalType = AxisArrayType::WritePortalType;
3
4 // Create array for x axis coordinates with values [0.0, 1.1, 5.0]
5 AxisArrayType xAxisArray;
6 xAxisArray.Allocate(3);
7 AxisPortalType xAxisPortal = xAxisArray.WritePortal();
8 xAxisPortal.Set(0, 0.0f);
9 xAxisPortal.Set(1, 1.1f);
10 xAxisPortal.Set(2, 5.0f);
11
12 // Create array for y axis coordinates with values [0.0, 2.0]
13 AxisArrayType yAxisArray;
14 yAxisArray.Allocate(2);
15 AxisPortalType yAxisPortal = yAxisArray.WritePortal();
16 yAxisPortal.Set(0, 0.0f);
17 yAxisPortal.Set(1, 2.0f);
18
19 // Create array for z axis coordinates with values [0.0, 0.5]
20 AxisArrayType zAxisArray;
21 zAxisArray.Allocate(2);
22 AxisPortalType zAxisPortal = zAxisArray.WritePortal();
23 zAxisPortal.Set(0, 0.0f);
24 zAxisPortal.Set(1, 0.5f);
25
26 // Create point coordinates for a "rectilinear grid" with axis-aligned points
27 // with variable spacing by taking the Cartesian product of the three
28 // previously defined arrays. This generates the following 3x2x2 = 12 values:
29 //
30 // [0.0, 0.0, 0.0], [1.1, 0.0, 0.0], [5.0, 0.0, 0.0],
31 // [0.0, 2.0, 0.0], [1.1, 2.0, 0.0], [5.0, 2.0, 0.0],
32 // [0.0, 0.0, 0.5], [1.1, 0.0, 0.5], [5.0, 0.0, 0.5],
33 // [0.0, 2.0, 0.5], [1.1, 2.0, 0.5], [5.0, 2.0, 0.5]
34 vtkm::cont::ArrayHandleCartesianProduct<AxisArrayType, AxisArrayType, AxisArrayType>
35 rectilinearCoordinates(xAxisArray, yAxisArray, zAxisArray);
The vtkm/cont/ArrayHandleCartesianProduct.h header also contains the templated convenience function vtkm::cont::make_ArrayHandleCartesianProduct() that takes the three axis arrays and returns an array of the Cartesian product.
This function can sometimes be used to avoid having to declare the full array type.
-
template<typename FirstHandleType, typename SecondHandleType, typename ThirdHandleType>
vtkm::cont::ArrayHandleCartesianProduct<FirstHandleType, SecondHandleType, ThirdHandleType> vtkm::cont::make_ArrayHandleCartesianProduct(const FirstHandleType &first, const SecondHandleType &second, const ThirdHandleType &third) A convenience function for creating an ArrayHandleCartesianProduct.
It takes the two arrays to be zipped together.
1 vtkm::cont::make_ArrayHandleCartesianProduct(xAxisArray, yAxisArray, zAxisArray)
Did You Know?
These specialized arrays for coordinate systems greatly reduce the code duplication in VTK‑m. Most scientific visualization systems need separate implementations of algorithms for uniform, rectilinear, and unstructured grids. But in VTK‑m an algorithm can be written once and then applied to all these different grid structures by using these specialized array handles and letting the compiler’s templates optimize the code.
Did You Know?
The special array handles in this section are designed to represent point coordinates in particular, common configurations.
However, the array for a vtkm::cont::CoordinateSystem does not have to be one of these arrays.
For example, it is common to use a vtkm::cont::ArrayHandleBasic to represent points in general position.
4.9.9. Composite Vector Arrays
A composite vector array is a fancy array handle that combines two to four arrays of the same size and value type and combines their corresponding values to form a vtkm::Vec.
A composite vector array is similar in nature to a zipped array (described in Section 4.9.7 (Zipped Arrays)) except that values are combined into vtkm::Vec’s instead of vtkm::Pair’s.
The composite vector array is also similar to a structure of arrays (described in Section 4.8.2 (Structure of Arrays)) except that any type of array handles can be used for the components rather than a basic array handle.
The created vtkm::Vec’s are not stored in their own memory space.
Rather, the vtkm::Vec’s are generated as the array is used.
Writing vtkm::Vec’s to the composite vector array writes values into the components of the source arrays.
A composite vector array can be created using the vtkm::cont::ArrayHandleCompositeVector class.
This class has a variadic template argument that is a “signature” for the arrays to be combined.
The constructor for vtkm::cont::ArrayHandleCompositeVector takes instances of the array handles to combine.
-
template<typename ...ArrayTs>
class ArrayHandleCompositeVector : public vtkm::cont::ArrayHandle<internal::CompositeVectorTraits<ArrayTs...>::ValueType, internal::CompositeVectorTraits<ArrayTs...>::StorageTag> An
ArrayHandlethat combines components from other arrays.ArrayHandleCompositeVectoris a specialization ofArrayHandlethat derives its content from other arrays. It takes any number of single-componentArrayHandleobjects and mimics an array that contains vectors with components that come from these delegate arrays.The easiest way to create and type an
ArrayHandleCompositeVectoris to use themake_ArrayHandleCompositeVectorfunctions.The
ArrayHandleExtractComponentclass may be helpful when a desired component is part of anArrayHandlewith avtkm::VecValueType.If you are attempted to combine components that you know are stored in basic
ArrayHandles, consider usingArrayHandleSOAinstead.Public Functions
-
inline ArrayHandleCompositeVector(const ArrayTs&... arrays)
Construct an
ArrayHandleCompositeVectorfrom a set of component vectors.
-
inline vtkm::Tuple<ArrayTs...> GetArrayTuple() const
Return the arrays of all of the components in a
vtkm::Tupleobject.
-
inline ArrayHandleCompositeVector(const ArrayTs&... arrays)
1 // Create an array with [0, 1, 2, 3, 4]
2 using ArrayType1 = vtkm::cont::ArrayHandleIndex;
3 ArrayType1 array1(5);
4
5 // Create an array with [3, 1, 4, 1, 5]
6 using ArrayType2 = vtkm::cont::ArrayHandle<vtkm::Id>;
7 ArrayType2 array2;
8 array2.Allocate(5);
9 ArrayType2::WritePortalType arrayPortal2 = array2.WritePortal();
10 arrayPortal2.Set(0, 3);
11 arrayPortal2.Set(1, 1);
12 arrayPortal2.Set(2, 4);
13 arrayPortal2.Set(3, 1);
14 arrayPortal2.Set(4, 5);
15
16 // Create an array with [2, 7, 1, 8, 2]
17 using ArrayType3 = vtkm::cont::ArrayHandle<vtkm::Id>;
18 ArrayType3 array3;
19 array3.Allocate(5);
20 ArrayType2::WritePortalType arrayPortal3 = array3.WritePortal();
21 arrayPortal3.Set(0, 2);
22 arrayPortal3.Set(1, 7);
23 arrayPortal3.Set(2, 1);
24 arrayPortal3.Set(3, 8);
25 arrayPortal3.Set(4, 2);
26
27 // Create an array with [0, 0, 0, 0]
28 using ArrayType4 = vtkm::cont::ArrayHandleConstant<vtkm::Id>;
29 ArrayType4 array4(0, 5);
30
31 // Use ArrayhandleCompositeVector to create the array
32 // [(0,3,2,0), (1,1,7,0), (2,4,1,0), (3,1,8,0), (4,5,2,0)].
33 using CompositeArrayType = vtkm::cont::
34 ArrayHandleCompositeVector<ArrayType1, ArrayType2, ArrayType3, ArrayType4>;
35 CompositeArrayType compositeArray(array1, array2, array3, array4);
The vtkm/cont/ArrayHandleCompositeVector.h header also contains the templated convenience function vtkm::cont::make_ArrayHandleCompositeVector() which takes a variable number of array handles and returns an vtkm::cont::ArrayHandleCompositeVector.
This function can sometimes be used to avoid having to declare the full array type.
-
template<typename ...ArrayTs>
ArrayHandleCompositeVector<ArrayTs...> vtkm::cont::make_ArrayHandleCompositeVector(const ArrayTs&... arrays) Create a composite vector array from other arrays.
1 vtkm::cont::make_ArrayHandleCompositeVector(array1, array2, array3, array4)
4.9.10. Extract Component Arrays
Component extraction allows access to a single component of an vtkm::cont::ArrayHandle with a vtkm::Vec as the vtkm::cont::ArrayHandle::ValueType.
vtkm::cont::ArrayHandleExtractComponent allows one component of a vector array to be extracted without creating a copy of the data.
vtkm::cont::ArrayHandleExtractComponent can also be combined with vtkm::cont::ArrayHandleCompositeVector (described in Section 4.9.9 (Composite Vector Arrays)) to arbitrarily stitch several components from multiple arrays together.
-
template<typename ArrayHandleType>
class ArrayHandleExtractComponent : public vtkm::cont::ArrayHandle<vtkm::VecTraits<ArrayHandleType::ValueType>::ComponentType, StorageTagExtractComponent<ArrayHandleType>> A fancy
ArrayHandlethat turns a vector array into a scalar array by slicing out a single component of each vector.ArrayHandleExtractComponentis a specialization ofArrayHandle. It takes an inputArrayHandlewith avtkm::VecValueTypeand a component index and uses this information to expose a scalar array consisting of the specified component across all vectors in the inputArrayHandle. So for a given index i,ArrayHandleExtractComponentlooks up the i-thvtkm::Vecin the index array and reads or writes to the specified component, leave all other components unmodified. This is done on the fly rather than creating a copy of the array.Public Functions
-
inline ArrayHandleExtractComponent(const ArrayHandleType &array, vtkm::IdComponent component)
Construct an
ArrayHandleExtractComponentwith a given array and component.
-
inline vtkm::IdComponent GetComponent() const
Get the component index being extracted from the source array.
-
inline ArrayHandleType GetArray() const
Get the source array of
Vecs to get a component out of.
-
inline ArrayHandleExtractComponent(const ArrayHandleType &array, vtkm::IdComponent component)
As a simple example, consider an vtkm::cont::ArrayHandle containing 3D coordinates for a collection of points and a filter that only operates on the points’ elevations (Z, in this example).
We can easily create the elevation array on-the-fly without allocating a new array as in the following example.
vtkm::Vec’s in an array with vtkm::cont::ArrayHandleExtractComponent. 1 using ValueArrayType = vtkm::cont::ArrayHandle<vtkm::Vec3f_64>;
2
3 // Create array with values [ (0.0, 0.1, 0.2), (1.0, 1.1, 1.2), (2.0, 2.1, 2.2) ]
4 ValueArrayType valueArray;
5 valueArray.Allocate(3);
6 auto valuePortal = valueArray.WritePortal();
7 valuePortal.Set(0, vtkm::make_Vec(0.0, 0.1, 0.2));
8 valuePortal.Set(1, vtkm::make_Vec(1.0, 1.1, 1.2));
9 valuePortal.Set(2, vtkm::make_Vec(2.0, 2.1, 2.2));
10
11 // Use ArrayHandleExtractComponent to make an array = [1.3, 2.3, 3.3].
12 vtkm::cont::ArrayHandleExtractComponent<ValueArrayType> extractedComponentArray(
13 valueArray, 2);
The vtkm/cont/ArrayHandleExtractComponent.h header also contains the templated convenience function vtkm::cont::make_ArrayHandleExtractComponent() that takes an vtkm::cont::ArrayHandle of vtkm::Vec’s and vtkm::IdComponent which returns an appropriately typed vtkm::cont::ArrayHandleExtractComponent containing the values for a specified component.
The index of the component to extract is provided as an argument to vtkm::cont::make_ArrayHandleExtractComponent(), which is required.
The use of vtkm::cont::make_ArrayHandleExtractComponent() can be used to avoid having to declare the full array type.
-
template<typename ArrayHandleType>
ArrayHandleExtractComponent<ArrayHandleType> vtkm::cont::make_ArrayHandleExtractComponent(const ArrayHandleType &array, vtkm::IdComponent component) make_ArrayHandleExtractComponentis convenience function to generate anArrayHandleExtractComponent.
1 vtkm::cont::make_ArrayHandleExtractComponent(valueArray, 2)
Did You Know?
An alternate way to extract a component from a vtkm::cont::ArrayHandle is to use the vtkm::cont::ArrayExtractComponent() function.
Rather than wrap a vtkm::cont::ArrayHandleExtractComponent around the target array, it converts the array into a vtkm::cont::ArrayHandleStride, as described in Section 4.8.3 (Strided Arrays).
This can be advantageous when trying to unify the storage type of different array types, but can work poorly for some array types.
4.9.11. Swizzle Arrays
It is often useful to reorder or remove specific components from an vtkm::cont::ArrayHandle with a vtkm::Vec vtkm::cont::ArrayHandle::ValueType.
vtkm::cont::ArrayHandleSwizzle provides an easy way to accomplish this.
The constructor of vtkm::cont::ArrayHandleSwizzle specifies a “component map,” which defines the swizzle operation.
This map consists of the components from the input vtkm::cont::ArrayHandle, which will be exposed in the vtkm::cont::ArrayHandleSwizzle.
For instance, constructing vtkm::cont::ArrayHandleSwizzle<Some3DArrayType, 3> with vtkm::IdComponent3(0, 2, 1) as the second constructor argument will allow access to a 3D array, but with the Y and Z components exchanged.
This rearrangement does not create a copy, and occurs on-the-fly as data are accessed through the vtkm::cont::ArrayHandleSwizzle’s portal.
This fancy array handle can also be used to eliminate unnecessary components from an vtkm::cont::ArrayHandle’s data, as shown below.
-
template<typename ArrayHandleType, vtkm::IdComponent OutSize>
class ArrayHandleSwizzle : public vtkm::cont::ArrayHandleTransform<ArrayHandleType, SwizzleFunctor, InverseSwizzleFunctor> Swizzle the components of the values in an
ArrayHandle.Given an
ArrayHandlewithVecvalues,ArrayHandleSwizzleallows you to reorder the components of all theVecvalues. This reordering is done in place, so the array does not have to be duplicated.The resulting array does not have to contain all of the components of the input. For example, you could use
ArrayHandleSwizzleto drop one of the components of each vector. However, if you do that, then the swizzled array is read-only. If there is a 1:1 map from input components to output components, writing to the array will be enabled.The swizzle map given to
ArrayHandleSwizzlemust comprise valid component indices (between 0 and number of components - 1). Also, the component indices should not be repeated, particularly if you expect to write to the array. These conditions are not checked.Public Functions
-
inline ArrayHandleSwizzle(const ArrayHandleType &array, const MapType &map)
Construct an
ArrayHandleSwizzlewith a source array and a swizzle map.The swizzle map is a
vtkm::Veccontainingvtkm::IdComponentcomponents and sized to the number of components in the array. Each value in the map specifies from which component of the input the corresponding component of the output should come from.
-
inline ArrayHandleSwizzle(const ArrayHandleType &array, const MapType &map)
1 using ValueArrayType = vtkm::cont::ArrayHandle<vtkm::Vec4f_64>;
2
3 // Create array with values
4 // [ (0.0, 0.1, 0.2, 0.3), (1.0, 1.1, 1.2, 1.3), (2.0, 2.1, 2.2, 2.3) ]
5 ValueArrayType valueArray;
6 valueArray.Allocate(3);
7 auto valuePortal = valueArray.WritePortal();
8 valuePortal.Set(0, vtkm::make_Vec(0.0, 0.1, 0.2, 0.3));
9 valuePortal.Set(1, vtkm::make_Vec(1.0, 1.1, 1.2, 1.3));
10 valuePortal.Set(2, vtkm::make_Vec(2.0, 2.1, 2.2, 2.3));
11
12 // Use ArrayHandleSwizzle to make an array of Vec-3 with x,y,z,w swizzled to z,x,w
13 // [ (0.2, 0.0, 0.3), (1.2, 1.0, 1.3), (2.2, 2.0, 2.3) ]
14 vtkm::cont::ArrayHandleSwizzle<ValueArrayType, 3> swizzledArray(
15 valueArray, vtkm::IdComponent3(2, 0, 3));
The vtkm/cont/ArrayHandleSwizzle.h header also contains the templated convenience function vtkm::cont::make_ArrayHandleSwizzle() that takes an vtkm::cont::ArrayHandle of vtkm::Vec’s and returns an appropriately typed vtkm::cont::ArrayHandleSwizzle containing swizzled vectors.
The use of vtkm::cont::make_ArrayHandleSwizzle() can be used to avoid having to declare the full array type.
-
template<typename ArrayHandleType, vtkm::IdComponent OutSize>
ArrayHandleSwizzle<ArrayHandleType, OutSize> vtkm::cont::make_ArrayHandleSwizzle(const ArrayHandleType &array, const vtkm::Vec<vtkm::IdComponent, OutSize> &map) Construct an
ArrayHandleSwizzlefrom a provided array and swizzle map.The swizzle map is a
vtkm::Veccontainingvtkm::IdComponentcomponents and sized to the number of components in the array. Each value in the map specifies from which component of the input the corresponding component of the output should come from.
-
template<typename ArrayHandleType, typename ...SwizzleIndexTypes>
auto vtkm::cont::make_ArrayHandleSwizzle(const ArrayHandleType &array, vtkm::IdComponent swizzleIndex0, SwizzleIndexTypes... swizzleIndices) Construct an
ArrayHandleSwizzlefrom a provided array and swizzle map.The swizzle map is specified as independent function parameters after the array. Each value in the map specifies from which component of the input the corresponding component of the output should come from.
1 vtkm::cont::make_ArrayHandleSwizzle(valueArray, 2, 0, 3)
4.9.12. Grouped Vector Arrays
A grouped vector array is a fancy array handle that groups consecutive values of an array together to form a vtkm::Vec.
The source array must be of a length that is divisible by the requested vtkm::Vec size.
The created vtkm::Vec’s are not stored in their own memory space.
Rather, the vtkm::Vec’s are generated as the array is used.
Writing vtkm::Vec’s to the grouped vector array writes values into the the source array.
A grouped vector array is created using the vtkm::cont::ArrayHandleGroupVec class.
This templated class has two template arguments.
The first argument is the type of array being grouped and the second argument is an integer specifying the size of the vtkm::Vec’s to create (the number of values to group together).
-
template<typename ComponentsArrayHandleType, vtkm::IdComponent NUM_COMPONENTS>
class ArrayHandleGroupVec : public vtkm::cont::ArrayHandle<vtkm::Vec<ComponentsArrayHandleType::ValueType, NUM_COMPONENTS>, vtkm::cont::StorageTagGroupVec<ComponentsArrayHandleType::StorageTag, NUM_COMPONENTS>> Fancy array handle that groups values into vectors.
It is sometimes the case that an array is stored such that consecutive entries are meant to form a group. This fancy array handle takes an array of values and a size of groups and then groups the consecutive values stored in a
vtkm::Vec.For example, if you have an array handle with the six values 0,1,2,3,4,5 and give it to a
ArrayHandleGroupVecwith the number of components set to 3, you get an array that looks like it contains two values ofvtkm::Vecof size 3 with the data [0,1,2], [3,4,5].The array of components should have a number of values that divides evenly with the size of the
vtkm::Vec. If the components array does not divide evenly intovtkm::Vecs, then a warning will be logged and the extra component values will be ignored.Public Functions
-
inline ArrayHandleGroupVec(const ComponentsArrayHandleType &componentsArray)
Construct an
ArrayHandleGroupVecwith a provided components array.
-
inline ComponentsArrayHandleType GetComponentsArray() const
Retrieve the components array being grouped.
-
inline ArrayHandleGroupVec(const ComponentsArrayHandleType &componentsArray)
1 // Create an array containing [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
2 using ArrayType = vtkm::cont::ArrayHandleIndex;
3 ArrayType sourceArray(12);
4
5 // Create an array containing [(0,1), (2,3), (4,5), (6,7), (8,9), (10,11)]
6 vtkm::cont::ArrayHandleGroupVec<ArrayType, 2> vec2Array(sourceArray);
7
8 // Create an array containing [(0,1,2), (3,4,5), (6,7,8), (9,10,11)]
9 vtkm::cont::ArrayHandleGroupVec<ArrayType, 3> vec3Array(sourceArray);
The vtkm/cont/ArrayHandleGroupVec.h header also contains the templated convenience function vtkm::cont::make_ArrayHandleGroupVec() that takes an instance of the array to group into vtkm::Vec’s.
You must specify the size of the vtkm::Vec’s as a template parameter when using vtkm::cont::make_ArrayHandleGroupVec().
-
template<vtkm::IdComponent NUM_COMPONENTS, typename ArrayHandleType>
vtkm::cont::ArrayHandleGroupVec<ArrayHandleType, NUM_COMPONENTS> vtkm::cont::make_ArrayHandleGroupVec(const ArrayHandleType &array) make_ArrayHandleGroupVecis convenience function to generate an ArrayHandleGroupVec.It takes in an ArrayHandle and the number of components (as a specified template parameter), and returns an array handle with consecutive entries grouped in a Vec.
1 // Create an array containing [(0,1,2,3), (4,5,6,7), (8,9,10,11)]
2 vtkm::cont::make_ArrayHandleGroupVec<4>(sourceArray)
Did You Know?
vtkm::cont::ArrayHandleGroupVec requires you to specify the number of components at compile time.
For a similar functionality, consider using vtkm::cont::ArrayHandleRuntimeVec, described in Section 4.8.4 (Runtime Vec Arrays).
This allows the runtime selection of vtkm::Vec sizes and can be applied to existing basic arrays, but is limited in other ways.
vtkm::cont::ArrayHandleGroupVec is handy when you need to build an array of vectors that are all of the same length, but what about when you need an array of vectors of different lengths?
One common use case for this is if you are defining a collection of polygons of different sizes (triangles, quadrilaterals, pentagons, and so on).
We would like to define an array such that the data for each polygon were stored in its own vtkm::Vec (or, rather, Vec-like) object.
vtkm::cont::ArrayHandleGroupVecVariable does just that.
vtkm::cont::ArrayHandleGroupVecVariable takes two arrays. The first array, identified as the “source” array, is a flat representation of the values (much like the array used with vtkm::cont::ArrayHandleGroupVec).
The second array, identified as the “offsets” array, provides for each vector the index into the source array where the start of the vector is.
The offsets array must be monotonically increasing.
The size of the offsets array is one greater than the number of vectors in the resulting array.
The first offset is always 0 and the last offset is always the size of the input source array.
The first and second template parameters to vtkm::cont::ArrayHandleGroupVecVariable are the types for the source and offset arrays, respectively.
-
template<typename ComponentsArrayHandleType, typename OffsetsArrayHandleType>
class ArrayHandleGroupVecVariable : public vtkm::cont::ArrayHandle<vtkm::VecFromPortal<ComponentsArrayHandleType::WritePortalType>, vtkm::cont::StorageTagGroupVecVariable<ComponentsArrayHandleType::StorageTag, OffsetsArrayHandleType::StorageTag>> Fancy array handle that groups values into vectors of different sizes.
It is sometimes the case that you need to run a worklet with an input or output that has a different number of values per instance. For example, the cells of a
vtkm::cont::CellCetExplicitcan have different numbers of points in each cell. If inputting or outputting cells of this type, each instance of the worklet might need avtkm::Vecof a different length. This fancy array handle takes an array of values and an array of offsets and groups the consecutive values in Vec-like objects. The values are treated as tightly packed, so that each Vec contains the values from one offset to the next. The last value contains values from the last offset to the end of the array.For example, if you have an array handle with the 9 values 0,1,2,3,4,5,6,7,8 an offsets array handle with the 4 values 0,4,6,9 and give them to an
ArrayHandleGroupVecVariable, you get an array that looks like it contains three values of Vec-like objects with the data [0,1,2,3], [4,5], and [6,7,8].Note that caution should be used with
ArrayHandleRuntimeVecbecause the size of thevtkm::Vecvalues is not known at compile time. Thus, the value type of this array is forced to a specialvtkm::VecFromPortalclass that can cause surprises if treated as avtkm::Vec. In particular, the staticNUM_COMPONENTSexpression does not exist. Furthermore, new variables of typevtkm::VecFromPortalcannot be created. This means that simple operators like+will not work because they require an intermediate object to be created. (Equal operators like+=do work because they are given an existing variable to place the output.)The offsets array is often derived from a list of sizes for each of the entries. You can use the convenience function
vtkm::cont::ConvertNumComponentsToOffsetsto take an array of sizes (i.e. the number of components for each entry) and get an array of offsets needed forArrayHandleGroupVecVariable.Public Functions
-
inline ArrayHandleGroupVecVariable(const ComponentsArrayHandleType &componentsArray, const OffsetsArrayHandleType &offsetsArray)
Construct an
ArrayHandleGroupVecVariable
-
inline ComponentsArrayHandleType GetComponentsArray() const
Return the components array providing the data for the grouped vec array.
-
inline OffsetsArrayHandleType GetOffsetsArray() const
Return the offsets array defining the locations and sizes of each value.
-
inline ArrayHandleGroupVecVariable(const ComponentsArrayHandleType &componentsArray, const OffsetsArrayHandleType &offsetsArray)
It is often the case that you will start with a group of vector lengths rather than offsets into the source array.
If this is the case, then the vtkm::cont::ConvertNumComponentsToOffsets() helper function can convert an array of vector lengths to an array of offsets.
The first argument to this function is always the array of vector lengths.
The second argument, which is optional, is a reference to a vtkm::cont::ArrayHandle into which the offsets should be stored.
If this offset array is not specified, an vtkm::cont::ArrayHandle will be returned from the function instead.
The third argument, which is also optional, is a reference to a vtkm::Id into which the expected size of the source array is put.
Having the size of the source array is often helpful, as it can be used to allocate data for the source array or check the source array’s size.
It is also OK to give the expected size reference but not the offset array reference.
-
void vtkm::cont::ConvertNumComponentsToOffsets(const vtkm::cont::UnknownArrayHandle &numComponentsArray, vtkm::cont::ArrayHandle<vtkm::Id> &offsetsArray, vtkm::Id &componentsArraySize, vtkm::cont::DeviceAdapterId device = vtkm::cont::DeviceAdapterTagAny{})
ConvertNumComponentsToOffsetstakes an array of Vec sizes (i.e.the number of components in each
Vec) and returns an array of offsets to a packed array of suchVecs. The resulting array can be used withArrayHandleGroupVecVariable.Note that this function is pre-compiled for some set of
ArrayHandletypes. If you get a warning about an inefficient conversion (or the operation fails outright), you might need to usevtkm::cont::internal::ConvertNumComponentsToOffsetsTemplate.- Parameters:
numComponentsArray – [in] the input array that specifies the number of components in each group Vec.
offsetsArray – [out] (optional) the output
ArrayHandle, which must have a value type ofvtkm::Id. If the outputArrayHandleis not given, it is returned.componentsArraySize – [in] (optional) a reference to a
vtkm::Idand is filled with the expected size of the component values array.device – [in] (optional) specifies the device on which to run the conversion.
1 // Create an array of counts containing [4, 2, 3, 3]
2 vtkm::cont::ArrayHandle<vtkm::IdComponent> countArray =
3 vtkm::cont::make_ArrayHandle<vtkm::IdComponent>({ 4, 2, 3, 3 });
4
5 // Convert the count array to an offset array [0, 4, 6, 9, 12]
6 // Returns the number of total components: 12
7 vtkm::Id sourceArraySize;
8 using OffsetArrayType = vtkm::cont::ArrayHandle<vtkm::Id>;
9 OffsetArrayType offsetArray =
10 vtkm::cont::ConvertNumComponentsToOffsets(countArray, sourceArraySize);
11
12 // Create an array containing [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
13 using SourceArrayType = vtkm::cont::ArrayHandleIndex;
14 SourceArrayType sourceArray(sourceArraySize);
15
16 // Create an array containing [(0,1,2,3), (4,5), (6,7,8), (9,10,11)]
17 vtkm::cont::ArrayHandleGroupVecVariable<SourceArrayType, OffsetArrayType>
18 vecVariableArray(sourceArray, offsetArray);
The vtkm/cont/ArrayHandleGroupVecVariable.h header also contains the templated convenience function vtkm::cont::make_ArrayHandleGroupVecVariable() that takes an instance of the source array to group into Vec-like objects and the offset array.
-
template<typename ComponentsArrayHandleType, typename OffsetsArrayHandleType>
vtkm::cont::ArrayHandleGroupVecVariable<ComponentsArrayHandleType, OffsetsArrayHandleType> vtkm::cont::make_ArrayHandleGroupVecVariable(const ComponentsArrayHandleType &componentsArray, const OffsetsArrayHandleType &offsetsArray) make_ArrayHandleGroupVecVariableis convenience function to generate an ArrayHandleGroupVecVariable.It takes in an ArrayHandle of values and an array handle of offsets and returns an array handle with consecutive entries grouped in a Vec.
1 // Create an array containing [(0,1,2,3), (4,5), (6,7,8), (9,10,11)]
2 vtkm::cont::make_ArrayHandleGroupVecVariable(sourceArray, offsetArray)
Did You Know?
You can write to vtkm::cont::ArrayHandleGroupVec and vtkm::cont::ArrayHandleGroupVecVariable by, for example, using it as an output array.
Writes to these arrays will go to the respective location in the source array.
vtkm::cont::ArrayHandleGroupVec can also be allocated and resized (which in turn causes the source array to be allocated).
However, vtkm::cont::ArrayHandleGroupVecVariable cannot be resized and the source array must be pre-allocated.
You can use the source array size value returned from vtkm::cont::ConvertNumComponentsToOffsets() to allocate source arrays.
Common Errors
Keep in mind that the values stored in a vtkm::cont::ArrayHandleGroupVecVariable are not actually vtkm::Vec objects.
Rather, they are “Vec-like” objects, which has some subtle but important ramifications.
First, the type will not match the vtkm::Vec template, and there is no automatic conversion to vtkm::Vec objects.
Thus, many functions that accept vtkm::Vec objects as parameters will not accept the Vec-like object.
Second, the size of Vec-like objects are not known until runtime.
See Section 2.1.3 (Vector Types) and Section 4.1.6.2 (Vector Traits) for more information on the difference between vtkm::Vec and Vec-like objects.
4.9.13. Random Arrays
The basis of generating random numbers in VTK‑m is built on the vtkm::cont::ArrayHandleRandomUniformBits.
An uniform random bits array is a fancy array handle that generates pseudo random bits as vtkm::Unit64 in its entries.
The uniform random bits array provides this array without actually using any memory.
-
class ArrayHandleRandomUniformBits : public vtkm::cont::ArrayHandleImplicit<detail::PhiloxFunctor>
An
ArrayHandlethat provides a source of random bits.ArrayHandleRandomUniformBitsis a specialization ofArrayHandleImplicit. It takes a user supplied seed and hash it with the a given index value. The hashed value is the value of the array at that position.Currently, Philox2x32x10 as described in the “Parallel Random Numbers: As Easy as 1, 2, 3,” Proceedings of the International Conference for High Performance Computing, Networking, Storage and Analysis (SC11) is used as the hash function.
Note: In contrast to traditional random number generator,
ArrayHandleRandomUniformBitsdoes not have “state”, i.e. multiple calls the Get() method with the same index will always return the same hash value. To get a new set of random bits, create a newArrayHandleRandomUniformBitswith a different seed.Public Functions
-
inline explicit ArrayHandleRandomUniformBits(vtkm::Id length, SeedType seed = {std::random_device{}()})
Construct an
ArrayHandleRandomUniformBits.- Parameters:
length – Specifies the length of the generated array.
seed – Provides a seed to use for the pseudorandom numbers. To prevent confusion between the seed and the length, the type of the seed is a
vtkm::Vecof size 1. To specify the seed, declare it in braces. For example, to construct a random array of size 50 with seed 123, useArrayHandleRandomUniformBits(50, { 123 }).
-
inline explicit ArrayHandleRandomUniformBits(vtkm::Id length, SeedType seed = {std::random_device{}()})
The constructor for vtkm::cont::ArrayHandleRandomUniformBits takes two arguments: the first argument is the length of the array handle, the second is a seed of type vtkm::Vec<Uint32, 1>.
If the seed is not specified, the C++11 std::random_device is used as default.
1 // Create an array containing a sequence of random bits seeded
2 // by std::random_device.
3 vtkm::cont::ArrayHandleRandomUniformBits randomArray(50);
4 // Create an array containing a sequence of random bits with
5 // a user supplied seed.
6 vtkm::cont::ArrayHandleRandomUniformBits randomArraySeeded(50, { 123 });
vtkm::cont::ArrayHandleRandomUniformBits is functional, in the sense that once an instance of vtkm::cont::ArrayHandleRandomUniformBits is created, its content does not change and always returns the same vtkm::UInt64 value given the same index.
1 // ArrayHandleRandomUniformBits is functional, it returns
2 // the same value for the same entry is accessed.
3 auto r0 = randomArray.ReadPortal().Get(5);
4 auto r1 = randomArray.ReadPortal().Get(5);
5 assert(r0 == r1);
To generate a new set of random bits, we need to create another instance of vtkm::cont::ArrayHandleRandomUniformBits with a different seed, we can either let std::random_device provide a unique seed or use some unique identifier such as iteration number as the seed.
1 // Create a new insance of ArrayHandleRandomUniformBits
2 // for each set of random bits.
3 vtkm::cont::ArrayHandleRandomUniformBits randomArray0(50, { 0 });
4 vtkm::cont::ArrayHandleRandomUniformBits randomArray1(50, { 1 });
5 assert(randomArray0.ReadPortal().Get(5) != randomArray1.ReadPortal().Get(5));
The random bits provided by vtkm::cont::ArrayHandleRandomUniformBits can be manipulated to provide random numbers with specific distributions.
VTK‑m provides some specialized classes that implement common distributions.
The vtkm::cont::ArrayHandleRandomUniformReal class generates an array of numbers sampled from a real uniform distribution in the range \([0, 1)\).
-
template<typename Real = vtkm::Float64>
class ArrayHandleRandomUniformReal : public vtkm::cont::ArrayHandleTransform<vtkm::cont::ArrayHandleRandomUniformBits, detail::CanonicalFunctor<vtkm::Float64>> An
ArrayHandlethat provides a source of random numbers with uniform distribution.ArrayHandleRandomUniformRealtakes a user supplied seed and hashes it to provide a sequence of numbers drawn from a random uniform distribution in the range [0, 1).ArrayHandleRandomUniformRealis built on top ofArrayHandleRandomUniformBitsso shares its behavior with that array.Note: In contrast to traditional random number generator,
ArrayHandleRandomUniformRealdoes not have “state”, i.e. multiple calls the Get() method with the same index will always return the same hash value. To get a new set of random bits, create a newArrayHandleRandomUniformBitswith a different seed.Public Functions
-
inline explicit ArrayHandleRandomUniformReal(vtkm::Id length, SeedType seed = {std::random_device{}()})
Construct an
ArrayHandleRandomUniformReal.- Parameters:
length – Specifies the length of the generated array.
seed – Provides a seed to use for the pseudorandom numbers. To prevent confusion between the seed and the length, the type of the seed is a
vtkm::Vecof size 1. To specify the seed, declare it in braces. For example, to construct a random array of size 50 with seed 123, useArrayHandleRandomUniformReal(50, { 123 }).
-
inline explicit ArrayHandleRandomUniformReal(vtkm::Id length, SeedType seed = {std::random_device{}()})
1 constexpr vtkm::Id NumPoints = 50;
2 auto randomPointsInBox = vtkm::cont::make_ArrayHandleCompositeVector(
3 vtkm::cont::ArrayHandleRandomUniformReal<vtkm::FloatDefault>(NumPoints),
4 vtkm::cont::ArrayHandleRandomUniformReal<vtkm::FloatDefault>(NumPoints),
5 vtkm::cont::ArrayHandleRandomUniformReal<vtkm::FloatDefault>(NumPoints));
The vtkm::cont::ArrayHandleRandomStandardNormal class generates an array of numbers sampled from a standard normal distribution.
This provides a set of points centered at 0 and with probability exponentially diminishing away from 0 in both the positive and negative directions.
-
template<typename Real = vtkm::Float64>
class ArrayHandleRandomStandardNormal : public vtkm::cont::ArrayHandleTransform<vtkm::cont::ArrayHandleZip<vtkm::cont::ArrayHandleRandomUniformReal<vtkm::Float64>, vtkm::cont::ArrayHandleRandomUniformReal<vtkm::Float64>>, detail::BoxMuller> An
ArrayHandlethat provides a source of random numbers with a standard normal distribution.ArrayHandleRandomStandardNormaltakes a user supplied seed and hashes it to provide a sequence of numbers drawn from a random standard normal distribution. The probability density function of the numbers is \(\frac{e^{-x^2/2}}{\sqrt{2\pi}}\). The range of possible values is technically infinite, but the probability of large positive or negative numbers becomes vanishingly small.This array uses the Box-Muller transform to pick random numbers in the stanard normal distribution.
Note: In contrast to traditional random number generator,
ArrayHandleRandomStandardNormaldoes not have “state”, i.e. multiple calls the Get() method with the same index will always return the same hash value. To get a new set of random bits, create a newArrayHandleRandomUniformBitswith a different seed.Public Functions
-
inline explicit ArrayHandleRandomStandardNormal(vtkm::Id length, SeedType seed = {std::random_device{}()})
Construct an
ArrayHandleRandomStandardNormal.- Parameters:
length – Specifies the length of the generated array.
seed – Provides a seed to use for the pseudorandom numbers. To prevent confusion between the seed and the length, the type of the seed is a
vtkm::Vecof size 1. To specify the seed, declare it in braces. For example, to construct a random array of size 50 with seed 123, useArrayHandleRandomStandardNormal(50, { 123 }).
-
inline explicit ArrayHandleRandomStandardNormal(vtkm::Id length, SeedType seed = {std::random_device{}()})
1 constexpr vtkm::Id NumPoints = 50;
2 auto randomPointsInGaussian = vtkm::cont::make_ArrayHandleCompositeVector(
3 vtkm::cont::ArrayHandleRandomStandardNormal<vtkm::FloatDefault>(NumPoints),
4 vtkm::cont::ArrayHandleRandomStandardNormal<vtkm::FloatDefault>(NumPoints),
5 vtkm::cont::ArrayHandleRandomStandardNormal<vtkm::FloatDefault>(NumPoints));
Did You Know?
The distributions of the provided random array handles can manipulated by shifting and scaling the values they provide.
This will keep the general distribution shape but change the range.
This manipulation can happen in a worklet from the values returned from the arrays or they can be generated automatically by wrapping the random arrays in a vtkm::cont::ArrayHandleTransform.