Merge branch 'master' into hdf5_image_io

This commit is contained in:
Li-Ta Lo 2021-01-14 14:08:00 -07:00
commit ca0ce4de7b
110 changed files with 3746 additions and 2194 deletions

@ -32,6 +32,7 @@
# - tbb
# - openmp
# - mpich2
# - hdf5
# * .gitlab/ci/docker/ubuntu1804/cuda11.1/
# - cuda
# - gcc 7
@ -75,8 +76,7 @@
- .docker_image
.ubuntu1804: &ubuntu1804
# image: "kitware/vtkm:ci-ubuntu1804-20201016"
image: "ollielo/vtkm:ci-ubuntu1804-01042020"
image: "kitware/vtkm:ci-ubuntu1804-20210107"
extends:
- .docker_image

@ -29,6 +29,10 @@ foreach(option IN LISTS options)
elseif(vtk_types STREQUAL option)
set(VTKm_USE_DEFAULT_TYPES_FOR_VTK "ON" CACHE STRING "")
elseif(ascent_types STREQUAL option)
# Note: ascent_types also requires 32bit_ids and 64bit_floats
set(VTKm_USE_DEFAULT_TYPES_FOR_ASCENT "ON" CACHE STRING "")
elseif(32bit_ids STREQUAL option)
set(VTKm_USE_64BIT_IDS "OFF" CACHE STRING "")

@ -10,7 +10,7 @@ readonly tarball="$filename.tar.gz"
cd .gitlab
echo "$sha256sum $tarball" > sccache.sha256sum
curl -OL "https://github.com/robertmaynard/sccache/releases/download/$version/$tarball"
curl --insecure -OL "https://github.com/robertmaynard/sccache/releases/download/$version/$tarball"
sha256sum --check sccache.sha256sum
tar xf "$tarball"
#mv "$filename/sccache" .

@ -18,7 +18,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
software-properties-common
# extra dependencies for charm machine
#RUN add-apt-repository ppa:jonathonf/gcc-9.2
RUN add-apt-repository ppa:jonathonf/gcc
RUN apt-get update && apt-get install -y --no-install-recommends \
clang-8 \

@ -17,7 +17,7 @@ build:ubuntu1604_gcc5:
CC: "gcc-5"
CXX: "g++-5"
CMAKE_BUILD_TYPE: RelWithDebInfo
VTKM_SETTINGS: "cuda+pascal+no_virtual"
VTKM_SETTINGS: "cuda+pascal+no_virtual+ascent_types+32bit_ids+64bit_floats"
test:ubuntu1604_gcc5:
tags:

@ -33,7 +33,7 @@ function(vtkm_get_kit_name kitvar)
# Optional second argument to get dir_prefix.
if (${ARGC} GREATER 1)
set(${ARGV1} "${dir_prefix}" PARENT_SCOPE)
endif (${ARGC} GREATER 1)
endif ()
endfunction(vtkm_get_kit_name)
#-----------------------------------------------------------------------------

@ -226,7 +226,7 @@ if (VTKm_ENABLE_TESTING)
# Setup compiler flags for dynamic analysis if needed
include(testing/VTKmCompilerDynamicAnalysisFlags)
endif (VTKm_ENABLE_TESTING)
endif()
#-----------------------------------------------------------------------------
# Check basic type sizes.

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:b4f049b4f0e79a27ebbdab187325db55653abe2ce661c8f1d2f3fcb413e3b961
size 10883

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:8c22f2d4e19191ff05d9dc52ea740269fcdfe129b9d100ea8db6d4cbb989b161
size 9652

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:c1a54c159483076a2eed1f7cf8f8d947e6ec59dcfbd8ed41355e92cf052d344e
size 19884

@ -0,0 +1,26 @@
# Recombine extracted component arrays from unknown arrays
Building on the recent capability to [extract component arrays from unknown
arrays](array-extract-component.md), there is now also the ability to
recombine these extracted arrays to a single `ArrayHandle`. It might seem
counterintuitive to break an `ArrayHandle` into component arrays and then
combine the component arrays back into a single `ArrayHandle`, but this is
a very handy way to run algorithms without knowing the exact `ArrayHandle`
type.
Recall that when extracting a component array from an `UnknownArrayHandle`
you only need to know the base component of the value type of the contained
`ArrayHandle`. That makes extracting a component array independent from
either the size of any `Vec` value type and any storage type.
The added `UnknownArrayHandle::ExtractArrayFromComponents` method allows
you to use the functionality to transform the unknown array handle to a
form of `ArrayHandle` that depends only on this base component type. This
method internally uses a new `ArrayHandleRecombineVec` class, but this
class is mostly intended for internal use by this class.
As an added convenience, `UnknownArrayHandle` now also provides the
`CastAndCallWithExtractedArray` method. This method works like other
`CastAndCall`s except that it uses the `ExtractArrayFromComponents` feature
to allow you to handle most `ArrayHandle` types with few template
instances.

@ -0,0 +1,22 @@
Support `ArrayHandleSOA` as a "default" array
Many programs, particularly simulations, store fields of vectors in
separate arrays for each component. This maps to the storage of
`ArrayHandleSOA`. The VTK-m code tends to prefer the AOS storage (which is
what is implemented in `ArrayHandleBasic`, and the behavior of which is
inherited from VTK). VTK-m should better support adding `ArrayHandleSOA` as
one of the types.
We now have a set of default types for Ascent that uses SOA as one of the
basic types.
Part of this change includes an intentional feature regression of
`ArrayHandleSOA` to only support value types of `Vec`. Previously, scalar
types were supported. However, the behavior of `ArrayHandleSOA` is exactly
the same as `ArrayHandleBasic`, except a lot more template code has to be
generated. That itself is not a huge deal, but because you have 2 types
that essentially do the same thing, a lot of template code in VTK-m would
unwind to create two separate code paths that do the same thing with the
same data. To avoid creating those code paths, we simply make any use of
`ArrayHandleSOA` without a `Vec` value invalid. This will prevent VTK-m
from creating those code paths.

@ -463,7 +463,7 @@ VTKM_EXEC_CONT inline vtkm::UInt64 AtomicLoadImpl(vtkm::UInt64* const addr, vtkm
VTKM_EXEC_CONT inline void AtomicStoreImpl(vtkm::UInt8* addr,
vtkm::UInt8 val,
vtkm::MemoryOrder order)
vtkm::MemoryOrder vtkmNotUsed(order))
{
// There doesn't seem to be an atomic store instruction in the windows
// API, so just exchange and discard the result.
@ -471,7 +471,7 @@ VTKM_EXEC_CONT inline void AtomicStoreImpl(vtkm::UInt8* addr,
}
VTKM_EXEC_CONT inline void AtomicStoreImpl(vtkm::UInt16* addr,
vtkm::UInt16 val,
vtkm::MemoryOrder order)
vtkm::MemoryOrder vtkmNotUsed(order))
{
// There doesn't seem to be an atomic store instruction in the windows
// API, so just exchange and discard the result.
@ -499,31 +499,31 @@ VTKM_EXEC_CONT inline void AtomicStoreImpl(vtkm::UInt64* addr,
winName##suffix(reinterpret_cast<volatile winType*>(addr), BitCast<winType>(arg))); \
}
#define VTKM_ATOMIC_OPS_FOR_TYPE(vtkmType, winType, suffix) \
VTKM_ATOMIC_OP(AtomicAddImpl, _InterlockedExchangeAdd, vtkmType, winType, suffix) \
VTKM_ATOMIC_OP(AtomicAndImpl, _InterlockedAnd, vtkmType, winType, suffix) \
VTKM_ATOMIC_OP(AtomicOrImpl, _InterlockedOr, vtkmType, winType, suffix) \
VTKM_ATOMIC_OP(AtomicXorImpl, _InterlockedXor, vtkmType, winType, suffix) \
VTKM_EXEC_CONT inline vtkmType AtomicNotImpl(vtkmType* addr, vtkm::MemoryOrder order) \
{ \
return AtomicXorImpl(addr, static_cast<vtkmType>(~vtkmType{ 0u }), order); \
} \
VTKM_EXEC_CONT inline bool AtomicCompareExchangeImpl( \
vtkmType* addr, vtkmType* expected, vtkmType desired, vtkm::MemoryOrder order) \
{ \
vtkmType result = BitCast<vtkmType>( \
_InterlockedCompareExchange##suffix(reinterpret_cast<volatile winType*>(addr), \
BitCast<winType>(desired), \
BitCast<winType>(*expected))); \
if (result == *expected) \
{ \
return true; \
} \
else \
{ \
*expected = result; \
return false; \
} \
#define VTKM_ATOMIC_OPS_FOR_TYPE(vtkmType, winType, suffix) \
VTKM_ATOMIC_OP(AtomicAddImpl, _InterlockedExchangeAdd, vtkmType, winType, suffix) \
VTKM_ATOMIC_OP(AtomicAndImpl, _InterlockedAnd, vtkmType, winType, suffix) \
VTKM_ATOMIC_OP(AtomicOrImpl, _InterlockedOr, vtkmType, winType, suffix) \
VTKM_ATOMIC_OP(AtomicXorImpl, _InterlockedXor, vtkmType, winType, suffix) \
VTKM_EXEC_CONT inline vtkmType AtomicNotImpl(vtkmType* addr, vtkm::MemoryOrder order) \
{ \
return AtomicXorImpl(addr, static_cast<vtkmType>(~vtkmType{ 0u }), order); \
} \
VTKM_EXEC_CONT inline bool AtomicCompareExchangeImpl( \
vtkmType* addr, vtkmType* expected, vtkmType desired, vtkm::MemoryOrder vtkmNotUsed(order)) \
{ \
vtkmType result = BitCast<vtkmType>( \
_InterlockedCompareExchange##suffix(reinterpret_cast<volatile winType*>(addr), \
BitCast<winType>(desired), \
BitCast<winType>(*expected))); \
if (result == *expected) \
{ \
return true; \
} \
else \
{ \
*expected = result; \
return false; \
} \
}
VTKM_ATOMIC_OPS_FOR_TYPE(vtkm::UInt8, CHAR, 8)

@ -1722,7 +1722,7 @@ static inline VTKM_EXEC_CONT vtkm::Float64 Max(vtkm::Float64 x, vtkm::Float64 y)
///
template <typename T>
static inline VTKM_EXEC_CONT T Min(const T& x, const T& y);
#ifdef VTKM_USE_STL
#if defined(VTKM_USE_STL) && !defined(VTKM_HIP)
static inline VTKM_EXEC_CONT vtkm::Float32 Min(vtkm::Float32 x, vtkm::Float32 y)
{
return (std::min)(x, y);
@ -1731,7 +1731,7 @@ static inline VTKM_EXEC_CONT vtkm::Float64 Min(vtkm::Float64 x, vtkm::Float64 y)
{
return (std::min)(x, y);
}
#else // !VTKM_USE_STL
#else // !VTKM_USE_STL OR HIP
static inline VTKM_EXEC_CONT vtkm::Float32 Min(vtkm::Float32 x, vtkm::Float32 y)
{
#ifdef VTKM_CUDA

@ -564,10 +564,10 @@ $#
///
template <typename T>
static inline VTKM_EXEC_CONT T Min(const T& x, const T& y);
#ifdef VTKM_USE_STL
#if defined(VTKM_USE_STL) && !defined(VTKM_HIP)
$binary_template_function('Min', '(std::min)(x, y)')\
$#
#else // !VTKM_USE_STL
#else // !VTKM_USE_STL OR HIP
$binary_math_function('Min', 'fmin')\
$#
#endif // !VTKM_USE_STL

@ -86,7 +86,12 @@ using TypeListField = vtkm::List<vtkm::Float32,
vtkm::Vec4f_64>;
/// A list of all scalars defined in vtkm/Types.h. A scalar is a type that
/// holds a single number.
/// holds a single number. This should containing all true variations of
/// scalars, but there might be some arithmetic C types not included. For
/// example, this list contains `signed char`, and `unsigned char`, but not
/// `char` as one of those types will behave the same as it. Two of the three
/// types behave the same, but be aware that template resolution will treat
/// them differently.
///
using TypeListScalarAll = vtkm::List<vtkm::Int8,
vtkm::UInt8,
@ -97,12 +102,16 @@ using TypeListScalarAll = vtkm::List<vtkm::Int8,
vtkm::Int64,
vtkm::UInt64,
vtkm::Float32,
vtkm::Float64,
// Other base C types that are the same as above but
// recognized as different by the compiler
char,
signed VTKM_UNUSED_INT_TYPE,
unsigned VTKM_UNUSED_INT_TYPE>;
vtkm::Float64>;
// A list that containes all the base arithmetric C types (i.e. char, int, float, etc.).
// The list contains C types that are functionally equivalent but considered different
// types (e.g. it contains both `char` and `signed char`).
using TypeListBaseC = vtkm::ListAppend<
vtkm::TypeListScalarAll,
// Other base C types that are the same as above but
// recognized as different by the compiler
vtkm::List<bool, char, signed VTKM_UNUSED_INT_TYPE, unsigned VTKM_UNUSED_INT_TYPE>>;
/// A list of the most commonly use Vec classes. Specifically, these are
/// vectors of size 2, 3, or 4 containing either unsigned bytes, signed

@ -343,15 +343,14 @@ public:
}
}
template <typename OtherComponentType, typename OtherVecType>
VTKM_EXEC_CONT DerivedClass& operator=(
const vtkm::detail::VecBaseCommon<OtherComponentType, OtherVecType>& src)
// Only works with Vec-like objects with operator[] and GetNumberOfComponents().
template <typename OtherVecType>
VTKM_EXEC_CONT DerivedClass& operator=(const OtherVecType& src)
{
const OtherVecType& srcDerived = static_cast<const OtherVecType&>(src);
VTKM_ASSERT(this->NumComponents() == srcDerived.GetNumberOfComponents());
VTKM_ASSERT(this->NumComponents() == src.GetNumberOfComponents());
for (vtkm::IdComponent i = 0; i < this->NumComponents(); ++i)
{
this->Component(i) = OtherComponentType(srcDerived[i]);
this->Component(i) = src[i];
}
return this->Derived();
}
@ -413,14 +412,12 @@ public:
}
template <typename OtherClass>
inline VTKM_EXEC_CONT DerivedClass& operator+=(
const VecBaseCommon<ComponentType, OtherClass>& other)
inline VTKM_EXEC_CONT DerivedClass& operator+=(const OtherClass& other)
{
const OtherClass& other_derived = static_cast<const OtherClass&>(other);
VTKM_ASSERT(this->NumComponents() == other_derived.GetNumberOfComponents());
VTKM_ASSERT(this->NumComponents() == other.GetNumberOfComponents());
for (vtkm::IdComponent i = 0; i < this->NumComponents(); ++i)
{
this->Component(i) += other_derived[i];
this->Component(i) += other[i];
}
return this->Derived();
}
@ -439,14 +436,12 @@ public:
}
template <typename OtherClass>
inline VTKM_EXEC_CONT DerivedClass& operator-=(
const VecBaseCommon<ComponentType, OtherClass>& other)
inline VTKM_EXEC_CONT DerivedClass& operator-=(const OtherClass& other)
{
const OtherClass& other_derived = static_cast<const OtherClass&>(other);
VTKM_ASSERT(this->NumComponents() == other_derived.GetNumberOfComponents());
VTKM_ASSERT(this->NumComponents() == other.GetNumberOfComponents());
for (vtkm::IdComponent i = 0; i < this->NumComponents(); ++i)
{
this->Component(i) -= other_derived[i];
this->Component(i) -= other[i];
}
return this->Derived();
}
@ -464,14 +459,12 @@ public:
}
template <typename OtherClass>
inline VTKM_EXEC_CONT DerivedClass& operator*=(
const VecBaseCommon<ComponentType, OtherClass>& other)
inline VTKM_EXEC_CONT DerivedClass& operator*=(const OtherClass& other)
{
const OtherClass& other_derived = static_cast<const OtherClass&>(other);
VTKM_ASSERT(this->NumComponents() == other_derived.GetNumberOfComponents());
VTKM_ASSERT(this->NumComponents() == other.GetNumberOfComponents());
for (vtkm::IdComponent i = 0; i < this->NumComponents(); ++i)
{
this->Component(i) *= other_derived[i];
this->Component(i) *= other[i];
}
return this->Derived();
}
@ -489,13 +482,12 @@ public:
}
template <typename OtherClass>
VTKM_EXEC_CONT DerivedClass& operator/=(const VecBaseCommon<ComponentType, OtherClass>& other)
VTKM_EXEC_CONT DerivedClass& operator/=(const OtherClass& other)
{
const OtherClass& other_derived = static_cast<const OtherClass&>(other);
VTKM_ASSERT(this->NumComponents() == other_derived.GetNumberOfComponents());
VTKM_ASSERT(this->NumComponents() == other.GetNumberOfComponents());
for (vtkm::IdComponent i = 0; i < this->NumComponents(); ++i)
{
this->Component(i) /= other_derived[i];
this->Component(i) /= other[i];
}
return this->Derived();
}

@ -12,6 +12,7 @@
#include <vtkm/Types.h>
#include <vtkm/cont/BitField.h>
#include <vtkm/cont/DeviceAdapter.h>
#include <vtkm/cont/ExecutionObjectBase.h>
#include <vtkm/cont/Token.h>

@ -16,6 +16,8 @@
#include <vtkm/cont/ErrorExecution.h>
#include <vtkm/cont/Logging.h>
#include <vtkm/cont/internal/ArrayHandleDeprecated.h>
#include <vtkm/cont/vtkm_cont_export.h>
// TODO: When virtual arrays are available, compile the implementation in a .cxx/.cu file. Common
@ -149,11 +151,12 @@ VTKM_CONT void ArrayCopy(const vtkm::cont::ArrayHandle<InValueType, InStorage>&
"Cannot copy to a read-only array with a different "
"type than the source.");
using IsNewStyle =
std::is_base_of<vtkm::cont::ArrayHandleNewStyle<InValueType, InStorage>, InArrayType>;
using IsOldStyle =
std::is_base_of<vtkm::cont::internal::ArrayHandleDeprecated<InValueType, InStorage>,
InArrayType>;
// Static dispatch cases 1 & 2
detail::ArrayCopyImpl(source, destination, std::integral_constant<bool, IsNewStyle::value>{});
detail::ArrayCopyImpl(source, destination, std::integral_constant<bool, !IsOldStyle::value>{});
}
// Forward declaration

