This project is archived. Its data is read-only. This project is read-only.
Enable writing fields with Vecs of unknown length
Like VTK, VTK-m has an explicit way to represent vectors/tuples in an array to express things such as 3D coordinates. Although the memory layout is (typically) the same between the two, there is a subtle but important limitation in the way VTK-m represents them. In VTK, the size of a "tuple" is selected at runtime. This allows the size of the tuples to easily be adjusted to whatever is needed. When using an array with a tuple size determined at runtime, small arrays are allocated to move data in and out of the array. However, this approach does not work well on a GPU because dynamically allocating memory of the appropriate size is problematic. Instead, VTK-m takes a slightly different approach. VTK-m defines a simple templated type named `Vec` that represents a short vector of components with a length defined at compile time. Because the length is defined at compile time, operating on arrays of indeterminate type is problematic. Operating directly on the data requires a separate compilation path for each vector length. When the size of the `Vec` in a VTK-m array is not specifiable, then creating all code paths for any possible array type is problematic. Thus, VTK-m needs ways to operate on these arrays. Fortunately, we have made some recent strides on making this possible for a variety of use cases, but some problems still exist. This issue will start with listing the features that are currently available and then list those that remain. ## Features that are available Several recent additions allow VTK-m algorithms to operate on arrays with arbitrary `Vec` lengths. The most important feature is the `ArrayExtractComponent` function that allows pulling a single component of the array out without copying data and without knowing the length of the `Vec`s. This is used for multiple methods of `UnknownArrayHandle` to extract arrays of known type regardless of what kind of array is stored. It is also possible to create new arrays that have the same vector size as an input array. The `NewInstance`, `NewInstanceBasic` and `NewInstanceFloatBasic` methods of `UnknownArrayHandle` all provide a means of creating a new array with an unknown vector size although you need an existing array with the target vector size already. It is also usually straightforward to create a scalar array with the same component type as that of an input array of `Vec`s. This is usually done after some sort of `CastAndCall` determines the component type of the input. ## What is missing There are some features that are still difficult or impossible with the current features. ### Get extracted array with float fallback As mentioned, `UnknownArrayHandle` has a way of extracting a component from an array knowing only the base component type of the array. This can be used to get an "extracted array," and this in turn is used with a special `CastAndCall` to get arrays of any storage or `Vec` length. However, this `CastAndCall` does not have a means for a float fallback. This is less important than other `CastAndCall`s as there are only about 10 possibilities. However, for complex operations it might be better to just worry about a restricted set of types. Thus, it would be helpful to have a `CastAndCallWithExtractedArrayWithFloatFallback`. This mouthful of a method would allow someone to provide a `vtkm::List` of component types to try, and would convert to `vtkm::FloatDefault` if none of these worked. ### Construct an array of arbitrary `Vec` length Currently, to create an array of `Vec`s, you either need to know the size of the `Vec`s at compile time or have an array of the same `Vec` size you want. This can be problematic in some instances. For example, if a filter were to create a field that had `Vec`s with twice as many components as the input (say, computing a confidence interval), that could not be done in a single array. This also comes up a lot when importing data from other sources such as when reading data from a file or converting from VTK. The proposed solution would be to create a new type of `ArrayHandle` that is a cross between `ArrayHandleGroupVec` and `ArrayHandleGroupVecVariable`. It would essentially behave like `ArrayHandleGroupVecVariable` in that the size of the `Vec`s could be assigned at runtime, but it would limit the array to having the same `Vec` size for every entry. In this respect it is like `ArrayHandleGroupVec` but would not have to set the size at compile time. We could call this class `ArrayHandleGroupVecRuntime` (unless a better name comes along). We won't dwell on the implementation specifics of `ArrayHandleGroupVecRuntime`. The implementation will be very similar to `ArrayHandleGroupVecVariable` except that the offsets can be implied implicitly. Of course, simply creating an `ArrayHandleGroupVecRuntime` does not really solve the problem. Sure, you could create this array and put it in a field, but we don't want to add yet another type of storage to compile into all the algorithms in VTK-m. However, we can get around this problem by doing some implicit conversions in `UnknownArrayHandle`. `UnknownArrayHandle` already provides some implicit conversions when data does not need to be copied. For example, if you ask an `UnknownArrayHandle` for an `ArrayHandleMultiplexer`, then it will return the array if it matches any of the conditions of that array. In the same way, we can create special checks for a basic `ArrayHandle`. When requesting an `ArrayHandleBasic`, `UnknownArrayHandle` can check if it contains an `ArrayHandleGroupVecRuntime` of the appropriate type and length. It should then be possible to share `Buffer` objects to transform the data to the expected type. Although a bit more tricky, we should be able to do the opposite as well. That is, ask for an `ArrayHandleGroupVecRuntime` and have it match any `ArrayHandleBasic` of the appropriate component type.
issue