From 3039a18bafd3a0eaa5217f68d3b9f5444dc43959 Mon Sep 17 00:00:00 2001 From: Kenneth Moreland Date: Thu, 5 Sep 2019 10:41:52 -0600 Subject: [PATCH] Add ability to get an array from a Field for a particular type This is done through a new version of ApplyPolicy. This version takes a type of the array as its first template argument, which must be specified. This requires having a list of potential storage to try. It will use that to construct an ArrayHandleMultiplexer containing all potential types. This list of storages comes from the policy. A StorageList item was added to the policy. Types are automatically converted. So if you ask for a vtkm::Float64 and field contains a vtkm::Float32, it will the array wrapped in an ArrayHandleCast to give the expected type. --- .../apply-policy-with-single-type.md | 44 ++++ vtkm/ListTag.h | 7 +- vtkm/cont/ArrayHandleMultiplexer.h | 9 + vtkm/filter/PolicyBase.h | 199 ++++++++++++++++++ vtkm/internal/ListTagDetail.h | 4 +- 5 files changed, 256 insertions(+), 7 deletions(-) create mode 100644 docs/changelog/apply-policy-with-single-type.md diff --git a/docs/changelog/apply-policy-with-single-type.md b/docs/changelog/apply-policy-with-single-type.md new file mode 100644 index 000000000..fc8e46fb5 --- /dev/null +++ b/docs/changelog/apply-policy-with-single-type.md @@ -0,0 +1,44 @@ +# Add ability to get an array from a Field for a particular type + +Previously, whenever you got an array from a `Field` object from a call to +an `ApplyPolicy`, you would get back a `VariantArrayHandle` that allows you +to cast to multiple types. To use that, you then have to cast it to +multiple different types and multiple different storage. + +Often, this is what you want. If you are operating on a field, then you +want to cast to the native type. But there are also cases where you know a +specific type you want. For example, if you are operating on two fields, it +makes sense to find the exact type for the first field and then cast the +second field to that type if necessary rather than pointlessly unroll +templates for the cross of every possible combination. Also, we are not +unrolling for different storage types or attempting to create a virtual +array. Instead, we are using an `ArrayHandleMultiplexer` so that you only +have to compile for this array once. + +This is done through a new version of `ApplyPolicy`. This version takes a +type of the array as its first template argument, which must be specified. + +This requires having a list of potential storage to try. It will use that +to construct an `ArrayHandleMultiplexer` containing all potential types. +This list of storages comes from the policy. A `StorageList` item was added +to the policy. + +Types are automatically converted. So if you ask for a `vtkm::Float64` and +field contains a `vtkm::Float32`, it will the array wrapped in an +`ArrayHandleCast` to give the expected type. + +Here is an example where you are doing an operation on a field and +coordinate system. The superclass finds the correct type of the field. Your +result is just going to follow the type of the field. + +``` cpp +template +inline VTKM_CONT vtkm::cont::DataSet CrossProduct::DoExecute( + const vtkm::cont::DataSet& inDataSet, + const vtkm::cont::ArrayHandle& field, + const vtkm::filter::FieldMetadata& fieldMetadata, + vtkm::filter::PolicyBase policy) +{ + vtkm::cont::CoordinateSystem coords = inDataSet.GetCoordianteSystem(); + auto coordsArray = vtkm::filter::ApplyPolicy(coords, policy); +``` diff --git a/vtkm/ListTag.h b/vtkm/ListTag.h index e3cd8a094..3c83a290d 100644 --- a/vtkm/ListTag.h +++ b/vtkm/ListTag.h @@ -103,13 +103,10 @@ struct ListTagEmpty : detail::ListRoot /// A tag that is a construction of two other tags joined together. This struct /// can be subclassed and still behave like a list tag. -template +template struct ListTagJoin : detail::ListRoot { - VTKM_IS_LIST_TAG(ListTag1); - VTKM_IS_LIST_TAG(ListTag2); - using list = typename detail::ListJoin, - internal::ListTagAsBrigandList>::type; + using list = typename detail::ListJoin...>::type; }; diff --git a/vtkm/cont/ArrayHandleMultiplexer.h b/vtkm/cont/ArrayHandleMultiplexer.h index 0bd2da3a3..35dedbb87 100644 --- a/vtkm/cont/ArrayHandleMultiplexer.h +++ b/vtkm/cont/ArrayHandleMultiplexer.h @@ -526,6 +526,15 @@ public: } }; +/// \brief Converts a \c vtkm::ListTag to an \c ArrayHandleMultiplexer +/// +/// The argument of this template must be a vtkm::ListTag and furthermore all the types in +/// the list tag must be some type of \c ArrayHandle. The templated type gets aliased to +/// an \c ArrayHandleMultiplexer that can store any of these ArrayHandle types. +/// +template +using ArrayHandleMultiplexerFromListTag = vtkm::ListTagApply; + } // namespace cont } // namespace vtkm diff --git a/vtkm/filter/PolicyBase.h b/vtkm/filter/PolicyBase.h index 752b42252..e2f50da34 100644 --- a/vtkm/filter/PolicyBase.h +++ b/vtkm/filter/PolicyBase.h @@ -32,12 +32,201 @@ template struct PolicyBase { using FieldTypeList = VTKM_DEFAULT_TYPE_LIST_TAG; + using StorageList = vtkm::ListTagJoin< + VTKM_DEFAULT_STORAGE_LIST_TAG, + vtkm::ListTagBase< + vtkm::cont::ArrayHandleUniformPointCoordinates::StorageTag, + vtkm::cont::ArrayHandleCartesianProduct, + vtkm::cont::ArrayHandle, + vtkm::cont::ArrayHandle>::StorageTag, + vtkm::cont::ArrayHandleCartesianProduct, + vtkm::cont::ArrayHandle, + vtkm::cont::ArrayHandle>::StorageTag>>; using StructuredCellSetList = vtkm::cont::CellSetListTagStructured; using UnstructuredCellSetList = vtkm::cont::CellSetListTagUnstructured; using AllCellSetList = VTKM_DEFAULT_CELL_SET_LIST_TAG; }; +namespace internal +{ + +namespace detail +{ + +// Given a base type, forms a list of all types with the same Vec structure but with the +// base component replaced with each of the basic C types. +template +struct AllCastingTypes +{ + using VTraits = vtkm::VecTraits; + + using type = + vtkm::ListTagBase, + typename VTraits::template ReplaceBaseComponentType, + typename VTraits::template ReplaceBaseComponentType, + typename VTraits::template ReplaceBaseComponentType, + typename VTraits::template ReplaceBaseComponentType, + typename VTraits::template ReplaceBaseComponentType, + typename VTraits::template ReplaceBaseComponentType, + typename VTraits::template ReplaceBaseComponentType, + typename VTraits::template ReplaceBaseComponentType, + typename VTraits::template ReplaceBaseComponentType>; +}; + +template +struct CastArrayIfValid; + +template +struct CastArrayIfValid +{ + using type = vtkm::cont::ArrayHandleCast>; +}; + +template +struct CastArrayIfValid +{ + using type = vtkm::cont::ArrayHandleDiscard; +}; + +// Provides a transform template that builds a cast from an array of some source type to a +// cast array to a specific target type. +template +struct CastArrayTransform +{ + template + using Transform = typename CastArrayIfValid< + TargetT, + SourceT, + Storage, + vtkm::cont::internal::IsValidArrayHandle::value>::type; +}; + +template +struct AllCastArraysForStorageImpl; + +template +struct AllCastArraysForStorageImpl +{ + using SourceTypes = typename AllCastingTypes::type; + using type = vtkm::ListTagJoin< + vtkm::ListTagBase>, + vtkm::ListTagTransform::template Transform>>; +}; + +template +struct AllCastArraysForStorageImpl +{ + using SourceTypes = typename AllCastingTypes::type; + using type = + vtkm::ListTagTransform::template Transform>; +}; + +// Special cases for known storage with limited type support. +template <> +struct AllCastArraysForStorageImpl +{ + using type = vtkm::ListTagBase; +}; +template +struct AllCastArraysForStorageImpl, + vtkm::cont::ArrayHandleUniformPointCoordinates::StorageTag, + false> +{ + using type = vtkm::ListTagBase, + vtkm::cont::ArrayHandle>>; +}; +template +struct AllCastArraysForStorageImpl +{ + using type = vtkm::ListTagEmpty; +}; + +template +struct AllCastArraysForStorageImpl< + vtkm::Vec, + vtkm::cont::internal::StorageTagCartesianProduct, + vtkm::cont::ArrayHandle, + vtkm::cont::ArrayHandle>, + true> +{ + using type = + vtkm::ListTagBase, + vtkm::cont::ArrayHandle, + vtkm::cont::ArrayHandle>>; +}; +template +struct AllCastArraysForStorageImpl< + vtkm::Vec, + vtkm::cont::internal::StorageTagCartesianProduct, + vtkm::cont::ArrayHandle, + vtkm::cont::ArrayHandle>, + false> +{ + using type = vtkm::ListTagBase, + vtkm::cont::ArrayHandleCartesianProduct, + vtkm::cont::ArrayHandle, + vtkm::cont::ArrayHandle>>>; +}; +template +struct AllCastArraysForStorageImpl< + TargetT, + vtkm::cont::internal::StorageTagCartesianProduct, + vtkm::cont::ArrayHandle, + vtkm::cont::ArrayHandle>, + false> +{ + using type = vtkm::ListTagEmpty; +}; + +// Given a target type and storage of an array handle, provides a list this array handle plus all +// array handles that can be cast to the target type wrapped in an ArrayHandleCast that does so. +template +struct AllCastArraysForStorage +{ + using SourceTypes = typename AllCastingTypes::type; + using type = typename AllCastArraysForStorageImpl< + TargetT, + Storage, + vtkm::cont::internal::IsValidArrayHandle::value>::type; +}; + +// Provides a transform template that converts a storage type to a list of all arrays that come +// from that storage type and can be cast to a target type (wrapped in an ArrayHandleCast as +// appropriate). +template +struct AllCastArraysTransform +{ + template + using Transform = typename AllCastArraysForStorage::type; +}; + +// Given a target type and a list of storage types, provides a joined list of all possible arrays +// of any of these storage cast to the target type. +template +struct AllCastArraysForStorageList +{ + VTKM_IS_LIST_TAG(StorageList); + using listOfLists = + vtkm::ListTagTransform::template Transform>; + using type = vtkm::ListTagApply; +}; + +} // detail + +template +using ArrayHandleMultiplexerForStorageList = vtkm::cont::ArrayHandleMultiplexerFromListTag< + typename detail::AllCastArraysForStorageList::type>; + +} // namespace internal + //----------------------------------------------------------------------------- template VTKM_CONT vtkm::cont::VariantArrayHandleBase ApplyPolicy( @@ -48,6 +237,16 @@ VTKM_CONT vtkm::cont::VariantArrayHandleBase +VTKM_CONT internal::ArrayHandleMultiplexerForStorageList +ApplyPolicy(const vtkm::cont::Field& field, const vtkm::filter::PolicyBase&) +{ + using ArrayHandleMultiplexerType = + internal::ArrayHandleMultiplexerForStorageList; + return field.GetData().AsMultiplexer(); +} + //----------------------------------------------------------------------------- template VTKM_CONT vtkm::cont::VariantArrayHandleBase +template struct ListJoin { - using type = brigand::append; + using type = brigand::append; }; template