@ -17,7 +17,6 @@
#include <vtkm/Flags.h>
#include <vtkm/Types.h>
#include <vtkm/cont/ArrayPortalToIterators.h>
#include <vtkm/cont/DeviceAdapterList.h>
#include <vtkm/cont/ErrorBadValue.h>
#include <vtkm/cont/ErrorInternal.h>
@ -33,10 +32,7 @@
#include <mutex>
#include <vector>
#include <vtkm/cont/internal/ArrayHandleExecutionManager.h>
#include <vtkm/cont/internal/ArrayPortalFromIterators.h>
#include <vtkm/cont/internal/Buffer.h>
#include <vtkm/cont/internal/StorageDeprecated.h>
namespace vtkm
{
@ -256,652 +252,6 @@ struct GetTypeInParentheses<void(T)>
#define VTKM_ARRAY_HANDLE_SUBCLASS_NT(classname, superclass) \
VTK_M_ARRAY_HANDLE_SUBCLASS_IMPL(classname, (classname), superclass, )
/// \brief Manages an array-worth of data.
///
/// \c ArrayHandle manages as array of data that can be manipulated by VTKm
/// algorithms. The \c ArrayHandle may have up to two copies of the array, one
/// for the control environment and one for the execution environment, although
/// depending on the device and how the array is being used, the \c ArrayHandle
/// will only have one copy when possible.
///
/// An ArrayHandle can be constructed one of two ways. Its default construction
/// creates an empty, unallocated array that can later be allocated and filled
/// either by the user or a VTKm algorithm. The \c ArrayHandle can also be
/// constructed with iterators to a user's array. In this case the \c
/// ArrayHandle will keep a reference to this array but will throw an exception
/// if asked to re-allocate to a larger size.
///
/// \c ArrayHandle behaves like a shared smart pointer in that when it is copied
/// each copy holds a reference to the same array. These copies are reference
/// counted so that when all copies of the \c ArrayHandle are destroyed, any
/// allocated memory is released.
///
///
template <typename T, typename StorageTag_ = VTKM_DEFAULT_STORAGE_TAG>
class VTKM_ALWAYS_EXPORT ArrayHandle : public internal::ArrayHandleBase
{
private:
// Basic storage is specialized; this template should not be instantiated
// for it. Specialization is in ArrayHandleBasicImpl.h
static_assert(!std::is_same<StorageTag_, StorageTagBasic>::value,
"StorageTagBasic should not use this implementation.");
using ExecutionManagerType =
vtkm::cont::internal::ArrayHandleExecutionManagerBase<T, StorageTag_>;
using MutexType = std::mutex;
using LockType = std::unique_lock<MutexType>;
mutable vtkm::cont::internal::Buffer BufferAsStorageWrapper;
public:
using StorageType = vtkm::cont::internal::Storage<T, StorageTag_>;
using ValueType = T;
using StorageTag = StorageTag_;
using WritePortalType = typename StorageType::PortalType;
using ReadPortalType = typename StorageType::PortalConstType;
template <typename DeviceAdapterTag>
struct ExecutionTypes
{
using Portal = typename ExecutionManagerType::template ExecutionTypes<DeviceAdapterTag>::Portal;
using PortalConst =
typename ExecutionManagerType::template ExecutionTypes<DeviceAdapterTag>::PortalConst;
};
using PortalControl VTKM_DEPRECATED(1.6, "Use ArrayHandle::WritePortalType instead.") =
typename StorageType::PortalType;
using PortalConstControl VTKM_DEPRECATED(1.6, "Use ArrayHandle::ReadPortalType instead.") =
typename StorageType::PortalConstType;
// Handle the fact that the ArrayHandle design has changed.
VTKM_STATIC_ASSERT_MSG((std::is_same<typename StorageType::HasOldBridge, std::true_type>::value),
"ArrayHandle design has changed. To support old-style arrays, have the "
"Storage implementation subclass StorageDeprecated.");
VTKM_CONT static constexpr vtkm::IdComponent GetNumberOfBuffers() { return 1; }
VTKM_CONT vtkm::cont::internal::Buffer* GetBuffers() const
{
this->BufferAsStorageWrapper.SetMetaData(*this);
return &this->BufferAsStorageWrapper;
}
VTKM_CONT ArrayHandle(const vtkm::cont::internal::Buffer* buffers)
{
VTKM_ASSERT(buffers[0].MetaDataIsType<ArrayHandle>());
*this = buffers[0].GetMetaData<ArrayHandle>();
}
/// Constructs an empty ArrayHandle. Typically used for output or
/// intermediate arrays that will be filled by a VTKm algorithm.
///
VTKM_CONT ArrayHandle();
/// Copy constructor.
///
/// 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 copy constructor could be
/// created for all devices, and it would not be valid for all devices.
///
ArrayHandle(const vtkm::cont::ArrayHandle<ValueType, StorageTag>& src);
/// Move constructor.
///
/// 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 move constructor could be
/// created for all devices, and it would not be valid for all devices.
///
ArrayHandle(vtkm::cont::ArrayHandle<ValueType, StorageTag>&& src) noexcept;
/// Special constructor for subclass specializations that need to set the
/// initial state of the control array. When this constructor is used, it
/// is assumed that the control array is valid.
///
ArrayHandle(const StorageType& storage);
/// Special constructor for subclass specializations that need to set the
/// initial state of the control array. When this constructor is used, it
/// is assumed that the control array is valid.
///
ArrayHandle(StorageType&& storage) noexcept;
/// Destructs an empty ArrayHandle.
///
/// 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.
///
~ArrayHandle();
/// \brief Copies an ArrayHandle
///
VTKM_CONT
vtkm::cont::ArrayHandle<ValueType, StorageTag>& operator=(
const vtkm::cont::ArrayHandle<ValueType, StorageTag>& src);
/// \brief Move and Assignment of an ArrayHandle
///
VTKM_CONT
vtkm::cont::ArrayHandle<ValueType, StorageTag>& operator=(
vtkm::cont::ArrayHandle<ValueType, StorageTag>&& src) noexcept;
/// Like a pointer, two \c ArrayHandles are considered equal if they point
/// to the same location in memory.
///
VTKM_CONT
bool operator==(const ArrayHandle<ValueType, StorageTag>& rhs) const
{
return (this->Internals == rhs.Internals);
}
VTKM_CONT
bool operator!=(const ArrayHandle<ValueType, StorageTag>& rhs) const
{
return (this->Internals != rhs.Internals);
}
template <typename VT, typename ST>
VTKM_CONT bool operator==(const ArrayHandle<VT, ST>&) const
{
return false; // different valuetype and/or storage
}
template <typename VT, typename ST>
VTKM_CONT bool operator!=(const ArrayHandle<VT, ST>&) const
{
return true; // different valuetype and/or storage
}
/// Get the storage.
///
VTKM_CONT StorageType& GetStorage();
/// Get the storage.
///
VTKM_CONT const StorageType& GetStorage() const;
/// Get the array portal of the control array.
/// Since worklet invocations are asynchronous and this routine is a synchronization point,
/// exceptions maybe thrown for errors from previously executed worklets.
///
/// \deprecated Use `WritePortal` instead. Note that the portal returned from `WritePortal`
/// will disallow any other reads or writes to the array while it is in scope.
///
VTKM_CONT
VTKM_DEPRECATED(1.6,
"Use ArrayHandle::WritePortal() instead. "
"Note that the returned portal will lock the array while it is in scope.")
/// \cond NOPE
typename StorageType::PortalType GetPortalControl();
/// \endcond
/// Get the array portal of the control array.
/// Since worklet invocations are asynchronous and this routine is a synchronization point,
/// exceptions maybe thrown for errors from previously executed worklets.
///
/// \deprecated Use `ReadPortal` instead. Note that the portal returned from `ReadPortal`
/// will disallow any writes to the array while it is in scope.
///
VTKM_CONT
VTKM_DEPRECATED(1.6,
"Use ArrayHandle::ReadPortal() instead. "
"Note that the returned portal will lock the array while it is in scope.")
/// \cond NOPE
typename StorageType::PortalConstType GetPortalConstControl() const;
/// \endcond
/// \@{
/// \brief Get an array portal that can be used in the control environment.
///
/// The returned array can be used in the control environment to read values from the array. (It
/// is not possible to write to the returned portal. That is `Get` will work on the portal, but
/// `Set` will not.)
///
/// **Note:** The returned portal cannot be used in the execution environment. This is because
/// the portal will not work on some devices like GPUs. To get a portal that will work in the
/// execution environment, use `PrepareForInput`.
///
VTKM_CONT ReadPortalType ReadPortal() const;
/// \@}
/// \@{
/// \brief Get an array portal that can be used in the control environment.
///
/// The returned array can be used in the control environment to reand and write values to the
/// array.
///
///
/// **Note:** The returned portal cannot be used in the execution environment. This is because
/// the portal will not work on some devices like GPUs. To get a portal that will work in the
/// execution environment, use `PrepareForInput`.
///
VTKM_CONT WritePortalType WritePortal() const;
/// \@}
/// Returns the number of entries in the array.
///
VTKM_CONT vtkm::Id GetNumberOfValues() const
{
LockType lock = this->GetLock();
return this->GetNumberOfValues(lock);
}
/// \brief Allocates an array large enough to hold the given number of values.
///
/// The allocation may be done on an already existing array, but can wipe out
/// any data already in the array. This method can throw
/// ErrorBadAllocation if the array cannot be allocated or
/// ErrorBadValue if the allocation is not feasible (for example, the
/// array storage is read-only).
///
VTKM_CONT
void Allocate(vtkm::Id numberOfValues)
{
vtkm::cont::Token token;
this->Allocate(numberOfValues, token);
}
VTKM_CONT void Allocate(vtkm::Id numberOfValues, vtkm::cont::Token& token)
{
LockType lock = this->GetLock();
this->WaitToWrite(lock, token);
this->ReleaseResourcesExecutionInternal(lock, token);
this->Internals->GetControlArray(lock)->Allocate(numberOfValues);
// Set to false and then to true to ensure anything pointing to an array before the allocate
// is invalidated.
this->Internals->SetControlArrayValid(lock, false);
this->Internals->SetControlArrayValid(lock, true);
}
/// \brief Reduces the size of the array without changing its values.
///
/// This method allows you to resize the array without reallocating it. The
/// number of entries in the array is changed to \c numberOfValues. The data
/// in the array (from indices 0 to \c numberOfValues - 1) are the same, but
/// \c numberOfValues must be equal or less than the preexisting size
/// (returned from GetNumberOfValues). That is, this method can only be used
/// to shorten the array, not lengthen.
VTKM_CONT void Shrink(vtkm::Id numberOfValues)
{
vtkm::cont::Token token;
this->Shrink(numberOfValues, token);
}
VTKM_CONT void Shrink(vtkm::Id numberOfValues, vtkm::cont::Token& token);
/// Releases any resources being used in the execution environment (that are
/// not being shared by the control environment).
///
VTKM_CONT void ReleaseResourcesExecution()
{
// A Token should not be declared within the scope of a lock. when the token goes out of scope
// it will attempt to aquire the lock, which is undefined behavior of the thread already has
// the lock.
vtkm::cont::Token token;
{
LockType lock = this->GetLock();
this->WaitToWrite(lock, token);
// Save any data in the execution environment by making sure it is synced
// with the control environment.
this->SyncControlArray(lock, token);
this->ReleaseResourcesExecutionInternal(lock, token);
}
}
/// Releases all resources in both the control and execution environments.
///
VTKM_CONT void ReleaseResources()
{
// A Token should not be declared within the scope of a lock. when the token goes out of scope
// it will attempt to aquire the lock, which is undefined behavior of the thread already has
// the lock.
vtkm::cont::Token token;
{
LockType lock = this->GetLock();
this->ReleaseResourcesExecutionInternal(lock, token);
if (this->Internals->IsControlArrayValid(lock))
{
this->Internals->GetControlArray(lock)->ReleaseResources();
this->Internals->SetControlArrayValid(lock, false);
}
}
}
/// Prepares this array to be used as an input to an operation in the
/// execution environment. If necessary, copies data to the execution
/// environment. Can throw an exception if this array does not yet contain
/// any data. Returns a portal that can be used in code running in the
/// execution environment.
///
/// The `Token` object provided will be attached to this `ArrayHandle`.
/// The returned portal is guaranteed to be valid while the `Token` is
/// still attached and in scope. Other operations on this `ArrayHandle`
/// that would invalidate the returned portal will block until the `Token`
/// is released. Likewise, this method will block if another `Token` is
/// already attached. This can potentially lead to deadlocks.
///
template <typename DeviceAdapterTag>
VTKM_CONT typename ExecutionTypes<DeviceAdapterTag>::PortalConst PrepareForInput(
DeviceAdapterTag,
vtkm::cont::Token& token) const;
/// Prepares (allocates) this array to be used as an output from an operation
/// in the execution environment. The internal state of this class is set to
/// have valid data in the execution array with the assumption that the array
/// will be filled soon (i.e. before any other methods of this object are
/// called). Returns a portal that can be used in code running in the
/// execution environment.
///
/// The `Token` object provided will be attached to this `ArrayHandle`.
/// The returned portal is guaranteed to be valid while the `Token` is
/// still attached and in scope. Other operations on this `ArrayHandle`
/// that would invalidate the returned portal will block until the `Token`
/// is released. Likewise, this method will block if another `Token` is
/// already attached. This can potentially lead to deadlocks.
///
template <typename DeviceAdapterTag>
VTKM_CONT typename ExecutionTypes<DeviceAdapterTag>::Portal
PrepareForOutput(vtkm::Id numberOfValues, DeviceAdapterTag, vtkm::cont::Token& token);
/// Prepares this array to be used in an in-place operation (both as input
/// and output) in the execution environment. If necessary, copies data to
/// the execution environment. Can throw an exception if this array does not
/// yet contain any data. Returns a portal that can be used in code running
/// in the execution environment.
///
/// The `Token` object provided will be attached to this `ArrayHandle`.
/// The returned portal is guaranteed to be valid while the `Token` is
/// still attached and in scope. Other operations on this `ArrayHandle`
/// that would invalidate the returned portal will block until the `Token`
/// is released. Likewise, this method will block if another `Token` is
/// already attached. This can potentially lead to deadlocks.
///
template <typename DeviceAdapterTag>
VTKM_CONT typename ExecutionTypes<DeviceAdapterTag>::Portal PrepareForInPlace(
DeviceAdapterTag,
vtkm::cont::Token& token);
template <typename DeviceAdapterTag>
VTKM_CONT VTKM_DEPRECATED(1.6, "PrepareForInput now requires a vtkm::cont::Token object.")
typename ExecutionTypes<DeviceAdapterTag>::PortalConst PrepareForInput(DeviceAdapterTag) const
{
vtkm::cont::Token token;
return this->PrepareForInput(DeviceAdapterTag{}, token);
}
template <typename DeviceAdapterTag>
VTKM_CONT VTKM_DEPRECATED(1.6, "PrepareForOutput now requires a vtkm::cont::Token object.")
typename ExecutionTypes<DeviceAdapterTag>::Portal
PrepareForOutput(vtkm::Id numberOfValues, DeviceAdapterTag)
{
vtkm::cont::Token token;
return this->PrepareForOutput(numberOfValues, DeviceAdapterTag{}, token);
}
template <typename DeviceAdapterTag>
VTKM_CONT VTKM_DEPRECATED(1.6, "PrepareForInPlace now requires a vtkm::cont::Token object.")
typename ExecutionTypes<DeviceAdapterTag>::Portal PrepareForInPlace(DeviceAdapterTag)
{
vtkm::cont::Token token;
return this->PrepareForInPlace(DeviceAdapterTag{}, token);
}
/// Returns the DeviceAdapterId for the current device. If there is no device
/// with an up-to-date copy of the data, VTKM_DEVICE_ADAPTER_UNDEFINED is
/// returned.
///
/// Note that in a multithreaded environment the validity of this result can
/// change.
VTKM_CONT
DeviceAdapterId GetDeviceAdapterId() const
{
LockType lock = this->GetLock();
return this->Internals->IsExecutionArrayValid(lock)
? this->Internals->GetExecutionArray(lock)->GetDeviceAdapterId()
: DeviceAdapterTagUndefined{};
}
/// Synchronizes the control array with the execution array. If either the
/// user array or control array is already valid, this method does nothing
/// (because the data is already available in the control environment).
/// Although the internal state of this class can change, the method is
/// declared const because logically the data does not.
///
VTKM_CONT void SyncControlArray() const
{
// A Token should not be declared within the scope of a lock. when the token goes out of scope
// it will attempt to aquire the lock, which is undefined behavior of the thread already has
// the lock.
vtkm::cont::Token token;
{
LockType lock = this->GetLock();
this->SyncControlArray(lock, token);
}
}
/// \brief Enqueue a token for access to this ArrayHandle.
///
/// This method places the given `Token` into the queue of `Token`s waiting for
/// access to this `ArrayHandle` and then returns immediately. When this token
/// is later used to get data from this `ArrayHandle` (for example, in a call to
/// `PrepareForInput`), it will use this place in the queue while waiting for
/// access.
///
/// This method is to be used to ensure that a set of accesses to an `ArrayHandle`
/// that happen on multiple threads occur in a specified order. For example, if
/// you spawn of a job to modify data in an `ArrayHandle` and then spawn off a job
/// that reads that same data, you need to make sure that the first job gets
/// access to the `ArrayHandle` before the second. If they both just attempt to call
/// their respective `Prepare` methods, there is no guarantee which order they
/// will occur. Having the spawning thread first call this method will ensure the order.
///
/// \warning After calling this method it is required to subsequently
/// call a method like one of the `Prepare` methods that attaches the token
/// to this `ArrayHandle`. Otherwise, the enqueued token will block any subsequent
/// access to the `ArrayHandle`, even if the `Token` is destroyed.
///
VTKM_CONT void Enqueue(const vtkm::cont::Token& token) const;
private:
/// Acquires a lock on the internals of this `ArrayHandle`. The calling
/// function should keep the returned lock and let it go out of scope
/// when the lock is no longer needed.
///
LockType GetLock() const { return LockType(this->Internals->Mutex); }
/// Returns true if read operations can currently be performed.
///
VTKM_CONT bool CanRead(const LockType& lock, const vtkm::cont::Token& token) const;
//// Returns true if write operations can currently be performed.
///
VTKM_CONT bool CanWrite(const LockType& lock, const vtkm::cont::Token& token) const;
//// Will block the current thread until a read can be performed.
///
VTKM_CONT void WaitToRead(LockType& lock, vtkm::cont::Token& token) const;
//// Will block the current thread until a write can be performed.
///
VTKM_CONT void WaitToWrite(LockType& lock, vtkm::cont::Token& token, bool fakeRead = false) const;
/// Gets this array handle ready to interact with the given device. If the
/// array handle has already interacted with this device, then this method
/// does nothing. Although the internal state of this class can change, the
/// method is declared const because logically the data does not.
///
template <typename DeviceAdapterTag>
VTKM_CONT void PrepareForDevice(LockType& lock, vtkm::cont::Token& token, DeviceAdapterTag) const;
/// Synchronizes the control array with the execution array. If either the
/// user array or control array is already valid, this method does nothing
/// (because the data is already available in the control environment).
/// Although the internal state of this class can change, the method is
/// declared const because logically the data does not.
///
VTKM_CONT void SyncControlArray(LockType& lock, vtkm::cont::Token& token) const;
vtkm::Id GetNumberOfValues(LockType& lock) const;
VTKM_CONT
void ReleaseResourcesExecutionInternal(LockType& lock, vtkm::cont::Token& token) const
{
if (this->Internals->IsExecutionArrayValid(lock))
{
this->WaitToWrite(lock, token);
// Note that it is possible that while waiting someone else deleted the execution array.
// That is why we check again.
}
if (this->Internals->IsExecutionArrayValid(lock))
{
this->Internals->GetExecutionArray(lock)->ReleaseResources();
this->Internals->SetExecutionArrayValid(lock, false);
}
}
VTKM_CONT void Enqueue(const LockType& lock, const vtkm::cont::Token& token) const;
class VTKM_ALWAYS_EXPORT InternalStruct
{
mutable StorageType ControlArray;
mutable std::shared_ptr<bool> ControlArrayValid;
mutable std::unique_ptr<ExecutionManagerType> ExecutionArray;
mutable bool ExecutionArrayValid = false;
mutable vtkm::cont::Token::ReferenceCount ReadCount = 0;
mutable vtkm::cont::Token::ReferenceCount WriteCount = 0;
mutable std::deque<vtkm::cont::Token::Reference> Queue;
VTKM_CONT void CheckLock(const LockType& lock) const
{
VTKM_ASSERT((lock.mutex() == &this->Mutex) && (lock.owns_lock()));
}
public:
MutexType Mutex;
std::condition_variable ConditionVariable;
InternalStruct() = default;
InternalStruct(const StorageType& storage);
InternalStruct(StorageType&& storage);
~InternalStruct()
{
// It should not be possible to destroy this array if any tokens are still attached to it.
LockType lock(this->Mutex);
VTKM_ASSERT((*this->GetReadCount(lock) == 0) && (*this->GetWriteCount(lock) == 0));
this->SetControlArrayValid(lock, false);
}
// To access any feature in InternalStruct, you must have locked the mutex. You have
// to prove it by passing in a reference to a std::unique_lock.
VTKM_CONT bool IsControlArrayValid(const LockType& lock) const
{
this->CheckLock(lock);
if (!this->ControlArrayValid)
{
return false;
}
else
{
return *this->ControlArrayValid;
}
}
VTKM_CONT void SetControlArrayValid(const LockType& lock, bool value)
{
this->CheckLock(lock);
if (IsControlArrayValid(lock) == value)
{
return;
}
if (value) // ControlArrayValid == false or nullptr
{
// If we are changing the valid flag from false to true, then refresh the pointer.
// There may be array portals that already have a reference to the flag. Those portals
// will stay in an invalid state whereas new portals will go to a valid state. To
// handle both conditions, drop the old reference and create a new one.
this->ControlArrayValid.reset(new bool(true));
}
else // value == false and ControlArrayValid == true
{
*this->ControlArrayValid = false;
}
}
VTKM_CONT std::shared_ptr<bool> GetControlArrayValidPointer(const LockType& lock) const
{
this->CheckLock(lock);
return this->ControlArrayValid;
}
VTKM_CONT StorageType* GetControlArray(const LockType& lock) const
{
this->CheckLock(lock);
return &this->ControlArray;
}
VTKM_CONT bool IsExecutionArrayValid(const LockType& lock) const
{
this->CheckLock(lock);
return this->ExecutionArrayValid;
}
VTKM_CONT void SetExecutionArrayValid(const LockType& lock, bool value)
{
this->CheckLock(lock);
this->ExecutionArrayValid = value;
}
VTKM_CONT ExecutionManagerType* GetExecutionArray(const LockType& lock) const
{
this->CheckLock(lock);
return this->ExecutionArray.get();
}
VTKM_CONT void DeleteExecutionArray(const LockType& lock)
{
this->CheckLock(lock);
this->ExecutionArray.reset();
this->ExecutionArrayValid = false;
}
template <typename DeviceAdapterTag>
VTKM_CONT void NewExecutionArray(const LockType& lock, DeviceAdapterTag)
{
VTKM_IS_DEVICE_ADAPTER_TAG(DeviceAdapterTag);
this->CheckLock(lock);
VTKM_ASSERT(this->ExecutionArray == nullptr);
VTKM_ASSERT(!this->ExecutionArrayValid);
this->ExecutionArray.reset(
new vtkm::cont::internal::ArrayHandleExecutionManager<T, StorageTag, DeviceAdapterTag>(
&this->ControlArray));
}
VTKM_CONT vtkm::cont::Token::ReferenceCount* GetReadCount(const LockType& lock) const
{
this->CheckLock(lock);
return &this->ReadCount;
}
VTKM_CONT vtkm::cont::Token::ReferenceCount* GetWriteCount(const LockType& lock) const
{
this->CheckLock(lock);
return &this->WriteCount;
}
VTKM_CONT std::deque<vtkm::cont::Token::Reference>& GetQueue(const LockType& lock) const
{
this->CheckLock(lock);
return this->Queue;
}
};
VTKM_CONT
ArrayHandle(const std::shared_ptr<InternalStruct>& i)
: Internals(i)
{
}
std::shared_ptr<InternalStruct> Internals;
};
namespace detail
{
@ -917,91 +267,31 @@ VTKM_CONT_EXPORT VTKM_CONT vtkm::cont::DeviceAdapterId ArrayHandleGetDeviceAdapt
} // namespace detail
// This macro is used to declare an ArrayHandle that uses the new style of Storage
// that leverages Buffer objects. This macro will go away once ArrayHandle
// is replaced with ArrayHandleNewStyle. To use this macro, first have a declaration
// of the template and then put the macro like this:
//
// template <typename T>
// VTKM_ARRAY_HANDLE_NEW_STYLE(T, vtkm::cont::StorageTagFoo);
//
// Don't forget to use VTKM_PASS_COMMAS if one of the macro arguments contains
// a template with multiple parameters.
#define VTKM_ARRAY_HANDLE_NEW_STYLE(ValueType_, StorageType_) \
class VTKM_ALWAYS_EXPORT ArrayHandle<ValueType_, StorageType_> \
: public ArrayHandleNewStyle<ValueType_, StorageType_> \
{ \
using Superclass = ArrayHandleNewStyle<ValueType_, StorageType_>; \
\
public: \
VTKM_CONT \
ArrayHandle() \
: Superclass() \
{ \
} \
\
VTKM_CONT \
ArrayHandle(const ArrayHandle<ValueType_, StorageType_>& src) \
: Superclass(src) \
{ \
} \
\
VTKM_CONT \
ArrayHandle(ArrayHandle<ValueType_, StorageType_>&& src) noexcept \
: Superclass(std::move(src)) \
{ \
} \
\
VTKM_CONT \
ArrayHandle(const ArrayHandleNewStyle<ValueType_, StorageType_>& src) \
: Superclass(src) \
{ \
} \
\
VTKM_CONT \
ArrayHandle(ArrayHandleNewStyle<ValueType_, StorageType_>&& src) noexcept \
: Superclass(std::move(src)) \
{ \
} \
\
VTKM_CONT ArrayHandle(const vtkm::cont::internal::Buffer* buffers) \
: Superclass(buffers) \
{ \
} \
\
VTKM_CONT ArrayHandle(const std::vector<vtkm::cont::internal::Buffer>& buffers) \
: Superclass(buffers) \
{ \
} \
\
VTKM_CONT ArrayHandle(std::vector<vtkm::cont::internal::Buffer>&& buffers) \
: Superclass(std::move(buffers)) \
{ \
} \
\
VTKM_CONT \
ArrayHandle<ValueType_, StorageType_>& operator=( \
const ArrayHandle<ValueType_, StorageType_>& src) \
{ \
this->Superclass::operator=(src); \
return *this; \
} \
\
VTKM_CONT \
ArrayHandle<ValueType_, StorageType_>& operator=( \
ArrayHandle<ValueType_, StorageType_>&& src) noexcept \
{ \
this->Superclass::operator=(std::move(src)); \
return *this; \
} \
\
VTKM_CONT ~ArrayHandle() {} \
}
/// This new style of ArrayHandle will eventually replace the classic ArrayHandle
/// \brief Manages an array-worth of data.
///
/// `ArrayHandle` manages as array of data that can be manipulated by VTKm
/// algorithms. The `ArrayHandle` may have up to two copies of the array, one
/// for the control environment and one for the execution environment, although
/// depending on the device and how the array is being used, the `ArrayHandle`
/// will only have one copy when possible.
///
/// An `ArrayHandle` is often constructed by instantiating one of the `ArrayHandle`
/// subclasses. Several basic `ArrayHandle` types can also be constructed directly
/// and then allocated. The `ArrayHandleBasic` subclass provides mechanisms for
/// importing user arrays into an `ArrayHandle`.
///
/// `ArrayHandle` behaves like a shared smart pointer in that when it is copied
/// each copy holds a reference to the same array. These copies are reference
/// counted so that when all copies of the `ArrayHandle` are destroyed, any
/// allocated memory is released.
///
template <typename T, typename StorageTag_ = VTKM_DEFAULT_STORAGE_TAG>
class VTKM_ALWAYS_EXPORT ArrayHandleNewStyle : public internal::ArrayHandleBase
class VTKM_ALWAYS_EXPORT ArrayHandle : public internal::ArrayHandleBase
{
VTKM_STATIC_ASSERT_MSG(
(internal::IsValidArrayHandle<T, StorageTag_>::value),
"Attempted to create an ArrayHandle with an invalid type/storage combination.");
public:
using ValueType = T;
using StorageTag = StorageTag_;
@ -1025,7 +315,7 @@ public:
/// Constructs an empty ArrayHandle.
///
VTKM_CONT ArrayHandleNewStyle()
VTKM_CONT ArrayHandle()
: Buffers(static_cast<std::size_t>(StorageType::GetNumberOfBuffers()))
{
}
@ -1037,7 +327,7 @@ public:
/// with CUDA), then the automatically generated copy constructor could be
/// created for all devices, and it would not be valid for all devices.
///
VTKM_CONT ArrayHandleNewStyle(const vtkm::cont::ArrayHandleNewStyle<ValueType, StorageTag>& src)
VTKM_CONT ArrayHandle(const vtkm::cont::ArrayHandle<ValueType, StorageTag>& src)
: Buffers(src.Buffers)
{
}
@ -1049,8 +339,7 @@ public:
/// with CUDA), then the automatically generated move constructor could be
/// created for all devices, and it would not be valid for all devices.
///
VTKM_CONT ArrayHandleNewStyle(
vtkm::cont::ArrayHandleNewStyle<ValueType, StorageTag>&& src) noexcept
VTKM_CONT ArrayHandle(vtkm::cont::ArrayHandle<ValueType, StorageTag>&& src) noexcept
: Buffers(std::move(src.Buffers))
{
}
@ -1059,19 +348,19 @@ public:
/// Special constructor for subclass specializations that need to set the
/// initial state array. Used when pulling data from other sources.
///
VTKM_CONT ArrayHandleNewStyle(const std::vector<vtkm::cont::internal::Buffer>& buffers)
VTKM_CONT ArrayHandle(const std::vector<vtkm::cont::internal::Buffer>& buffers)
: Buffers(buffers)
{
VTKM_ASSERT(static_cast<vtkm::IdComponent>(this->Buffers.size()) == this->GetNumberOfBuffers());
}
VTKM_CONT ArrayHandleNewStyle(std::vector<vtkm::cont::internal::Buffer>&& buffers) noexcept
VTKM_CONT ArrayHandle(std::vector<vtkm::cont::internal::Buffer>&& buffers) noexcept
: Buffers(std::move(buffers))
{
VTKM_ASSERT(static_cast<vtkm::IdComponent>(this->Buffers.size()) == this->GetNumberOfBuffers());
}
VTKM_CONT ArrayHandleNewStyle(const vtkm::cont::internal::Buffer* buffers)
VTKM_CONT ArrayHandle(const vtkm::cont::internal::Buffer* buffers)
: Buffers(buffers, buffers + StorageType::GetNumberOfBuffers())
{
}
@ -1084,13 +373,13 @@ public:
/// with CUDA), then the automatically generated destructor could be
/// created for all devices, and it would not be valid for all devices.
///
VTKM_CONT ~ArrayHandleNewStyle() {}
VTKM_CONT ~ArrayHandle() {}
/// \brief Copies an ArrayHandle
///
VTKM_CONT
vtkm::cont::ArrayHandleNewStyle<ValueType, StorageTag>& operator=(
const vtkm::cont::ArrayHandleNewStyle<ValueType, StorageTag>& src)
vtkm::cont::ArrayHandle<ValueType, StorageTag>& operator=(
const vtkm::cont::ArrayHandle<ValueType, StorageTag>& src)
{
this->Buffers = src.Buffers;
return *this;
@ -1099,8 +388,8 @@ public:
/// \brief Move and Assignment of an ArrayHandle
///
VTKM_CONT
vtkm::cont::ArrayHandleNewStyle<ValueType, StorageTag>& operator=(
vtkm::cont::ArrayHandleNewStyle<ValueType, StorageTag>&& src) noexcept
vtkm::cont::ArrayHandle<ValueType, StorageTag>& operator=(
vtkm::cont::ArrayHandle<ValueType, StorageTag>&& src) noexcept
{
this->Buffers = std::move(src.Buffers);
return *this;
@ -1411,8 +700,7 @@ public:
///
/// Takes the data that is in \a source and copies that data into this array.
///
VTKM_CONT void DeepCopyFrom(
const vtkm::cont::ArrayHandleNewStyle<ValueType, StorageTag>& source) const
VTKM_CONT void DeepCopyFrom(const vtkm::cont::ArrayHandle<ValueType, StorageTag>& source) const
{
VTKM_ASSERT(this->Buffers.size() == source.Buffers.size());
@ -1667,8 +955,4 @@ VTKM_CONT inline std::vector<vtkm::cont::internal::Buffer> CreateBuffers(const A
#include <vtkm/cont/ArrayHandleBasic.h>
#endif
#ifndef vtk_m_cont_ArrayHandle_hxx
#include <vtkm/cont/ArrayHandle.hxx>
#endif
#endif //vtk_m_cont_ArrayHandle_h

@ -1,596 +0,0 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
//
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//============================================================================
#ifndef vtk_m_cont_ArrayHandle_hxx
#define vtk_m_cont_ArrayHandle_hxx
#include <vtkm/cont/ArrayHandle.h>
namespace vtkm
{
namespace cont
{
template <typename T, typename S>
ArrayHandle<T, S>::InternalStruct::InternalStruct(
const typename ArrayHandle<T, S>::StorageType& storage)
: ControlArray(storage)
, ControlArrayValid(new bool(true))
, ExecutionArrayValid(false)
{
}
template <typename T, typename S>
ArrayHandle<T, S>::InternalStruct::InternalStruct(typename ArrayHandle<T, S>::StorageType&& storage)
: ControlArray(std::move(storage))
, ControlArrayValid(new bool(true))
, ExecutionArrayValid(false)
{
}
template <typename T, typename S>
ArrayHandle<T, S>::ArrayHandle()
: Internals(std::make_shared<InternalStruct>())
{
}
template <typename T, typename S>
ArrayHandle<T, S>::ArrayHandle(const ArrayHandle<T, S>& src)
: Internals(src.Internals)
{
}
template <typename T, typename S>
ArrayHandle<T, S>::ArrayHandle(ArrayHandle<T, S>&& src) noexcept
: Internals(std::move(src.Internals))
{
}
template <typename T, typename S>
ArrayHandle<T, S>::ArrayHandle(const typename ArrayHandle<T, S>::StorageType& storage)
: Internals(std::make_shared<InternalStruct>(storage))
{
}
template <typename T, typename S>
ArrayHandle<T, S>::ArrayHandle(typename ArrayHandle<T, S>::StorageType&& storage) noexcept
: Internals(std::make_shared<InternalStruct>(std::move(storage)))
{
}
template <typename T, typename S>
ArrayHandle<T, S>::~ArrayHandle()
{
}
template <typename T, typename S>
ArrayHandle<T, S>& ArrayHandle<T, S>::operator=(const ArrayHandle<T, S>& src)
{
this->Internals = src.Internals;
return *this;
}
template <typename T, typename S>
ArrayHandle<T, S>& ArrayHandle<T, S>::operator=(ArrayHandle<T, S>&& src) noexcept
{
this->Internals = std::move(src.Internals);
return *this;
}
template <typename T, typename S>
typename ArrayHandle<T, S>::StorageType& ArrayHandle<T, S>::GetStorage()
{
// A Token should not be declared within the scope of a lock. when the token goes out of scope
// it will attempt to aquire the lock, which is undefined behavior of the thread already has
// the lock.
vtkm::cont::Token token;
{
LockType lock = this->GetLock();
this->SyncControlArray(lock, token);
if (this->Internals->IsControlArrayValid(lock))
{
return *this->Internals->GetControlArray(lock);
}
else
{
throw vtkm::cont::ErrorInternal(
"ArrayHandle::SyncControlArray did not make control array valid.");
}
}
}
template <typename T, typename S>
const typename ArrayHandle<T, S>::StorageType& ArrayHandle<T, S>::GetStorage() const
{
// A Token should not be declared within the scope of a lock. when the token goes out of scope
// it will attempt to aquire the lock, which is undefined behavior of the thread already has
// the lock.
vtkm::cont::Token token;
{
LockType lock = this->GetLock();
this->SyncControlArray(lock, token);
if (this->Internals->IsControlArrayValid(lock))
{
return *this->Internals->GetControlArray(lock);
}
else
{
throw vtkm::cont::ErrorInternal(
"ArrayHandle::SyncControlArray did not make control array valid.");
}
}
}
template <typename T, typename S>
typename ArrayHandle<T, S>::StorageType::PortalType ArrayHandle<T, S>::GetPortalControl()
{
// A Token should not be declared within the scope of a lock. when the token goes out of scope
// it will attempt to aquire the lock, which is undefined behavior of the thread already has
// the lock.
vtkm::cont::Token token;
{
LockType lock = this->GetLock();
this->SyncControlArray(lock, token);
if (this->Internals->IsControlArrayValid(lock))
{
// If the user writes into the iterator we return, then the execution
// array will become invalid. Play it safe and release the execution
// resources. (Use the const version to preserve the execution array.)
this->ReleaseResourcesExecutionInternal(lock, token);
return this->Internals->GetControlArray(lock)->GetPortal();
}
else
{
throw vtkm::cont::ErrorInternal(
"ArrayHandle::SyncControlArray did not make control array valid.");
}
}
}
template <typename T, typename S>
typename ArrayHandle<T, S>::StorageType::PortalConstType ArrayHandle<T, S>::GetPortalConstControl()
const
{
// A Token should not be declared within the scope of a lock. when the token goes out of scope
// it will attempt to aquire the lock, which is undefined behavior of the thread already has
// the lock.
vtkm::cont::Token token;
{
LockType lock = this->GetLock();
this->SyncControlArray(lock, token);
if (this->Internals->IsControlArrayValid(lock))
{
return this->Internals->GetControlArray(lock)->GetPortalConst();
}
else
{
throw vtkm::cont::ErrorInternal(
"ArrayHandle::SyncControlArray did not make control array valid.");
}
}
}
template <typename T, typename S>
typename ArrayHandle<T, S>::ReadPortalType ArrayHandle<T, S>::ReadPortal() const
{
// A Token should not be declared within the scope of a lock. when the token goes out of scope
// it will attempt to aquire the lock, which is undefined behavior of the thread already has
// the lock.
vtkm::cont::Token token;
{
LockType lock = this->GetLock();
this->WaitToRead(lock, token);
this->SyncControlArray(lock, token);
if (this->Internals->IsControlArrayValid(lock))
{
return ReadPortalType(this->Internals->GetControlArray(lock)->GetPortalConst());
}
else
{
throw vtkm::cont::ErrorInternal(
"ArrayHandle::SyncControlArray did not make control array valid.");
}
}
}
template <typename T, typename S>
typename ArrayHandle<T, S>::WritePortalType ArrayHandle<T, S>::WritePortal() const
{
// A Token should not be declared within the scope of a lock. when the token goes out of scope
// it will attempt to aquire the lock, which is undefined behavior of the thread already has
// the lock.
vtkm::cont::Token token;
{
LockType lock = this->GetLock();
this->WaitToWrite(lock, token);
this->SyncControlArray(lock, token);
if (this->Internals->IsControlArrayValid(lock))
{
// If the user writes into the iterator we return, then the execution
// array will become invalid. Play it safe and release the execution
// resources. (Use the const version to preserve the execution array.)
this->ReleaseResourcesExecutionInternal(lock, token);
return WritePortalType(this->Internals->GetControlArray(lock)->GetPortal());
}
else
{
throw vtkm::cont::ErrorInternal(
"ArrayHandle::SyncControlArray did not make control array valid.");
}
}
}
template <typename T, typename S>
vtkm::Id ArrayHandle<T, S>::GetNumberOfValues(LockType& lock) const
{
if (this->Internals->IsControlArrayValid(lock))
{
return this->Internals->GetControlArray(lock)->GetNumberOfValues();
}
else if (this->Internals->IsExecutionArrayValid(lock))
{
return this->Internals->GetExecutionArray(lock)->GetNumberOfValues();
}
else
{
return 0;
}
}
template <typename T, typename S>
void ArrayHandle<T, S>::Shrink(vtkm::Id numberOfValues, vtkm::cont::Token& token)
{
VTKM_ASSERT(numberOfValues >= 0);
if (numberOfValues > 0)
{
LockType lock = this->GetLock();
vtkm::Id originalNumberOfValues = this->GetNumberOfValues(lock);
if (numberOfValues < originalNumberOfValues)
{
this->WaitToWrite(lock, token);
if (this->Internals->IsControlArrayValid(lock))
{
this->Internals->GetControlArray(lock)->Shrink(numberOfValues);
}
if (this->Internals->IsExecutionArrayValid(lock))
{
this->Internals->GetExecutionArray(lock)->Shrink(numberOfValues);
}
}
else if (numberOfValues == originalNumberOfValues)
{
// Nothing to do.
}
else // numberOfValues > originalNumberOfValues
{
throw vtkm::cont::ErrorBadValue("ArrayHandle::Shrink cannot be used to grow array.");
}
VTKM_ASSERT(this->GetNumberOfValues(lock) == numberOfValues);
}
else // numberOfValues == 0
{
// If we are shrinking to 0, there is nothing to save and we might as well
// free up memory. Plus, some storage classes expect that data will be
// deallocated when the size goes to zero.
this->Allocate(0, token);
}
}
template <typename T, typename S>
template <typename DeviceAdapterTag>
typename ArrayHandle<T, S>::template ExecutionTypes<DeviceAdapterTag>::PortalConst
ArrayHandle<T, S>::PrepareForInput(DeviceAdapterTag device, vtkm::cont::Token& token) const
{
VTKM_IS_DEVICE_ADAPTER_TAG(DeviceAdapterTag);
LockType lock = this->GetLock();
this->WaitToRead(lock, token);
if (!this->Internals->IsControlArrayValid(lock) && !this->Internals->IsExecutionArrayValid(lock))
{
// Want to use an empty array.
// Set up ArrayHandle state so this actually works.
this->Internals->GetControlArray(lock)->Allocate(0);
this->Internals->SetControlArrayValid(lock, true);
}
this->PrepareForDevice(lock, token, device);
auto portal = this->Internals->GetExecutionArray(lock)->PrepareForInput(
!this->Internals->IsExecutionArrayValid(lock), device, token);
this->Internals->SetExecutionArrayValid(lock, true);
return portal;
}
template <typename T, typename S>
template <typename DeviceAdapterTag>
typename ArrayHandle<T, S>::template ExecutionTypes<DeviceAdapterTag>::Portal
ArrayHandle<T, S>::PrepareForOutput(vtkm::Id numberOfValues,
DeviceAdapterTag device,
vtkm::cont::Token& token)
{
VTKM_IS_DEVICE_ADAPTER_TAG(DeviceAdapterTag);
LockType lock = this->GetLock();
this->WaitToWrite(lock, token);
// Invalidate any control arrays.
// Should the control array resource be released? Probably not a good
// idea when shared with execution.
this->Internals->SetControlArrayValid(lock, false);
this->PrepareForDevice(lock, token, device);
auto portal =
this->Internals->GetExecutionArray(lock)->PrepareForOutput(numberOfValues, device, token);
// We are assuming that the calling code will fill the array using the
// iterators we are returning, so go ahead and mark the execution array as
// having valid data. (A previous version of this class had a separate call
// to mark the array as filled, but that was onerous to call at the the
// right time and rather pointless since it is basically always the case
// that the array is going to be filled before anything else. In this
// implementation the only access to the array is through the iterators
// returned from this method, so you would have to work to invalidate this
// assumption anyway.)
this->Internals->SetExecutionArrayValid(lock, true);
return portal;
}
template <typename T, typename S>
template <typename DeviceAdapterTag>
typename ArrayHandle<T, S>::template ExecutionTypes<DeviceAdapterTag>::Portal
ArrayHandle<T, S>::PrepareForInPlace(DeviceAdapterTag device, vtkm::cont::Token& token)
{
VTKM_IS_DEVICE_ADAPTER_TAG(DeviceAdapterTag);
LockType lock = this->GetLock();
this->WaitToWrite(lock, token);
if (!this->Internals->IsControlArrayValid(lock) && !this->Internals->IsExecutionArrayValid(lock))
{
// Want to use an empty array.
// Set up ArrayHandle state so this actually works.
this->Internals->GetControlArray(lock)->Allocate(0);
this->Internals->SetControlArrayValid(lock, true);
}
this->PrepareForDevice(lock, token, device);
auto portal = this->Internals->GetExecutionArray(lock)->PrepareForInPlace(
!this->Internals->IsExecutionArrayValid(lock), device, token);
this->Internals->SetExecutionArrayValid(lock, true);
// Invalidate any control arrays since their data will become invalid when
// the execution data is overwritten. Don't actually release the control
// array. It may be shared as the execution array.
this->Internals->SetControlArrayValid(lock, false);
return portal;
}
template <typename T, typename S>
template <typename DeviceAdapterTag>
void ArrayHandle<T, S>::PrepareForDevice(LockType& lock,
vtkm::cont::Token& token,
DeviceAdapterTag device) const
{
if (this->Internals->GetExecutionArray(lock) != nullptr)
{
if (this->Internals->GetExecutionArray(lock)->IsDeviceAdapter(DeviceAdapterTag()))
{
// Already have manager for correct device adapter. Nothing to do.
return;
}
else
{
// Have the wrong manager. Delete the old one and create a new one
// of the right type. (TODO: it would be possible for the array handle
// to hold references to execution arrays on multiple devices. When data
// are written on one devices, all the other devices should get cleared.)
// BUG: There is a non-zero chance that while waiting for the write lock, another thread
// could change the ExecutionInterface, which would cause problems. In the future we should
// support multiple devices, in which case we would not have to delete one execution array
// to load another.
// BUG: The current implementation does not allow the ArrayHandle to be on two devices
// at the same time. Thus, it is not possible for two simultaneously read from the same
// ArrayHandle on two different devices. This might cause unexpected deadlocks.
this->WaitToWrite(lock, token, true); // Make sure no one is reading device array
this->SyncControlArray(lock, token);
// Need to change some state that does not change the logical state from
// an external point of view.
this->Internals->DeleteExecutionArray(lock);
}
}
// Need to change some state that does not change the logical state from
// an external point of view.
this->Internals->NewExecutionArray(lock, device);
}
template <typename T, typename S>
void ArrayHandle<T, S>::SyncControlArray(LockType& lock, vtkm::cont::Token& token) const
{
if (!this->Internals->IsControlArrayValid(lock))
{
// It may be the case that `SyncControlArray` is called from a method that has a `Token`.
// However, if we are here, that `Token` should not already be attached to this array.
// If it were, then there should be no reason to move data arround (unless the `Token`
// was used when preparing for multiple devices, which it should not be used like that).
this->WaitToRead(lock, token);
// Need to change some state that does not change the logical state from
// an external point of view.
if (this->Internals->IsExecutionArrayValid(lock))
{
this->Internals->GetExecutionArray(lock)->RetrieveOutputData(
this->Internals->GetControlArray(lock));
this->Internals->SetControlArrayValid(lock, true);
}
else
{
// This array is in the null state (there is nothing allocated), but
// the calling function wants to do something with the array. Put this
// class into a valid state by allocating an array of size 0.
this->Internals->GetControlArray(lock)->Allocate(0);
this->Internals->SetControlArrayValid(lock, true);
}
}
}
template <typename T, typename S>
bool ArrayHandle<T, S>::CanRead(const LockType& lock, const vtkm::cont::Token& token) const
{
// If the token is already attached to this array, then we allow reading.
if (token.IsAttached(this->Internals->GetWriteCount(lock)) ||
token.IsAttached(this->Internals->GetReadCount(lock)))
{
return true;
}
// If there is anyone else waiting at the top of the queue, we cannot access this array.
auto& queue = this->Internals->GetQueue(lock);
if (!queue.empty() && (queue.front() != token))
{
return false;
}
// No one else is waiting, so we can read the array as long as no one else is writing.
return (*this->Internals->GetWriteCount(lock) < 1);
}
template <typename T, typename S>
bool ArrayHandle<T, S>::CanWrite(const LockType& lock, const vtkm::cont::Token& token) const
{
// If the token is already attached to this array, then we allow writing.
if (token.IsAttached(this->Internals->GetWriteCount(lock)) ||
token.IsAttached(this->Internals->GetReadCount(lock)))
{
return true;
}
// If there is anyone else waiting at the top of the queue, we cannot access this array.
auto& queue = this->Internals->GetQueue(lock);
if (!queue.empty() && (queue.front() != token))
{
return false;
}
// No one else is waiting, so we can write the array as long as no one else is reading or writing.
return ((*this->Internals->GetWriteCount(lock) < 1) &&
(*this->Internals->GetReadCount(lock) < 1));
}
template <typename T, typename S>
void ArrayHandle<T, S>::WaitToRead(LockType& lock, vtkm::cont::Token& token) const
{
this->Enqueue(lock, token);
// Note that if you deadlocked here, that means that you are trying to do a read operation on an
// array where an object is writing to it.
this->Internals->ConditionVariable.wait(
lock, [&lock, &token, this] { return this->CanRead(lock, token); });
token.Attach(this->Internals,
this->Internals->GetReadCount(lock),
lock,
&this->Internals->ConditionVariable);
// We successfully attached the token. Pop it off the queue.
auto& queue = this->Internals->GetQueue(lock);
if (!queue.empty() && queue.front() == token)
{
queue.pop_front();
}
}
template <typename T, typename S>
void ArrayHandle<T, S>::WaitToWrite(LockType& lock, vtkm::cont::Token& token, bool fakeRead) const
{
this->Enqueue(lock, token);
// Note that if you deadlocked here, that means that you are trying to do a write operation on an
// array where an object is reading or writing to it.
this->Internals->ConditionVariable.wait(
lock, [&lock, &token, this] { return this->CanWrite(lock, token); });
if (!fakeRead)
{
token.Attach(this->Internals,
this->Internals->GetWriteCount(lock),
lock,
&this->Internals->ConditionVariable);
}
else
{
// A current feature limitation of ArrayHandle is that it can only exist on one device at
// a time. Thus, if a read request comes in for a different device, the prepare has to
// get satisfy a write lock to boot the array off the existing device. However, we don't
// want to attach the Token as a write lock because the resulting state is for reading only
// and others might also want to read. So, we have to pretend that this is a read lock even
// though we have to make a change to the array.
//
// The main point is, this condition is a hack that should go away once ArrayHandle supports
// multiple devices at once.
token.Attach(this->Internals,
this->Internals->GetReadCount(lock),
lock,
&this->Internals->ConditionVariable);
}
// We successfully attached the token. Pop it off the queue.
auto& queue = this->Internals->GetQueue(lock);
if (!queue.empty() && queue.front() == token)
{
queue.pop_front();
}
}
template <typename T, typename S>
void ArrayHandle<T, S>::Enqueue(const vtkm::cont::Token& token) const
{
LockType lock = this->GetLock();
this->Enqueue(lock, token);
}
template <typename T, typename S>
void ArrayHandle<T, S>::Enqueue(const LockType& lock, const vtkm::cont::Token& token) const
{
if (token.IsAttached(this->Internals->GetWriteCount(lock)) ||
token.IsAttached(this->Internals->GetReadCount(lock)))
{
// Do not need to enqueue if we are already attached.
return;
}
auto& queue = this->Internals->GetQueue(lock);
if (std::find(queue.begin(), queue.end(), token.GetReference()) != queue.end())
{
// This token is already in the queue.
return;
}
this->Internals->GetQueue(lock).push_back(token.GetReference());
}
}
} // vtkm::cont
#endif //vtk_m_cont_ArrayHandle_hxx

@ -41,11 +41,11 @@ VTKM_STORAGE_INSTANTIATE(vtkm::Float64)
} // namespace internal
#define VTKM_ARRAYHANDLE_INSTANTIATE(Type) \
template class VTKM_CONT_EXPORT ArrayHandleNewStyle<Type, StorageTagBasic>; \
template class VTKM_CONT_EXPORT ArrayHandleNewStyle<vtkm::Vec<Type, 2>, StorageTagBasic>; \
template class VTKM_CONT_EXPORT ArrayHandleNewStyle<vtkm::Vec<Type, 3>, StorageTagBasic>; \
template class VTKM_CONT_EXPORT ArrayHandleNewStyle<vtkm::Vec<Type, 4>, StorageTagBasic>;
#define VTKM_ARRAYHANDLE_INSTANTIATE(Type) \
template class VTKM_CONT_EXPORT ArrayHandle<Type, StorageTagBasic>; \
template class VTKM_CONT_EXPORT ArrayHandle<vtkm::Vec<Type, 2>, StorageTagBasic>; \
template class VTKM_CONT_EXPORT ArrayHandle<vtkm::Vec<Type, 3>, StorageTagBasic>; \
template class VTKM_CONT_EXPORT ArrayHandle<vtkm::Vec<Type, 4>, StorageTagBasic>;
VTKM_ARRAYHANDLE_INSTANTIATE(char)
VTKM_ARRAYHANDLE_INSTANTIATE(vtkm::Int8)

@ -11,6 +11,7 @@
#define vtk_m_cont_ArrayHandleBasic_h
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ArrayPortalToIterators.h>
#include <vtkm/cont/SerializableTypeString.h>
#include <vtkm/cont/Serialization.h>
#include <vtkm/cont/Storage.h>
@ -70,9 +71,6 @@ public:
} // namespace internal
template <typename T>
VTKM_ARRAY_HANDLE_NEW_STYLE(T, vtkm::cont::StorageTagBasic);
template <typename T>
class VTKM_ALWAYS_EXPORT ArrayHandleBasic : public ArrayHandle<T, vtkm::cont::StorageTagBasic>
{
@ -383,14 +381,13 @@ VTKM_STORAGE_EXPORT(vtkm::Float64)
} // namespace internal
#define VTKM_ARRAYHANDLE_EXPORT(Type) \
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandleNewStyle<Type, StorageTagBasic>; \
extern template class VTKM_CONT_TEMPLATE_EXPORT \
ArrayHandleNewStyle<vtkm::Vec<Type, 2>, StorageTagBasic>; \
extern template class VTKM_CONT_TEMPLATE_EXPORT \
ArrayHandleNewStyle<vtkm::Vec<Type, 3>, StorageTagBasic>; \
extern template class VTKM_CONT_TEMPLATE_EXPORT \
ArrayHandleNewStyle<vtkm::Vec<Type, 4>, StorageTagBasic>;
#define VTKM_ARRAYHANDLE_EXPORT(Type) \
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandle<Type, StorageTagBasic>; \
extern template class VTKM_CONT_TEMPLATE_EXPORT \
ArrayHandle<vtkm::Vec<Type, 2>, StorageTagBasic>; \
extern template class VTKM_CONT_TEMPLATE_EXPORT \
ArrayHandle<vtkm::Vec<Type, 3>, StorageTagBasic>; \
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandle<vtkm::Vec<Type, 4>, StorageTagBasic>;
VTKM_ARRAYHANDLE_EXPORT(char)
VTKM_ARRAYHANDLE_EXPORT(vtkm::Int8)

@ -136,9 +136,6 @@ public:
} // end namespace internal
template <typename T>
VTKM_ARRAY_HANDLE_NEW_STYLE(T, vtkm::cont::internal::StorageTagBitField);
/// The ArrayHandleBitField class is a boolean-valued ArrayHandle that is backed
/// by a BitField.
///

@ -284,11 +284,6 @@ public:
};
} // namespace internal
template <typename T, typename ST1, typename ST2, typename ST3>
VTKM_ARRAY_HANDLE_NEW_STYLE(
T,
VTKM_PASS_COMMAS(vtkm::cont::StorageTagCartesianProduct<ST1, ST2, ST3>));
/// 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.

@ -131,9 +131,6 @@ struct Storage<TargetT, vtkm::cont::StorageTagCast<SourceT, SourceStorage_>>
} // namespace internal
template <typename T1, typename T2, typename S>
VTKM_ARRAY_HANDLE_NEW_STYLE(T1, VTKM_PASS_COMMAS(vtkm::cont::StorageTagCast<T2, S>));
/// \brief Cast the values of an array to the specified type, on demand.
///
/// ArrayHandleCast is a specialization of ArrayHandleTransform. Given an ArrayHandle

