mirror of
https://gitlab.kitware.com/vtk/vtk-m
synced 2024-09-08 21:33:55 +00:00
Allow ArrayHandleTransform to work with ExecObject
This change allows you to set a subclass of vtkm::cont::ExecutionObjectBase as a functor used in ArrayHandleTransform. This latter class will then detect that the functor is an ExecObject and will call PrepareForExecution with the appropriate device to get the actual Functor object. This change allows you to use virtual objects and other device dependent objects as functors for ArrayHandleTransform without knowing a priori what device the portal will be used on.
This commit is contained in:
parent
bc9772021c
commit
98a0a20feb
97
docs/changelog/array-handle-transform-exec-object.md
Normal file
97
docs/changelog/array-handle-transform-exec-object.md
Normal file
@ -0,0 +1,97 @@
|
||||
# Allow ArrayHandleTransform to work with ExecObject
|
||||
|
||||
Previously, the `ArrayHandleTransform` class only worked with plain old
|
||||
data (POD) objects as is functors. For simple transforms, this makes sense
|
||||
since all the data comes from a target `ArrayHandle` that will be sent to
|
||||
the device through a different path. However, this also requires the
|
||||
transform to be known at compile time.
|
||||
|
||||
However, there are cases where the functor cannot be a POD object and has
|
||||
to be built for a specific device. There are numerous reasons for this. One
|
||||
might be that you need some lookup tables. Another might be you want to
|
||||
support a virtual object, which has to be initialized for a particular
|
||||
device. The standard way to implement this in VTK-m is to create an
|
||||
"executive object." This actually means that we create a wrapper around
|
||||
executive objects that inherits from `vtkm::cont::ExecutionObjectBase` that
|
||||
contains a `PrepareForExecution` method.
|
||||
|
||||
As an example, consider the use case of a special `ArrayHandle` that takes
|
||||
the value in one array and returns the index of that value in another
|
||||
sorted array. We can do that by creating a functor that finds a value in an
|
||||
array and returns the index.
|
||||
|
||||
``` cpp
|
||||
template <typename ArrayPortalType>
|
||||
struct FindValueFunctor
|
||||
{
|
||||
ArrayPortalType SortedArrayPortal;
|
||||
|
||||
FindValueFunctor() = default;
|
||||
|
||||
VTKM_CONT FindValueFunctor(const ArrayPortalType& sortedPortal)
|
||||
: SortedArrayPortal(sortedPortal)
|
||||
{ }
|
||||
|
||||
VTKM_EXEC vtkm::Id operator()(const typename PortalType::ValueType& value)
|
||||
{
|
||||
vtkm::Id leftIndex = 0;
|
||||
vtkm::Id rightIndex = this->SortedArrayPortal.GetNubmerOfValues();
|
||||
while (leftIndex < rightIndex)
|
||||
{
|
||||
vtkm::Id middleIndex = (leftIndex + rightIndex) / 2;
|
||||
auto middleValue = this->SortedArrayPortal.Get(middleIndex);
|
||||
if (middleValue <= value)
|
||||
{
|
||||
rightIndex = middleValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
leftIndex = middleValue + 1;
|
||||
}
|
||||
}
|
||||
return leftIndex;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
Simple enough, except that the type of `ArrayPortalType` depends on what
|
||||
device the functor runs on (not to mention its memory might need to be
|
||||
moved to different hardware). We can now solve this problem by creating an
|
||||
execution object to set this up for a device.
|
||||
|
||||
``` cpp
|
||||
template <typename ArrayHandleType>
|
||||
struct FindValueExecutionObject : vtkm::cont::ExecutionObjectBase
|
||||
{
|
||||
VTKM_IS_ARRAY_HANDLE(ArrayHandleType);
|
||||
|
||||
ArrayHandleType SortedArray;
|
||||
|
||||
FindValueExecutionObject() = default;
|
||||
|
||||
VTKM_CONT FindValueExecutionObject(const ArrayHandleType& sortedArray)
|
||||
: SortedArray(sortedArray)
|
||||
{ }
|
||||
|
||||
template <typename Device>
|
||||
VTKM_CONT
|
||||
FindValueFunctor<decltype(std::declval<FunctorType>()(Device()))>
|
||||
PrepareForExecution(Device device)
|
||||
{
|
||||
using FunctorType =
|
||||
FindValueFunctor<decltype(std::declval<FunctorType>()(Device()))>
|
||||
|
||||
return FunctorType(this->SortedArray.PrepareForInput(device));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Now you can use this execution object in an `ArrayHandleTransform`. It will
|
||||
automatically be detected as an execution object and be converted to a
|
||||
functor in the execution environment.
|
||||
|
||||
``` cpp
|
||||
auto transformArray =
|
||||
vtkm::cont::make_ArrayHandleTransform(
|
||||
inputArray, FindValueExecutionObject<decltype(sortedArray)>(sortedArray));
|
||||
```
|
@ -25,6 +25,9 @@
|
||||
#include <vtkm/cont/ArrayHandle.h>
|
||||
#include <vtkm/cont/ErrorBadType.h>
|
||||
#include <vtkm/cont/ErrorInternal.h>
|
||||
#include <vtkm/cont/ExecutionObjectBase.h>
|
||||
#include <vtkm/cont/RuntimeDeviceTracker.h>
|
||||
#include <vtkm/cont/serial/DeviceAdapterSerial.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
@ -178,18 +181,94 @@ namespace cont
|
||||
namespace internal
|
||||
{
|
||||
|
||||
template <typename ProvidedFunctorType, typename Device, typename FunctorIsExecObject>
|
||||
struct TransformFunctorManagerImpl;
|
||||
|
||||
template <typename ProvidedFunctorType, typename Device>
|
||||
struct TransformFunctorManagerImpl<ProvidedFunctorType, Device, std::false_type>
|
||||
{
|
||||
using FunctorType = ProvidedFunctorType;
|
||||
ProvidedFunctorType Functor;
|
||||
|
||||
TransformFunctorManagerImpl() = default;
|
||||
|
||||
VTKM_CONT
|
||||
TransformFunctorManagerImpl(const ProvidedFunctorType& functor)
|
||||
: Functor(functor)
|
||||
{
|
||||
}
|
||||
|
||||
VTKM_CONT
|
||||
FunctorType GetFunctor() const { return this->Functor; }
|
||||
};
|
||||
|
||||
template <typename ProvidedFunctorType, typename Device>
|
||||
struct TransformFunctorManagerImpl<ProvidedFunctorType, Device, std::true_type>
|
||||
{
|
||||
using FunctorType = decltype(std::declval<ProvidedFunctorType>().PrepareForExecution(Device()));
|
||||
ProvidedFunctorType Functor;
|
||||
|
||||
TransformFunctorManagerImpl() = default;
|
||||
|
||||
VTKM_CONT
|
||||
TransformFunctorManagerImpl(const ProvidedFunctorType& functor)
|
||||
: Functor(functor)
|
||||
{
|
||||
}
|
||||
|
||||
VTKM_CONT
|
||||
FunctorType GetFunctor() const { return this->Functor.PrepareForExecution(Device()); }
|
||||
};
|
||||
|
||||
template <typename ProvidedFunctorType, typename Device = vtkm::cont::DeviceAdapterTagSerial>
|
||||
struct TransformFunctorManager
|
||||
: TransformFunctorManagerImpl<
|
||||
ProvidedFunctorType,
|
||||
Device,
|
||||
typename std::is_base_of<vtkm::cont::ExecutionObjectBase, ProvidedFunctorType>::type>
|
||||
{
|
||||
using Superclass = TransformFunctorManagerImpl<
|
||||
ProvidedFunctorType,
|
||||
Device,
|
||||
typename std::is_base_of<vtkm::cont::ExecutionObjectBase, ProvidedFunctorType>::type>;
|
||||
using FunctorType = typename Superclass::FunctorType;
|
||||
|
||||
VTKM_CONT TransformFunctorManager() = default;
|
||||
|
||||
VTKM_CONT TransformFunctorManager(const TransformFunctorManager& other) = default;
|
||||
|
||||
VTKM_CONT TransformFunctorManager(const ProvidedFunctorType& functor)
|
||||
: Superclass(functor)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename OtherDevice>
|
||||
VTKM_CONT TransformFunctorManager(
|
||||
const TransformFunctorManager<ProvidedFunctorType, OtherDevice>& other)
|
||||
: Superclass(other.Functor)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
using TransformedValueType = decltype(std::declval<FunctorType>()(ValueType{}));
|
||||
};
|
||||
|
||||
template <typename ArrayHandleType,
|
||||
typename FunctorType,
|
||||
typename InverseFunctorType = NullFunctorType>
|
||||
struct VTKM_ALWAYS_EXPORT StorageTagTransform
|
||||
{
|
||||
using ValueType = decltype(FunctorType{}(typename ArrayHandleType::ValueType{}));
|
||||
using FunctorManager = TransformFunctorManager<FunctorType>;
|
||||
using ValueType =
|
||||
typename FunctorManager::template TransformedValueType<typename ArrayHandleType::ValueType>;
|
||||
};
|
||||
|
||||
template <typename ArrayHandleType, typename FunctorType>
|
||||
class Storage<typename StorageTagTransform<ArrayHandleType, FunctorType>::ValueType,
|
||||
StorageTagTransform<ArrayHandleType, FunctorType>>
|
||||
{
|
||||
using FunctorManager = TransformFunctorManager<FunctorType>;
|
||||
|
||||
public:
|
||||
using ValueType = typename StorageTagTransform<ArrayHandleType, FunctorType>::ValueType;
|
||||
|
||||
@ -204,7 +283,7 @@ public:
|
||||
using PortalConstType =
|
||||
vtkm::exec::internal::ArrayPortalTransform<ValueType,
|
||||
typename ArrayHandleType::PortalConstControl,
|
||||
FunctorType>;
|
||||
typename FunctorManager::FunctorType>;
|
||||
|
||||
VTKM_CONT
|
||||
Storage()
|
||||
@ -223,15 +302,17 @@ public:
|
||||
VTKM_CONT
|
||||
PortalType GetPortal()
|
||||
{
|
||||
VTKM_ASSERT(this->Valid);
|
||||
return PortalType(this->Array.GetPortalControl(), this->Functor);
|
||||
throw vtkm::cont::ErrorBadType(
|
||||
"ArrayHandleTransform is read only. Cannot get writable portal.");
|
||||
}
|
||||
|
||||
VTKM_CONT
|
||||
PortalConstType GetPortalConst() const
|
||||
{
|
||||
VTKM_ASSERT(this->Valid);
|
||||
return PortalConstType(this->Array.GetPortalConstControl(), this->Functor);
|
||||
vtkm::cont::ScopedGlobalRuntimeDeviceTracker trackerScope;
|
||||
vtkm::cont::GetGlobalRuntimeDeviceTracker().ForceDevice(vtkm::cont::DeviceAdapterTagSerial());
|
||||
return PortalConstType(this->Array.GetPortalConstControl(), this->Functor.GetFunctor());
|
||||
}
|
||||
|
||||
VTKM_CONT
|
||||
@ -269,11 +350,11 @@ public:
|
||||
}
|
||||
|
||||
VTKM_CONT
|
||||
const FunctorType& GetFunctor() const { return this->Functor; }
|
||||
const FunctorManager& GetFunctor() const { return this->Functor; }
|
||||
|
||||
private:
|
||||
ArrayHandleType Array;
|
||||
FunctorType Functor;
|
||||
FunctorManager Functor;
|
||||
bool Valid;
|
||||
};
|
||||
|
||||
@ -282,6 +363,9 @@ class Storage<
|
||||
typename StorageTagTransform<ArrayHandleType, FunctorType, InverseFunctorType>::ValueType,
|
||||
StorageTagTransform<ArrayHandleType, FunctorType, InverseFunctorType>>
|
||||
{
|
||||
using FunctorManager = TransformFunctorManager<FunctorType>;
|
||||
using InverseFunctorManager = TransformFunctorManager<InverseFunctorType>;
|
||||
|
||||
public:
|
||||
using ValueType =
|
||||
typename StorageTagTransform<ArrayHandleType, FunctorType, InverseFunctorType>::ValueType;
|
||||
@ -289,13 +373,13 @@ public:
|
||||
using PortalType =
|
||||
vtkm::exec::internal::ArrayPortalTransform<ValueType,
|
||||
typename ArrayHandleType::PortalControl,
|
||||
FunctorType,
|
||||
InverseFunctorType>;
|
||||
typename FunctorManager::FunctorType,
|
||||
typename InverseFunctorManager::FunctorType>;
|
||||
using PortalConstType =
|
||||
vtkm::exec::internal::ArrayPortalTransform<ValueType,
|
||||
typename ArrayHandleType::PortalConstControl,
|
||||
FunctorType,
|
||||
InverseFunctorType>;
|
||||
typename FunctorManager::FunctorType,
|
||||
typename InverseFunctorManager::FunctorType>;
|
||||
|
||||
VTKM_CONT
|
||||
Storage()
|
||||
@ -318,15 +402,22 @@ public:
|
||||
PortalType GetPortal()
|
||||
{
|
||||
VTKM_ASSERT(this->Valid);
|
||||
return PortalType(this->Array.GetPortalControl(), this->Functor, this->InverseFunctor);
|
||||
vtkm::cont::ScopedGlobalRuntimeDeviceTracker trackerScope;
|
||||
vtkm::cont::GetGlobalRuntimeDeviceTracker().ForceDevice(vtkm::cont::DeviceAdapterTagSerial());
|
||||
return PortalType(this->Array.GetPortalControl(),
|
||||
this->Functor.GetFunctor(),
|
||||
this->InverseFunctor.GetFunctor());
|
||||
}
|
||||
|
||||
VTKM_CONT
|
||||
PortalConstType GetPortalConst() const
|
||||
{
|
||||
VTKM_ASSERT(this->Valid);
|
||||
return PortalConstType(
|
||||
this->Array.GetPortalConstControl(), this->Functor, this->InverseFunctor);
|
||||
vtkm::cont::ScopedGlobalRuntimeDeviceTracker trackerScope;
|
||||
vtkm::cont::GetGlobalRuntimeDeviceTracker().ForceDevice(vtkm::cont::DeviceAdapterTagSerial());
|
||||
return PortalConstType(this->Array.GetPortalConstControl(),
|
||||
this->Functor.GetFunctor(),
|
||||
this->InverseFunctor.GetFunctor());
|
||||
}
|
||||
|
||||
VTKM_CONT
|
||||
@ -361,15 +452,15 @@ public:
|
||||
}
|
||||
|
||||
VTKM_CONT
|
||||
const FunctorType& GetFunctor() const { return this->Functor; }
|
||||
const FunctorManager& GetFunctor() const { return this->Functor; }
|
||||
|
||||
VTKM_CONT
|
||||
const InverseFunctorType& GetInverseFunctor() const { return this->InverseFunctor; }
|
||||
const InverseFunctorManager& GetInverseFunctor() const { return this->InverseFunctor; }
|
||||
|
||||
private:
|
||||
ArrayHandleType Array;
|
||||
FunctorType Functor;
|
||||
InverseFunctorType InverseFunctor;
|
||||
FunctorManager Functor;
|
||||
InverseFunctorManager InverseFunctor;
|
||||
bool Valid;
|
||||
};
|
||||
|
||||
@ -379,6 +470,7 @@ class ArrayTransfer<typename StorageTagTransform<ArrayHandleType, FunctorType>::
|
||||
Device>
|
||||
{
|
||||
using StorageTag = StorageTagTransform<ArrayHandleType, FunctorType>;
|
||||
using FunctorManager = TransformFunctorManager<FunctorType, Device>;
|
||||
|
||||
public:
|
||||
using ValueType = typename StorageTagTransform<ArrayHandleType, FunctorType>::ValueType;
|
||||
@ -392,7 +484,7 @@ public:
|
||||
using PortalConstExecution = vtkm::exec::internal::ArrayPortalTransform<
|
||||
ValueType,
|
||||
typename ArrayHandleType::template ExecutionTypes<Device>::PortalConst,
|
||||
FunctorType>;
|
||||
typename FunctorManager::FunctorType>;
|
||||
|
||||
VTKM_CONT
|
||||
ArrayTransfer(StorageType* storage)
|
||||
@ -407,7 +499,7 @@ public:
|
||||
VTKM_CONT
|
||||
PortalConstExecution PrepareForInput(bool vtkmNotUsed(updateData))
|
||||
{
|
||||
return PortalConstExecution(this->Array.PrepareForInput(Device()), this->Functor);
|
||||
return PortalConstExecution(this->Array.PrepareForInput(Device()), this->Functor.GetFunctor());
|
||||
}
|
||||
|
||||
VTKM_CONT
|
||||
@ -443,7 +535,7 @@ public:
|
||||
|
||||
private:
|
||||
ArrayHandleType Array;
|
||||
FunctorType Functor;
|
||||
FunctorManager Functor;
|
||||
};
|
||||
|
||||
template <typename ArrayHandleType,
|
||||
@ -456,6 +548,8 @@ class ArrayTransfer<
|
||||
Device>
|
||||
{
|
||||
using StorageTag = StorageTagTransform<ArrayHandleType, FunctorType, InverseFunctorType>;
|
||||
using FunctorManager = TransformFunctorManager<FunctorType, Device>;
|
||||
using InverseFunctorManager = TransformFunctorManager<InverseFunctorType, Device>;
|
||||
|
||||
public:
|
||||
using ValueType = typename StorageTagTransform<ArrayHandleType, FunctorType>::ValueType;
|
||||
@ -467,13 +561,13 @@ public:
|
||||
using PortalExecution = vtkm::exec::internal::ArrayPortalTransform<
|
||||
ValueType,
|
||||
typename ArrayHandleType::template ExecutionTypes<Device>::Portal,
|
||||
FunctorType,
|
||||
InverseFunctorType>;
|
||||
typename FunctorManager::FunctorType,
|
||||
typename InverseFunctorManager::FunctorType>;
|
||||
using PortalConstExecution = vtkm::exec::internal::ArrayPortalTransform<
|
||||
ValueType,
|
||||
typename ArrayHandleType::template ExecutionTypes<Device>::PortalConst,
|
||||
FunctorType,
|
||||
InverseFunctorType>;
|
||||
typename FunctorManager::FunctorType,
|
||||
typename InverseFunctorManager::FunctorType>;
|
||||
|
||||
VTKM_CONT
|
||||
ArrayTransfer(StorageType* storage)
|
||||
@ -489,22 +583,25 @@ public:
|
||||
VTKM_CONT
|
||||
PortalConstExecution PrepareForInput(bool vtkmNotUsed(updateData))
|
||||
{
|
||||
return PortalConstExecution(
|
||||
this->Array.PrepareForInput(Device()), this->Functor, this->InverseFunctor);
|
||||
return PortalConstExecution(this->Array.PrepareForInput(Device()),
|
||||
this->Functor.GetFunctor(),
|
||||
this->InverseFunctor.GetFunctor());
|
||||
}
|
||||
|
||||
VTKM_CONT
|
||||
PortalExecution PrepareForInPlace(bool& vtkmNotUsed(updateData))
|
||||
{
|
||||
return PortalExecution(
|
||||
this->Array.PrepareForInPlace(Device()), this->Functor, this->InverseFunctor);
|
||||
return PortalExecution(this->Array.PrepareForInPlace(Device()),
|
||||
this->Functor.GetFunctor(),
|
||||
this->InverseFunctor.GetFunctor());
|
||||
}
|
||||
|
||||
VTKM_CONT
|
||||
PortalExecution PrepareForOutput(vtkm::Id numberOfValues)
|
||||
{
|
||||
return PortalExecution(
|
||||
this->Array.PrepareForOutput(numberOfValues, Device()), this->Functor, this->InverseFunctor);
|
||||
return PortalExecution(this->Array.PrepareForOutput(numberOfValues, Device()),
|
||||
this->Functor.GetFunctor(),
|
||||
this->InverseFunctor.GetFunctor());
|
||||
}
|
||||
|
||||
VTKM_CONT
|
||||
@ -522,8 +619,8 @@ public:
|
||||
|
||||
private:
|
||||
ArrayHandleType Array;
|
||||
FunctorType Functor;
|
||||
InverseFunctorType InverseFunctor;
|
||||
FunctorManager Functor;
|
||||
InverseFunctorManager InverseFunctor;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
@ -235,6 +235,29 @@ thread_local static vtkm::cont::RuntimeDeviceTracker runtimeDeviceTracker;
|
||||
VTKM_CONT_EXPORT
|
||||
VTKM_CONT
|
||||
vtkm::cont::RuntimeDeviceTracker GetGlobalRuntimeDeviceTracker();
|
||||
|
||||
struct ScopedGlobalRuntimeDeviceTracker
|
||||
{
|
||||
vtkm::cont::RuntimeDeviceTracker SavedTracker;
|
||||
|
||||
VTKM_CONT ScopedGlobalRuntimeDeviceTracker()
|
||||
: SavedTracker(vtkm::cont::GetGlobalRuntimeDeviceTracker().DeepCopy())
|
||||
{
|
||||
}
|
||||
|
||||
VTKM_CONT ScopedGlobalRuntimeDeviceTracker(vtkm::cont::RuntimeDeviceTracker tracker)
|
||||
: SavedTracker(vtkm::cont::GetGlobalRuntimeDeviceTracker().DeepCopy())
|
||||
{
|
||||
vtkm::cont::GetGlobalRuntimeDeviceTracker().DeepCopy(tracker);
|
||||
}
|
||||
|
||||
VTKM_CONT ~ScopedGlobalRuntimeDeviceTracker()
|
||||
{
|
||||
vtkm::cont::GetGlobalRuntimeDeviceTracker().DeepCopy(this->SavedTracker);
|
||||
}
|
||||
|
||||
ScopedGlobalRuntimeDeviceTracker(const ScopedGlobalRuntimeDeviceTracker&) = delete;
|
||||
};
|
||||
}
|
||||
} // namespace vtkm::cont
|
||||
|
||||
|
@ -26,7 +26,6 @@
|
||||
#include <vtkm/UnaryPredicates.h>
|
||||
|
||||
#include <vtkm/cont/ArrayHandle.h>
|
||||
#include <vtkm/cont/ArrayHandleCast.h>
|
||||
#include <vtkm/cont/DeviceAdapterAlgorithm.h>
|
||||
#include <vtkm/cont/ErrorExecution.h>
|
||||
#include <vtkm/cont/vtkm_cont_export.h>
|
||||
@ -126,6 +125,26 @@ __global__ void SumExclusiveScan(T a, T b, T result, BinaryOperationType binary_
|
||||
#if (defined(VTKM_GCC) || defined(VTKM_CLANG))
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
template <typename PortalType, typename OutValueType>
|
||||
struct CastPortal
|
||||
{
|
||||
using ValueType = OutValueType;
|
||||
|
||||
PortalType Portal;
|
||||
|
||||
VTKM_CONT
|
||||
CastPortal(const PortalType& portal)
|
||||
: Portal(portal)
|
||||
{
|
||||
}
|
||||
|
||||
VTKM_EXEC
|
||||
vtkm::Id GetNumberOfValues() const { return this->Portal.GetNumberOfValues(); }
|
||||
|
||||
VTKM_EXEC
|
||||
ValueType Get(vtkm::Id index) const { return static_cast<OutValueType>(this->Portal.Get(index)); }
|
||||
};
|
||||
}
|
||||
} // end namespace cuda::internal
|
||||
|
||||
@ -313,9 +332,7 @@ private:
|
||||
//The portal type and the initial value AREN'T the same type so we have
|
||||
//to a slower approach, where we wrap the input portal inside a cast
|
||||
//portal
|
||||
using CastFunctor = vtkm::cont::internal::Cast<typename InputPortal::ValueType, T>;
|
||||
|
||||
vtkm::exec::internal::ArrayPortalTransform<T, InputPortal, CastFunctor> castPortal(input);
|
||||
vtkm::cont::cuda::internal::CastPortal<InputPortal, T> castPortal(input);
|
||||
|
||||
vtkm::exec::cuda::internal::WrappedBinaryOperator<T, BinaryFunctor> bop(binary_functor);
|
||||
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include <vtkm/cont/ArrayHandleTransform.h>
|
||||
#include <vtkm/cont/ArrayHandleView.h>
|
||||
#include <vtkm/cont/ArrayHandleZip.h>
|
||||
#include <vtkm/cont/VirtualObjectHandle.h>
|
||||
|
||||
#include <vtkm/worklet/DispatcherMapField.h>
|
||||
#include <vtkm/worklet/WorkletMapField.h>
|
||||
@ -73,7 +74,7 @@ struct ValueSquared
|
||||
struct ValueScale
|
||||
{
|
||||
ValueScale()
|
||||
: Factor()
|
||||
: Factor(1.0)
|
||||
{
|
||||
}
|
||||
|
||||
@ -102,6 +103,107 @@ struct ValueScale
|
||||
private:
|
||||
vtkm::Float64 Factor;
|
||||
};
|
||||
|
||||
struct InverseValueScale
|
||||
{
|
||||
InverseValueScale()
|
||||
: InverseFactor(1.0)
|
||||
{
|
||||
}
|
||||
|
||||
InverseValueScale(vtkm::Float64 factor)
|
||||
: InverseFactor(1.0 / factor)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
VTKM_EXEC_CONT ValueType operator()(const ValueType& v) const
|
||||
{
|
||||
using Traits = vtkm::VecTraits<ValueType>;
|
||||
using TTraits = vtkm::TypeTraits<ValueType>;
|
||||
using ComponentType = typename Traits::ComponentType;
|
||||
|
||||
ValueType result = TTraits::ZeroInitialization();
|
||||
for (vtkm::IdComponent i = 0; i < Traits::GetNumberOfComponents(v); ++i)
|
||||
{
|
||||
vtkm::Float64 vi = static_cast<vtkm::Float64>(Traits::GetComponent(v, i));
|
||||
vtkm::Float64 ri = vi * this->InverseFactor;
|
||||
Traits::SetComponent(result, i, static_cast<ComponentType>(ri));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
vtkm::Float64 InverseFactor;
|
||||
};
|
||||
|
||||
template <typename ValueType>
|
||||
struct VirtualTransformFunctorBase : public vtkm::VirtualObjectBase
|
||||
{
|
||||
VirtualTransformFunctorBase() = default;
|
||||
|
||||
VTKM_EXEC_CONT
|
||||
virtual ValueType operator()(const ValueType& v) const = 0;
|
||||
};
|
||||
|
||||
template <typename ValueType, typename FunctorType>
|
||||
struct VirtualTransformFunctor : VirtualTransformFunctorBase<ValueType>
|
||||
{
|
||||
FunctorType Functor;
|
||||
|
||||
VTKM_CONT
|
||||
VirtualTransformFunctor(const FunctorType& functor)
|
||||
: Functor(functor)
|
||||
{
|
||||
}
|
||||
|
||||
VTKM_EXEC_CONT
|
||||
ValueType operator()(const ValueType& v) const override { return this->Functor(v); }
|
||||
};
|
||||
|
||||
template <typename ValueType>
|
||||
struct TransformExecObject : public vtkm::cont::ExecutionObjectBase
|
||||
{
|
||||
vtkm::cont::VirtualObjectHandle<VirtualTransformFunctorBase<ValueType>> VirtualFunctor;
|
||||
|
||||
VTKM_CONT TransformExecObject() = default;
|
||||
|
||||
template <typename FunctorType>
|
||||
VTKM_CONT TransformExecObject(const FunctorType& functor)
|
||||
{
|
||||
// Need to make sure the serial device is supported, since that is what is used on the
|
||||
// control side.
|
||||
vtkm::cont::ScopedGlobalRuntimeDeviceTracker scopedTracker;
|
||||
vtkm::cont::GetGlobalRuntimeDeviceTracker().ResetDevice(vtkm::cont::DeviceAdapterTagSerial());
|
||||
this->VirtualFunctor.Reset(new VirtualTransformFunctor<ValueType, FunctorType>(functor));
|
||||
}
|
||||
|
||||
template <typename DeviceAdapterTag>
|
||||
struct ExecutionObject
|
||||
{
|
||||
const VirtualTransformFunctorBase<ValueType>* FunctorPointer;
|
||||
|
||||
ExecutionObject() = default;
|
||||
|
||||
VTKM_CONT
|
||||
ExecutionObject(const VirtualTransformFunctorBase<ValueType>* functorPointer)
|
||||
: FunctorPointer(functorPointer)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename InValueType>
|
||||
VTKM_EXEC ValueType operator()(const InValueType& value) const
|
||||
{
|
||||
return (*this->FunctorPointer)(value);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename DeviceAdapterTag>
|
||||
VTKM_CONT ExecutionObject<DeviceAdapterTag> PrepareForExecution(DeviceAdapterTag device) const
|
||||
{
|
||||
return ExecutionObject<DeviceAdapterTag>(this->VirtualFunctor.PrepareForExecution(device));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace vtkm
|
||||
@ -476,6 +578,44 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
struct TestTransformVirtualAsInput
|
||||
{
|
||||
template <typename ValueType>
|
||||
VTKM_CONT void operator()(const ValueType vtkmNotUsed(v)) const
|
||||
{
|
||||
using FunctorType = fancy_array_detail::ValueScale;
|
||||
using VirtualFunctorType = fancy_array_detail::TransformExecObject<ValueType>;
|
||||
|
||||
const vtkm::Id length = ARRAY_SIZE;
|
||||
FunctorType functor(2.0);
|
||||
VirtualFunctorType virtualFunctor(functor);
|
||||
|
||||
vtkm::cont::ArrayHandle<ValueType> input;
|
||||
auto transformed = vtkm::cont::make_ArrayHandleTransform(input, virtualFunctor);
|
||||
|
||||
input.Allocate(length);
|
||||
SetPortal(input.GetPortalControl());
|
||||
|
||||
vtkm::cont::printSummary_ArrayHandle(transformed, std::cout);
|
||||
std::cout << std::endl;
|
||||
|
||||
vtkm::cont::ArrayHandle<ValueType> result;
|
||||
|
||||
vtkm::worklet::DispatcherMapField<PassThrough> dispatcher;
|
||||
dispatcher.Invoke(transformed, result);
|
||||
|
||||
//verify that the control portal works
|
||||
for (vtkm::Id i = 0; i < length; ++i)
|
||||
{
|
||||
const ValueType result_v = result.GetPortalConstControl().Get(i);
|
||||
const ValueType correct_value = functor(TestValue(i, ValueType()));
|
||||
const ValueType control_value = transformed.GetPortalConstControl().Get(i);
|
||||
VTKM_TEST_ASSERT(test_equal(result_v, correct_value), "Transform Handle Failed");
|
||||
VTKM_TEST_ASSERT(test_equal(result_v, control_value), "Transform Handle Control Failed");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct TestCountingTransformAsInput
|
||||
{
|
||||
template <typename ValueType>
|
||||
@ -917,6 +1057,88 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
struct TestTransformAsOutput
|
||||
{
|
||||
template <typename ValueType>
|
||||
VTKM_CONT void operator()(const ValueType vtkmNotUsed(v)) const
|
||||
{
|
||||
using FunctorType = fancy_array_detail::ValueScale;
|
||||
using InverseFunctorType = fancy_array_detail::InverseValueScale;
|
||||
|
||||
const vtkm::Id length = ARRAY_SIZE;
|
||||
FunctorType functor(2.0);
|
||||
InverseFunctorType inverseFunctor(2.0);
|
||||
|
||||
vtkm::cont::ArrayHandle<ValueType> input;
|
||||
input.Allocate(length);
|
||||
SetPortal(input.GetPortalControl());
|
||||
|
||||
vtkm::cont::ArrayHandle<ValueType> output;
|
||||
auto transformed = vtkm::cont::make_ArrayHandleTransform(output, functor, inverseFunctor);
|
||||
|
||||
vtkm::worklet::DispatcherMapField<PassThrough> dispatcher;
|
||||
dispatcher.Invoke(input, transformed);
|
||||
|
||||
vtkm::cont::printSummary_ArrayHandle(transformed, std::cout);
|
||||
std::cout << std::endl;
|
||||
|
||||
//verify that the control portal works
|
||||
for (vtkm::Id i = 0; i < length; ++i)
|
||||
{
|
||||
const ValueType result_v = output.GetPortalConstControl().Get(i);
|
||||
const ValueType correct_value = inverseFunctor(TestValue(i, ValueType()));
|
||||
const ValueType control_value = transformed.GetPortalConstControl().Get(i);
|
||||
VTKM_TEST_ASSERT(test_equal(result_v, correct_value), "Transform Handle Failed");
|
||||
VTKM_TEST_ASSERT(test_equal(functor(result_v), control_value),
|
||||
"Transform Handle Control Failed");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct TestTransformVirtualAsOutput
|
||||
{
|
||||
template <typename ValueType>
|
||||
VTKM_CONT void operator()(const ValueType vtkmNotUsed(v)) const
|
||||
{
|
||||
using FunctorType = fancy_array_detail::ValueScale;
|
||||
using InverseFunctorType = fancy_array_detail::InverseValueScale;
|
||||
|
||||
using VirtualFunctorType = fancy_array_detail::TransformExecObject<ValueType>;
|
||||
|
||||
const vtkm::Id length = ARRAY_SIZE;
|
||||
FunctorType functor(2.0);
|
||||
InverseFunctorType inverseFunctor(2.0);
|
||||
|
||||
VirtualFunctorType virtualFunctor(functor);
|
||||
VirtualFunctorType virtualInverseFunctor(inverseFunctor);
|
||||
|
||||
vtkm::cont::ArrayHandle<ValueType> input;
|
||||
input.Allocate(length);
|
||||
SetPortal(input.GetPortalControl());
|
||||
|
||||
vtkm::cont::ArrayHandle<ValueType> output;
|
||||
auto transformed =
|
||||
vtkm::cont::make_ArrayHandleTransform(output, virtualFunctor, virtualInverseFunctor);
|
||||
|
||||
vtkm::worklet::DispatcherMapField<PassThrough> dispatcher;
|
||||
dispatcher.Invoke(input, transformed);
|
||||
|
||||
vtkm::cont::printSummary_ArrayHandle(transformed, std::cout);
|
||||
std::cout << std::endl;
|
||||
|
||||
//verify that the control portal works
|
||||
for (vtkm::Id i = 0; i < length; ++i)
|
||||
{
|
||||
const ValueType result_v = output.GetPortalConstControl().Get(i);
|
||||
const ValueType correct_value = inverseFunctor(TestValue(i, ValueType()));
|
||||
const ValueType control_value = transformed.GetPortalConstControl().Get(i);
|
||||
VTKM_TEST_ASSERT(test_equal(result_v, correct_value), "Transform Handle Failed");
|
||||
VTKM_TEST_ASSERT(test_equal(functor(result_v), control_value),
|
||||
"Transform Handle Control Failed");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct TestZipAsOutput
|
||||
{
|
||||
template <typename KeyType, typename ValueType>
|
||||
@ -1047,6 +1269,12 @@ private:
|
||||
vtkm::testing::Testing::TryTypes(
|
||||
TestingFancyArrayHandles<DeviceAdapterTag>::TestTransformAsInput(), HandleTypesToTest());
|
||||
|
||||
std::cout << "-------------------------------------------" << std::endl;
|
||||
std::cout << "Testing ArrayHandleTransform with virtual as Input" << std::endl;
|
||||
vtkm::testing::Testing::TryTypes(
|
||||
TestingFancyArrayHandles<DeviceAdapterTag>::TestTransformVirtualAsInput(),
|
||||
HandleTypesToTest());
|
||||
|
||||
std::cout << "-------------------------------------------" << std::endl;
|
||||
std::cout << "Testing ArrayHandleTransform with Counting as Input" << std::endl;
|
||||
vtkm::testing::Testing::TryTypes(
|
||||
@ -1105,6 +1333,17 @@ private:
|
||||
vtkm::testing::Testing::TryTypes(
|
||||
TestingFancyArrayHandles<DeviceAdapterTag>::TestViewAsOutput(), HandleTypesToTest());
|
||||
|
||||
std::cout << "-------------------------------------------" << std::endl;
|
||||
std::cout << "Testing ArrayHandleTransform as Output" << std::endl;
|
||||
vtkm::testing::Testing::TryTypes(
|
||||
TestingFancyArrayHandles<DeviceAdapterTag>::TestTransformAsOutput(), HandleTypesToTest());
|
||||
|
||||
std::cout << "-------------------------------------------" << std::endl;
|
||||
std::cout << "Testing ArrayHandleTransform with virtual as Output" << std::endl;
|
||||
vtkm::testing::Testing::TryTypes(
|
||||
TestingFancyArrayHandles<DeviceAdapterTag>::TestTransformVirtualAsOutput(),
|
||||
HandleTypesToTest());
|
||||
|
||||
std::cout << "-------------------------------------------" << std::endl;
|
||||
std::cout << "Testing ArrayHandleDiscard as Output" << std::endl;
|
||||
vtkm::testing::Testing::TryTypes(
|
||||
|
Loading…
Reference in New Issue
Block a user