Add support for CastAndCallVariableVecField in FilterField

The `FilterField` class provides convenience functions for subclasses to
determine the `ArrayHandle` type for scalar and vector fields. However, you
needed to know the specific size of vectors. For filters that support an
input field of any type, a new form, `CastAndCallVariableVecField` has been
added. This calls the underlying functor with an `ArrayHandleRecombineVec`
of the appropriate component type.

The `CastAndaCallVariableVecField` method also reduces the number of
instances created by having a float fallback for any component type that
does not satisfy the field types.
This commit is contained in:
Kenneth Moreland 2023-05-22 09:26:06 -06:00
parent 3fe452662b
commit c802adcbeb
3 changed files with 88 additions and 19 deletions

@ -0,0 +1,12 @@
# Added support for `CastAndCallVariableVecField` in `FilterField`
The `FilterField` class provides convenience functions for subclasses to
determine the `ArrayHandle` type for scalar and vector fields. However, you
needed to know the specific size of vectors. For filters that support an
input field of any type, a new form, `CastAndCallVariableVecField` has been
added. This calls the underlying functor with an `ArrayHandleRecombineVec`
of the appropriate component type.
The `CastAndaCallVariableVecField` method also reduces the number of
instances created by having a float fallback for any component type that
does not satisfy the field types.

@ -13,6 +13,8 @@
#include <vtkm/filter/Filter.h>
#include <vtkm/cont/ArrayCopy.h>
namespace vtkm
{
namespace filter
@ -160,6 +162,16 @@ protected:
}
}
///@{
/// \brief Convenience method to get the array from a filter's input scalar field.
///
/// A field filter typically gets its input fields using the internal `GetFieldFromDataSet`.
/// To use this field in a worklet, it eventually needs to be converted to an
/// `ArrayHandle`. If the input field is limited to be a scalar field, then this method
/// provides a convenient way to determine the correct array type. Like other `CastAndCall`
/// methods, it takes as input a `Field` (or `UnknownArrayHandle`) and a function/functor
/// to call with the appropriate `ArrayHandle` type.
///
template <typename Functor, typename... Args>
VTKM_CONT void CastAndCallScalarField(const vtkm::cont::UnknownArrayHandle& fieldArray,
Functor&& functor,
@ -178,6 +190,7 @@ protected:
this->CastAndCallScalarField(
field.GetData(), std::forward<Functor>(functor), std::forward<Args>(args)...);
}
///@}
private:
@ -189,6 +202,18 @@ private:
};
protected:
///@{
/// \brief Convenience method to get the array from a filter's input vector field.
///
/// A field filter typically gets its input fields using the internal `GetFieldFromDataSet`.
/// To use this field in a worklet, it eventually needs to be converted to an
/// `ArrayHandle`. If the input field is limited to be a vector field with vectors of a
/// specific size, then this method provides a convenient way to determine the correct array
/// type. Like other `CastAndCall` methods, it takes as input a `Field` (or
/// `UnknownArrayHandle`) and a function/functor to call with the appropriate `ArrayHandle`
/// type. You also have to provide the vector size as the first template argument.
/// For example `CastAndCallVecField<3>(field, functor);`.
///
template <vtkm::IdComponent VecSize, typename Functor, typename... Args>
VTKM_CONT void CastAndCallVecField(const vtkm::cont::UnknownArrayHandle& fieldArray,
Functor&& functor,
@ -208,6 +233,52 @@ protected:
this->CastAndCallVecField<VecSize>(
field.GetData(), std::forward<Functor>(functor), std::forward<Args>(args)...);
}
///@}
///@{
/// This method is like `CastAndCallVecField` except that it can be used for a
/// field of unknown vector size (or scalars). This method will call the given
/// functor with an `ArrayHandleRecombineVec`.
///
/// Note that there are limitations with using `ArrayHandleRecombineVec` within a
/// worklet. Because the size of the vectors are not known at compile time, you
/// cannot just create an intermediate `Vec` of the correct size. Typically, you
/// must allocate the output array (for example, with `ArrayHandleRuntimeVec`), and
/// the worklet must iterate over the components and store them in the prealocated
/// output.
///
template <typename Functor, typename... Args>
VTKM_CONT void CastAndCallVariableVecField(const vtkm::cont::UnknownArrayHandle& fieldArray,
Functor&& functor,
Args&&... args) const
{
if (fieldArray.IsBaseComponentType<vtkm::Float32>())
{
functor(fieldArray.ExtractArrayFromComponents<vtkm::Float32>(), std::forward<Args>(args)...);
}
else if (fieldArray.IsBaseComponentType<vtkm::Float64>())
{
functor(fieldArray.ExtractArrayFromComponents<vtkm::Float64>(), std::forward<Args>(args)...);
}
else
{
// Field component type is not directly supported. Copy to floating point array.
vtkm::cont::UnknownArrayHandle floatArray = fieldArray.NewInstanceFloatBasic();
vtkm::cont::ArrayCopy(fieldArray, floatArray);
functor(floatArray.ExtractArrayFromComponents<vtkm::FloatDefault>(),
std::forward<Args>(args)...);
}
}
template <typename Functor, typename... Args>
VTKM_CONT void CastAndCallVariableVecField(const vtkm::cont::Field& field,
Functor&& functor,
Args&&... args) const
{
this->CastAndCallVariableVecField(
field.GetData(), std::forward<Functor>(functor), std::forward<Args>(args)...);
}
///@}
/// \brief Create the output data set for `DoExecute`
///

@ -78,11 +78,9 @@ VTKM_CONT DotProduct::DotProduct()
VTKM_CONT vtkm::cont::DataSet DotProduct::DoExecute(const vtkm::cont::DataSet& inDataSet)
{
vtkm::cont::Field primaryField = this->GetFieldFromDataSet(0, inDataSet);
vtkm::cont::UnknownArrayHandle primaryArray = primaryField.GetData();
vtkm::cont::Field secondaryField = this->GetFieldFromDataSet(1, inDataSet);
if (primaryArray.GetNumberOfComponentsFlat() !=
if (primaryField.GetData().GetNumberOfComponentsFlat() !=
secondaryField.GetData().GetNumberOfComponentsFlat())
{
throw vtkm::cont::ErrorFilterExecution(
@ -91,22 +89,10 @@ VTKM_CONT vtkm::cont::DataSet DotProduct::DoExecute(const vtkm::cont::DataSet& i
vtkm::cont::UnknownArrayHandle outArray;
if (primaryArray.IsBaseComponentType<vtkm::Float32>())
{
outArray =
DoDotProduct(primaryArray.ExtractArrayFromComponents<vtkm::Float32>(), secondaryField);
}
else if (primaryArray.IsBaseComponentType<vtkm::Float64>())
{
outArray =
DoDotProduct(primaryArray.ExtractArrayFromComponents<vtkm::Float64>(), secondaryField);
}
else
{
primaryArray = primaryField.GetDataAsDefaultFloat();
outArray =
DoDotProduct(primaryArray.ExtractArrayFromComponents<vtkm::FloatDefault>(), secondaryField);
}
auto resolveArray = [&](const auto& concretePrimaryField) {
outArray = DoDotProduct(concretePrimaryField, secondaryField);
};
this->CastAndCallVariableVecField(primaryField, resolveArray);
return this->CreateResultField(inDataSet,
this->GetOutputFieldName(),