@ -402,9 +402,6 @@ struct Storage<T, vtkm::cont::StorageTagCompositeVec<StorageTag>> : Storage<T, S
} // namespace internal
template <typename T, typename... Ss>
VTKM_ARRAY_HANDLE_NEW_STYLE(T, vtkm::cont::StorageTagCompositeVec<Ss...>);
/// \brief An \c ArrayHandle that combines components from other arrays.
///
/// \c ArrayHandleCompositeVector is a specialization of \c ArrayHandle that

@ -245,9 +245,6 @@ namespace vtkm
namespace cont
{
template <typename T, typename S1, typename S2>
VTKM_ARRAY_HANDLE_NEW_STYLE(T, VTKM_PASS_COMMAS(StorageTagConcatenate<S1, S2>));
template <typename ArrayHandleType1, typename ArrayHandleType2>
class ArrayHandleConcatenate
: public vtkm::cont::ArrayHandle<typename ArrayHandleType1::ValueType,

@ -51,9 +51,6 @@ struct Storage<T, vtkm::cont::StorageTagConstant> : Storage<T, StorageTagConstan
} // namespace internal
template <typename T>
VTKM_ARRAY_HANDLE_NEW_STYLE(T, vtkm::cont::StorageTagConstant);
/// \brief An array handle with a constant value.
///
/// ArrayHandleConstant is an implicit array handle with a constant value. A

@ -12,6 +12,7 @@
#include <vtkm/cont/ArrayHandleImplicit.h>
#include <vtkm/TypeTraits.h>
#include <vtkm/VecTraits.h>
namespace vtkm
@ -72,20 +73,53 @@ private:
vtkm::Id NumberOfValues;
};
namespace detail
{
template <typename T, typename UseVecTraits = vtkm::HasVecTraits<T>>
struct CanCountImpl;
template <typename T>
struct CanCountImpl<T, std::false_type>
{
using TTraits = vtkm::TypeTraits<T>;
static constexpr bool IsNumeric =
!std::is_same<typename TTraits::NumericTag, vtkm::TypeTraitsUnknownTag>::value;
static constexpr bool value = IsNumeric;
};
template <typename T>
struct CanCountImpl<T, std::true_type>
{
using VTraits = vtkm::VecTraits<T>;
using BaseType = typename VTraits::BaseComponentType;
static constexpr bool IsBool = std::is_same<BaseType, bool>::value;
static constexpr bool value = CanCountImpl<BaseType, std::false_type>::value && !IsBool;
};
} // namespace detail
// Not all types can be counted.
template <typename T>
struct CanCount
{
static constexpr bool value = detail::CanCountImpl<T>::value;
};
template <typename T>
using StorageTagCountingSuperclass =
vtkm::cont::StorageTagImplicit<internal::ArrayPortalCounting<T>>;
template <typename T>
struct Storage<T, vtkm::cont::StorageTagCounting> : Storage<T, StorageTagCountingSuperclass<T>>
struct Storage<T, typename std::enable_if<CanCount<T>::value, vtkm::cont::StorageTagCounting>::type>
: Storage<T, StorageTagCountingSuperclass<T>>
{
};
} // namespace internal
template <typename T>
VTKM_ARRAY_HANDLE_NEW_STYLE(T, 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

@ -590,11 +590,6 @@ struct DecoratorHandleTraits
} // namespace internal
template <typename T, typename DecoratorImplT, typename... ArrayTs>
VTKM_ARRAY_HANDLE_NEW_STYLE(
T,
VTKM_PASS_COMMAS(internal::StorageTagDecorator<DecoratorImplT, ArrayTs...>));
/// \brief A fancy ArrayHandle that can be used to modify the results from one
/// or more source ArrayHandle.
///

@ -144,10 +144,6 @@ struct ArrayHandleDiscardTraits
} // end namespace internal
// This can go away once ArrayHandle is replaced with ArrayHandleNewStyle
template <typename T>
VTKM_ARRAY_HANDLE_NEW_STYLE(T, vtkm::cont::internal::StorageTagDiscard);
/// 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.

@ -170,9 +170,6 @@ namespace vtkm
namespace cont
{
template <typename T, typename ArrayT>
VTKM_ARRAY_HANDLE_NEW_STYLE(T, vtkm::cont::StorageTagExtractComponent<ArrayT>);
/// \brief A fancy ArrayHandle that turns a vector array into a scalar array by
/// slicing out a single component of each vector.
///

@ -14,11 +14,17 @@
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/internal/ArrayHandleDeprecated.h>
namespace vtkm
{
namespace cont
{
template <typename T>
VTKM_ARRAY_HANDLE_DEPRECATED(VTKM_PASS_COMMAS(vtkm::Vec<T, 3>),
vtkm::cont::internal::StorageTagExtrude);
template <typename T>
class VTKM_ALWAYS_EXPORT ArrayHandleExtrudeCoords
: public vtkm::cont::ArrayHandle<vtkm::Vec<T, 3>, internal::StorageTagExtrude>

@ -13,11 +13,16 @@
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/StorageExtrude.h>
#include <vtkm/cont/internal/ArrayHandleDeprecated.h>
namespace vtkm
{
namespace cont
{
template <typename T>
VTKM_ARRAY_HANDLE_DEPRECATED(T, vtkm::cont::internal::StorageTagExtrude);
template <typename T>
class VTKM_ALWAYS_EXPORT ArrayHandleExtrudeField
: public vtkm::cont::ArrayHandle<T, internal::StorageTagExtrude>

@ -174,9 +174,6 @@ public:
} // namespace internal
template <typename T, vtkm::IdComponent N, typename S>
VTKM_ARRAY_HANDLE_NEW_STYLE(T, VTKM_PASS_COMMAS(vtkm::cont::StorageTagGroupVec<S, N>));
/// \brief Fancy array handle that groups values into vectors.
///
/// It is sometimes the case that an array is stored such that consecutive

@ -22,8 +22,6 @@
#include <vtkm/Assert.h>
#include <vtkm/VecFromPortal.h>
#include <vtkm/exec/arg/FetchTagArrayDirectOut.h>
namespace vtkm
{
namespace internal
@ -104,49 +102,8 @@ private:
OffsetsPortalType OffsetsPortal;
};
} // namespace internal (in vtkm)
namespace exec
{
namespace arg
{
// We need to override the fetch for output fields using
// ArrayPortalGroupVecVariable because this portal does not behave like most
// ArrayPortals. Usually you ignore the Load and implement the Store. But if
// you ignore the Load, the VecFromPortal gets no portal to set values into.
// Instead, you need to implement the Load to point to the array portal. You
// can also ignore the Store because the data is already set in the array at
// that point.
template <typename ComponentsPortalType, typename OffsetsPortalType>
struct Fetch<vtkm::exec::arg::FetchTagArrayDirectOut,
vtkm::exec::arg::AspectTagDefault,
vtkm::internal::ArrayPortalGroupVecVariable<ComponentsPortalType, OffsetsPortalType>>
{
using ExecObjectType =
vtkm::internal::ArrayPortalGroupVecVariable<ComponentsPortalType, OffsetsPortalType>;
using ValueType = typename ExecObjectType::ValueType;
VTKM_SUPPRESS_EXEC_WARNINGS
template <typename ThreadIndicesType>
VTKM_EXEC ValueType Load(const ThreadIndicesType& indices,
const ExecObjectType& arrayPortal) const
{
return arrayPortal.Get(indices.GetOutputIndex());
}
VTKM_SUPPRESS_EXEC_WARNINGS
template <typename ThreadIndicesType>
VTKM_EXEC void Store(const ThreadIndicesType&, const ExecObjectType&, const ValueType&) const
{
// We can actually ignore this because the VecFromPortal will already have
// set new values in the array.
}
};
}
}
} // namespace vtkm::exec::arg
} // namespace vtkm::internal
namespace vtkm
{
@ -254,9 +211,6 @@ public:
} // namespace internal
template <typename T, typename S1, typename S2>
VTKM_ARRAY_HANDLE_NEW_STYLE(T, VTKM_PASS_COMMAS(vtkm::cont::StorageTagGroupVecVariable<S1, S2>));
/// \brief 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
@ -423,6 +377,10 @@ VTKM_CONT vtkm::cont::ArrayHandle<vtkm::Id> ConvertNumComponentsToOffsets(
}
} // namespace vtkm::cont
//=============================================================================
// Specializations of worklet arguments using ArrayHandleGropuVecVariable
#include <vtkm/exec/arg/FetchTagArrayDirectOutArrayHandleGroupVecVariable.h>
//=============================================================================
// Specializations of serialization related classes
/// @cond SERIALIZATION

@ -160,11 +160,6 @@ struct ArrayHandleImplicitTraits
} // namespace detail
// This can go away once ArrayHandle is replaced with ArrayHandleNewStyle
template <typename PortalType>
VTKM_ARRAY_HANDLE_NEW_STYLE(typename PortalType::ValueType,
vtkm::cont::StorageTagImplicit<PortalType>);
/// \brief An \c ArrayHandle that computes values on the fly.
///
/// \c ArrayHandleImplicit is a specialization of ArrayHandle.

