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.
This commit is contained in:
Kenneth Moreland 2019-09-05 10:41:52 -06:00
parent 2b6e6da6ca
commit 3039a18baf
5 changed files with 256 additions and 7 deletions

@ -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 <typename T, typename StorageType, typename DerivedPolicy>
inline VTKM_CONT vtkm::cont::DataSet CrossProduct::DoExecute(
const vtkm::cont::DataSet& inDataSet,
const vtkm::cont::ArrayHandle<T, StorageType>& field,
const vtkm::filter::FieldMetadata& fieldMetadata,
vtkm::filter::PolicyBase<DerivedPolicy> policy)
{
vtkm::cont::CoordinateSystem coords = inDataSet.GetCoordianteSystem();
auto coordsArray = vtkm::filter::ApplyPolicy<T>(coords, policy);
```

@ -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 <typename ListTag1, typename ListTag2>
template <typename... ListTags>
struct ListTagJoin : detail::ListRoot
{
VTKM_IS_LIST_TAG(ListTag1);
VTKM_IS_LIST_TAG(ListTag2);
using list = typename detail::ListJoin<internal::ListTagAsBrigandList<ListTag1>,
internal::ListTagAsBrigandList<ListTag2>>::type;
using list = typename detail::ListJoin<internal::ListTagAsBrigandList<ListTags>...>::type;
};

@ -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 <typename ListTag>
using ArrayHandleMultiplexerFromListTag = vtkm::ListTagApply<ListTag, ArrayHandleMultiplexer>;
} // namespace cont
} // namespace vtkm

@ -32,12 +32,201 @@ template <typename Derived>
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::Float32>,
vtkm::cont::ArrayHandle<vtkm::Float32>,
vtkm::cont::ArrayHandle<vtkm::Float32>>::StorageTag,
vtkm::cont::ArrayHandleCartesianProduct<vtkm::cont::ArrayHandle<vtkm::Float64>,
vtkm::cont::ArrayHandle<vtkm::Float64>,
vtkm::cont::ArrayHandle<vtkm::Float64>>::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 <typename BaseType>
struct AllCastingTypes
{
using VTraits = vtkm::VecTraits<BaseType>;
using type =
vtkm::ListTagBase<typename VTraits::template ReplaceBaseComponentType<vtkm::Int8>,
typename VTraits::template ReplaceBaseComponentType<vtkm::UInt8>,
typename VTraits::template ReplaceBaseComponentType<vtkm::Int16>,
typename VTraits::template ReplaceBaseComponentType<vtkm::UInt8>,
typename VTraits::template ReplaceBaseComponentType<vtkm::Int32>,
typename VTraits::template ReplaceBaseComponentType<vtkm::UInt32>,
typename VTraits::template ReplaceBaseComponentType<vtkm::Int64>,
typename VTraits::template ReplaceBaseComponentType<vtkm::UInt64>,
typename VTraits::template ReplaceBaseComponentType<vtkm::Float32>,
typename VTraits::template ReplaceBaseComponentType<vtkm::Float64>>;
};
template <typename TargetT, typename SourceT, typename Storage, bool Valid>
struct CastArrayIfValid;
template <typename TargetT, typename SourceT, typename Storage>
struct CastArrayIfValid<TargetT, SourceT, Storage, true>
{
using type = vtkm::cont::ArrayHandleCast<TargetT, vtkm::cont::ArrayHandle<SourceT, Storage>>;
};
template <typename TargetT, typename SourceT, typename Storage>
struct CastArrayIfValid<TargetT, SourceT, Storage, false>
{
using type = vtkm::cont::ArrayHandleDiscard<TargetT>;
};
// 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 <typename TargetT, typename Storage>
struct CastArrayTransform
{
template <typename SourceT>
using Transform = typename CastArrayIfValid<
TargetT,
SourceT,
Storage,
vtkm::cont::internal::IsValidArrayHandle<SourceT, Storage>::value>::type;
};
template <typename TargetT, typename Storage, bool Valid>
struct AllCastArraysForStorageImpl;
template <typename TargetT, typename Storage>
struct AllCastArraysForStorageImpl<TargetT, Storage, true>
{
using SourceTypes = typename AllCastingTypes<TargetT>::type;
using type = vtkm::ListTagJoin<
vtkm::ListTagBase<vtkm::cont::ArrayHandle<TargetT, Storage>>,
vtkm::ListTagTransform<SourceTypes, CastArrayTransform<TargetT, Storage>::template Transform>>;
};
template <typename TargetT, typename Storage>
struct AllCastArraysForStorageImpl<TargetT, Storage, false>
{
using SourceTypes = typename AllCastingTypes<TargetT>::type;
using type =
vtkm::ListTagTransform<SourceTypes, CastArrayTransform<TargetT, Storage>::template Transform>;
};
// Special cases for known storage with limited type support.
template <>
struct AllCastArraysForStorageImpl<vtkm::Vec3f,
vtkm::cont::ArrayHandleUniformPointCoordinates::StorageTag,
true>
{
using type = vtkm::ListTagBase<vtkm::cont::ArrayHandleUniformPointCoordinates>;
};
template <typename T>
struct AllCastArraysForStorageImpl<vtkm::Vec<T, 3>,
vtkm::cont::ArrayHandleUniformPointCoordinates::StorageTag,
false>
{
using type = vtkm::ListTagBase<vtkm::cont::ArrayHandleCast<
vtkm::Vec<T, 3>,
vtkm::cont::ArrayHandle<vtkm::Vec3f,
vtkm::cont::ArrayHandleUniformPointCoordinates::StorageTag>>>;
};
template <typename TargetT>
struct AllCastArraysForStorageImpl<TargetT,
vtkm::cont::ArrayHandleUniformPointCoordinates::StorageTag,
false>
{
using type = vtkm::ListTagEmpty;
};
template <typename T, typename S1, typename S2, typename S3>
struct AllCastArraysForStorageImpl<
vtkm::Vec<T, 3>,
vtkm::cont::internal::StorageTagCartesianProduct<vtkm::cont::ArrayHandle<T, S1>,
vtkm::cont::ArrayHandle<T, S2>,
vtkm::cont::ArrayHandle<T, S3>>,
true>
{
using type =
vtkm::ListTagBase<vtkm::cont::ArrayHandleCartesianProduct<vtkm::cont::ArrayHandle<T, S1>,
vtkm::cont::ArrayHandle<T, S2>,
vtkm::cont::ArrayHandle<T, S3>>>;
};
template <typename TargetT, typename SourceT, typename S1, typename S2, typename S3>
struct AllCastArraysForStorageImpl<
vtkm::Vec<TargetT, 3>,
vtkm::cont::internal::StorageTagCartesianProduct<vtkm::cont::ArrayHandle<SourceT, S1>,
vtkm::cont::ArrayHandle<SourceT, S2>,
vtkm::cont::ArrayHandle<SourceT, S3>>,
false>
{
using type = vtkm::ListTagBase<vtkm::cont::ArrayHandleCast<
vtkm::Vec<TargetT, 3>,
vtkm::cont::ArrayHandleCartesianProduct<vtkm::cont::ArrayHandle<SourceT, S1>,
vtkm::cont::ArrayHandle<SourceT, S2>,
vtkm::cont::ArrayHandle<SourceT, S3>>>>;
};
template <typename TargetT, typename SourceT, typename S1, typename S2, typename S3>
struct AllCastArraysForStorageImpl<
TargetT,
vtkm::cont::internal::StorageTagCartesianProduct<vtkm::cont::ArrayHandle<SourceT, S1>,
vtkm::cont::ArrayHandle<SourceT, S2>,
vtkm::cont::ArrayHandle<SourceT, S3>>,
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 <typename TargetT, typename Storage>
struct AllCastArraysForStorage
{
using SourceTypes = typename AllCastingTypes<TargetT>::type;
using type = typename AllCastArraysForStorageImpl<
TargetT,
Storage,
vtkm::cont::internal::IsValidArrayHandle<TargetT, Storage>::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 <typename TargetT>
struct AllCastArraysTransform
{
template <typename Storage>
using Transform = typename AllCastArraysForStorage<TargetT, Storage>::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 <typename TargetT, typename StorageList>
struct AllCastArraysForStorageList
{
VTKM_IS_LIST_TAG(StorageList);
using listOfLists =
vtkm::ListTagTransform<StorageList, AllCastArraysTransform<TargetT>::template Transform>;
using type = vtkm::ListTagApply<listOfLists, vtkm::ListTagJoin>;
};
} // detail
template <typename TargetT, typename StorageList>
using ArrayHandleMultiplexerForStorageList = vtkm::cont::ArrayHandleMultiplexerFromListTag<
typename detail::AllCastArraysForStorageList<TargetT, StorageList>::type>;
} // namespace internal
//-----------------------------------------------------------------------------
template <typename DerivedPolicy>
VTKM_CONT vtkm::cont::VariantArrayHandleBase<typename DerivedPolicy::FieldTypeList> ApplyPolicy(
@ -48,6 +237,16 @@ VTKM_CONT vtkm::cont::VariantArrayHandleBase<typename DerivedPolicy::FieldTypeLi
return field.GetData().ResetTypes(TypeList());
}
//-----------------------------------------------------------------------------
template <typename T, typename DerivedPolicy>
VTKM_CONT internal::ArrayHandleMultiplexerForStorageList<T, typename DerivedPolicy::StorageList>
ApplyPolicy(const vtkm::cont::Field& field, const vtkm::filter::PolicyBase<DerivedPolicy>&)
{
using ArrayHandleMultiplexerType =
internal::ArrayHandleMultiplexerForStorageList<T, typename DerivedPolicy::StorageList>;
return field.GetData().AsMultiplexer<ArrayHandleMultiplexerType>();
}
//-----------------------------------------------------------------------------
template <typename DerivedPolicy, typename FilterType>
VTKM_CONT vtkm::cont::VariantArrayHandleBase<typename vtkm::filter::DeduceFilterFieldTypes<

@ -44,10 +44,10 @@ struct UniversalTag
};
//-----------------------------------------------------------------------------
template <typename ListTag1, typename ListTag2>
template <typename... ListTags>
struct ListJoin
{
using type = brigand::append<ListTag1, ListTag2>;
using type = brigand::append<ListTags...>;
};
template <typename ListTag>