@ -45,9 +45,6 @@ struct Storage<vtkm::Id, vtkm::cont::StorageTagIndex> : Storage<vtkm::Id, Storag
} // namespace internal
template <>
VTKM_ARRAY_HANDLE_NEW_STYLE(vtkm::Id, vtkm::cont::StorageTagIndex);
/// \brief An implicit array handle containing the its own indices.
///
/// \c ArrayHandleIndex is an implicit array handle containing the values

@ -353,9 +353,6 @@ struct ArrayHandleMultiplexerTraits
};
} // namespace detail
template <typename T, typename... Ss>
VTKM_ARRAY_HANDLE_NEW_STYLE(T, vtkm::cont::StorageTagMultiplexer<Ss...>);
/// \brief An ArrayHandle that can behave like several other handles.
///
/// An \c ArrayHandleMultiplexer simply redirects its calls to another \c ArrayHandle. However

@ -172,9 +172,6 @@ public:
} // namespace internal
template <typename T, typename IS, typename VS>
VTKM_ARRAY_HANDLE_NEW_STYLE(T, VTKM_PASS_COMMAS(vtkm::cont::StorageTagPermutation<IS, VS>));
/// \brief Implicitly permutes the values in an array.
///
/// ArrayHandlePermutation is a specialization of ArrayHandle. It takes two

@ -0,0 +1,614 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
//
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//============================================================================
#ifndef vtk_m_cont_ArrayHandleRecombineVec_h
#define vtk_m_cont_ArrayHandleRecombineVec_h
#include <vtkm/cont/ArrayExtractComponent.h>
#include <vtkm/cont/ArrayHandleMultiplexer.h>
#include <vtkm/cont/ArrayHandleStride.h>
#include <vtkm/cont/DeviceAdapterTag.h>
#include <vtkm/VecVariable.h>
#include <vtkm/internal/ArrayPortalValueReference.h>
namespace vtkm
{
namespace internal
{
template <typename PortalType>
class RecombineVec
{
vtkm::VecCConst<PortalType> Portals;
vtkm::Id Index;
public:
using ComponentType = typename std::remove_const<typename PortalType::ValueType>::type;
RecombineVec(const RecombineVec&) = default;
VTKM_EXEC_CONT RecombineVec(const vtkm::VecCConst<PortalType>& portals, vtkm::Id index)
: Portals(portals)
, Index(index)
{
}
VTKM_EXEC_CONT vtkm::IdComponent GetNumberOfComponents() const
{
return this->Portals.GetNumberOfComponents();
}
VTKM_EXEC_CONT
vtkm::internal::ArrayPortalValueReference<PortalType> operator[](vtkm::IdComponent cIndex) const
{
return vtkm::internal::ArrayPortalValueReference<PortalType>(this->Portals[cIndex],
this->Index);
}
template <typename T, vtkm::IdComponent DestSize>
VTKM_EXEC_CONT void CopyInto(vtkm::Vec<T, DestSize>& dest) const
{
vtkm::IdComponent numComponents = vtkm::Min(DestSize, this->GetNumberOfComponents());
for (vtkm::IdComponent cIndex = 0; cIndex < numComponents; ++cIndex)
{
dest[cIndex] = this->Portals[cIndex].Get(this->Index);
}
// Clear out any components not held by this dynamic Vec-like
for (vtkm::IdComponent cIndex = numComponents; cIndex < DestSize; ++cIndex)
{
dest[cIndex] = vtkm::TypeTraits<T>::ZeroInitialization();
}
}
VTKM_EXEC_CONT vtkm::Id GetIndex() const { return this->Index; }
VTKM_EXEC_CONT RecombineVec& operator=(const RecombineVec& src)
{
this->DoCopy(src);
return *this;
}
template <typename T, typename = typename std::enable_if<vtkm::HasVecTraits<T>::value>::type>
VTKM_EXEC_CONT RecombineVec& operator=(const T& src)
{
this->DoCopy(src);
return *this;
}
VTKM_EXEC_CONT operator ComponentType() const { return this->Portals[0].Get(this->Index); }
template <vtkm::IdComponent N>
VTKM_EXEC_CONT operator vtkm::Vec<ComponentType, N>() const
{
vtkm::Vec<ComponentType, N> result;
this->CopyInto(result);
return result;
}
template <typename T, typename = typename std::enable_if<vtkm::HasVecTraits<T>::value>::type>
VTKM_EXEC_CONT RecombineVec& operator+=(const T& src)
{
using VTraits = vtkm::VecTraits<T>;
VTKM_ASSERT(this->GetNumberOfComponents() == VTraits::GetNumberOfComponents(src));
for (vtkm::IdComponent cIndex = 0; cIndex < this->GetNumberOfComponents(); ++cIndex)
{
(*this)[cIndex] += VTraits::GetComponent(src, cIndex);
}
return *this;
}
template <typename T, typename = typename std::enable_if<vtkm::HasVecTraits<T>::value>::type>
VTKM_EXEC_CONT RecombineVec& operator-=(const T& src)
{
using VTraits = vtkm::VecTraits<T>;
VTKM_ASSERT(this->GetNumberOfComponents() == VTraits::GetNumberOfComponents(src));
for (vtkm::IdComponent cIndex = 0; cIndex < this->GetNumberOfComponents(); ++cIndex)
{
(*this)[cIndex] -= VTraits::GetComponent(src, cIndex);
}
return *this;
}
template <typename T, typename = typename std::enable_if<vtkm::HasVecTraits<T>::value>::type>
VTKM_EXEC_CONT RecombineVec& operator*=(const T& src)
{
using VTraits = vtkm::VecTraits<T>;
VTKM_ASSERT(this->GetNumberOfComponents() == VTraits::GetNumberOfComponents(src));
for (vtkm::IdComponent cIndex = 0; cIndex < this->GetNumberOfComponents(); ++cIndex)
{
(*this)[cIndex] *= VTraits::GetComponent(src, cIndex);
}
return *this;
}
template <typename T, typename = typename std::enable_if<vtkm::HasVecTraits<T>::value>::type>
VTKM_EXEC_CONT RecombineVec& operator/=(const T& src)
{
using VTraits = vtkm::VecTraits<T>;
VTKM_ASSERT(this->GetNumberOfComponents() == VTraits::GetNumberOfComponents(src));
for (vtkm::IdComponent cIndex = 0; cIndex < this->GetNumberOfComponents(); ++cIndex)
{
(*this)[cIndex] /= VTraits::GetComponent(src, cIndex);
}
return *this;
}
template <typename T, typename = typename std::enable_if<vtkm::HasVecTraits<T>::value>::type>
VTKM_EXEC_CONT RecombineVec& operator%=(const T& src)
{
using VTraits = vtkm::VecTraits<T>;
VTKM_ASSERT(this->GetNumberOfComponents() == VTraits::GetNumberOfComponents(src));
for (vtkm::IdComponent cIndex = 0; cIndex < this->GetNumberOfComponents(); ++cIndex)
{
(*this)[cIndex] %= VTraits::GetComponent(src, cIndex);
}
return *this;
}
template <typename T, typename = typename std::enable_if<vtkm::HasVecTraits<T>::value>::type>
VTKM_EXEC_CONT RecombineVec& operator&=(const T& src)
{
using VTraits = vtkm::VecTraits<T>;
VTKM_ASSERT(this->GetNumberOfComponents() == VTraits::GetNumberOfComponents(src));
for (vtkm::IdComponent cIndex = 0; cIndex < this->GetNumberOfComponents(); ++cIndex)
{
(*this)[cIndex] &= VTraits::GetComponent(src, cIndex);
}
return *this;
}
template <typename T, typename = typename std::enable_if<vtkm::HasVecTraits<T>::value>::type>
VTKM_EXEC_CONT RecombineVec& operator|=(const T& src)
{
using VTraits = vtkm::VecTraits<T>;
VTKM_ASSERT(this->GetNumberOfComponents() == VTraits::GetNumberOfComponents(src));
for (vtkm::IdComponent cIndex = 0; cIndex < this->GetNumberOfComponents(); ++cIndex)
{
(*this)[cIndex] |= VTraits::GetComponent(src, cIndex);
}
return *this;
}
template <typename T, typename = typename std::enable_if<vtkm::HasVecTraits<T>::value>::type>
VTKM_EXEC_CONT RecombineVec& operator^=(const T& src)
{
using VTraits = vtkm::VecTraits<T>;
VTKM_ASSERT(this->GetNumberOfComponents() == VTraits::GetNumberOfComponents(src));
for (vtkm::IdComponent cIndex = 0; cIndex < this->GetNumberOfComponents(); ++cIndex)
{
(*this)[cIndex] ^= VTraits::GetComponent(src, cIndex);
}
return *this;
}
template <typename T, typename = typename std::enable_if<vtkm::HasVecTraits<T>::value>::type>
VTKM_EXEC_CONT RecombineVec& operator>>=(const T& src)
{
using VTraits = vtkm::VecTraits<T>;
VTKM_ASSERT(this->GetNumberOfComponents() == VTraits::GetNumberOfComponents(src));
for (vtkm::IdComponent cIndex = 0; cIndex < this->GetNumberOfComponents(); ++cIndex)
{
(*this)[cIndex] >>= VTraits::GetComponent(src, cIndex);
}
return *this;
}
template <typename T, typename = typename std::enable_if<vtkm::HasVecTraits<T>::value>::type>
VTKM_EXEC_CONT RecombineVec& operator<<=(const T& src)
{
using VTraits = vtkm::VecTraits<T>;
VTKM_ASSERT(this->GetNumberOfComponents() == VTraits::GetNumberOfComponents(src));
for (vtkm::IdComponent cIndex = 0; cIndex < this->GetNumberOfComponents(); ++cIndex)
{
(*this)[cIndex] <<= VTraits::GetComponent(src, cIndex);
}
return *this;
}
private:
template <typename T>
VTKM_EXEC_CONT void DoCopy(const T& src)
{
using VTraits = vtkm::VecTraits<T>;
vtkm::IdComponent numComponents = VTraits::GetNumberOfComponents(src);
if (numComponents > 1)
{
if (numComponents > this->GetNumberOfComponents())
{
numComponents = this->GetNumberOfComponents();
}
for (vtkm::IdComponent cIndex = 0; cIndex < numComponents; ++cIndex)
{
this->Portals[cIndex].Set(this->Index, VTraits::GetComponent(src, cIndex));
}
}
else
{
// Special case when copying from a scalar
for (vtkm::IdComponent cIndex = 0; cIndex < this->GetNumberOfComponents(); ++cIndex)
{
this->Portals[cIndex].Set(this->Index, VTraits::GetComponent(src, 0));
}
}
}
};
} // namespace internal
template <typename PortalType>
struct TypeTraits<vtkm::internal::RecombineVec<PortalType>>
{
private:
using VecType = vtkm::internal::RecombineVec<PortalType>;
using ComponentType = typename VecType::ComponentType;
public:
using NumericTag = typename vtkm::TypeTraits<ComponentType>::NumericTag;
using DimensionalityTag = vtkm::TypeTraitsVectorTag;
VTKM_EXEC_CONT static vtkm::internal::RecombineVec<PortalType> ZeroInitialization()
{
// Return a vec-like of size 0.
return vtkm::internal::RecombineVec<PortalType>{};
}
};
template <typename PortalType>
struct VecTraits<vtkm::internal::RecombineVec<PortalType>>
{
using VecType = vtkm::internal::RecombineVec<PortalType>;
using ComponentType = typename VecType::ComponentType;
using BaseComponentType = typename vtkm::VecTraits<ComponentType>::BaseComponentType;
using HasMultipleComponents = vtkm::VecTraitsTagMultipleComponents;
using IsSizeStatic = vtkm::VecTraitsTagSizeVariable;
VTKM_EXEC_CONT static vtkm::IdComponent GetNumberOfComponents(const VecType& vector)
{
return vector.GetNumberOfComponents();
}
VTKM_EXEC_CONT
static ComponentType GetComponent(const VecType& vector, vtkm::IdComponent componentIndex)
{
return vector[componentIndex];
}
VTKM_EXEC_CONT static void SetComponent(const VecType& vector,
vtkm::IdComponent componentIndex,
const ComponentType& component)
{
vector[componentIndex] = component;
}
template <vtkm::IdComponent destSize>
VTKM_EXEC_CONT static void CopyInto(const VecType& src, vtkm::Vec<ComponentType, destSize>& dest)
{
src.CopyInto(dest);
}
};
namespace internal
{
template <typename SourcePortalType>
class ArrayPortalRecombineVec
{
vtkm::VecCConst<SourcePortalType> Portals;
public:
using ValueType = vtkm::internal::RecombineVec<SourcePortalType>;
ArrayPortalRecombineVec() = default;
ArrayPortalRecombineVec(const vtkm::VecCConst<SourcePortalType>& portals)
: Portals(portals)
{
}
ArrayPortalRecombineVec(const SourcePortalType* portals, vtkm::IdComponent numComponents)
: Portals(portals, numComponents)
{
}
VTKM_EXEC_CONT vtkm::Id GetNumberOfValues() const { return this->Portals[0].GetNumberOfValues(); }
VTKM_EXEC_CONT ValueType Get(vtkm::Id index) const { return ValueType(this->Portals, index); }
VTKM_EXEC_CONT void Set(vtkm::Id index, const ValueType& value) const
{
// The ValueType is actually a reference back to the portals, and sets to it should
// already be set in the portal. Thus, we don't really need to do anything.
VTKM_ASSERT(value.GetIndex() == index);
}
template <typename T>
VTKM_EXEC_CONT void Set(vtkm::Id index, const T& value) const
{
using Traits = vtkm::VecTraits<T>;
VTKM_ASSERT(Traits::GetNumberOfComponents(value) == this->Portals.GetNumberOfComponents());
for (vtkm::IdComponent cIndex = 0; cIndex < this->Portals.GetNumberOfComponents(); ++cIndex)
{
this->Portals[cIndex].Set(index, Traits::GetComponent(value, cIndex));
}
}
};
}
} // namespace vtkm::internal
namespace vtkm
{
namespace cont
{
namespace internal
{
struct StorageTagRecombineVec
{
};
namespace detail
{
// Note: Normally a decorating ArrayHandle holds the buffers of the arrays it is decorating
// in its list of arrays. However, the numbers of buffers is expected to be compile-time static
// and ArrayHandleRecombineVec needs to set the number of buffers at runtime. We cheat around
// this by stuffing the decorated buffers in the metadata. To make sure deep copies work
// right, a copy of the metadata results in a deep copy of the contained buffers. The
// vtkm::cont::internal::Buffer holding the metadata is not supposed to copy the metadata
// except for a deep copy (and when it is first set). If this behavior changes, there could
// be a performance degredation.
struct RecombineVecMetaData
{
mutable std::vector<vtkm::cont::internal::Buffer> PortalBuffers;
std::vector<std::vector<vtkm::cont::internal::Buffer>> ArrayBuffers;
RecombineVecMetaData() = default;
RecombineVecMetaData(const RecombineVecMetaData& src) { *this = src; }
RecombineVecMetaData& operator=(const RecombineVecMetaData& src)
{
this->ArrayBuffers.resize(src.ArrayBuffers.size());
for (std::size_t arrayIndex = 0; arrayIndex < src.ArrayBuffers.size(); ++arrayIndex)
{
this->ArrayBuffers[arrayIndex].resize(src.ArrayBuffers[arrayIndex].size());
for (std::size_t bufferIndex = 0; bufferIndex < src.ArrayBuffers[arrayIndex].size();
++bufferIndex)
{
this->ArrayBuffers[arrayIndex][bufferIndex].DeepCopyFrom(
src.ArrayBuffers[arrayIndex][bufferIndex]);
}
}
this->PortalBuffers.clear();
// Intentionally not copying portals. Portals will be recreated from proper array when requsted.
return *this;
}
};
template <typename T>
using RecombinedPortalType = vtkm::internal::ArrayPortalMultiplexer<
typename vtkm::cont::internal::Storage<T, vtkm::cont::StorageTagStride>::ReadPortalType,
typename vtkm::cont::internal::Storage<T, vtkm::cont::StorageTagStride>::WritePortalType>;
template <typename T>
using RecombinedValueType = vtkm::internal::RecombineVec<RecombinedPortalType<T>>;
} // namespace detail
template <typename ReadWritePortal>
class Storage<vtkm::internal::RecombineVec<ReadWritePortal>,
vtkm::cont::internal::StorageTagRecombineVec>
{
using ComponentType = typename ReadWritePortal::ValueType;
using SourceStorage = vtkm::cont::internal::Storage<ComponentType, vtkm::cont::StorageTagStride>;
using ArrayType = vtkm::cont::ArrayHandle<ComponentType, vtkm::cont::StorageTagStride>;
VTKM_STATIC_ASSERT(
(std::is_same<ReadWritePortal, detail::RecombinedPortalType<ComponentType>>::value));
template <typename Buff>
VTKM_CONT static Buff* BuffersForComponent(Buff* buffers, vtkm::IdComponent componentIndex)
{
return buffers[0]
.template GetMetaData<detail::RecombineVecMetaData>()
.ArrayBuffers[componentIndex]
.data();
}
public:
VTKM_STORAGE_NO_RESIZE;
using ReadPortalType = vtkm::internal::ArrayPortalRecombineVec<ReadWritePortal>;
using WritePortalType = vtkm::internal::ArrayPortalRecombineVec<ReadWritePortal>;
VTKM_CONT static vtkm::IdComponent NumberOfComponents(const vtkm::cont::internal::Buffer* buffers)
{
return static_cast<vtkm::IdComponent>(
buffers[0].GetMetaData<detail::RecombineVecMetaData>().ArrayBuffers.size());
}
VTKM_CONT static vtkm::IdComponent GetNumberOfBuffers() { return 1; }
VTKM_CONT static vtkm::Id GetNumberOfValues(const vtkm::cont::internal::Buffer* buffers)
{
return SourceStorage::GetNumberOfValues(BuffersForComponent(buffers, 0));
}
VTKM_CONT static ReadPortalType CreateReadPortal(const vtkm::cont::internal::Buffer* buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
{
ReadPortalType portal;
vtkm::IdComponent numComponents = NumberOfComponents(buffers);
// The array portal needs a runtime-allocated array of portals for each component.
// We use the vtkm::cont::internal::Buffer object to allow us to allocate memory on the
// device and copy data there.
vtkm::cont::internal::Buffer portalBuffer;
portalBuffer.SetNumberOfBytes(static_cast<vtkm::BufferSizeType>(sizeof(ReadWritePortal)) *
numComponents,
vtkm::CopyFlag::Off,
token);
// Save a reference of the portal in our metadata.
// Note that the buffer we create is going to hang around until the ArrayHandle gets
// destroyed. The buffers are small and should not be a problem unless you create a
// lot of portals.
buffers[0].GetMetaData<detail::RecombineVecMetaData>().PortalBuffers.push_back(portalBuffer);
// Get the control-side memory and fill it with the execution-side portals
ReadWritePortal* portals =
reinterpret_cast<ReadWritePortal*>(portalBuffer.WritePointerHost(token));
for (vtkm::IdComponent cIndex = 0; cIndex < numComponents; ++cIndex)
{
portals[cIndex] = ReadWritePortal(
SourceStorage::CreateReadPortal(BuffersForComponent(buffers, cIndex), device, token));
}
// Now get the execution-side memory (portals will be copied as necessary) and create
// the portal for the appropriate device
return ReadPortalType(
reinterpret_cast<const ReadWritePortal*>(portalBuffer.ReadPointerDevice(device, token)),
numComponents);
}
VTKM_CONT static WritePortalType CreateWritePortal(vtkm::cont::internal::Buffer* buffers,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token)
{
WritePortalType portal;
vtkm::IdComponent numComponents = NumberOfComponents(buffers);
// The array portal needs a runtime-allocated array of portals for each component.
// We use the vtkm::cont::internal::Buffer object to allow us to allocate memory on the
// device and copy data there.
vtkm::cont::internal::Buffer portalBuffer;
portalBuffer.SetNumberOfBytes(static_cast<vtkm::BufferSizeType>(sizeof(ReadWritePortal)) *
numComponents,
vtkm::CopyFlag::Off,
token);
// Save a reference of the portal in our metadata.
// Note that the buffer we create is going to hang around until the ArrayHandle gets
// destroyed. The buffers are small and should not be a problem unless you create a
// lot of portals.
buffers[0].GetMetaData<detail::RecombineVecMetaData>().PortalBuffers.push_back(portalBuffer);
// Get the control-side memory and fill it with the execution-side portals
ReadWritePortal* portals =
reinterpret_cast<ReadWritePortal*>(portalBuffer.WritePointerHost(token));
for (vtkm::IdComponent cIndex = 0; cIndex < numComponents; ++cIndex)
{
portals[cIndex] = ReadWritePortal(
SourceStorage::CreateWritePortal(BuffersForComponent(buffers, cIndex), device, token));
}
// Now get the execution-side memory (portals will be copied as necessary) and create
// the portal for the appropriate device
return WritePortalType(
reinterpret_cast<const ReadWritePortal*>(portalBuffer.ReadPointerDevice(device, token)),
numComponents);
}
VTKM_CONT static ArrayType ArrayForComponent(const vtkm::cont::internal::Buffer* buffers,
vtkm::IdComponent componentIndex)
{
return ArrayType(BuffersForComponent(buffers, componentIndex));
}
VTKM_CONT static void AppendComponent(vtkm::cont::internal::Buffer* buffers,
const ArrayType& array)
{
std::vector<vtkm::cont::internal::Buffer> arrayBuffers(
array.GetBuffers(), array.GetBuffers() + SourceStorage::GetNumberOfBuffers());
buffers[0].GetMetaData<detail::RecombineVecMetaData>().ArrayBuffers.push_back(
std::move(arrayBuffers));
}
};
} // namespace internal
/// \brief A grouping of `ArrayHandleStride`s into an `ArrayHandle` of `Vec`s.
///
/// The main intention of `ArrayHandleStride` is to pull out a component of an
/// `ArrayHandle` without knowing there `ArrayHandle`'s storage or `Vec` shape.
/// However, usually you want to do an operation on all the components together.
/// `ArrayHandleRecombineVec` implements the functionality to easily take a
/// group of extracted components and treat them as a single `ArrayHandle` of
/// `Vec` values.
///
/// Note that caution should be used with `ArrayHandleRecombineVec` because the
/// size of the `Vec` values is not known at compile time. Thus, the value
/// type of this array is forced to a `VecVariable`, which can cause surprises
/// if treated as a `Vec`. In particular, the static `NUM_COMPONENTS` expression
/// does not exist.
///
template <typename ComponentType>
class ArrayHandleRecombineVec
: public vtkm::cont::ArrayHandle<internal::detail::RecombinedValueType<ComponentType>,
vtkm::cont::internal::StorageTagRecombineVec>
{
public:
VTKM_ARRAY_HANDLE_SUBCLASS(
ArrayHandleRecombineVec,
(ArrayHandleRecombineVec<ComponentType>),
(vtkm::cont::ArrayHandle<internal::detail::RecombinedValueType<ComponentType>,
vtkm::cont::internal::StorageTagRecombineVec>));
private:
using StorageType = vtkm::cont::internal::Storage<ValueType, StorageTag>;
public:
vtkm::IdComponent GetNumberOfComponents() const
{
return StorageType::NumberOfComponents(this->GetBuffers());
}
vtkm::cont::ArrayHandleStride<ComponentType> GetComponentArray(
vtkm::IdComponent componentIndex) const
{
return StorageType::ArrayForComponent(this->GetBuffers(), componentIndex);
}
void AppendComponentArray(
const vtkm::cont::ArrayHandle<ComponentType, vtkm::cont::StorageTagStride>& array)
{
StorageType::AppendComponent(this->GetBuffers(), array);
}
};
namespace internal
{
template <>
struct ArrayExtractComponentImpl<vtkm::cont::internal::StorageTagRecombineVec>
{
template <typename RecombineVec>
vtkm::cont::ArrayHandleStride<
typename vtkm::VecFlat<typename RecombineVec::ComponentType>::ComponentType>
operator()(
const vtkm::cont::ArrayHandle<RecombineVec, vtkm::cont::internal::StorageTagRecombineVec>& src,
vtkm::IdComponent componentIndex,
vtkm::CopyFlag allowCopy) const
{
using ComponentType = typename RecombineVec::ComponentType;
vtkm::cont::ArrayHandleRecombineVec<ComponentType> array(src);
constexpr vtkm::IdComponent subComponents = vtkm::VecFlat<ComponentType>::NUM_COMPONENTS;
return vtkm::cont::ArrayExtractComponent(
array.GetComponentArray(componentIndex / subComponents),
componentIndex % subComponents,
allowCopy);
}
};
} // namespace internal
}
} // namespace vtkm::cont
//=============================================================================
// Specializations of worklet arguments using ArrayHandleGropuVecVariable
#include <vtkm/exec/arg/FetchTagArrayDirectOutArrayHandleRecombineVec.h>
#endif //vtk_m_cont_ArrayHandleRecombineVec_h

@ -163,9 +163,6 @@ public:
} // namespace internal
template <typename T, typename S>
VTKM_ARRAY_HANDLE_NEW_STYLE(T, vtkm::cont::StorageTagReverse<S>);
/// \brief Reverse the order of an array, on demand.
///
/// ArrayHandleReverse is a specialization of ArrayHandle. Given an ArrayHandle,

@ -17,7 +17,6 @@ namespace cont
{
#define VTKM_ARRAYHANDLE_SOA_INSTANTIATE(Type) \
template class VTKM_CONT_EXPORT ArrayHandle<Type, StorageTagSOA>; \
template class VTKM_CONT_EXPORT ArrayHandle<vtkm::Vec<Type, 2>, StorageTagSOA>; \
template class VTKM_CONT_EXPORT ArrayHandle<vtkm::Vec<Type, 3>, StorageTagSOA>; \
template class VTKM_CONT_EXPORT ArrayHandle<vtkm::Vec<Type, 4>, StorageTagSOA>;

@ -128,20 +128,17 @@ struct VTKM_ALWAYS_EXPORT StorageTagSOA
namespace internal
{
template <typename T>
class VTKM_ALWAYS_EXPORT Storage<T, vtkm::cont::StorageTagSOA>
template <typename ComponentType, vtkm::IdComponent NUM_COMPONENTS>
class VTKM_ALWAYS_EXPORT
Storage<vtkm::Vec<ComponentType, NUM_COMPONENTS>, vtkm::cont::StorageTagSOA>
{
VTKM_STATIC_ASSERT(vtkm::HasVecTraits<T>::value);
using VTraits = vtkm::VecTraits<T>;
using ComponentType = typename VTraits::ComponentType;
static constexpr vtkm::IdComponent NUM_COMPONENTS = VTraits::NUM_COMPONENTS;
using ValueType = vtkm::Vec<ComponentType, NUM_COMPONENTS>;
public:
using ReadPortalType =
vtkm::internal::ArrayPortalSOA<T, vtkm::internal::ArrayPortalBasicRead<ComponentType>>;
vtkm::internal::ArrayPortalSOA<ValueType, vtkm::internal::ArrayPortalBasicRead<ComponentType>>;
using WritePortalType =
vtkm::internal::ArrayPortalSOA<T, vtkm::internal::ArrayPortalBasicWrite<ComponentType>>;
vtkm::internal::ArrayPortalSOA<ValueType, vtkm::internal::ArrayPortalBasicWrite<ComponentType>>;
VTKM_CONT constexpr static vtkm::IdComponent GetNumberOfBuffers() { return NUM_COMPONENTS; }
@ -204,9 +201,6 @@ public:
} // namespace internal
template <typename T>
VTKM_ARRAY_HANDLE_NEW_STYLE(T, vtkm::cont::StorageTagSOA);
/// \brief An `ArrayHandle` that for Vecs stores each component in a separate physical array.
///
/// `ArrayHandleSOA` behaves like a regular `ArrayHandle` (with a basic storage) except that
@ -632,7 +626,6 @@ namespace cont
{
#define VTKM_ARRAYHANDLE_SOA_EXPORT(Type) \
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandle<Type, StorageTagSOA>; \
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandle<vtkm::Vec<Type, 2>, StorageTagSOA>; \
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandle<vtkm::Vec<Type, 3>, StorageTagSOA>; \
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandle<vtkm::Vec<Type, 4>, StorageTagSOA>;

@ -33,17 +33,17 @@ template class VTKM_CONT_EXPORT Storage<vtkm::Float64, StorageTagStride>;
} // namespace internal
template class VTKM_CONT_EXPORT ArrayHandleNewStyle<char, StorageTagStride>;
template class VTKM_CONT_EXPORT ArrayHandleNewStyle<vtkm::Int8, StorageTagStride>;
template class VTKM_CONT_EXPORT ArrayHandleNewStyle<vtkm::UInt8, StorageTagStride>;
template class VTKM_CONT_EXPORT ArrayHandleNewStyle<vtkm::Int16, StorageTagStride>;
template class VTKM_CONT_EXPORT ArrayHandleNewStyle<vtkm::UInt16, StorageTagStride>;
template class VTKM_CONT_EXPORT ArrayHandleNewStyle<vtkm::Int32, StorageTagStride>;
template class VTKM_CONT_EXPORT ArrayHandleNewStyle<vtkm::UInt32, StorageTagStride>;
template class VTKM_CONT_EXPORT ArrayHandleNewStyle<vtkm::Int64, StorageTagStride>;
template class VTKM_CONT_EXPORT ArrayHandleNewStyle<vtkm::UInt64, StorageTagStride>;
template class VTKM_CONT_EXPORT ArrayHandleNewStyle<vtkm::Float32, StorageTagStride>;
template class VTKM_CONT_EXPORT ArrayHandleNewStyle<vtkm::Float64, StorageTagStride>;
template class VTKM_CONT_EXPORT ArrayHandle<char, StorageTagStride>;
template class VTKM_CONT_EXPORT ArrayHandle<vtkm::Int8, StorageTagStride>;
template class VTKM_CONT_EXPORT ArrayHandle<vtkm::UInt8, StorageTagStride>;
template class VTKM_CONT_EXPORT ArrayHandle<vtkm::Int16, StorageTagStride>;
template class VTKM_CONT_EXPORT ArrayHandle<vtkm::UInt16, StorageTagStride>;
template class VTKM_CONT_EXPORT ArrayHandle<vtkm::Int32, StorageTagStride>;
template class VTKM_CONT_EXPORT ArrayHandle<vtkm::UInt32, StorageTagStride>;
template class VTKM_CONT_EXPORT ArrayHandle<vtkm::Int64, StorageTagStride>;
template class VTKM_CONT_EXPORT ArrayHandle<vtkm::UInt64, StorageTagStride>;
template class VTKM_CONT_EXPORT ArrayHandle<vtkm::Float32, StorageTagStride>;
template class VTKM_CONT_EXPORT ArrayHandle<vtkm::Float64, StorageTagStride>;
}
} // namespace vtkm::cont

@ -205,10 +205,7 @@ public:
} // namespace internal
template <typename T>
VTKM_ARRAY_HANDLE_NEW_STYLE(T, vtkm::cont::StorageTagStride);
/// \brief An `ArrayHandle` that access a basic array with strides and offsets.
/// \brief An `ArrayHandle` that accesses a basic array with strides and offsets.
///
/// `ArrayHandleStride` is a simple `ArrayHandle` that accesses data with a prescribed
/// stride and offset. You specify the stride and offset at construction. So when a portal
@ -393,19 +390,17 @@ extern template class VTKM_CONT_TEMPLATE_EXPORT Storage<vtkm::Float64, StorageTa
} // namespace internal
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandleNewStyle<char, StorageTagStride>;
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandleNewStyle<vtkm::Int8, StorageTagStride>;
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandleNewStyle<vtkm::UInt8, StorageTagStride>;
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandleNewStyle<vtkm::Int16, StorageTagStride>;
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandleNewStyle<vtkm::UInt16, StorageTagStride>;
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandleNewStyle<vtkm::Int32, StorageTagStride>;
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandleNewStyle<vtkm::UInt32, StorageTagStride>;
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandleNewStyle<vtkm::Int64, StorageTagStride>;
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandleNewStyle<vtkm::UInt64, StorageTagStride>;
extern template class VTKM_CONT_TEMPLATE_EXPORT
ArrayHandleNewStyle<vtkm::Float32, StorageTagStride>;
extern template class VTKM_CONT_TEMPLATE_EXPORT
ArrayHandleNewStyle<vtkm::Float64, StorageTagStride>;
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandle<char, StorageTagStride>;
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandle<vtkm::Int8, StorageTagStride>;
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandle<vtkm::UInt8, StorageTagStride>;
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandle<vtkm::Int16, StorageTagStride>;
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandle<vtkm::UInt16, StorageTagStride>;
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandle<vtkm::Int32, StorageTagStride>;
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandle<vtkm::UInt32, StorageTagStride>;
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandle<vtkm::Int64, StorageTagStride>;
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandle<vtkm::UInt64, StorageTagStride>;
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandle<vtkm::Float32, StorageTagStride>;
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandle<vtkm::Float64, StorageTagStride>;
}
} // namespace vtkm::cont

@ -416,9 +416,6 @@ public:
} // namespace internal
template <typename T, typename A, typename F, typename IF>
VTKM_ARRAY_HANDLE_NEW_STYLE(T, VTKM_PASS_COMMAS(internal::StorageTagTransform<A, F, IF>));
/// \brief Implicitly transform values of one array to another with a functor.
///
/// ArrayHandleTransforms is a specialization of ArrayHandle. It takes a

@ -37,9 +37,6 @@ struct Storage<vtkm::Vec3f, vtkm::cont::StorageTagUniformPoints>
} // namespace internal
template <>
VTKM_ARRAY_HANDLE_NEW_STYLE(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

@ -196,10 +196,6 @@ public:
} // namespace internal
// This can go away once ArrayHandle is replaced with ArrayHandleNewStyle
template <typename T, typename S>
VTKM_ARRAY_HANDLE_NEW_STYLE(T, vtkm::cont::StorageTagView<S>);
template <typename ArrayHandleType>
class ArrayHandleView
: public vtkm::cont::ArrayHandle<typename ArrayHandleType::ValueType,

@ -15,9 +15,10 @@
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ArrayHandleUniformPointCoordinates.h>
#include <vtkm/cont/DeviceAdapterTag.h>
#include <vtkm/cont/StorageVirtual.h>
#include <vtkm/cont/internal/ArrayHandleDeprecated.h>
#include <memory>
#ifdef VTKM_NO_DEPRECATED_VIRTUAL
@ -29,8 +30,11 @@ namespace vtkm
namespace cont
{
VTKM_DEPRECATED_SUPPRESS_BEGIN
template <typename T>
VTKM_ARRAY_HANDLE_DEPRECATED(T, vtkm::cont::StorageTagVirtual);
template <typename T>
class VTKM_ALWAYS_EXPORT VTKM_DEPRECATED(1.6) ArrayHandleVirtual
: public vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagVirtual>

@ -201,10 +201,6 @@ public:
};
} // namespace internal
template <typename T1, typename S1, typename T2, typename S2>
VTKM_ARRAY_HANDLE_NEW_STYLE(VTKM_PASS_COMMAS(vtkm::Pair<T1, T2>),
VTKM_PASS_COMMAS(vtkm::cont::StorageTagZip<S1, S2>));
/// 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.

@ -74,6 +74,10 @@ VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_VEC(2, vtkm::cont::StorageTagBasic);
VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_VEC(3, vtkm::cont::StorageTagBasic);
VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_VEC(4, vtkm::cont::StorageTagBasic);
VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_VEC(2, vtkm::cont::StorageTagSOA);
VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_VEC(3, vtkm::cont::StorageTagSOA);
VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_VEC(4, vtkm::cont::StorageTagSOA);
#undef VTKM_ARRAY_RANGE_COMPUTE_IMPL_T
#undef VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC
#undef VTKM_ARRAY_RANGE_COMPUTE_IMPL_ALL_SCALAR_T

@ -15,6 +15,7 @@
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ArrayHandleCartesianProduct.h>
#include <vtkm/cont/ArrayHandleCompositeVector.h>
#include <vtkm/cont/ArrayHandleSOA.h>
#include <vtkm/cont/ArrayHandleUniformPointCoordinates.h>
#include <vtkm/cont/DeviceAdapterTag.h>
@ -94,6 +95,10 @@ VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_ALL_VEC(2, vtkm::cont::StorageTagBasic);
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_ALL_VEC(3, vtkm::cont::StorageTagBasic);
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_ALL_VEC(4, vtkm::cont::StorageTagBasic);
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_ALL_VEC(2, vtkm::cont::StorageTagSOA);
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_ALL_VEC(3, vtkm::cont::StorageTagSOA);
VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_ALL_VEC(4, vtkm::cont::StorageTagSOA);
#undef VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_T
#undef VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_VEC
#undef VTK_M_ARRAY_RANGE_COMPUTE_EXPORT_ALL_SCALAR_T

@ -33,6 +33,7 @@ set(headers
ArrayHandleIndex.h
ArrayHandleMultiplexer.h
ArrayHandlePermutation.h
ArrayHandleRecombineVec.h
ArrayHandleReverse.h
ArrayHandleRandomStandardNormal.h
ArrayHandleRandomUniformBits.h
@ -126,7 +127,6 @@ set(headers
)
set(template_sources
ArrayHandle.hxx
ArrayRangeCompute.hxx # Deprecated, replaced with ArrayRangeComputeTemplate.h
CellSetExplicit.hxx
CellSetExtrude.hxx
@ -217,12 +217,36 @@ endif()
vtkm_get_kit_name(kit_name kit_dir)
# Some custom types included with VTK-m
vtkm_option(VTKm_USE_DEFAULT_TYPES_FOR_VTK "Compile VTK-m algorithms for use with types from VTK." OFF)
vtkm_option(VTKm_USE_DEFAULT_TYPES_FOR_VTK
"Compile VTK-m algorithms for use with types from VTK."
OFF
)
if (VTKm_USE_DEFAULT_TYPES_FOR_VTK)
set(VTKm_DEFAULT_TYPES_HEADER "internal/DefaultTypesVTK.h.in")
endif()
mark_as_advanced(VTKm_USE_DEFAULT_TYPES_FOR_VTK)
vtkm_option(VTKm_USE_DEFAULT_TYPES_FOR_ASCENT
"Compile VTK-m algorithms for use with types from Ascent."
OFF
)
if (VTKm_USE_DEFAULT_TYPES_FOR_ASCENT)
set(VTKm_DEFAULT_TYPES_HEADER "internal/DefaultTypesAscent.h.in")
if (VTKm_USE_64BIT_IDS)
message(SEND_ERROR
"When VTKm_USE_DEFAULT_TYPES_FOR_ASCENT is ON, VTKm_USE_64BIT_IDS must be set to OFF"
)
endif()
if (NOT VTKm_USE_DOUBLE_PRECISION)
message(SEND_ERROR
"When VTKm_USE_DEFAULT_TYPES_FOR_ASCENT is ON, VTKm_USE_DOUBLE_PRECISION must be set to ON"
)
endif()
endif()
mark_as_advanced(
VTKm_USE_DEFAULT_TYPES_FOR_VTK
VTKm_USE_DEFAULT_TYPES_FOR_ASCENT
)
if (VTKm_DEFAULT_TYPES_HEADER)
set(VTK_M_HAS_DEFAULT_TYPES_HEADER TRUE)

@ -59,13 +59,10 @@ namespace internal
using StorageListField = vtkm::ListAppend<
vtkm::cont::StorageListBasic,
vtkm::List<
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>>;
vtkm::cont::StorageTagUniformPoints,
vtkm::cont::StorageTagCartesianProduct<vtkm::cont::StorageTagBasic,
vtkm::cont::StorageTagBasic,
vtkm::cont::StorageTagBasic>>>;
}
}

@ -35,7 +35,7 @@ namespace cont
/// constructors for points / whole mesh
VTKM_CONT
Field::Field(std::string name, Association association, const vtkm::cont::VariantArrayHandle& data)
Field::Field(std::string name, Association association, const vtkm::cont::UnknownArrayHandle& data)
: Name(name)
, FieldAssociation(association)
, Data(data)

@ -58,13 +58,13 @@ public:
Field() = default;
VTKM_CONT
Field(std::string name, Association association, const vtkm::cont::VariantArrayHandle& data);
Field(std::string name, Association association, const vtkm::cont::UnknownArrayHandle& data);
template <typename T, typename Storage>
VTKM_CONT Field(std::string name,
Association association,
const vtkm::cont::ArrayHandle<T, Storage>& data)
: Field(name, association, vtkm::cont::VariantArrayHandle{ data })
: Field(name, association, vtkm::cont::UnknownArrayHandle{ data })
{
}

@ -152,6 +152,16 @@ struct SerializableTypeString<vtkm::Float64>
}
};
template <>
struct SerializableTypeString<bool>
{
static VTKM_CONT const std::string& Get()
{
static std::string name = "B8";
return name;
}
};
template <>
struct SerializableTypeString<char>
{

@ -16,6 +16,9 @@
#include <vtkm/cont/ErrorBadType.h>
#include <vtkm/cont/internal/ArrayTransfer.h>
#include <vtkm/cont/internal/StorageDeprecated.h>
#include <vtkm/cont/serial/DeviceAdapterSerial.h>
#include <vtkm/cont/tbb/DeviceAdapterTBB.h>

@ -15,6 +15,8 @@
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ErrorBadType.h>
#include <vtkm/cont/Storage.h>
#include <vtkm/cont/internal/ArrayHandleDeprecated.h>
#include <vtkm/cont/internal/StorageDeprecated.h>
#include <vtkm/cont/internal/TransferInfo.h>
#include <vtkm/internal/ArrayPortalVirtual.h>

@ -12,8 +12,9 @@
#include <vtkm/cont/StorageVirtual.h>
#include <vtkm/cont/TryExecute.h>
#include <vtkm/cont/internal/TransferInfo.h>
#include <vtkm/cont/internal/ArrayTransfer.h>
#include <vtkm/cont/internal/TransferInfo.h>
#include <vtkm/cont/internal/VirtualObjectTransfer.h>
#include <vtkm/cont/internal/VirtualObjectTransferShareWithControl.h>

@ -22,7 +22,24 @@
#include <vtkm/cont/ArrayHandleUniformPointCoordinates.h>
#include <vtkm/cont/UncertainArrayHandle.h>
using UnknownSerializationTypes = vtkm::TypeListAll;
namespace
{
template <vtkm::IdComponent N, typename ScalarList>
struct AllVecImpl;
template <vtkm::IdComponent N, typename... Scalars>
struct AllVecImpl<N, vtkm::List<Scalars...>>
{
using type = vtkm::List<vtkm::Vec<Scalars, N>...>;
};
// Normally I would implement this with vtkm::ListTransform, but that is causing an ICE in GCC 4.8.
// This implementation is not much different.
template <vtkm::IdComponent N>
using AllVec = typename AllVecImpl<N, vtkm::TypeListBaseC>::type;
using UnknownSerializationTypes =
vtkm::ListAppend<vtkm::TypeListBaseC, AllVec<2>, AllVec<3>, AllVec<4>>;
using UnknownSerializationStorage =
vtkm::ListAppend<VTKM_DEFAULT_STORAGE_LIST,
vtkm::List<vtkm::cont::StorageTagBasic,
@ -41,6 +58,8 @@ using UnknownSerializationStorage =
vtkm::cont::StorageTagSOA,
vtkm::cont::StorageTagUniformPoints>>;
} // anonymous namespace
namespace vtkm
{
namespace cont
@ -59,6 +78,20 @@ std::shared_ptr<UnknownAHContainer> UnknownAHContainer::MakeNewInstance() const
return newContainer;
}
bool UnknownAHComponentInfo::operator==(const UnknownAHComponentInfo& rhs)
{
if (this->IsIntegral || this->IsFloat)
{
return ((this->IsIntegral == rhs.IsIntegral) && (this->IsFloat == rhs.IsFloat) &&
(this->IsSigned == rhs.IsSigned) && (this->Size == rhs.Size));
}
else
{
// Needs optimization based on platform. OSX cannot compare typeid across translation units?
return this->Type == rhs.Type;
}
}
} // namespace detail
VTKM_CONT bool UnknownArrayHandle::IsValueTypeImpl(std::type_index type) const
@ -83,7 +116,8 @@ VTKM_CONT bool UnknownArrayHandle::IsStorageTypeImpl(std::type_index type) const
return this->Container->StorageType == type;
}
VTKM_CONT bool UnknownArrayHandle::IsBaseComponentTypeImpl(std::type_index type) const
VTKM_CONT bool UnknownArrayHandle::IsBaseComponentTypeImpl(
const detail::UnknownAHComponentInfo& type) const
{
if (!this->Container)
{

@ -16,11 +16,10 @@
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ArrayHandleCast.h>
#include <vtkm/cont/ArrayHandleMultiplexer.h>
#include <vtkm/cont/ArrayHandleRecombineVec.h>
#include <vtkm/cont/ArrayHandleStride.h>
#include <vtkm/cont/DefaultTypes.h>
#include <vtkm/cont/internal/ArrayPortalFromExtractedComponents.h>
#include <memory>
#include <typeindex>
@ -143,13 +142,50 @@ struct MakeUnknownAHContainerFunctor
std::shared_ptr<UnknownAHContainer> operator()(const vtkm::cont::ArrayHandle<T, S>& array) const;
};
struct VTKM_CONT_EXPORT UnknownAHComponentInfo
{
std::type_index Type;
bool IsIntegral;
bool IsFloat;
bool IsSigned;
std::size_t Size;
UnknownAHComponentInfo() = delete;
bool operator==(const UnknownAHComponentInfo& rhs);
template <typename T>
static UnknownAHComponentInfo Make()
{
return UnknownAHComponentInfo{ typeid(T),
std::is_integral<T>::value,
std::is_floating_point<T>::value,
std::is_signed<T>::value,
sizeof(T) };
}
private:
UnknownAHComponentInfo(std::type_index&& type,
bool isIntegral,
bool isFloat,
bool isSigned,
std::size_t size)
: Type(std::move(type))
, IsIntegral(isIntegral)
, IsFloat(isFloat)
, IsSigned(isSigned)
, Size(size)
{
}
};
struct VTKM_CONT_EXPORT UnknownAHContainer
{
void* ArrayHandlePointer;
std::type_index ValueType;
std::type_index StorageType;
std::type_index BaseComponentType;
UnknownAHComponentInfo BaseComponentType;
using DeleteType = void(void*);
DeleteType* DeleteFunction;
@ -248,7 +284,8 @@ inline UnknownAHContainer::UnknownAHContainer(const vtkm::cont::ArrayHandle<T, S
: ArrayHandlePointer(new vtkm::cont::ArrayHandle<T, S>(array))
, ValueType(typeid(T))
, StorageType(typeid(S))
, BaseComponentType(typeid(typename vtkm::VecTraits<T>::BaseComponentType))
, BaseComponentType(
UnknownAHComponentInfo::Make<typename vtkm::VecTraits<T>::BaseComponentType>())
, DeleteFunction(detail::UnknownAHDelete<T, S>)
, NewInstance(detail::UnknownADNewInstance<T, S>)
, NewInstanceBasic(detail::UnknownADNewInstanceBasic<T>)
@ -312,7 +349,7 @@ class VTKM_CONT_EXPORT UnknownArrayHandle
VTKM_CONT bool IsValueTypeImpl(std::type_index type) const;
VTKM_CONT bool IsStorageTypeImpl(std::type_index type) const;
VTKM_CONT bool IsBaseComponentTypeImpl(std::type_index type) const;
VTKM_CONT bool IsBaseComponentTypeImpl(const detail::UnknownAHComponentInfo& type) const;
public:
VTKM_CONT UnknownArrayHandle() = default;
@ -388,7 +425,7 @@ public:
template <typename BaseComponentType>
VTKM_CONT bool IsBaseComponentType() const
{
return this->IsBaseComponentTypeImpl(typeid(BaseComponentType));
return this->IsBaseComponentTypeImpl(detail::UnknownAHComponentInfo::Make<BaseComponentType>());
}
/// Returns true if this array matches the ArrayHandleType template argument.
@ -425,8 +462,7 @@ public:
/// If the array holds `Vec`-like objects that have the number of components that can vary
/// at runtime, this method will return 0 (because there is no consistent answer).
///
VTKM_CONT VTKM_DEPRECATED(1.6, "Use GetNumberOfComponentsFlat.") vtkm::IdComponent
GetNumberOfComponents() const;
VTKM_CONT vtkm::IdComponent GetNumberOfComponents() const;
/// \brief Returns the total number of components for each value in the array.
///
@ -553,61 +589,96 @@ public:
return ComponentArrayType(buffers);
}
///@{
/// \brief Convenience portal to access all components (in control environment).
/// \brief Extract the array knowing only the component type of the array.
///
/// This method returns a portal that allows you to access all the values in the contained
/// portal by knowing only the type of the base component. The `BaseComponentType` has to
/// be specified and must match the contained array (i.e.the result of `IsBaseComponentType`
/// must succeed for the given type).
/// This method returns an `ArrayHandle` that points to the data in the array. This method
/// differs from `AsArrayHandle` because you do not need to know the exact `ValueType` and
/// `StorageTag` of the array. Instead, you only need to know the base component type.
///
/// Note that the returned portal is not thread safe, but you may safely create multiple portals
/// for multiple threads.
/// `ExtractArrayFromComponents` works by calling the `ExtractComponent` method and then
/// combining them together in a fancy `ArrayHandle`. This allows you to ignore the storage
/// type of the underlying array as well as any `Vec` structure of the value type. However,
/// it also places some limitations on how the data can be pulled from the data.
///
/// First, you have to specify the base component type. This must match the data in the
/// underlying array (as reported by `IsBaseComponentType`).
///
/// Second, the array returned will have the `Vec`s flattened. For example, if the underlying
/// array has a `ValueType` of `Vec<Vec<T, 3>, 3>`, then this method will tread the data as
/// if it was `Vec<T, 9>`. There is no way to get an array with `Vec` of `Vec` values.
///
/// Third, because the `Vec` length of the values in the returned `ArrayHandle` must be
/// determined at runtime, that can break many assumptions of using `Vec` objects. The
/// type is not going to be a `Vec<T,N>` type but rather an internal class that is intended
/// to behave like that. The type should behave mostly like a `Vec`, but will have some
/// differences that can lead to unexpected behavior. For example, this `Vec`-like object
/// will not have a `NUM_COMPONENTS` constant static expression because it is not known
/// at compile time. (Use the `GetNumberOfComponents` method instead.) And for the same
/// reason you will not be able to pass these objects to classes overloaded or templated
/// on the `Vec` type. Also, these `Vec`-like objects cannot be created as new instances.
/// Thus, you will likely have to iterate over all components rather than do operations on
/// the whole `Vec`.
///
/// Fourth, because `ExtractArrayFromComponents` uses `ExtractComponent` to pull data from
/// the array (which in turn uses `ArrayExtractComponent`), there are some `ArrayHandle` types
/// that will require copying data to a new array. This could be problematic in cases where
/// you want to write to the array. To prevent data from being copied, set the optional
/// `allowCopy` to `vtkm::CopyFlag::Off`. This will cause an exception to be thrown if
/// the resulting array cannot reference the memory held in this `UnknownArrayHandle`.
///
/// Fifth, component arrays are extracted using `ArrayHandleStride` as the representation
/// for each component. This array adds a slight overhead for each lookup as it performs the
/// arithmetic for finding the index of each component.
///
template <typename BaseComponentType>
VTKM_CONT vtkm::cont::internal::ArrayPortalFromExtractedComponents<
typename vtkm::cont::ArrayHandleStride<BaseComponentType>::ReadPortalType>
ReadPortalForBaseComponentType() const
VTKM_CONT vtkm::cont::ArrayHandleRecombineVec<BaseComponentType> ExtractArrayFromComponents(
vtkm::CopyFlag allowCopy = vtkm::CopyFlag::On) const
{
vtkm::cont::ArrayHandleRecombineVec<BaseComponentType> result;
vtkm::IdComponent numComponents = this->GetNumberOfComponentsFlat();
vtkm::cont::internal::ArrayPortalFromExtractedComponents<
typename vtkm::cont::ArrayHandleStride<BaseComponentType>::ReadPortalType>
portal(numComponents);
for (vtkm::IdComponent cIndex = 0; cIndex < numComponents; ++cIndex)
{
auto array = this->ExtractComponent<BaseComponentType>(cIndex, vtkm::CopyFlag::On);
portal.AddArray(array, array.ReadPortal());
result.AppendComponentArray(this->ExtractComponent<BaseComponentType>(cIndex, allowCopy));
}
return portal;
return result;
}
template <typename BaseComponentType>
VTKM_CONT vtkm::cont::internal::ArrayPortalFromExtractedComponents<
typename vtkm::cont::ArrayHandleStride<BaseComponentType>::WritePortalType>
WritePortalForBaseComponentType() const
{
vtkm::IdComponent numComponents = this->GetNumberOfComponentsFlat();
vtkm::cont::internal::ArrayPortalFromExtractedComponents<
typename vtkm::cont::ArrayHandleStride<BaseComponentType>::WritePortalType>
portal(numComponents);
for (vtkm::IdComponent cIndex = 0; cIndex < numComponents; ++cIndex)
{
auto array = this->ExtractComponent<BaseComponentType>(cIndex, vtkm::CopyFlag::Off);
portal.AddArray(array, array.WritePortal());
}
return portal;
}
///@}
/// \brief Call a functor using the underlying array type.
///
/// `CastAndCall` attempts to cast the held array to a specific value type,
/// `CastAndCallForTypes` attempts to cast the held array to a specific value type,
/// and then calls the given functor with the cast array. You must specify
/// the `TypeList` and `StorageList` as template arguments.
///
/// After the functor argument you may add any number of arguments that will be
/// passed to the functor after the converted `ArrayHandle`.
///
template <typename TypeList, typename StorageList, typename Functor, typename... Args>
VTKM_CONT void CastAndCallForTypes(Functor&& functor, Args&&... args) const;
/// \brief Call a functor on an array extracted from the components.
///
/// `CastAndCallWithExtractedArray` behaves similarly to `CastAndCallForTypes`.
/// It converts the contained data to an `ArrayHandle` and calls a functor with
/// that `ArrayHandle` (and any number of optionally specified arguments).
///
/// The advantage of `CastAndCallWithExtractedArray` is that you do not need to
/// specify any `TypeList` or `StorageList`. Instead, it internally uses
/// `ExtractArrayFromComponents` to work with most `ArrayHandle` types with only
/// about 10 instances of the functor. In contrast, calling `CastAndCallForTypes`
/// with, for example, `VTKM_DEFAULT_TYPE_LIST` and `VTKM_DEFAULT_STORAGE_LIST`
/// results in many more instances of the functor but handling many fewer types
/// of `ArrayHandle`.
///
/// There are, however, costs to using this method. Details of these costs are
/// documented for the `ExtractArrayFromComponents` method, but briefly they
/// are that `Vec` types get flattened, the resulting array has a strange `Vec`-like
/// value type that has many limitations on its use, there is an overhead for
/// retrieving each value from the array, and there is a potential that data
/// must be copied.
///
template <typename Functor, typename... Args>
VTKM_CONT void CastAndCallWithExtractedArray(Functor&& functor, Args&&... args) const;
/// Releases any resources being used in the execution environment (that are
/// not being shared by the control environment).
///
@ -776,10 +847,8 @@ VTKM_CONT_EXPORT void ThrowCastAndCallException(const vtkm::cont::UnknownArrayHa
} // namespace detail
template <typename TypeList, typename StorageTagList, typename Functor, typename... Args>
VTKM_CONT void UnknownArrayHandle::CastAndCallForTypes(Functor&& f, Args&&... args) const
inline void UnknownArrayHandle::CastAndCallForTypes(Functor&& f, Args&&... args) const
{
using crossProduct = detail::ListAllArrayTypes<TypeList, StorageTagList>;
@ -805,6 +874,59 @@ void CastAndCall(const UnknownArrayHandle& handle, Functor&& f, Args&&... args)
std::forward<Functor>(f), std::forward<Args>(args)...);
}
namespace detail
{
struct UnknownArrayHandleTryExtract
{
template <typename T, typename Functor, typename... Args>
void operator()(T,
Functor&& f,
bool& called,
const vtkm::cont::UnknownArrayHandle& unknownArray,
Args&&... args) const
{
if (!called && unknownArray.IsBaseComponentType<T>())
{
called = true;
auto extractedArray = unknownArray.ExtractArrayFromComponents<T>();
VTKM_LOG_CAST_SUCC(unknownArray, extractedArray);
// If you get a compile error here, it means that you have called
// CastAndCallWithExtractedArray for a vtkm::cont::UnknownArrayHandle and the arguments of
// the functor do not match those being passed. This is often because it is calling the
// functor with an ArrayHandle type that was not expected. Add overloads to the functor to
// accept all possible array types or constrain the types tried for the CastAndCall. Note
// that the functor will be called with an array of type that is different than the actual
// type of the `ArrayHandle` stored in the `UnknownArrayHandle`.
f(extractedArray, std::forward<Args>(args)...);
}
}
};
} // namespace detail
template <typename Functor, typename... Args>
inline void UnknownArrayHandle::CastAndCallWithExtractedArray(Functor&& functor,
Args&&... args) const
{
bool called = false;
vtkm::ListForEach(detail::UnknownArrayHandleTryExtract{},
vtkm::TypeListScalarAll{},
std::forward<Functor>(functor),
called,
*this,
std::forward<Args>(args)...);
if (!called)
{
// Throw an exception.
// The message will be a little wonky because the types are just the value types, not the
// full type to cast to.
VTKM_LOG_CAST_FAIL(*this, vtkm::TypeListScalarAll);
detail::ThrowCastAndCallException(*this, typeid(vtkm::TypeListScalarAll));
}
}
namespace internal
{

File diff suppressed because it is too large Load Diff

@ -1,96 +0,0 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
//
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//============================================================================
#ifndef vtk_m_cont_internal_ArrayPortalFromExtractedComponents_h
#define vtk_m_cont_internal_ArrayPortalFromExtractedComponents_h
#include <vtkm/cont/ArrayHandleStride.h>
#include <vtkm/internal/ArrayPortalHelpers.h>
#include <vtkm/Types.h>
#include <vtkm/VecTraits.h>
#include <vector>
namespace vtkm
{
namespace cont
{
class UnknownArrayHandle;
namespace internal
{
/// `ArrayPortalFromExtractedComponents` is a convenience class that allows you to treat
/// a group of arrays that were extracted from the components of an array and treat them
/// like a portal to the array itself. It is used internally by `UnknownArrayHandle` to
/// get read and write portals to the array
///
/// Note that this portal only works on the control environment.
///
template <typename PortalType>
class ArrayPortalFromExtractedComponents
{
private:
using T = typename PortalType::ValueType;
std::vector<vtkm::cont::ArrayHandleStride<T>> Arrays;
std::vector<PortalType> Portals;
mutable std::vector<T> Values;
friend UnknownArrayHandle;
void AddArray(const vtkm::cont::ArrayHandleStride<T>& array, const PortalType& portal)
{
this->Arrays.push_back(array);
this->Portals.push_back(portal);
}
public:
using ValueType = vtkm::VecCConst<T>;
ArrayPortalFromExtractedComponents(vtkm::IdComponent expectedArrays = 0)
{
this->Arrays.reserve(static_cast<std::size_t>(expectedArrays));
this->Portals.reserve(static_cast<std::size_t>(expectedArrays));
}
VTKM_CONT vtkm::Id GetNumberOfValues() const { return this->Portals[0].GetNumberOfValues(); }
VTKM_CONT ValueType Get(vtkm::Id index) const
{
// Note: this is not thread-safe
this->Values.clear();
for (auto&& portal : this->Portals)
{
this->Values.push_back(portal.Get(index));
}
return ValueType(this->Values.data(), static_cast<vtkm::IdComponent>(this->Values.size()));
}
template <typename VecType,
typename Writable = vtkm::internal::PortalSupportsSets<PortalType>,
typename = typename std::enable_if<Writable::value>::type>
VTKM_CONT void Set(vtkm::Id index, const VecType& value) const
{
using Traits = vtkm::VecTraits<VecType>;
for (vtkm::IdComponent cIndex = 0; cIndex < Traits::GetNumberOfComponents(value); ++cIndex)
{
this->Portals[static_cast<std::size_t>(cIndex)].Set(index,
Traits::GetComponent(value, index));
}
}
};
}
}
} // namespace vtkm::cont::internal
#endif //vtk_m_cont_internal_ArrayPortalFromExtractedComponents_h

@ -110,17 +110,6 @@ struct MetaDataManager
MetaDataManager() = default;
MetaDataManager(void* data,
const std::string& type,
vtkm::cont::internal::detail::DeleterType* deleter,
vtkm::cont::internal::detail::CopierType* copier)
: Data(data)
, Type(type)
, Deleter(deleter)
, Copier(copier)
{
}
~MetaDataManager()
{
if (this->Data != nullptr)
@ -131,20 +120,23 @@ struct MetaDataManager
}
}
MetaDataManager(const MetaDataManager& src)
// We don't know how much information is the metadata, and copying it could be expensive.
// Thus, we want to be intentional about copying the metadata only for deep copies.
MetaDataManager(const MetaDataManager& src) = delete;
MetaDataManager& operator=(const MetaDataManager& src) = delete;
void Initialize(void* data,
const std::string& type,
vtkm::cont::internal::detail::DeleterType* deleter,
vtkm::cont::internal::detail::CopierType* copier)
{
if (src.Data != nullptr)
{
VTKM_ASSERT(src.Copier);
VTKM_ASSERT(src.Deleter);
this->Data = src.Copier(src.Data);
this->Type = src.Type;
this->Deleter = src.Deleter;
this->Copier = src.Copier;
}
Data = data;
Type = type;
Deleter = deleter;
Copier = copier;
}
MetaDataManager& operator=(const MetaDataManager& src)
void DeepCopyFrom(const MetaDataManager& src)
{
if (this->Data != nullptr)
{
@ -162,7 +154,6 @@ struct MetaDataManager
this->Deleter = src.Deleter;
this->Copier = src.Copier;
}
return *this;
}
};
@ -599,7 +590,7 @@ struct VTKM_NEVER_EXPORT BufferHelper
srcInternals->GetHostBuffer(srcLock).GetPointer(),
static_cast<std::size_t>(size));
destInternals->MetaData = srcInternals->MetaData;
destInternals->MetaData.DeepCopyFrom(srcInternals->MetaData);
}
static void CopyOnDevice(
@ -641,7 +632,7 @@ struct VTKM_NEVER_EXPORT BufferHelper
destInternals->SetNumberOfBytes(destLock, srcInternals->GetNumberOfBytes(srcLock));
destInternals->MetaData = srcInternals->MetaData;
destInternals->MetaData.DeepCopyFrom(srcInternals->MetaData);
}
};
@ -710,7 +701,7 @@ void Buffer::SetMetaData(void* data,
detail::DeleterType* deleter,
detail::CopierType* copier) const
{
this->Internals->MetaData = MetaDataManager(data, type, deleter, copier);
this->Internals->MetaData.Initialize(data, type, deleter, copier);
}
void* Buffer::GetMetaData(const std::string& type) const
@ -881,7 +872,7 @@ void Buffer::DeepCopyFrom(const vtkm::cont::internal::Buffer& src) const
src.Internals->GetNumberOfBytes(srcLock),
vtkm::CopyFlag::Off,
token);
dest.Internals->MetaData = src.Internals->MetaData;
dest.Internals->MetaData.DeepCopyFrom(src.Internals->MetaData);
}
}
}

@ -9,8 +9,8 @@
##============================================================================
set(headers
ArrayHandleDeprecated.h
ArrayHandleExecutionManager.h
ArrayPortalFromExtractedComponents.h
ArrayPortalFromIterators.h
ArrayTransfer.h
AtomicInterfaceControl.h

@ -0,0 +1,69 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
//
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//============================================================================
#ifndef vtk_m_cont_internal_DefaultTypesAscent_h
#define vtk_m_cont_internal_DefaultTypesAscent_h
#include <vtkm/TypeList.h>
#include <vtkm/Types.h>
#include <vtkm/cont/ArrayHandleCartesianProduct.h>
#include <vtkm/cont/ArrayHandleSOA.h>
#include <vtkm/cont/ArrayHandleUniformPointCoordinates.h>
#include <vtkm/cont/StorageList.h>
#ifdef VTKM_USE_64BIT_IDS
#error "VTK-m must be compiled with VTKM_USE_64BITS_IDS set to OFF for Ascent."
#endif
#ifndef VTKM_USE_DOUBLE_PRECISION
#error "VTK-m must be compiled with VTKM_USE_DOUBLE_PRECISION to ON for Ascent."
#endif
namespace vtkm
{
namespace internal
{
// Default value types for fields in Ascent.
using TypeListAscent = vtkm::List<vtkm::FloatDefault,
vtkm::Vec3f,
// We should not need Float32 types, but currently the tests need
// them. We should remove these types once we are able to "fix"
// the tests by converting to supported default types.
vtkm::Float32,
vtkm::Vec3f_32>;
}
} // namespace vtkm::internal
#define VTKM_DEFAULT_TYPE_LIST ::vtkm::internal::TypeListAscent
namespace vtkm
{
namespace cont
{
namespace internal
{
using StorageListAscent = vtkm::List<
vtkm::cont::StorageTagBasic, // Basic storage should always be included
vtkm::cont::StorageTagSOA, // Support separate arrays for each component
vtkm::cont::StorageTagUniformPoints, // Support uniform structured grids
vtkm::cont::StorageTagCartesianProduct<vtkm::cont::StorageTagBasic, // Support rectilinear grids
vtkm::cont::StorageTagBasic,
vtkm::cont::StorageTagBasic>>;
}
}
} // namespace vtkm::cont::internal
#define VTKM_DEFAULT_STORAGE_LIST ::vtkm::cont::internal::StorageListAscent
#endif //vtk_m_cont_internal_DefaultTypesAscent_h

@ -7,8 +7,8 @@
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//============================================================================
#ifndef vtkmDefaultTypes_h
#define vtkmDefaultTypes_h
#ifndef vtk_m_cont_internal_DefaultTypesVTK_h
#define vtk_m_cont_internal_DefaultTypesVTK_h
// This configures the default types to use when compiling VTK-m for use as an
// accelerator in VTK.
@ -105,4 +105,4 @@ using CellListAllOutVTK = vtkm::ListAppend<CellListStructuredOutVTK, CellListUns
#define VTKM_DEFAULT_CELL_SET_LIST_STRUCTURED ::tovtkm::CellListStructuredInVTK
#define VTKM_DEFAULT_CELL_SET_LIST_UNSTRUCTURED ::tovtkm::CellListUnstructuredInVTK
#endif //vtkmDefaultTypes_h
#endif //vtk_m_cont_internal_DefaultTypesVTK_h

@ -12,8 +12,8 @@
#define vtk_m_cont_internal_DeviceAdapterAlgorithmGeneral_h
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ArrayHandleDecorator.h>
#include <vtkm/cont/ArrayHandleDiscard.h>
#include <vtkm/cont/ArrayHandleImplicit.h>
#include <vtkm/cont/ArrayHandleIndex.h>
#include <vtkm/cont/ArrayHandleView.h>
#include <vtkm/cont/ArrayHandleZip.h>
@ -529,6 +529,33 @@ public:
//--------------------------------------------------------------------------
// Reduce
private:
template <typename T, typename BinaryFunctor>
class ReduceDecoratorImpl
{
public:
VTKM_CONT ReduceDecoratorImpl() = default;
VTKM_CONT
ReduceDecoratorImpl(const T& initialValue, const BinaryFunctor& binaryFunctor)
: InitialValue(initialValue)
, ReduceOperator(binaryFunctor)
{
}
template <typename Portal>
VTKM_CONT ReduceKernel<Portal, T, BinaryFunctor> CreateFunctor(const Portal& portal) const
{
return ReduceKernel<Portal, T, BinaryFunctor>(
portal, this->InitialValue, this->ReduceOperator);
}
private:
T InitialValue;
BinaryFunctor ReduceOperator;
};
public:
template <typename T, typename U, class CIn>
VTKM_CONT static U Reduce(const vtkm::cont::ArrayHandle<T, CIn>& input, U initialValue)
{
@ -544,24 +571,16 @@ public:
{
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
vtkm::cont::Token token;
//Crazy Idea:
//We create a implicit array handle that wraps the input
//array handle. The implicit functor is passed the input array handle, and
//the number of elements it needs to sum. This way the implicit handle
//acts as the first level reduction. Say for example reducing 16 values
//at a time.
//
//Now that we have an implicit array that is 1/16 the length of full array
//we can use scan inclusive to compute the final sum
auto inputPortal = input.PrepareForInput(DeviceAdapterTag(), token);
ReduceKernel<decltype(inputPortal), U, BinaryFunctor> kernel(
inputPortal, initialValue, binary_functor);
//We perform the reduction in two levels. The first level is performed by
//an `ArrayHandleDecorator` which reduces 16 input values and maps them to
//one value. The decorator array is then 1/16 the length of the input array,
//and we can use inclusive scan as the second level to compute the final
//result.
vtkm::Id length = (input.GetNumberOfValues() / 16);
length += (input.GetNumberOfValues() % 16 == 0) ? 0 : 1;
auto reduced = vtkm::cont::make_ArrayHandleImplicit(kernel, length);
auto reduced = vtkm::cont::make_ArrayHandleDecorator(
length, ReduceDecoratorImpl<U, BinaryFunctor>(initialValue, binary_functor), input);
vtkm::cont::ArrayHandle<U, vtkm::cont::StorageTagBasic> inclusiveScanStorage;
const U scanResult =

@ -25,12 +25,12 @@ namespace vtkm
namespace cont
{
template <typename T, typename S>
class ArrayHandle;
namespace internal
{
template <typename T, typename S>
class ArrayHandleDeprecated;
namespace detail
{
@ -98,7 +98,7 @@ class StorageDeprecated
using T = typename detail::StorageTemplateParams<StorageType>::ValueType;
using StorageTag = typename detail::StorageTemplateParams<StorageType>::StorageTag;
using ArrayType = vtkm::cont::ArrayHandle<T, StorageTag>;
using ArrayType = vtkm::cont::internal::ArrayHandleDeprecated<T, StorageTag>;
VTKM_CONT static ArrayType GetArray(const vtkm::cont::internal::Buffer* buffers)
{

@ -8,6 +8,7 @@
// PURPOSE. See the above copyright notice for more information.
//============================================================================
#include <vtkm/cont/internal/ArrayPortalFromIterators.h>
#include <vtkm/cont/internal/Buffer.h>
#include <vtkm/cont/serial/DeviceAdapterSerial.h>

@ -10,10 +10,9 @@
#ifndef vtk_m_cont_kokkos_internal_DeviceAdapterAlgorithmKokkos_h
#define vtk_m_cont_kokkos_internal_DeviceAdapterAlgorithmKokkos_h
#include <vtkm/cont/DeviceAdapterAlgorithm.h>
#include <vtkm/cont/ArrayHandleImplicit.h>
#include <vtkm/cont/ArrayHandleIndex.h>
#include <vtkm/cont/DeviceAdapterAlgorithm.h>
#include <vtkm/cont/ErrorExecution.h>
#include <vtkm/cont/internal/DeviceAdapterAlgorithmGeneral.h>
#include <vtkm/cont/vtkm_cont_export.h>
@ -164,6 +163,7 @@ struct ReductionIdentity<vtkm::BitwiseOr, ResultType>
}
} // kokkos::internal
//=============================================================================
template <>
struct DeviceAdapterAlgorithm<vtkm::cont::DeviceAdapterTagKokkos>
: vtkm::cont::internal::DeviceAdapterAlgorithmGeneral<
@ -208,6 +208,7 @@ public:
vtkm::Id{ 0 });
}
//----------------------------------------------------------------------------
using Superclass::Copy;
template <typename T>
@ -227,66 +228,104 @@ public:
Kokkos::deep_copy(vtkm::cont::kokkos::internal::GetExecutionSpaceInstance(), viewOut, viewIn);
}
//----------------------------------------------------------------------------
private:
template <typename ArrayHandle, typename BinaryFunctor, typename ResultType>
template <typename ArrayHandle, typename BinaryOperator, typename ResultType>
VTKM_CONT static ResultType ReduceImpl(const ArrayHandle& input,
BinaryFunctor binary_functor,
BinaryOperator binaryOperator,
ResultType initialValue,
std::false_type)
{
return Superclass::Reduce(input, initialValue, binary_functor);
return Superclass::Reduce(input, initialValue, binaryOperator);
}
template <typename ArrayPortal, typename BinaryFunctor, typename ResultType>
class ReduceFunctor
template <typename BinaryOperator, typename FunctorOperator, typename ResultType>
class KokkosReduceFunctor
{
public:
using size_type = vtkm::Id;
using value_type = ResultType;
KOKKOS_INLINE_FUNCTION
ReduceFunctor() {}
KokkosReduceFunctor() {}
KOKKOS_INLINE_FUNCTION
explicit ReduceFunctor(const ArrayPortal& portal, const BinaryFunctor& op)
: Portal(portal)
, Operator(op)
template <typename... Args>
KOKKOS_INLINE_FUNCTION explicit KokkosReduceFunctor(const BinaryOperator& op, Args... args)
: Operator(op)
, Functor(std::forward<Args>(args)...)
{
}
KOKKOS_INLINE_FUNCTION
void operator()(const size_type i, value_type& update) const
{
update = this->Operator(update, this->Portal.Get(i));
}
KOKKOS_INLINE_FUNCTION
void join(volatile value_type& dst, const volatile value_type& src) const
{
dst = this->Operator(dst, src);
}
KOKKOS_INLINE_FUNCTION void init(value_type& dst) const
KOKKOS_INLINE_FUNCTION
void init(value_type& dst) const
{
dst = kokkos::internal::ReductionIdentity<BinaryFunctor, value_type>::value;
dst = kokkos::internal::ReductionIdentity<BinaryOperator, value_type>::value;
}
// Reduce operator
KOKKOS_INLINE_FUNCTION
void operator()(vtkm::Id i, ResultType& update) const
{
this->Functor(this->Operator, i, update);
}
// Scan operator
KOKKOS_INLINE_FUNCTION
void operator()(vtkm::Id i, ResultType& update, const bool final) const
{
this->Functor(this->Operator, i, update, final);
}
private:
BinaryOperator Operator;
FunctorOperator Functor;
};
template <typename ArrayPortal, typename BinaryOperator, typename ResultType>
class ReduceOperator
{
public:
KOKKOS_INLINE_FUNCTION
ReduceOperator() {}
KOKKOS_INLINE_FUNCTION
explicit ReduceOperator(const ArrayPortal& portal)
: Portal(portal)
{
}
KOKKOS_INLINE_FUNCTION
void operator()(const BinaryOperator& op, vtkm::Id i, ResultType& update) const
{
update = op(update, this->Portal.Get(i));
}
private:
ArrayPortal Portal;
BinaryFunctor Operator;
};
template <typename ArrayHandle, typename BinaryFunctor, typename ResultType>
template <typename BinaryOperator, typename ArrayPortal, typename ResultType>
using ReduceFunctor = KokkosReduceFunctor<BinaryOperator,
ReduceOperator<ArrayPortal, BinaryOperator, ResultType>,
ResultType>;
template <typename ArrayHandle, typename BinaryOperator, typename ResultType>
VTKM_CONT static ResultType ReduceImpl(const ArrayHandle& input,
BinaryFunctor binary_functor,
BinaryOperator binaryOperator,
ResultType initialValue,
std::true_type)
{
vtkm::cont::Token token;
auto inputPortal = input.PrepareForInput(vtkm::cont::DeviceAdapterTagKokkos{}, token);
ReduceFunctor<decltype(inputPortal), BinaryFunctor, ResultType> functor(inputPortal,
binary_functor);
ReduceFunctor<BinaryOperator, decltype(inputPortal), ResultType> functor(binaryOperator,
inputPortal);
ResultType result;
@ -294,36 +333,47 @@ private:
vtkm::cont::kokkos::internal::GetExecutionSpaceInstance(), 0, input.GetNumberOfValues());
Kokkos::parallel_reduce(policy, functor, result);
return binary_functor(initialValue, result);
return binaryOperator(initialValue, result);
}
template <bool P1, typename BinaryFunctor, typename ResultType>
template <bool P1, typename BinaryOperator, typename ResultType>
struct UseKokkosReduceP1 : std::false_type
{
};
template <typename BinaryFunctor, typename ResultType>
struct UseKokkosReduceP1<true, BinaryFunctor, ResultType>
template <typename BinaryOperator, typename ResultType>
struct UseKokkosReduceP1<true, BinaryOperator, ResultType>
: vtkm::internal::is_type_complete<
kokkos::internal::ReductionIdentity<BinaryFunctor, ResultType>>
kokkos::internal::ReductionIdentity<BinaryOperator, ResultType>>
{
};
template <typename BinaryFunctor, typename ResultType>
template <typename BinaryOperator, typename ResultType>
struct UseKokkosReduce
: UseKokkosReduceP1<
vtkm::internal::is_type_complete<Kokkos::reduction_identity<ResultType>>::value,
BinaryFunctor,
BinaryOperator,
ResultType>
{
};
public:
template <typename T, typename U, class CIn, class BinaryFunctor>
template <typename T, typename U, class CIn, class BinaryOperator>
VTKM_CONT static U Reduce(const vtkm::cont::ArrayHandle<T, CIn>& input,
U initialValue,
BinaryFunctor binary_functor)
BinaryOperator binaryOperator)
{
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
if (input.GetNumberOfValues() == 0)
{
return initialValue;
}
if (input.GetNumberOfValues() == 1)
{
return binaryOperator(initialValue, input.ReadPortal().Get(0));
}
#if defined(VTKM_KOKKOS_CUDA)
// Kokkos reduce is having some issues with the cuda backend. Please refer to issue #586.
// Following is a work around where we use the Superclass reduce implementation when using
@ -331,21 +381,276 @@ public:
std::integral_constant<
bool,
!std::is_same<vtkm::cont::kokkos::internal::ExecutionSpace, Kokkos::Cuda>::value &&
UseKokkosReduce<BinaryFunctor, U>::value>
UseKokkosReduce<BinaryOperator, U>::value>
use_kokkos_reduce;
#else
typename UseKokkosReduce<BinaryFunctor, U>::type use_kokkos_reduce;
typename UseKokkosReduce<BinaryOperator, U>::type use_kokkos_reduce;
#endif
return ReduceImpl(input, binary_functor, initialValue, use_kokkos_reduce);
return ReduceImpl(input, binaryOperator, initialValue, use_kokkos_reduce);
}
template <typename T, typename U, class CIn>
VTKM_CONT static U Reduce(const vtkm::cont::ArrayHandle<T, CIn>& input, U initialValue)
{
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
return Reduce(input, initialValue, vtkm::Add());
}
//----------------------------------------------------------------------------
private:
// Scan and Reduce have the same conditions
template <typename BinaryOperator, typename ResultType>
using UseKokkosScan = UseKokkosReduce<BinaryOperator, ResultType>;
template <typename T, typename StorageIn, typename StorageOut, typename BinaryOperator>
VTKM_CONT static T ScanExclusiveImpl(const vtkm::cont::ArrayHandle<T, StorageIn>& input,
vtkm::cont::ArrayHandle<T, StorageOut>& output,
BinaryOperator binaryOperator,
const T& initialValue,
std::false_type)
{
return Superclass::ScanExclusive(input, output, binaryOperator, initialValue);
}
template <typename T, typename StorageIn, typename StorageOut, typename BinaryOperator>
class ScanExclusiveOperator
{
private:
using ArrayPortalIn =
typename ArrayHandle<T,
StorageIn>::template ExecutionTypes<DeviceAdapterTagKokkos>::PortalConst;
using ArrayPortalOut =
typename ArrayHandle<T, StorageOut>::template ExecutionTypes<DeviceAdapterTagKokkos>::Portal;
public:
KOKKOS_INLINE_FUNCTION
ScanExclusiveOperator() {}
KOKKOS_INLINE_FUNCTION
explicit ScanExclusiveOperator(const ArrayPortalIn& portalIn,
const ArrayPortalOut& portalOut,
const T& initialValue)
: PortalIn(portalIn)
, PortalOut(portalOut)
, InitialValue(initialValue)
{
}
KOKKOS_INLINE_FUNCTION
void operator()(const BinaryOperator& op, const vtkm::Id i, T& update, const bool final) const
{
auto val = this->PortalIn.Get(i);
if (i == 0)
{
update = InitialValue;
}
if (final)
{
this->PortalOut.Set(i, update);
}
update = op(update, val);
}
private:
ArrayPortalIn PortalIn;
ArrayPortalOut PortalOut;
T InitialValue;
};
template <typename BinaryOperator, typename T, typename StorageIn, typename StorageOut>
using ScanExclusiveFunctor =
KokkosReduceFunctor<BinaryOperator,
ScanExclusiveOperator<T, StorageIn, StorageOut, BinaryOperator>,
T>;
template <typename T, typename StorageIn, typename StorageOut, typename BinaryOperator>
VTKM_CONT static T ScanExclusiveImpl(const vtkm::cont::ArrayHandle<T, StorageIn>& input,
vtkm::cont::ArrayHandle<T, StorageOut>& output,
BinaryOperator binaryOperator,
const T& initialValue,
std::true_type)
{
vtkm::Id length = input.GetNumberOfValues();
vtkm::cont::Token token;
auto inputPortal = input.PrepareForInput(vtkm::cont::DeviceAdapterTagKokkos{}, token);
auto outputPortal =
output.PrepareForOutput(length, vtkm::cont::DeviceAdapterTagKokkos{}, token);
ScanExclusiveFunctor<BinaryOperator, T, StorageIn, StorageOut> functor(
binaryOperator, inputPortal, outputPortal, initialValue);
T result = vtkm::TypeTraits<T>::ZeroInitialization();
Kokkos::RangePolicy<vtkm::cont::kokkos::internal::ExecutionSpace, vtkm::Id> policy(
vtkm::cont::kokkos::internal::GetExecutionSpaceInstance(), 0, length);
Kokkos::parallel_scan(policy, functor, result);
return result;
}
public:
template <typename T, class CIn, class COut, class BinaryOperator>
VTKM_CONT static T ScanExclusive(const vtkm::cont::ArrayHandle<T, CIn>& input,
vtkm::cont::ArrayHandle<T, COut>& output,
BinaryOperator binaryOperator,
const T& initialValue)
{
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
vtkm::Id length = input.GetNumberOfValues();
if (length == 0)
{
output.Shrink(0);
return initialValue;
}
if (length == 1)
{
auto v0 = input.ReadPortal().Get(0);
Fill(output, initialValue, 1);
return binaryOperator(initialValue, v0);
}
#if defined(VTKM_KOKKOS_CUDA)
// Kokkos scan for the cuda backend is not working correctly for int/uint types of 8 and 16 bits.
std::integral_constant<bool,
!(std::is_integral<T>::value && sizeof(T) < 4) &&
UseKokkosScan<BinaryOperator, T>::value>
use_kokkos_scan;
#else
typename UseKokkosScan<BinaryOperator, T>::type use_kokkos_scan;
#endif
return ScanExclusiveImpl(input, output, binaryOperator, initialValue, use_kokkos_scan);
}
template <typename T, class CIn, class COut>
VTKM_CONT static T ScanExclusive(const vtkm::cont::ArrayHandle<T, CIn>& input,
vtkm::cont::ArrayHandle<T, COut>& output)
{
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
return ScanExclusive(input, output, vtkm::Sum(), vtkm::TypeTraits<T>::ZeroInitialization());
}
//----------------------------------------------------------------------------
private:
template <typename T, typename StorageIn, typename StorageOut, typename BinaryOperator>
VTKM_CONT static T ScanInclusiveImpl(const vtkm::cont::ArrayHandle<T, StorageIn>& input,
vtkm::cont::ArrayHandle<T, StorageOut>& output,
BinaryOperator binaryOperator,
std::false_type)
{
return Superclass::ScanInclusive(input, output, binaryOperator);
}
template <typename T, typename StorageIn, typename StorageOut, typename BinaryOperator>
class ScanInclusiveOperator
{
private:
using ArrayPortalIn =
typename ArrayHandle<T,
StorageIn>::template ExecutionTypes<DeviceAdapterTagKokkos>::PortalConst;
using ArrayPortalOut =
typename ArrayHandle<T, StorageOut>::template ExecutionTypes<DeviceAdapterTagKokkos>::Portal;
public:
KOKKOS_INLINE_FUNCTION
ScanInclusiveOperator() {}
KOKKOS_INLINE_FUNCTION
explicit ScanInclusiveOperator(const ArrayPortalIn& portalIn, const ArrayPortalOut& portalOut)
: PortalIn(portalIn)
, PortalOut(portalOut)
{
}
KOKKOS_INLINE_FUNCTION
void operator()(const BinaryOperator& op, const vtkm::Id i, T& update, const bool final) const
{
update = op(update, this->PortalIn.Get(i));
if (final)
{
this->PortalOut.Set(i, update);
}
}
private:
ArrayPortalIn PortalIn;
ArrayPortalOut PortalOut;
};
template <typename BinaryOperator, typename T, typename StorageIn, typename StorageOut>
using ScanInclusiveFunctor =
KokkosReduceFunctor<BinaryOperator,
ScanInclusiveOperator<T, StorageIn, StorageOut, BinaryOperator>,
T>;
template <typename T, typename StorageIn, typename StorageOut, typename BinaryOperator>
VTKM_CONT static T ScanInclusiveImpl(const vtkm::cont::ArrayHandle<T, StorageIn>& input,
vtkm::cont::ArrayHandle<T, StorageOut>& output,
BinaryOperator binaryOperator,
std::true_type)
{
vtkm::Id length = input.GetNumberOfValues();
vtkm::cont::Token token;
auto inputPortal = input.PrepareForInput(vtkm::cont::DeviceAdapterTagKokkos{}, token);
auto outputPortal =
output.PrepareForOutput(length, vtkm::cont::DeviceAdapterTagKokkos{}, token);
ScanInclusiveFunctor<BinaryOperator, T, StorageIn, StorageOut> functor(
binaryOperator, inputPortal, outputPortal);
T result = vtkm::TypeTraits<T>::ZeroInitialization();
Kokkos::RangePolicy<vtkm::cont::kokkos::internal::ExecutionSpace, vtkm::Id> policy(
vtkm::cont::kokkos::internal::GetExecutionSpaceInstance(), 0, length);
Kokkos::parallel_scan(policy, functor, result);
return result;
}
public:
template <typename T, class CIn, class COut, class BinaryOperator>
VTKM_CONT static T ScanInclusive(const vtkm::cont::ArrayHandle<T, CIn>& input,
vtkm::cont::ArrayHandle<T, COut>& output,
BinaryOperator binaryOperator)
{
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
vtkm::Id length = input.GetNumberOfValues();
if (length == 0)
{
return vtkm::TypeTraits<T>::ZeroInitialization();
}
if (length == 1)
{
auto result = input.ReadPortal().Get(0);
Fill(output, result, 1);
return result;
}
#if defined(VTKM_KOKKOS_CUDA)
// Kokkos scan for the cuda backend is not working correctly for int/uint types of 8 and 16 bits.
std::integral_constant<bool,
!(std::is_integral<T>::value && sizeof(T) < 4) &&
UseKokkosScan<BinaryOperator, T>::value>
use_kokkos_scan;
#else
typename UseKokkosScan<BinaryOperator, T>::type use_kokkos_scan;
#endif
return ScanInclusiveImpl(input, output, binaryOperator, use_kokkos_scan);
}
template <typename T, class CIn, class COut>
VTKM_CONT static T ScanInclusive(const vtkm::cont::ArrayHandle<T, CIn>& input,
vtkm::cont::ArrayHandle<T, COut>& output)
{
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
return ScanInclusive(input, output, vtkm::Add());
}
//----------------------------------------------------------------------------
template <typename WType, typename IType>
VTKM_CONT static void ScheduleTask(
vtkm::exec::kokkos::internal::TaskBasic1D<WType, IType>& functor,
@ -415,6 +720,7 @@ public:
ScheduleTask(kernel, rangeMax);
}
//----------------------------------------------------------------------------
private:
template <typename T>
VTKM_CONT static void SortImpl(vtkm::cont::ArrayHandle<T>& values, vtkm::SortLess, std::true_type)
@ -456,6 +762,7 @@ public:
}
};
//=============================================================================
template <>
class DeviceTaskTypes<vtkm::cont::DeviceAdapterTagKokkos>
{

@ -36,6 +36,7 @@ set(unit_tests
UnitTestArrayGetValues.cxx
UnitTestArrayHandleCartesianProduct.cxx
UnitTestArrayHandleCompositeVector.cxx
UnitTestArrayHandleConcatenate.cxx
UnitTestArrayHandleCounting.cxx
UnitTestArrayHandleDecorator.cxx
UnitTestArrayHandleDiscard.cxx
@ -52,7 +53,6 @@ set(unit_tests
UnitTestArrayHandleThreadSafety.cxx
UnitTestArrayHandleTransform.cxx
UnitTestArrayHandleUniformPointCoordinates.cxx
UnitTestArrayHandleConcatenate.cxx
UnitTestArrayHandleVirtual.cxx
UnitTestArrayPortalToIterators.cxx
UnitTestCellLocatorGeneral.cxx

@ -29,6 +29,7 @@
#include <vtkm/cont/RuntimeDeviceInformation.h>
#include <vtkm/cont/Timer.h>
#include <vtkm/cont/internal/ArrayPortalFromIterators.h>
#include <vtkm/cont/internal/VirtualObjectTransfer.h>
#include <vtkm/cont/testing/Testing.h>

@ -24,6 +24,7 @@
#include <vtkm/cont/ArrayHandleIndex.h>
#include <vtkm/cont/ArrayHandleMultiplexer.h>
#include <vtkm/cont/ArrayHandlePermutation.h>
#include <vtkm/cont/ArrayHandleRecombineVec.h>
#include <vtkm/cont/ArrayHandleSOA.h>
#include <vtkm/cont/ArrayHandleTransform.h>
#include <vtkm/cont/ArrayHandleView.h>
@ -222,12 +223,12 @@ public:
struct PassThrough : public vtkm::worklet::WorkletMapField
{
using ControlSignature = void(FieldIn, FieldOut);
using ExecutionSignature = _2(_1);
using ExecutionSignature = void(_1, _2);
template <class ValueType>
VTKM_EXEC ValueType operator()(const ValueType& inValue) const
template <typename InValue, typename OutValue>
VTKM_EXEC void operator()(const InValue& inValue, OutValue& outValue) const
{
return inValue;
outValue = inValue;
}
};
@ -1154,6 +1155,61 @@ private:
}
};
struct TestRecombineVecAsInput
{
template <typename T>
VTKM_CONT void operator()(T) const
{
vtkm::cont::ArrayHandle<T> baseArray;
baseArray.Allocate(ARRAY_SIZE);
SetPortal(baseArray.WritePortal());
using VTraits = vtkm::VecTraits<T>;
vtkm::cont::ArrayHandleRecombineVec<typename VTraits::ComponentType> recombinedArray;
for (vtkm::IdComponent cIndex = 0; cIndex < VTraits::NUM_COMPONENTS; ++cIndex)
{
recombinedArray.AppendComponentArray(vtkm::cont::ArrayExtractComponent(baseArray, cIndex));
}
VTKM_TEST_ASSERT(recombinedArray.GetNumberOfComponents() == VTraits::NUM_COMPONENTS);
VTKM_TEST_ASSERT(recombinedArray.GetNumberOfValues() == ARRAY_SIZE);
vtkm::cont::ArrayHandle<T> outputArray;
vtkm::cont::Invoker invoke;
invoke(PassThrough{}, recombinedArray, outputArray);
VTKM_TEST_ASSERT(test_equal_ArrayHandles(baseArray, outputArray));
}
};
struct TestRecombineVecAsOutput
{
template <typename T>
VTKM_CONT void operator()(T) const
{
vtkm::cont::ArrayHandle<T> baseArray;
baseArray.Allocate(ARRAY_SIZE);
SetPortal(baseArray.WritePortal());
vtkm::cont::ArrayHandle<T> outputArray;
outputArray.Allocate(ARRAY_SIZE); // Cannot resize after recombine
using VTraits = vtkm::VecTraits<T>;
vtkm::cont::ArrayHandleRecombineVec<typename VTraits::ComponentType> recombinedArray;
for (vtkm::IdComponent cIndex = 0; cIndex < VTraits::NUM_COMPONENTS; ++cIndex)
{
recombinedArray.AppendComponentArray(
vtkm::cont::ArrayExtractComponent(outputArray, cIndex));
}
VTKM_TEST_ASSERT(recombinedArray.GetNumberOfComponents() == VTraits::NUM_COMPONENTS);
VTKM_TEST_ASSERT(recombinedArray.GetNumberOfValues() == ARRAY_SIZE);
vtkm::cont::Invoker invoke;
invoke(PassThrough{}, baseArray, recombinedArray);
VTKM_TEST_ASSERT(test_equal_ArrayHandles(baseArray, outputArray));
}
};
struct TestZipAsInput
{
template <typename KeyType, typename ValueType>
@ -1426,6 +1482,8 @@ private:
using ScalarTypesToTest = vtkm::List<vtkm::UInt8, vtkm::FloatDefault>;
using VectorTypesToTest = vtkm::List<vtkm::Vec2i_8, vtkm::Vec3f_32>;
using ZipTypesToTest = vtkm::List<vtkm::Pair<vtkm::UInt8, vtkm::Id>,
vtkm::Pair<vtkm::Float64, vtkm::Vec4ui_8>,
vtkm::Pair<vtkm::Vec3f_32, vtkm::Vec4i_8>>;
@ -1449,12 +1507,12 @@ private:
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing ArrayHandleSOA as Input" << std::endl;
vtkm::testing::Testing::TryTypes(TestingFancyArrayHandles<DeviceAdapterTag>::TestSOAAsInput(),
HandleTypesToTest());
VectorTypesToTest());
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing ArrayHandleSOA as Output" << std::endl;
vtkm::testing::Testing::TryTypes(
TestingFancyArrayHandles<DeviceAdapterTag>::TestSOAAsOutput(), HandleTypesToTest());
TestingFancyArrayHandles<DeviceAdapterTag>::TestSOAAsOutput(), VectorTypesToTest());
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing ArrayHandleCompositeVector as Input" << std::endl;
@ -1555,6 +1613,17 @@ private:
TestingFancyArrayHandles<DeviceAdapterTag>::TestGroupVecVariableAsOutput(),
ScalarTypesToTest());
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing ArrayHandleRecombineVec as Input" << std::endl;
vtkm::testing::Testing::TryTypes(
TestingFancyArrayHandles<DeviceAdapterTag>::TestRecombineVecAsInput(), HandleTypesToTest{});
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing ArrayHandleRecombineVec as Output" << std::endl;
vtkm::testing::Testing::TryTypes(
TestingFancyArrayHandles<DeviceAdapterTag>::TestRecombineVecAsOutput(),
HandleTypesToTest{});
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing ArrayHandleZip as Input" << std::endl;
vtkm::testing::Testing::TryTypes(TestingFancyArrayHandles<DeviceAdapterTag>::TestZipAsInput(),

@ -378,7 +378,7 @@ void TestArrayHandleSerialization()
TestArrayHandleBasic(), vtkm::List<char, long, long long, unsigned long, unsigned long long>());
std::cout << "Testing ArrayHandleSOA\n";
vtkm::testing::Testing::TryTypes(TestArrayHandleSOA(), TestTypesList());
vtkm::testing::Testing::TryTypes(TestArrayHandleSOA(), TestTypesListVec());
std::cout << "Testing ArrayHandleCartesianProduct\n";
vtkm::testing::Testing::TryTypes(TestArrayHandleCartesianProduct(), TestTypesListScalar());

@ -428,6 +428,26 @@ void TryAsArrayHandle()
TryAsArrayHandle(vtkm::cont::make_ArrayHandleConstant(5, ARRAY_SIZE));
}
struct CheckExtractedArray
{
template <typename ExtractedArray, typename OriginalArray>
void operator()(const ExtractedArray& extractedArray, const OriginalArray& originalArray) const
{
using ValueType = typename OriginalArray::ValueType;
using FlatVec = vtkm::VecFlat<ValueType>;
VTKM_TEST_ASSERT(extractedArray.GetNumberOfComponents() == FlatVec::NUM_COMPONENTS);
auto originalPortal = originalArray.ReadPortal();
auto extractedPortal = extractedArray.ReadPortal();
for (vtkm::Id valueIndex = 0; valueIndex < ARRAY_SIZE; ++valueIndex)
{
FlatVec originalData = originalPortal.Get(valueIndex);
auto extractedData = extractedPortal.Get(valueIndex);
VTKM_TEST_ASSERT(test_equal(originalData, extractedData));
}
}
};
template <typename ArrayHandleType>
void TryExtractComponent()
{
@ -443,15 +463,9 @@ void TryExtractComponent()
VTKM_TEST_ASSERT(unknownArray.GetNumberOfComponentsFlat() == FlatVec::NUM_COMPONENTS);
auto componentPortal = unknownArray.ReadPortalForBaseComponentType<ComponentType>();
CheckExtractedArray{}(unknownArray.ExtractArrayFromComponents<ComponentType>(), originalArray);
auto originalPortal = originalArray.ReadPortal();
for (vtkm::Id valueIndex = 0; valueIndex < ARRAY_SIZE; ++valueIndex)
{
FlatVec originalData = originalPortal.Get(valueIndex);
auto componentData = componentPortal.Get(valueIndex);
VTKM_TEST_ASSERT(test_equal(originalData, componentData));
}
unknownArray.CastAndCallWithExtractedArray(CheckExtractedArray{}, originalArray);
}
void TryExtractComponent()
@ -459,6 +473,9 @@ void TryExtractComponent()
std::cout << " Scalar array." << std::endl;
TryExtractComponent<vtkm::cont::ArrayHandle<vtkm::FloatDefault>>();
std::cout << " Equivalent scalar." << std::endl;
TryExtractComponent<vtkm::cont::ArrayHandle<VTKM_UNUSED_INT_TYPE>>();
std::cout << " Basic Vec." << std::endl;
TryExtractComponent<vtkm::cont::ArrayHandle<vtkm::Id3>>();

@ -416,17 +416,20 @@ void TryAsMultiplexer(T, ArrayVariantType sourceArray)
}
}
template <typename T>
void TryDefaultType(T)
struct TryDefaultType
{
vtkm::cont::VariantArrayHandle array = CreateArrayVariant(T());
template <typename T>
void operator()(T) const
{
vtkm::cont::VariantArrayHandle array = CreateArrayVariant(T());
CheckArrayVariant(array, vtkm::VecTraits<T>::NUM_COMPONENTS, true);
CheckArrayVariant(array, vtkm::VecTraits<T>::NUM_COMPONENTS, true);
TryNewInstance(T(), array);
TryNewInstance(T(), array);
TryAsMultiplexer(T(), array);
}
TryAsMultiplexer(T(), array);
}
};
struct TryBasicVTKmType
{
@ -471,18 +474,18 @@ void TryCastToArrayHandle(const ArrayHandleType& array)
void TryCastToArrayHandle()
{
std::cout << " Normal array handle." << std::endl;
vtkm::Id buffer[ARRAY_SIZE];
vtkm::FloatDefault buffer[ARRAY_SIZE];
for (vtkm::Id index = 0; index < ARRAY_SIZE; index++)
{
buffer[index] = TestValue(index, vtkm::Id());
buffer[index] = TestValue(index, vtkm::FloatDefault());
}
vtkm::cont::ArrayHandle<vtkm::Id> array =
vtkm::cont::ArrayHandle<vtkm::FloatDefault> array =
vtkm::cont::make_ArrayHandle(buffer, ARRAY_SIZE, vtkm::CopyFlag::On);
TryCastToArrayHandle(array);
std::cout << " Cast array handle." << std::endl;
TryCastToArrayHandle(vtkm::cont::make_ArrayHandleCast(array, vtkm::FloatDefault()));
TryCastToArrayHandle(vtkm::cont::make_ArrayHandleCast<vtkm::Id>(array));
std::cout << " Composite vector array handle." << std::endl;
TryCastToArrayHandle(vtkm::cont::make_ArrayHandleCompositeVector(array, array));
@ -495,7 +498,8 @@ void TryCastToArrayHandle()
TryCastToArrayHandle(countingArray);
std::cout << " Group vec array handle" << std::endl;
vtkm::cont::ArrayHandleGroupVec<vtkm::cont::ArrayHandle<vtkm::Id>, 2> groupVecArray(array);
vtkm::cont::ArrayHandleGroupVec<vtkm::cont::ArrayHandle<vtkm::FloatDefault>, 2> groupVecArray(
array);
TryCastToArrayHandle(groupVecArray);
std::cout << " Implicit array handle." << std::endl;
@ -522,18 +526,7 @@ void TryCastToArrayHandle()
void TestVariantArrayHandle()
{
std::cout << "Try common types with default type lists." << std::endl;
std::cout << "*** vtkm::Id **********************" << std::endl;
TryDefaultType(vtkm::Id());
std::cout << "*** vtkm::FloatDefault ************" << std::endl;
TryDefaultType(vtkm::FloatDefault());
std::cout << "*** vtkm::Float32 *****************" << std::endl;
TryDefaultType(vtkm::Float32());
std::cout << "*** vtkm::Float64 *****************" << std::endl;
TryDefaultType(vtkm::Float64());
std::cout << "*** vtkm::Vec<Float32,3> **********" << std::endl;
TryDefaultType(vtkm::Vec3f_32());
std::cout << "*** vtkm::Vec<Float64,3> **********" << std::endl;
TryDefaultType(vtkm::Vec3f_64());
vtkm::testing::Testing::TryTypes(TryDefaultType{}, VTKM_DEFAULT_TYPE_LIST{});
std::cout << "Try exemplar VTK-m types." << std::endl;
vtkm::testing::Testing::TryTypes(TryBasicVTKmType());

@ -172,14 +172,15 @@ public:
/// This operation is typically used in a loop. For example usage,
/// an atomic multiplication may be implemented using compare-exchange as follows:
///
/// ```
/// AtomicArrayExecutionObject<vtkm::Int32, ...> arr = ...;
/// ```cpp
/// AtomicArrayExecutionObject<vtkm::Int32, ...> atomicArray = ...;
///
/// // Compare-exchange multiplication:
/// vtkm::Int32 current = arr->Get(idx); // Load the current value at idx
/// vtkm::Int32 current = atomicArray.Get(idx); // Load the current value at idx
/// vtkm::Int32 newVal;
/// do {
/// vtkm::Int32 newVal = current * multFactor; // the actual multiplication
/// } while (!arr->CompareExchange(idx, &current, newVal));
/// newVal = current * multFactor; // the actual multiplication
/// } while (!atomicArray.CompareExchange(idx, &current, newVal));
/// ```
///
/// The while condition here updates \a newVal what the proper multiplication
@ -191,6 +192,15 @@ public:
/// loop body re-executes using the new value of \a current and tries again until
/// it succeeds.
///
/// Note that for demonstration purposes, the previous code is unnecessarily verbose.
/// We can express the same atomic operation more succinctly with just two lines where
/// \a newVal is just computed in place.
///
/// ```cpp
/// vtkm::Int32 current = atomicArray.Get(idx); // Load the current value at idx
/// while (!atomicArray.CompareExchange(idx, &current, current * multFactor));
/// ```
///
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC
bool CompareExchange(vtkm::Id index, ValueType* oldValue, const ValueType& newValue) const

@ -19,6 +19,8 @@ set(headers
FetchTagArrayDirectIn.h
FetchTagArrayDirectInOut.h
FetchTagArrayDirectOut.h
FetchTagArrayDirectOutArrayHandleGroupVecVariable.h
FetchTagArrayDirectOutArrayHandleRecombineVec.h
FetchTagArrayNeighborhoodIn.h
FetchTagArrayTopologyMapIn.h
FetchTagExecObject.h

@ -0,0 +1,69 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
//
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//============================================================================
#ifndef vtk_m_exec_arg_FetchTagArrayDirectOutArrayHandleGroupVecVariable_h
#define vtk_m_exec_arg_FetchTagArrayDirectOutArrayHandleGroupVecVariable_h
#include <vtkm/exec/arg/FetchTagArrayDirectOut.h>
// We need to override the fetch for output fields using
// ArrayPortalGroupVecVariable because this portal does not behave like most
// ArrayPortals. Usually you ignore the Load and implement the Store. But if
// you ignore the Load, the VecFromPortal gets no portal to set values into.
// Instead, you need to implement the Load to point to the array portal. You
// can also ignore the Store because the data is already set in the array at
// that point.
// This file is included from ArrayHandleGroupVecVariable.h
namespace vtkm
{
namespace exec
{
namespace arg
{
// We need to override the fetch for output fields using
// ArrayPortalGroupVecVariable because this portal does not behave like most
// ArrayPortals. Usually you ignore the Load and implement the Store. But if
// you ignore the Load, the VecFromPortal gets no portal to set values into.
// Instead, you need to implement the Load to point to the array portal. You
// can also ignore the Store because the data is already set in the array at
// that point.
template <typename ComponentsPortalType, typename OffsetsPortalType>
struct Fetch<vtkm::exec::arg::FetchTagArrayDirectOut,
vtkm::exec::arg::AspectTagDefault,
vtkm::internal::ArrayPortalGroupVecVariable<ComponentsPortalType, OffsetsPortalType>>
{
using ExecObjectType =
vtkm::internal::ArrayPortalGroupVecVariable<ComponentsPortalType, OffsetsPortalType>;
using ValueType = typename ExecObjectType::ValueType;
VTKM_SUPPRESS_EXEC_WARNINGS
template <typename ThreadIndicesType>
VTKM_EXEC ValueType Load(const ThreadIndicesType& indices,
const ExecObjectType& arrayPortal) const
{
return arrayPortal.Get(indices.GetOutputIndex());
}
VTKM_SUPPRESS_EXEC_WARNINGS
template <typename ThreadIndicesType>
VTKM_EXEC void Store(const ThreadIndicesType&, const ExecObjectType&, const ValueType&) const
{
// We can actually ignore this because the VecFromPortal will already have
// set new values in the array.
}
};
}
}
} // namespace vtkm::exec::arg
#endif //vtk_m_exec_arg_FetchTagArrayDirectOutArrayHandleGroupVecVariable_h

@ -0,0 +1,46 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
//
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//============================================================================
#ifndef vtk_m_exec_arg_FetchTagArrayDirectOutArrayHandleRecombineVec_h
#define vtk_m_exec_arg_FetchTagArrayDirectOutArrayHandleRecombineVec_h
#include <vtkm/exec/arg/FetchTagArrayDirectInOut.h>
#include <vtkm/exec/arg/FetchTagArrayDirectOut.h>
// The `Fetch` for direct array out breaks for `ArrayHandleRecombineVec` because the `Load`
// method attempts to create a `vtkm::internal::RecombineVec` with a default constructor,
// which does not exist. Instead, have the direct out `Fetch` behave like the direct in/out
// `Fetch`, which loads the initial value from the array. The actual load will not load the
// data but rather set up the portals in the returned object, which is necessary for the
// later `Store` to work anyway.
// This file is included from ArrayHandleRecombineVec.h
namespace vtkm
{
namespace exec
{
namespace arg
{
template <typename SourcePortalType>
struct Fetch<vtkm::exec::arg::FetchTagArrayDirectOut,
vtkm::exec::arg::AspectTagDefault,
vtkm::internal::ArrayPortalRecombineVec<SourcePortalType>>
: Fetch<vtkm::exec::arg::FetchTagArrayDirectInOut,
vtkm::exec::arg::AspectTagDefault,
vtkm::internal::ArrayPortalRecombineVec<SourcePortalType>>
{
};
}
}
} // namespace vtkm::exec::arg
#endif //vtk_m_exec_arg_FetchTagArrayDirectOutArrayHandleRecombineVec_h

@ -149,6 +149,12 @@ extern template VTKM_FILTER_GRADIENT_TEMPLATE_EXPORT vtkm::cont::DataSet Gradien
const vtkm::filter::FieldMetadata&,
vtkm::filter::PolicyBase<vtkm::filter::PolicyDefault>);
extern template VTKM_FILTER_GRADIENT_TEMPLATE_EXPORT vtkm::cont::DataSet Gradient::DoExecute(
const vtkm::cont::DataSet&,
const vtkm::cont::ArrayHandle<vtkm::Vec3f_32, vtkm::cont::StorageTagSOA>&,
const vtkm::filter::FieldMetadata&,
vtkm::filter::PolicyBase<vtkm::filter::PolicyDefault>);
#ifndef VTKM_NO_DEPRECATED_VIRTUAL
VTKM_DEPRECATED_SUPPRESS_BEGIN
extern template VTKM_FILTER_GRADIENT_TEMPLATE_EXPORT vtkm::cont::DataSet Gradient::DoExecute(
@ -165,6 +171,12 @@ extern template VTKM_FILTER_GRADIENT_TEMPLATE_EXPORT vtkm::cont::DataSet Gradien
const vtkm::filter::FieldMetadata&,
vtkm::filter::PolicyBase<vtkm::filter::PolicyDefault>);
extern template VTKM_FILTER_GRADIENT_TEMPLATE_EXPORT vtkm::cont::DataSet Gradient::DoExecute(
const vtkm::cont::DataSet&,
const vtkm::cont::ArrayHandle<vtkm::Vec3f_64, vtkm::cont::StorageTagSOA>&,
const vtkm::filter::FieldMetadata&,
vtkm::filter::PolicyBase<vtkm::filter::PolicyDefault>);
#ifndef VTKM_NO_DEPRECATED_VIRTUAL
VTKM_DEPRECATED_SUPPRESS_BEGIN
extern template VTKM_FILTER_GRADIENT_TEMPLATE_EXPORT vtkm::cont::DataSet Gradient::DoExecute(

@ -24,6 +24,12 @@ template VTKM_FILTER_GRADIENT_EXPORT vtkm::cont::DataSet Gradient::DoExecute(
const vtkm::filter::FieldMetadata&,
vtkm::filter::PolicyBase<vtkm::filter::PolicyDefault>);
template VTKM_FILTER_GRADIENT_EXPORT vtkm::cont::DataSet Gradient::DoExecute(
const vtkm::cont::DataSet&,
const vtkm::cont::ArrayHandle<vtkm::Vec3f_32, vtkm::cont::StorageTagSOA>&,
const vtkm::filter::FieldMetadata&,
vtkm::filter::PolicyBase<vtkm::filter::PolicyDefault>);
#ifndef VTKM_NO_DEPRECATED_VIRTUAL
VTKM_DEPRECATED_SUPPRESS_BEGIN
template VTKM_FILTER_GRADIENT_EXPORT vtkm::cont::DataSet Gradient::DoExecute(
@ -40,6 +46,12 @@ template VTKM_FILTER_GRADIENT_EXPORT vtkm::cont::DataSet Gradient::DoExecute(
const vtkm::filter::FieldMetadata&,
vtkm::filter::PolicyBase<vtkm::filter::PolicyDefault>);
template VTKM_FILTER_GRADIENT_EXPORT vtkm::cont::DataSet Gradient::DoExecute(
const vtkm::cont::DataSet&,
const vtkm::cont::ArrayHandle<vtkm::Vec3f_64, vtkm::cont::StorageTagSOA>&,
const vtkm::filter::FieldMetadata&,
vtkm::filter::PolicyBase<vtkm::filter::PolicyDefault>);
#ifndef VTKM_NO_DEPRECATED_VIRTUAL
VTKM_DEPRECATED_SUPPRESS_BEGIN
template VTKM_FILTER_GRADIENT_EXPORT vtkm::cont::DataSet Gradient::DoExecute(

@ -35,16 +35,31 @@ public:
VTKM_CONT ImageDifference();
VTKM_CONT vtkm::IdComponent GetRadius() const { return this->Radius; }
VTKM_CONT void SetRadius(const vtkm::IdComponent& radius) { this->Radius = radius; }
VTKM_CONT vtkm::FloatDefault GetThreshold() const { return this->Threshold; }
VTKM_CONT void SetThreshold(const vtkm::FloatDefault& threshold) { this->Threshold = threshold; }
VTKM_CONT bool GetAveragePixels() const { return this->AveragePixels; }
VTKM_CONT void SetAveragePixels(const bool& averagePixels)
VTKM_CONT vtkm::IdComponent GetAverageRadius() const { return this->AverageRadius; }
VTKM_CONT void SetAverageRadius(const vtkm::IdComponent& averageRadius)
{
this->AveragePixels = averagePixels;
this->AverageRadius = averageRadius;
}
VTKM_CONT vtkm::IdComponent GetPixelShiftRadius() const { return this->PixelShiftRadius; }
VTKM_CONT void SetPixelShiftRadius(const vtkm::IdComponent& pixelShiftRadius)
{
this->PixelShiftRadius = pixelShiftRadius;
}
VTKM_CONT vtkm::FloatDefault GetAllowedPixelErrorRatio() const
{
return this->AllowedPixelErrorRatio;
}
VTKM_CONT void SetAllowedPixelErrorRatio(const vtkm::FloatDefault& pixelErrorRatio)
{
this->AllowedPixelErrorRatio = pixelErrorRatio;
}
VTKM_CONT vtkm::FloatDefault GetPixelDiffThreshold() const { return this->PixelDiffThreshold; }
VTKM_CONT void SetPixelDiffThreshold(const vtkm::FloatDefault& threshold)
{
this->PixelDiffThreshold = threshold;
}
VTKM_CONT bool GetImageDiffWithinThreshold() const { return this->ImageDiffWithinThreshold; }
@ -91,9 +106,10 @@ public:
vtkm::filter::PolicyBase<DerivedPolicy> policy);
private:
vtkm::IdComponent Radius;
vtkm::FloatDefault Threshold;
bool AveragePixels;
vtkm::IdComponent AverageRadius;
vtkm::IdComponent PixelShiftRadius;
vtkm::FloatDefault AllowedPixelErrorRatio;
vtkm::FloatDefault PixelDiffThreshold;
bool ImageDiffWithinThreshold;
std::string SecondaryFieldName;
vtkm::cont::Field::Association SecondaryFieldAssociation;

@ -12,7 +12,6 @@
#include <vtkm/filter/ImageDifference.h>
#include <vtkm/BinaryOperators.h>
#include <vtkm/cont/Algorithm.h>
#include <vtkm/cont/ArrayPortalToIterators.h>
#include <vtkm/cont/Logging.h>
@ -25,11 +24,25 @@ namespace vtkm
namespace filter
{
namespace detail
{
struct GreaterThanThreshold
{
GreaterThanThreshold(const vtkm::FloatDefault& thresholdError)
: ThresholdError(thresholdError)
{
}
VTKM_EXEC_CONT bool operator()(const vtkm::FloatDefault& x) const { return x > ThresholdError; }
vtkm::FloatDefault ThresholdError;
};
} // namespace detail
inline VTKM_CONT ImageDifference::ImageDifference()
: vtkm::filter::FilterField<ImageDifference>()
, Radius(0)
, Threshold(0.05f)
, AveragePixels(false)
, AverageRadius(0)
, PixelShiftRadius(0)
, AllowedPixelErrorRatio(0.0001f)
, PixelDiffThreshold(0.05f)
, ImageDiffWithinThreshold(true)
, SecondaryFieldName("image-2")
, SecondaryFieldAssociation(vtkm::cont::Field::Association::ANY)
@ -62,12 +75,13 @@ inline VTKM_CONT vtkm::cont::DataSet ImageDifference::DoExecute(
vtkm::cont::ArrayHandle<T, StorageType> diffOutput;
vtkm::cont::ArrayHandle<T, StorageType> primaryOutput;
vtkm::cont::ArrayHandle<T, StorageType> secondaryOutput;
vtkm::cont::ArrayHandle<vtkm::FloatDefault, StorageType> thresholdOutput;
vtkm::cont::ArrayHandle<vtkm::FloatDefault> thresholdOutput;
if (this->AveragePixels && this->Radius > 0)
if (this->AverageRadius > 0)
{
VTKM_LOG_S(vtkm::cont::LogLevel::Info, "Performing Average with radius: " << this->Radius);
auto averageWorklet = vtkm::worklet::AveragePointNeighborhood(this->Radius);
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
"Performing Average with radius: " << this->AverageRadius);
auto averageWorklet = vtkm::worklet::AveragePointNeighborhood(this->AverageRadius);
this->Invoke(averageWorklet, cellSet, primary, primaryOutput);
this->Invoke(averageWorklet, cellSet, secondary, secondaryOutput);
}
@ -79,10 +93,11 @@ inline VTKM_CONT vtkm::cont::DataSet ImageDifference::DoExecute(
secondaryField.GetData().template Cast<vtkm::cont::ArrayHandle<T, StorageType>>();
}
if (this->Radius > 0)
if (this->PixelShiftRadius > 0)
{
VTKM_LOG_S(vtkm::cont::LogLevel::Info, "Diffing image in Neighborhood");
auto diffWorklet = vtkm::worklet::ImageDifferenceNeighborhood(this->Radius, this->Threshold);
auto diffWorklet =
vtkm::worklet::ImageDifferenceNeighborhood(this->PixelShiftRadius, this->PixelDiffThreshold);
this->Invoke(diffWorklet, cellSet, primaryOutput, secondaryOutput, diffOutput, thresholdOutput);
}
else
@ -92,17 +107,26 @@ inline VTKM_CONT vtkm::cont::DataSet ImageDifference::DoExecute(
this->Invoke(diffWorklet, primaryOutput, secondaryOutput, diffOutput, thresholdOutput);
}
// Dummy calculate the threshold. If any value is greater than the min our images
// are not similar enough.
vtkm::FloatDefault maxThreshold =
vtkm::cont::Algorithm::Reduce(thresholdOutput, vtkm::FloatDefault(0), vtkm::Maximum());
if (maxThreshold > this->Threshold)
vtkm::cont::ArrayHandle<vtkm::FloatDefault, StorageType> errorPixels;
vtkm::cont::Algorithm::CopyIf(thresholdOutput,
thresholdOutput,
errorPixels,
detail::GreaterThanThreshold(this->PixelDiffThreshold));
if (errorPixels.GetNumberOfValues() >
thresholdOutput.GetNumberOfValues() * this->AllowedPixelErrorRatio)
{
this->ImageDiffWithinThreshold = false;
}
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
"Difference within threshold: " << this->ImageDiffWithinThreshold);
"Difference within threshold: "
<< this->ImageDiffWithinThreshold
<< ", for pixels outside threshold: " << errorPixels.GetNumberOfValues()
<< ", with total number of pixels: " << thresholdOutput.GetNumberOfValues()
<< ", and an allowable percentage of errored pixels: "
<< this->AllowedPixelErrorRatio << ", with a total summed threshold error: "
<< vtkm::cont::Algorithm::Reduce(errorPixels, static_cast<FloatDefault>(0)));
vtkm::cont::DataSet clone;
clone.CopyStructure(input);

@ -21,31 +21,15 @@ namespace
struct DoMapFieldMerge
{
template <typename BaseComponentType>
void operator()(BaseComponentType,
const vtkm::cont::UnknownArrayHandle& input,
template <typename InputArrayType>
void operator()(const InputArrayType& input,
const vtkm::worklet::internal::KeysBase& keys,
vtkm::cont::UnknownArrayHandle& output,
bool& called) const
vtkm::cont::UnknownArrayHandle& output) const
{
if (!input.IsBaseComponentType<BaseComponentType>())
{
return;
}
using BaseComponentType = typename InputArrayType::ValueType::ComponentType;
output = input.NewInstanceBasic();
output.Allocate(keys.GetInputRange());
vtkm::IdComponent numComponents = input.GetNumberOfComponentsFlat();
for (vtkm::IdComponent cIndex = 0; cIndex < numComponents; ++cIndex)
{
vtkm::worklet::AverageByKey::Run(
keys,
input.ExtractComponent<BaseComponentType>(cIndex, vtkm::CopyFlag::On),
output.ExtractComponent<BaseComponentType>(cIndex, vtkm::CopyFlag::Off));
}
called = true;
vtkm::worklet::AverageByKey::Run(
keys, input, output.ExtractArrayFromComponents<BaseComponentType>(vtkm::CopyFlag::Off));
}
};
@ -57,23 +41,20 @@ bool vtkm::filter::MapFieldMergeAverage(const vtkm::cont::Field& inputField,
{
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
vtkm::cont::VariantArrayHandle outputArray;
bool calledMap = false;
vtkm::ListForEach(DoMapFieldMerge{},
vtkm::TypeListScalarAll{},
inputField.GetData(),
keys,
outputArray,
calledMap);
if (calledMap)
vtkm::cont::UnknownArrayHandle outputArray = inputField.GetData().NewInstanceBasic();
outputArray.Allocate(keys.GetInputRange());
try
{
inputField.GetData().CastAndCallWithExtractedArray(DoMapFieldMerge{}, keys, outputArray);
outputField = vtkm::cont::Field(inputField.GetName(), inputField.GetAssociation(), outputArray);
return true;
}
else
catch (...)
{
VTKM_LOG_S(vtkm::cont::LogLevel::Warn, "Faild to map field " << inputField.GetName());
return false;
}
return calledMap;
}
bool vtkm::filter::MapFieldMergeAverage(const vtkm::cont::Field& inputField,

@ -37,9 +37,12 @@ struct MapPermutationWorklet : vtkm::worklet::WorkletMapField
using ControlSignature = void(FieldIn permutationIndex, WholeArrayIn input, FieldOut output);
template <typename InputPortalType>
VTKM_EXEC void operator()(vtkm::Id permutationIndex, InputPortalType inputPortal, T& output) const
template <typename InputPortalType, typename OutputType>
VTKM_EXEC void operator()(vtkm::Id permutationIndex,
InputPortalType inputPortal,
OutputType& output) const
{
VTKM_STATIC_ASSERT(vtkm::HasVecTraits<OutputType>::value);
if ((permutationIndex >= 0) && (permutationIndex < inputPortal.GetNumberOfValues()))
{
output = inputPortal.Get(permutationIndex);
@ -53,36 +56,21 @@ struct MapPermutationWorklet : vtkm::worklet::WorkletMapField
struct DoMapFieldPermutation
{
template <typename BaseComponentType>
void operator()(BaseComponentType,
const vtkm::cont::UnknownArrayHandle& input,
template <typename InputArrayType>
void operator()(const InputArrayType& input,
const vtkm::cont::ArrayHandle<vtkm::Id>& permutation,
vtkm::cont::UnknownArrayHandle& output,
vtkm::Float64 invalidValue,
bool& called) const
vtkm::Float64 invalidValue) const
{
if (!input.IsBaseComponentType<BaseComponentType>())
{
return;
}
output = input.NewInstanceBasic();
output.Allocate(permutation.GetNumberOfValues());
vtkm::IdComponent numComponents = input.GetNumberOfComponentsFlat();
using BaseComponentType = typename InputArrayType::ValueType::ComponentType;
MapPermutationWorklet<BaseComponentType> worklet(
vtkm::cont::internal::CastInvalidValue<BaseComponentType>(invalidValue));
vtkm::cont::Invoker invoke;
for (vtkm::IdComponent cIndex = 0; cIndex < numComponents; ++cIndex)
{
invoke(worklet,
permutation,
input.ExtractComponent<BaseComponentType>(cIndex, vtkm::CopyFlag::On),
output.ExtractComponent<BaseComponentType>(cIndex, vtkm::CopyFlag::Off));
}
called = true;
vtkm::cont::Invoker{}(
worklet,
permutation,
input,
output.ExtractArrayFromComponents<BaseComponentType>(vtkm::CopyFlag::Off));
}
};
@ -96,24 +84,20 @@ VTKM_FILTER_COMMON_EXPORT VTKM_CONT bool vtkm::filter::MapFieldPermutation(
{
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
vtkm::cont::VariantArrayHandle outputArray;
bool calledMap = false;
vtkm::ListForEach(DoMapFieldPermutation{},
vtkm::TypeListScalarAll{},
inputField.GetData(),
permutation,
outputArray,
invalidValue,
calledMap);
if (calledMap)
vtkm::cont::UnknownArrayHandle outputArray = inputField.GetData().NewInstanceBasic();
outputArray.Allocate(permutation.GetNumberOfValues());
try
{
inputField.GetData().CastAndCallWithExtractedArray(
DoMapFieldPermutation{}, permutation, outputArray, invalidValue);
outputField = vtkm::cont::Field(inputField.GetName(), inputField.GetAssociation(), outputArray);
return true;
}
else
catch (...)
{
VTKM_LOG_S(vtkm::cont::LogLevel::Warn, "Faild to map field " << inputField.GetName());
return false;
}
return calledMap;
}
VTKM_FILTER_COMMON_EXPORT VTKM_CONT bool vtkm::filter::MapFieldPermutation(

@ -83,20 +83,16 @@ set(libraries
)
if (VTKm_ENABLE_RENDERING)
set(libraries
${libraries}
vtkm_rendering
)
list(APPEND libraries vtkm_rendering)
set(unit_tests
${unit_tests}
list(APPEND unit_tests
RegressionTestContourFilter.cxx
RegressionTestPointTransform.cxx
RegressionTestSplitSharpEdges.cxx
RegressionTestStreamline.cxx
RegressionTestSurfaceNormals.cxx
)
endif (VTKm_ENABLE_RENDERING)
endif()
vtkm_unit_tests(
SOURCES ${unit_tests}

@ -10,10 +10,13 @@
#include <vtkm/Math.h>
#include <vtkm/cont/DataSet.h>
#include <vtkm/cont/testing/MakeTestDataSet.h>
#include <vtkm/cont/testing/Testing.h>
#include <vtkm/filter/CleanGrid.h>
#include <vtkm/filter/Contour.h>
#include <vtkm/source/Tangle.h>
#include <vtkm/io/VTKDataSetReader.h>
#include <vtkm/rendering/CanvasRayTracer.h>
@ -53,11 +56,81 @@ void TestContourFilterWedge()
auto view = vtkm::rendering::testing::GetViewPtr<M, C, V3>(
result, "gyroid", canvas, mapper, scene, colorTable, static_cast<vtkm::FloatDefault>(0.08));
VTKM_TEST_ASSERT(test_equal_images_matching_name(view, "contour-wedge.png"));
VTKM_TEST_ASSERT(test_equal_images(view, "contour-wedge.png"));
}
void TestContourFilterUniform()
{
std::cout << "Generate Image for Contour filter on a uniform grid" << std::endl;
vtkm::cont::ColorTable colorTable(
{ 0, 1 }, { 0.20f, 0.80f, .20f }, { .20f, .80f, .201f }, vtkm::ColorSpace::RGB);
using M = vtkm::rendering::MapperRayTracer;
using C = vtkm::rendering::CanvasRayTracer;
using V3 = vtkm::rendering::View3D;
vtkm::cont::testing::MakeTestDataSet maker;
vtkm::cont::DataSet inputData = maker.Make3DUniformDataSet0();
std::string fieldName = "pointvar";
VTKM_TEST_ASSERT(inputData.HasField(fieldName));
vtkm::filter::Contour contour;
contour.SetGenerateNormals(false);
contour.SetMergeDuplicatePoints(true);
contour.SetIsoValue(0, 100.0);
contour.SetActiveField(fieldName);
contour.SetFieldsToPass(fieldName);
vtkm::cont::DataSet result = contour.Execute(inputData);
result.PrintSummary(std::cout);
C canvas(512, 512);
M mapper;
vtkm::rendering::Scene scene;
auto view = vtkm::rendering::testing::GetViewPtr<M, C, V3>(
result, "pointvar", canvas, mapper, scene, colorTable);
//Y axis Flying Edge algorithm has subtle differences at a couple of boundaries
VTKM_TEST_ASSERT(test_equal_images(view, "contour-uniform.png"));
}
void TestContourFilterTangle()
{
std::cout << "Generate Image for Contour filter on a uniform tangle grid" << std::endl;
vtkm::cont::ColorTable colorTable(
{ 0, 1 }, { 0.20f, 0.80f, .20f }, { .20f, .80f, .201f }, vtkm::ColorSpace::RGB);
using M = vtkm::rendering::MapperRayTracer;
using C = vtkm::rendering::CanvasRayTracer;
using V3 = vtkm::rendering::View3D;
vtkm::Id3 dims(4, 4, 4);
vtkm::source::Tangle tangle(dims);
vtkm::cont::DataSet dataSet = tangle.Execute();
vtkm::filter::Contour contour;
contour.SetGenerateNormals(true);
contour.SetIsoValue(0, 1);
contour.SetActiveField("nodevar");
contour.SetFieldsToPass("nodevar");
auto result = contour.Execute(dataSet);
result.PrintSummary(std::cout);
C canvas(512, 512);
M mapper;
vtkm::rendering::Scene scene;
auto view = vtkm::rendering::testing::GetViewPtr<M, C, V3>(
result, "nodevar", canvas, mapper, scene, colorTable);
//Y axis Flying Edge algorithm has subtle differences at a couple of boundaries
VTKM_TEST_ASSERT(test_equal_images(view, "contour-tangle.png"));
}
void TestContourFilter()
{
TestContourFilterUniform();
TestContourFilterTangle();
TestContourFilterWedge();
}
} // namespace

@ -18,7 +18,7 @@ void TestFieldToColors()
{
//faux input field
constexpr vtkm::Id nvals = 8;
constexpr int data[nvals] = { -1, 0, 10, 20, 30, 40, 50, 60 };
constexpr vtkm::FloatDefault data[nvals] = { -1, 0, 10, 20, 30, 40, 50, 60 };
//build a color table with clamping off and verify that sampling works
vtkm::Range range{ 0.0, 50.0 };

@ -102,8 +102,8 @@ void TestImageDifference()
vtkm::filter::ImageDifference filter;
filter.SetPrimaryField("primary");
filter.SetSecondaryField("secondary");
filter.SetThreshold(0.05f);
filter.SetRadius(0);
filter.SetPixelDiffThreshold(0.05f);
filter.SetPixelShiftRadius(0);
vtkm::cont::DataSet result = filter.Execute(dataSet);
std::vector<vtkm::Vec4f> expectedDiff = {
@ -125,9 +125,9 @@ void TestImageDifference()
vtkm::filter::ImageDifference filter;
filter.SetPrimaryField("primary");
filter.SetSecondaryField("secondary");
filter.SetThreshold(0.05f);
filter.SetRadius(1);
filter.SetAveragePixels(true);
filter.SetPixelDiffThreshold(0.05f);
filter.SetPixelShiftRadius(1);
filter.SetAverageRadius(1);
vtkm::cont::DataSet result = filter.Execute(dataSet);
std::vector<vtkm::Vec4f> expectedDiff = {
@ -149,8 +149,8 @@ void TestImageDifference()
vtkm::filter::ImageDifference filter;
filter.SetPrimaryField("primary");
filter.SetSecondaryField("secondary");
filter.SetThreshold(0.05f);
filter.SetRadius(0);
filter.SetPixelDiffThreshold(0.05f);
filter.SetPixelShiftRadius(0);
vtkm::cont::DataSet result = filter.Execute(dataSet);
std::vector<vtkm::Vec4f> expectedDiff = {
@ -166,6 +166,30 @@ void TestImageDifference()
expectedDiff, expectedThreshold, result, filter.GetImageDiffWithinThreshold(), false);
}
{
VTKM_LOG_S(vtkm::cont::LogLevel::Info, "Non Matching Images (Different R pixel)");
auto dataSet = FillDataSet(static_cast<vtkm::FloatDefault>(3));
vtkm::filter::ImageDifference filter;
filter.SetPrimaryField("primary");
filter.SetSecondaryField("secondary");
filter.SetPixelDiffThreshold(0.05f);
filter.SetPixelShiftRadius(0);
filter.SetAllowedPixelErrorRatio(1.00f);
vtkm::cont::DataSet result = filter.Execute(dataSet);
std::vector<vtkm::Vec4f> expectedDiff = {
{ 2, 0, 0, 0 }, { 2, 0, 0, 0 }, { 2, 0, 0, 0 }, { 2, 0, 0, 0 }, { 2, 0, 0, 0 },
{ 2, 0, 0, 0 }, { 2, 0, 0, 0 }, { 2, 0, 0, 0 }, { 2, 0, 0, 0 }, { 2, 0, 0, 0 },
{ 2, 0, 0, 0 }, { 2, 0, 0, 0 }, { 2, 0, 0, 0 }, { 2, 0, 0, 0 }, { 2, 0, 0, 0 },
{ 2, 0, 0, 0 }, { 2, 0, 0, 0 }, { 2, 0, 0, 0 }, { 2, 0, 0, 0 }, { 2, 0, 0, 0 },
{ 2, 0, 0, 0 }, { 2, 0, 0, 0 }, { 2, 0, 0, 0 }, { 2, 0, 0, 0 }, { 2, 0, 0, 0 }
};
std::vector<vtkm::FloatDefault> expectedThreshold = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 };
CheckResult(
expectedDiff, expectedThreshold, result, filter.GetImageDiffWithinThreshold(), true);
}
{
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
"Non Matching Images (Different R pixel), Large Threshold");
@ -173,8 +197,8 @@ void TestImageDifference()
vtkm::filter::ImageDifference filter;
filter.SetPrimaryField("primary");
filter.SetSecondaryField("secondary");
filter.SetThreshold(3.0f);
filter.SetRadius(0);
filter.SetPixelDiffThreshold(3.0f);
filter.SetPixelShiftRadius(0);
vtkm::cont::DataSet result = filter.Execute(dataSet);
std::vector<vtkm::Vec4f> expectedDiff = {

@ -70,7 +70,7 @@ vtkm::cont::PartitionedDataSet PartitionedDataSetBuilder(std::size_t partitionNu
}
return partitions;
}
template <typename D>
template <typename T, typename D>
void Result_Verify(const vtkm::cont::PartitionedDataSet& result,
D& filter,
const vtkm::cont::PartitionedDataSet& partitions,
@ -88,9 +88,9 @@ void Result_Verify(const vtkm::cont::PartitionedDataSet& result,
partitionResult.GetField(outputFieldName).GetNumberOfValues(),
"result vectors' size incorrect");
vtkm::cont::ArrayHandle<vtkm::Id> partitionArray;
vtkm::cont::ArrayHandle<T> partitionArray;
result.GetPartition(j).GetField(outputFieldName).GetData().CopyTo(partitionArray);
vtkm::cont::ArrayHandle<vtkm::Id> sDataSetArray;
vtkm::cont::ArrayHandle<T> sDataSetArray;
partitionResult.GetField(outputFieldName).GetData().CopyTo(sDataSetArray);
const vtkm::Id numValues = result.GetPartition(j).GetField(outputFieldName).GetNumberOfValues();
@ -109,12 +109,12 @@ void TestPartitionedDataSetFilters()
vtkm::cont::PartitionedDataSet result;
vtkm::cont::PartitionedDataSet partitions;
partitions = PartitionedDataSetBuilder<vtkm::Id>(partitionNum, "pointvar");
partitions = PartitionedDataSetBuilder<vtkm::FloatDefault>(partitionNum, "pointvar");
vtkm::filter::CellAverage cellAverage;
cellAverage.SetOutputFieldName("average");
cellAverage.SetActiveField("pointvar");
result = cellAverage.Execute(partitions);
Result_Verify(result, cellAverage, partitions, std::string("pointvar"));
Result_Verify<vtkm::FloatDefault>(result, cellAverage, partitions, std::string("pointvar"));
}
int UnitTestPartitionedDataSetFilters(int argc, char* argv[])

@ -19,6 +19,39 @@ namespace vtkm
namespace internal
{
namespace detail
{
// TODO: VecTraits should just always be supported. See #589.
template <typename Vec, typename = typename std::enable_if<vtkm::HasVecTraits<Vec>::value>::type>
VTKM_EXEC_CONT inline vtkm::IdComponent SafeGetNumberOfComponents(const Vec& vec)
{
return vtkm::VecTraits<Vec>::GetNumberOfComponents(vec);
}
VTKM_EXEC_CONT inline vtkm::IdComponent SafeGetNumberOfComponents(...)
{
return 1;
}
template <typename Vec, typename = typename std::enable_if<vtkm::HasVecTraits<Vec>::value>::type>
VTKM_EXEC_CONT inline typename vtkm::VecTraits<Vec>::ComponentType SafeGetComponent(
const Vec& vec,
vtkm::IdComponent index)
{
return vtkm::VecTraits<Vec>::GetComponent(vec, index);
}
template <typename T, typename = typename std::enable_if<!vtkm::HasVecTraits<T>::value>::type>
VTKM_EXEC_CONT inline T SafeGetComponent(const T& value, vtkm::IdComponent index)
{
VTKM_ASSERT(index == 0);
return value;
}
} // namespace detail
/// \brief A value class for returning setable values of an ArrayPortal
///
/// \c ArrayPortal classes have a pair of \c Get and \c Set methods that
@ -312,6 +345,19 @@ struct ArrayPortalValueReference
return lhs;
}
// Support Vec operations so that the reference can be treated as such Vec objects. Note
// that although the [] operator is supported, you can only read components this way. You
// cannot write components one at a time.
VTKM_EXEC_CONT vtkm::IdComponent GetNumberOfComponents() const
{
return detail::SafeGetNumberOfComponents(static_cast<ValueType>(*this));
}
VTKM_EXEC_CONT auto operator[](vtkm::IdComponent index) const
-> decltype(detail::SafeGetComponent(std::declval<ValueType>(), index))
{
return detail::SafeGetComponent(static_cast<ValueType>(*this), index);
}
private:
const ArrayPortalType& Portal;
vtkm::Id Index;

@ -86,7 +86,8 @@ struct OutputArrayDataFunctor
template <typename T>
VTKM_CONT void operator()(T, const vtkm::cont::UnknownArrayHandle& array, std::ostream& out) const
{
auto portal = array.ReadPortalForBaseComponentType<T>();
auto componentArray = array.ExtractArrayFromComponents<T>();
auto portal = componentArray.ReadPortal();
vtkm::Id numValues = portal.GetNumberOfValues();
for (vtkm::Id valueIndex = 0; valueIndex < numValues; ++valueIndex)

@ -19,16 +19,16 @@ set(unit_tests
set(unit_test_libraries vtkm_lodepng vtkm_io)
if(VTKm_ENABLE_RENDERING)
set(unit_tests ${unit_tests}
list(APPEND unit_tests
UnitTestImageWriter.cxx
)
)
if (VTKm_ENABLE_HDF5_IO)
set(unit_tests ${unit_tests}
list(APPEND unit_tests
UnitTestHDF5Image.cxx)
endif()
set(unit_test_libraries ${unit_test_libraries} vtkm_rendering)
list(APPEND unit_test_libraries vtkm_rendering)
endif()
vtkm_unit_tests(SOURCES ${unit_tests} ALL_BACKENDS LIBRARIES ${unit_test_libraries})

@ -44,6 +44,13 @@ struct CheckSameCoordinateSystem
CheckSameField{}(originalArray, fileCoords);
}
template <typename T>
void operator()(const vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagSOA>& originalArray,
const vtkm::cont::CoordinateSystem& fileCoords) const
{
CheckSameField{}(originalArray, fileCoords);
}
#ifndef VTKM_NO_DEPRECATED_VIRTUAL
VTKM_DEPRECATED_SUPPRESS_BEGIN
template <typename T>

Some files were not shown because too many files have changed in this diff Show More