Merge branch 'master' into new_connected_components

This commit is contained in:
Li-Ta Lo 2022-01-25 10:15:57 -07:00
commit 2540fb1b27
63 changed files with 1549 additions and 993 deletions

@ -324,6 +324,7 @@ if(VTKm_ENABLE_KOKKOS AND NOT TARGET vtkm::kokkos)
cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
enable_language(HIP)
add_library(vtkm::kokkos_hip INTERFACE IMPORTED GLOBAL)
set_property(TARGET Kokkos::kokkoscore PROPERTY INTERFACE_COMPILE_DEFINITIONS "")
set_property(TARGET Kokkos::kokkoscore PROPERTY INTERFACE_COMPILE_OPTIONS "")
set_property(TARGET Kokkos::kokkoscore PROPERTY INTERFACE_LINK_OPTIONS "")
endif()

@ -0,0 +1,11 @@
# Make ArrayCopy not depend on a device compiler
Rather than require `ArrayCopy` to create special versions of copy for
all arrays, use a precompiled versions. This should speed up compiles,
reduce the amount of code being generated, and require the device
compiler on fewer source files.
There are some cases where you still need to copy arrays that are not
well supported by the precompiled versions in `ArrayCopy`. (It will
always work, but the fallback is very slow.) In this case, you will want
to switch over to `ArrayCopyDevice`, which has the old behavior.

@ -9,178 +9,43 @@
//============================================================================
#include <vtkm/cont/ArrayCopy.h>
#include <vtkm/cont/DeviceAdapterList.h>
#include <vtkm/cont/Invoker.h>
#include <vtkm/cont/internal/ArrayCopyUnknown.h>
#include <vtkm/worklet/WorkletMapField.h>
namespace
{
// Use a worklet because device adapter copies often have an issue with casting the values from the
// `ArrayHandleRecomineVec` that comes from `UnknownArrayHandle::CastAndCallWithExtractedArray`.
struct CopyWorklet : vtkm::worklet::WorkletMapField
{
using ControlSignature = void(FieldIn, FieldOut);
using ExecutionSignature = void(_1, _2);
using InputDomain = _1;
template <typename InType, typename OutType>
VTKM_EXEC void operator()(const InType& in, OutType& out) const
{
out = in;
}
};
struct UnknownCopyOnDevice
{
bool Called = false;
template <typename InType, typename OutType>
void operator()(vtkm::cont::DeviceAdapterId device,
const vtkm::cont::ArrayHandleRecombineVec<InType>& in,
const vtkm::cont::ArrayHandleRecombineVec<OutType>& out)
{
// Note: ArrayHandleRecombineVec returns the wrong value for IsOnDevice (always true).
// This is one of the consequences of ArrayHandleRecombineVec breaking assumptions of
// ArrayHandle. It does this by stuffing Buffer objects in another Buffer's meta data
// rather than listing them explicitly (where they can be queried). We get around this
// by pulling out one of the component arrays and querying that.
if (!this->Called &&
((device == vtkm::cont::DeviceAdapterTagAny{}) ||
(in.GetComponentArray(0).IsOnDevice(device))))
{
vtkm::cont::Invoker invoke(device);
invoke(CopyWorklet{}, in, out);
this->Called = true;
}
}
};
struct UnknownCopyFunctor2
{
template <typename OutType, typename InType>
void operator()(const vtkm::cont::ArrayHandleRecombineVec<OutType>& out,
const vtkm::cont::ArrayHandleRecombineVec<InType>& in) const
{
UnknownCopyOnDevice doCopy;
// Try to copy on a device that the data are already on.
vtkm::ListForEach(doCopy, VTKM_DEFAULT_DEVICE_ADAPTER_LIST{}, in, out);
// If it was not on any device, call one more time with any adapter to copy wherever.
doCopy(vtkm::cont::DeviceAdapterTagAny{}, in, out);
}
};
struct UnknownCopyFunctor1
{
template <typename InType>
void operator()(const vtkm::cont::ArrayHandleRecombineVec<InType>& in,
const vtkm::cont::UnknownArrayHandle& out) const
{
out.Allocate(in.GetNumberOfValues());
this->DoIt(in, out, typename std::is_same<vtkm::FloatDefault, InType>::type{});
}
template <typename InType>
void DoIt(const vtkm::cont::ArrayHandleRecombineVec<InType>& in,
const vtkm::cont::UnknownArrayHandle& out,
std::false_type) const
{
// Source is not float.
if (out.IsBaseComponentType<InType>())
{
// Arrays have the same base component type. Copy directly.
UnknownCopyFunctor2{}(out.ExtractArrayFromComponents<InType>(), in);
}
else if (out.IsBaseComponentType<vtkm::FloatDefault>())
{
// Can copy anything to default float.
UnknownCopyFunctor2{}(out.ExtractArrayFromComponents<vtkm::FloatDefault>(), in);
}
else
{
// Arrays have different base types. To reduce the number of template paths from nxn to 3n,
// copy first to a temp array of default float.
vtkm::cont::UnknownArrayHandle temp = out.NewInstanceFloatBasic();
(*this)(in, temp);
vtkm::cont::ArrayCopy(temp, out);
}
}
template <typename InType>
void DoIt(const vtkm::cont::ArrayHandleRecombineVec<InType>& in,
const vtkm::cont::UnknownArrayHandle& out,
std::true_type) const
{
// Source array is FloatDefault. That should be copiable to anything.
out.CastAndCallWithExtractedArray(UnknownCopyFunctor2{}, in);
}
};
void DoUnknownArrayCopy(const vtkm::cont::UnknownArrayHandle& source,
const vtkm::cont::UnknownArrayHandle& destination)
{
if (source.GetNumberOfValues() > 0)
{
source.CastAndCallWithExtractedArray(UnknownCopyFunctor1{}, destination);
}
else
{
destination.ReleaseResources();
}
}
} // anonymous namespace
#include <vtkm/cont/ArrayCopyDevice.h>
namespace vtkm
{
namespace cont
{
void ArrayCopy(const vtkm::cont::UnknownArrayHandle& source,
vtkm::cont::UnknownArrayHandle& destination)
namespace detail
{
if (!destination.IsValid())
void ArrayCopyConcreteSrc<vtkm::cont::StorageTagCounting>::CopyCountingFloat(
vtkm::FloatDefault start,
vtkm::FloatDefault step,
vtkm::Id size,
const vtkm::cont::UnknownArrayHandle& result) const
{
if (result.IsBaseComponentType<vtkm::FloatDefault>())
{
destination = source.NewInstanceBasic();
auto outArray = result.ExtractComponent<vtkm::FloatDefault>(0);
vtkm::cont::ArrayCopyDevice(vtkm::cont::make_ArrayHandleCounting(start, step, size), outArray);
}
DoUnknownArrayCopy(source, destination);
}
void ArrayCopy(const vtkm::cont::UnknownArrayHandle& source,
const vtkm::cont::UnknownArrayHandle& destination)
{
if (!destination.IsValid())
else
{
throw vtkm::cont::ErrorBadValue(
"Attempty to copy to a constant UnknownArrayHandle with no valid array.");
vtkm::cont::ArrayHandle<vtkm::FloatDefault> outArray;
outArray.Allocate(size);
CopyCountingFloat(start, step, size, outArray);
result.DeepCopyFrom(outArray);
}
DoUnknownArrayCopy(source, destination);
}
namespace internal
vtkm::cont::ArrayHandle<Id> ArrayCopyConcreteSrc<vtkm::cont::StorageTagCounting>::CopyCountingId(
const vtkm::cont::ArrayHandleCounting<vtkm::Id>& source) const
{
void ArrayCopyUnknown(const vtkm::cont::UnknownArrayHandle& source,
vtkm::cont::UnknownArrayHandle& destination)
{
vtkm::cont::ArrayCopy(source, destination);
vtkm::cont::ArrayHandle<Id> destination;
vtkm::cont::ArrayCopyDevice(source, destination);
return destination;
}
void ArrayCopyUnknown(const vtkm::cont::UnknownArrayHandle& source,
const vtkm::cont::UnknownArrayHandle& destination)
{
vtkm::cont::ArrayCopy(source, destination);
}
} // namespace vtkm::cont::internal
} // namespace vtkm::cont
} // namespace vtkm
}
} // namespace vtkm::cont::detail

@ -10,19 +10,20 @@
#ifndef vtk_m_cont_ArrayCopy_h
#define vtk_m_cont_ArrayCopy_h
#include <vtkm/cont/Algorithm.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/DeviceAdapterTag.h>
#include <vtkm/cont/ErrorExecution.h>
#include <vtkm/cont/Logging.h>
#include <vtkm/cont/ArrayHandleConcatenate.h>
#include <vtkm/cont/ArrayHandleConstant.h>
#include <vtkm/cont/ArrayHandleCounting.h>
#include <vtkm/cont/ArrayHandleIndex.h>
#include <vtkm/cont/ArrayHandlePermutation.h>
#include <vtkm/cont/ArrayHandleView.h>
#include <vtkm/cont/UnknownArrayHandle.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
// arrays are copied directly but anything else would be copied through virtual methods.
#include <vtkm/cont/internal/MapArrayPermutation.h>
#include <vtkm/StaticAssert.h>
#include <vtkm/VecTraits.h>
namespace vtkm
{
@ -32,72 +33,91 @@ namespace cont
namespace detail
{
// Element-wise copy.
template <typename InArrayType, typename OutArrayType>
void ArrayCopyWithAlgorithm(const InArrayType& source, OutArrayType& destination)
// Compile-time check to make sure that an `ArrayHandle` passed to `ArrayCopy`
// can be passed to a `UnknownArrayHandle`. This function does nothing
// except provide a compile error that is easier to understand than if you
// let it go and error in `UnknownArrayHandle`. (Huh? I'm not using that.)
template <typename T>
inline void ArrayCopyValueTypeCheck()
{
// Current implementation of Algorithm::Copy will first try to copy on devices where the
// data is already available.
vtkm::cont::Algorithm::Copy(source, destination);
VTKM_STATIC_ASSERT_MSG(vtkm::HasVecTraits<T>::value,
"An `ArrayHandle` that has a special value type that is not supported "
"by the precompiled version of `ArrayCopy` has been used. If this array "
"must be deep copied, consider using `ArrayCopyDevice`. Look at the "
"compile error for the type assigned to template parameter `T` to "
"see the offending type.");
}
// TODO: Remove last argument once ArryHandleNewStyle becomes ArrayHandle
template <typename InArrayType, typename OutArrayType>
void ArrayCopyOldImpl(const InArrayType& in, OutArrayType& out, std::false_type /* Copy storage */)
{
ArrayCopyWithAlgorithm(in, out);
}
template <typename S>
struct ArrayCopyConcreteSrc;
// Copy storage for implicit arrays, must be of same type:
// TODO: This will go away once ArrayHandleNewStyle becomes ArrayHandle.
template <typename ArrayType>
void ArrayCopyOldImpl(const ArrayType& in, ArrayType& out, std::true_type /* Copy storage */)
template <typename SrcIsArrayHandle>
inline void ArrayCopyImpl(const vtkm::cont::UnknownArrayHandle& source,
vtkm::cont::UnknownArrayHandle& destination,
SrcIsArrayHandle,
std::false_type)
{
// This is only called if in/out are the same type and the handle is not
// writable. This allows read-only implicit array handles to be copied.
auto newStorage = in.GetStorage();
out = ArrayType(newStorage);
destination.DeepCopyFrom(source);
}
// TODO: This will go away once ArrayHandleNewStyle becomes ArrayHandle.
template <typename InArrayType, typename OutArrayType>
VTKM_CONT void ArrayCopyImpl(const InArrayType& source,
OutArrayType& destination,
std::false_type /* New style */)
{
using SameTypes = std::is_same<InArrayType, OutArrayType>;
using IsWritable = vtkm::cont::internal::IsWritableArrayHandle<OutArrayType>;
using JustCopyStorage = std::integral_constant<bool, SameTypes::value && !IsWritable::value>;
ArrayCopyOldImpl(source, destination, JustCopyStorage{});
}
// TODO: ArrayHandleNewStyle will eventually become ArrayHandle, in which case this
// will become ArrayCopyWithAlgorithm
template <typename T1, typename S1, typename T2, typename S2>
VTKM_CONT void ArrayCopyImpl(const vtkm::cont::ArrayHandle<T1, S1>& source,
vtkm::cont::ArrayHandle<T2, S2>& destination,
std::true_type /* New style */)
{
VTKM_STATIC_ASSERT((!std::is_same<T1, T2>::value || !std::is_same<S1, S2>::value));
ArrayCopyWithAlgorithm(source, destination);
}
// TODO: ArrayHandleNewStyle will eventually become ArrayHandle, in which case this
// will become the only version with the same array types.
template <typename T, typename S>
VTKM_CONT void ArrayCopyImpl(const vtkm::cont::ArrayHandle<T, S>& source,
vtkm::cont::ArrayHandle<T, S>& destination,
std::true_type /* New style */)
template <typename SrcIsArrayHandle>
inline void ArrayCopyImpl(const vtkm::cont::UnknownArrayHandle& source,
const vtkm::cont::UnknownArrayHandle& destination,
SrcIsArrayHandle,
std::false_type)
{
destination.DeepCopyFrom(source);
}
} // namespace detail
template <typename T, typename S>
void ArrayCopyImpl(const vtkm::cont::UnknownArrayHandle& source,
vtkm::cont::ArrayHandle<T, S>& destination,
std::false_type,
std::true_type)
{
detail::ArrayCopyValueTypeCheck<T>();
using DestType = vtkm::cont::ArrayHandle<T, S>;
if (source.CanConvert<DestType>())
{
destination.DeepCopyFrom(source.AsArrayHandle<DestType>());
}
else
{
vtkm::cont::UnknownArrayHandle destWrapper(destination);
vtkm::cont::detail::ArrayCopyImpl(source, destWrapper, std::false_type{}, std::false_type{});
// Destination array should not change, but just in case.
destWrapper.AsArrayHandle(destination);
}
}
template <typename TS, typename SS, typename TD, typename SD>
void ArrayCopyImpl(const vtkm::cont::ArrayHandle<TS, SS>& source,
vtkm::cont::ArrayHandle<TD, SD>& destination,
std::true_type,
std::true_type)
{
ArrayCopyValueTypeCheck<TS>();
ArrayCopyValueTypeCheck<TD>();
detail::ArrayCopyConcreteSrc<SS>{}(source, destination);
}
// Special case of copying data when type is the same.
template <typename T, typename S>
void ArrayCopyImpl(const vtkm::cont::ArrayHandle<T, S>& source,
vtkm::cont::ArrayHandle<T, S>& destination,
std::true_type,
std::true_type)
{
destination.DeepCopyFrom(source);
}
}
/// \brief Does a deep copy from one array to another array.
///
/// Given a source \c ArrayHandle and a destination \c ArrayHandle, this
/// function allocates the destination \c ArrayHandle to the correct size and
/// Given a source `ArrayHandle` and a destination `ArrayHandle`, this
/// function allocates the destination `ArrayHandle` to the correct size and
/// deeply copies all the values from the source to the destination.
///
/// This method will attempt to copy the data using the device that the input
@ -108,61 +128,41 @@ VTKM_CONT void ArrayCopyImpl(const vtkm::cont::ArrayHandle<T, S>& source,
/// This should work on some non-writable array handles as well, as long as
/// both \a source and \a destination are the same type.
///
/// This version of array copy uses a precompiled version of copy that is
/// efficient for most standard memory layouts. However, there are some
/// types of fancy `ArrayHandle` that cannot be handled directly, and
/// the fallback for these arrays can be slow. If you see a warning in
/// the log about an inefficient memory copy when extracting a component,
/// pay heed and look for a different way to copy the data (perhaps
/// using `ArrayCopyDevice`).
///
/// @{
///
template <typename InValueType, typename InStorage, typename OutValueType, typename OutStorage>
VTKM_CONT void ArrayCopy(const vtkm::cont::ArrayHandle<InValueType, InStorage>& source,
vtkm::cont::ArrayHandle<OutValueType, OutStorage>& destination)
template <typename SourceArrayType, typename DestArrayType>
inline void ArrayCopy(const SourceArrayType& source, DestArrayType& destination)
{
using InArrayType = vtkm::cont::ArrayHandle<InValueType, InStorage>;
using OutArrayType = vtkm::cont::ArrayHandle<OutValueType, OutStorage>;
using SameTypes = std::is_same<InArrayType, OutArrayType>;
using IsWritable = vtkm::cont::internal::IsWritableArrayHandle<OutArrayType>;
// There are three cases handled here:
// 1. The arrays are the same type:
// -> Deep copy the buffers and the Storage object
// 2. The arrays are different and the output is writable:
// -> Do element-wise copy
// 3. The arrays are different and the output is not writable:
// -> fail (cannot copy)
// Give a nice error message for case 3:
VTKM_STATIC_ASSERT_MSG(IsWritable::value || SameTypes::value,
"Cannot copy to a read-only array with a different "
"type than the source.");
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, !IsOldStyle::value>{});
detail::ArrayCopyImpl(source,
destination,
typename internal::ArrayHandleCheck<SourceArrayType>::type{},
typename internal::ArrayHandleCheck<DestArrayType>::type{});
}
VTKM_CONT_EXPORT void ArrayCopy(const vtkm::cont::UnknownArrayHandle& source,
vtkm::cont::UnknownArrayHandle& destination);
VTKM_CONT_EXPORT void ArrayCopy(const vtkm::cont::UnknownArrayHandle& source,
const vtkm::cont::UnknownArrayHandle& destination);
template <typename T, typename S>
VTKM_CONT void ArrayCopy(const vtkm::cont::UnknownArrayHandle& source,
vtkm::cont::ArrayHandle<T, S>& destination)
// Special case where we allow a const UnknownArrayHandle as output.
template <typename SourceArrayType>
inline void ArrayCopy(const SourceArrayType& source, vtkm::cont::UnknownArrayHandle& destination)
{
using DestType = vtkm::cont::ArrayHandle<T, S>;
if (source.CanConvert<DestType>())
{
ArrayCopy(source.AsArrayHandle<DestType>(), destination);
}
else
{
vtkm::cont::UnknownArrayHandle destWrapper(destination);
ArrayCopy(source, destWrapper);
// Destination array should not change, but just in case.
destWrapper.AsArrayHandle(destination);
}
detail::ArrayCopyImpl(source,
destination,
typename internal::ArrayHandleCheck<SourceArrayType>::type{},
std::false_type{});
}
// Invalid const ArrayHandle in destination, which is not allowed because it will
// not work in all cases.
template <typename T, typename S>
void ArrayCopy(const vtkm::cont::UnknownArrayHandle&, const vtkm::cont::ArrayHandle<T, S>&)
{
VTKM_STATIC_ASSERT_MSG(sizeof(T) == 0, "Copying to a constant ArrayHandle is not allowed.");
}
/// @}
@ -190,13 +190,160 @@ VTKM_CONT void ArrayCopyShallowIfPossible(const vtkm::cont::UnknownArrayHandle s
else
{
vtkm::cont::UnknownArrayHandle destWrapper(destination);
ArrayCopy(source, destWrapper);
vtkm::cont::ArrayCopy(source, destWrapper);
// Destination array should not change, but just in case.
destWrapper.AsArrayHandle(destination);
}
}
}
} // namespace vtkm::cont
namespace detail
{
template <typename S>
struct ArrayCopyConcreteSrc
{
template <typename T, typename DestArray>
void operator()(const vtkm::cont::ArrayHandle<T, S>& source, DestArray& destination) const
{
using ArrayType = vtkm::cont::ArrayHandle<T, S>;
this->DoIt(
source, destination, vtkm::cont::internal::ArrayExtractComponentIsInefficient<ArrayType>{});
}
template <typename T, typename DestArray>
void DoIt(const vtkm::cont::ArrayHandle<T, S>& source,
DestArray& destination,
std::false_type vtkmNotUsed(isInefficient)) const
{
vtkm::cont::ArrayCopy(vtkm::cont::UnknownArrayHandle{ source }, destination);
}
template <typename T, typename DestArray>
void DoIt(const vtkm::cont::ArrayHandle<T, S>& source,
DestArray& destination,
std::true_type vtkmNotUsed(isInefficient)) const
{
VTKM_LOG_S(vtkm::cont::LogLevel::Warn,
"Attempting to copy from an array of type " +
vtkm::cont::TypeToString<vtkm::cont::ArrayHandle<T, S>>() +
" with ArrayCopy is inefficient. It is highly recommended you use another method "
"such as vtkm::cont::ArrayCopyDevice.");
// Still call the precompiled `ArrayCopy`. You will get another warning after this,
// but it will still technically work, albiet slowly.
vtkm::cont::ArrayCopy(vtkm::cont::UnknownArrayHandle{ source }, destination);
}
};
// Special case for constant arrays to be efficient.
template <>
struct ArrayCopyConcreteSrc<vtkm::cont::StorageTagConstant>
{
template <typename T1, typename T2, typename S2>
void operator()(const vtkm::cont::ArrayHandle<T1, vtkm::cont::StorageTagConstant>& source_,
vtkm::cont::ArrayHandle<T2, S2>& destination) const
{
vtkm::cont::ArrayHandleConstant<T1> source = source_;
destination.AllocateAndFill(source.GetNumberOfValues(), static_cast<T2>(source.GetValue()));
}
};
// Special case for ArrayHandleIndex to be efficient.
template <>
struct ArrayCopyConcreteSrc<vtkm::cont::StorageTagIndex>
{
template <typename T, typename S>
void operator()(const vtkm::cont::ArrayHandleIndex& source,
vtkm::cont::ArrayHandle<T, S>& destination) const
{
// Skip warning about inefficient copy because there is a special case in ArrayCopyUnknown.cxx
// to copy ArrayHandleIndex efficiently.
vtkm::cont::ArrayCopy(vtkm::cont::UnknownArrayHandle{ source }, destination);
}
};
// Special case for ArrayHandleCounting to be efficient.
template <>
struct VTKM_CONT_EXPORT ArrayCopyConcreteSrc<vtkm::cont::StorageTagCounting>
{
template <typename T1, typename T2, typename S2>
void operator()(const vtkm::cont::ArrayHandle<T1, vtkm::cont::StorageTagCounting>& source,
vtkm::cont::ArrayHandle<T2, S2>& destination) const
{
vtkm::cont::ArrayHandleCounting<T1> countingSource = source;
T1 start = countingSource.GetStart();
T1 step = countingSource.GetStep();
vtkm::Id size = countingSource.GetNumberOfValues();
destination.Allocate(size);
vtkm::cont::UnknownArrayHandle unknownDest = destination;
using VTraits1 = vtkm::VecTraits<T1>;
using VTraits2 = vtkm::VecTraits<T2>;
for (vtkm::IdComponent comp = 0; comp < VTraits1::GetNumberOfComponents(start); ++comp)
{
this->CopyCountingFloat(
static_cast<vtkm::FloatDefault>(VTraits1::GetComponent(start, comp)),
static_cast<vtkm::FloatDefault>(VTraits1::GetComponent(step, comp)),
size,
unknownDest.ExtractComponent<typename VTraits2::BaseComponentType>(comp));
}
}
void operator()(const vtkm::cont::ArrayHandle<vtkm::Id, vtkm::cont::StorageTagCounting>& source,
vtkm::cont::ArrayHandle<vtkm::Id>& destination) const
{
destination = this->CopyCountingId(source);
}
private:
void CopyCountingFloat(vtkm::FloatDefault start,
vtkm::FloatDefault step,
vtkm::Id size,
const vtkm::cont::UnknownArrayHandle& result) const;
vtkm::cont::ArrayHandle<Id> CopyCountingId(
const vtkm::cont::ArrayHandleCounting<vtkm::Id>& source) const;
};
// Special case for ArrayHandleConcatenate to be efficient
template <typename ST1, typename ST2>
struct ArrayCopyConcreteSrc<vtkm::cont::StorageTagConcatenate<ST1, ST2>>
{
template <typename SourceArrayType, typename DestArrayType>
void operator()(const SourceArrayType& source, DestArrayType& destination) const
{
auto source1 = source.GetStorage().GetArray1(source.GetBuffers());
auto source2 = source.GetStorage().GetArray2(source.GetBuffers());
// Need to preallocate because view decorator will not be able to resize.
destination.Allocate(source.GetNumberOfValues());
auto dest1 = vtkm::cont::make_ArrayHandleView(destination, 0, source1.GetNumberOfValues());
auto dest2 = vtkm::cont::make_ArrayHandleView(
destination, source1.GetNumberOfValues(), source2.GetNumberOfValues());
vtkm::cont::ArrayCopy(source1, dest1);
vtkm::cont::ArrayCopy(source2, dest2);
}
};
// Special case for ArrayHandlePermutation to be efficient
template <typename SIndex, typename SValue>
struct ArrayCopyConcreteSrc<vtkm::cont::StorageTagPermutation<SIndex, SValue>>
{
using SourceStorageTag = vtkm::cont::StorageTagPermutation<SIndex, SValue>;
template <typename T1, typename T2, typename S2>
void operator()(const vtkm::cont::ArrayHandle<T1, SourceStorageTag>& source,
vtkm::cont::ArrayHandle<T2, S2>& destination) const
{
auto indexArray = source.GetStorage().GetIndexArray(source.GetBuffers());
auto valueArray = source.GetStorage().GetValueArray(source.GetBuffers());
vtkm::cont::UnknownArrayHandle copy =
vtkm::cont::internal::MapArrayPermutation(valueArray, indexArray);
vtkm::cont::ArrayCopyShallowIfPossible(copy, destination);
}
};
} // namespace detail
} // namespace cont
} // namespace vtkm
#endif //vtk_m_cont_ArrayCopy_h

153
vtkm/cont/ArrayCopyDevice.h Normal file

@ -0,0 +1,153 @@
//============================================================================
// 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_ArrayCopyDevice_h
#define vtk_m_cont_ArrayCopyDevice_h
#include <vtkm/cont/Algorithm.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/DeviceAdapterTag.h>
#include <vtkm/cont/ErrorExecution.h>
#include <vtkm/cont/Logging.h>
#include <vtkm/cont/UnknownArrayHandle.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
// arrays are copied directly but anything else would be copied through virtual methods.
namespace vtkm
{
namespace cont
{
namespace detail
{
// Element-wise copy.
template <typename InArrayType, typename OutArrayType>
void ArrayCopyWithAlgorithm(const InArrayType& source, OutArrayType& destination)
{
// Current implementation of Algorithm::Copy will first try to copy on devices where the
// data is already available.
vtkm::cont::Algorithm::Copy(source, destination);
}
// TODO: Remove last argument once ArryHandleNewStyle becomes ArrayHandle
template <typename InArrayType, typename OutArrayType>
void ArrayCopyOldImpl(const InArrayType& in, OutArrayType& out, std::false_type /* Copy storage */)
{
ArrayCopyWithAlgorithm(in, out);
}
// Copy storage for implicit arrays, must be of same type:
// TODO: This will go away once ArrayHandleNewStyle becomes ArrayHandle.
template <typename ArrayType>
void ArrayCopyOldImpl(const ArrayType& in, ArrayType& out, std::true_type /* Copy storage */)
{
// This is only called if in/out are the same type and the handle is not
// writable. This allows read-only implicit array handles to be copied.
auto newStorage = in.GetStorage();
out = ArrayType(newStorage);
}
// TODO: This will go away once ArrayHandleNewStyle becomes ArrayHandle.
template <typename InArrayType, typename OutArrayType>
VTKM_CONT void ArrayCopyImpl(const InArrayType& source,
OutArrayType& destination,
std::false_type /* New style */)
{
using SameTypes = std::is_same<InArrayType, OutArrayType>;
using IsWritable = vtkm::cont::internal::IsWritableArrayHandle<OutArrayType>;
using JustCopyStorage = std::integral_constant<bool, SameTypes::value && !IsWritable::value>;
ArrayCopyOldImpl(source, destination, JustCopyStorage{});
}
// TODO: ArrayHandleNewStyle will eventually become ArrayHandle, in which case this
// will become ArrayCopyWithAlgorithm
template <typename T1, typename S1, typename T2, typename S2>
VTKM_CONT void ArrayCopyImpl(const vtkm::cont::ArrayHandle<T1, S1>& source,
vtkm::cont::ArrayHandle<T2, S2>& destination,
std::true_type /* New style */)
{
VTKM_STATIC_ASSERT((!std::is_same<T1, T2>::value || !std::is_same<S1, S2>::value));
ArrayCopyWithAlgorithm(source, destination);
}
// TODO: ArrayHandleNewStyle will eventually become ArrayHandle, in which case this
// will become the only version with the same array types.
template <typename T, typename S>
VTKM_CONT void ArrayCopyImpl(const vtkm::cont::ArrayHandle<T, S>& source,
vtkm::cont::ArrayHandle<T, S>& destination,
std::true_type /* New style */)
{
destination.DeepCopyFrom(source);
}
} // namespace detail
/// \brief Does a deep copy from one array to another array.
///
/// Given a source `ArrayHandle` and a destination `ArrayHandle`, this
/// function allocates the destination `ArrayHandle` to the correct size and
/// deeply copies all the values from the source to the destination.
///
/// This method will attempt to copy the data using the device that the input
/// data is already valid on. If the input data is only valid in the control
/// environment, the runtime device tracker is used to try to find another
/// device.
///
/// This should work on some non-writable array handles as well, as long as
/// both \a source and \a destination are the same type.
///
/// This version of array copy is templated to create custom code for the
/// particular types of `ArrayHandle`s that you are copying. This will
/// ensure that you get the best possible copy, but requires a device
/// compiler and tends to bloat the code.
///
/// @{
///
template <typename InValueType, typename InStorage, typename OutValueType, typename OutStorage>
VTKM_CONT void ArrayCopyDevice(const vtkm::cont::ArrayHandle<InValueType, InStorage>& source,
vtkm::cont::ArrayHandle<OutValueType, OutStorage>& destination)
{
using InArrayType = vtkm::cont::ArrayHandle<InValueType, InStorage>;
using OutArrayType = vtkm::cont::ArrayHandle<OutValueType, OutStorage>;
using SameTypes = std::is_same<InArrayType, OutArrayType>;
using IsWritable = vtkm::cont::internal::IsWritableArrayHandle<OutArrayType>;
// There are three cases handled here:
// 1. The arrays are the same type:
// -> Deep copy the buffers and the Storage object
// 2. The arrays are different and the output is writable:
// -> Do element-wise copy
// 3. The arrays are different and the output is not writable:
// -> fail (cannot copy)
// Give a nice error message for case 3:
VTKM_STATIC_ASSERT_MSG(IsWritable::value || SameTypes::value,
"Cannot copy to a read-only array with a different "
"type than the source.");
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, !IsOldStyle::value>{});
}
/// @}
}
} // namespace vtkm::cont
#endif //vtk_m_cont_ArrayCopyDevice_h

@ -19,6 +19,8 @@
#include <vtkm/VecFlat.h>
#include <vtkm/VecTraits.h>
#include <vtkmstd/integer_sequence.h>
#include <vtkm/cont/vtkm_cont_export.h>
namespace vtkm
@ -137,6 +139,39 @@ struct ArrayExtractComponentImpl<vtkm::cont::StorageTagBasic>
}
};
namespace detail
{
template <std::size_t, typename Super>
struct ForwardSuper : Super
{
};
template <typename sequence, typename... Supers>
struct SharedSupersImpl;
template <std::size_t... Indices, typename... Supers>
struct SharedSupersImpl<vtkmstd::index_sequence<Indices...>, Supers...>
: ForwardSuper<Indices, Supers>...
{
};
} // namespace detail
// `ArrayExtractComponentImpl`s that modify the behavior from other storage types might
// want to inherit from the `ArrayExtractComponentImpl`s of these storage types. However,
// if the template specifies multiple storage types, two of the same might be specified,
// and it is illegal in C++ to directly inherit from the same type twice. This special
// superclass accepts a variable amout of superclasses. Inheriting from this will inherit
// from all these superclasses, and duplicates are allowed.
template <typename... Supers>
using DuplicatedSuperclasses =
detail::SharedSupersImpl<vtkmstd::make_index_sequence<sizeof...(Supers)>, Supers...>;
template <typename... StorageTags>
using ArrayExtractComponentImplInherit =
DuplicatedSuperclasses<vtkm::cont::internal::ArrayExtractComponentImpl<StorageTags>...>;
/// \brief Resolves to true if ArrayHandleComponent of the array handle would be inefficient.
///
template <typename ArrayHandleType>

@ -379,8 +379,11 @@ VTKM_CONT
namespace internal
{
// Superclass will inherit the ArrayExtractComponentImplInefficient property if any
// of the sub-storage are inefficient (thus making everything inefficient).
template <typename... STs>
struct ArrayExtractComponentImpl<vtkm::cont::StorageTagCartesianProduct<STs...>>
: vtkm::cont::internal::ArrayExtractComponentImplInherit<STs...>
{
template <typename T>
vtkm::cont::ArrayHandleStride<T> AdjustStrideForComponent(

@ -507,16 +507,19 @@ struct ExtractComponentCompositeVecFunctor
} // namespace detail
// Superclass will inherit the ArrayExtractComponentImplInefficient property if any
// of the sub-storage are inefficient (thus making everything inefficient).
template <typename... StorageTags>
struct ArrayExtractComponentImpl<StorageTagCompositeVec<StorageTags...>>
: vtkm::cont::internal::ArrayExtractComponentImplInherit<StorageTags...>
{
template <typename T, vtkm::IdComponent NUM_COMPONENTS>
typename detail::ExtractComponentCompositeVecFunctor<T>::ResultArray operator()(
const vtkm::cont::ArrayHandle<vtkm::Vec<T, NUM_COMPONENTS>,
vtkm::cont::StorageTagCompositeVec<StorageTags...>>& src,
template <typename VecT>
auto operator()(
const vtkm::cont::ArrayHandle<VecT, vtkm::cont::StorageTagCompositeVec<StorageTags...>>& src,
vtkm::IdComponent componentIndex,
vtkm::CopyFlag allowCopy) const
{
using T = typename vtkm::VecTraits<VecT>::ComponentType;
vtkm::cont::ArrayHandleCompositeVector<vtkm::cont::ArrayHandle<T, StorageTags>...> array(src);
constexpr vtkm::IdComponent NUM_SUB_COMPONENTS = vtkm::VecFlat<T>::NUM_COMPONENTS;

@ -248,12 +248,12 @@ public:
return vtkm::cont::internal::CreateBuffers(array1, array2);
}
VTKM_CONT static const ArrayHandleType1& GetArray1(const vtkm::cont::internal::Buffer* buffers)
VTKM_CONT static const ArrayHandleType1 GetArray1(const vtkm::cont::internal::Buffer* buffers)
{
return ArrayHandleType1(Buffers1(buffers));
}
VTKM_CONT static const ArrayHandleType2& GetArray2(const vtkm::cont::internal::Buffer* buffers)
VTKM_CONT static const ArrayHandleType2 GetArray2(const vtkm::cont::internal::Buffer* buffers)
{
return ArrayHandleType2(Buffers2(buffers));
}

@ -138,6 +138,10 @@ public:
internal::ArrayPortalCounting<CountingValueType>(start, step, length)))
{
}
VTKM_CONT CountingValueType GetStart() const { return this->ReadPortal().GetStart(); }
VTKM_CONT CountingValueType GetStep() const { return this->ReadPortal().GetStep(); }
};
/// A convenience function for creating an ArrayHandleCounting. It takes the

@ -249,9 +249,12 @@ VTKM_CONT vtkm::cont::ArrayHandleGroupVec<ArrayHandleType, NUM_COMPONENTS> make_
namespace internal
{
// Superclass will inherit the ArrayExtractComponentImplInefficient property if
// the sub-storage is inefficient (thus making everything inefficient).
template <typename ComponentsStorageTag, vtkm::IdComponent NUM_COMPONENTS>
struct ArrayExtractComponentImpl<
vtkm::cont::StorageTagGroupVec<ComponentsStorageTag, NUM_COMPONENTS>>
: vtkm::cont::internal::ArrayExtractComponentImpl<ComponentsStorageTag>
{
template <typename T>
vtkm::cont::ArrayHandleStride<typename vtkm::VecTraits<T>::BaseComponentType> operator()(

@ -216,6 +216,10 @@ class ArrayHandlePermutation
VTKM_IS_ARRAY_HANDLE(IndexArrayHandleType);
VTKM_IS_ARRAY_HANDLE(ValueArrayHandleType);
VTKM_STATIC_ASSERT_MSG(
(std::is_same<vtkm::Id, typename IndexArrayHandleType::ValueType>::value),
"Permutation array in ArrayHandlePermutation must have vtkm::Id value type.");
public:
VTKM_ARRAY_HANDLE_SUBCLASS(
ArrayHandlePermutation,

@ -217,8 +217,11 @@ VTKM_CONT ArrayHandleReverse<HandleType> make_ArrayHandleReverse(const HandleTyp
namespace internal
{
// Superclass will inherit the ArrayExtractComponentImplInefficient property if
// the sub-storage is inefficient (thus making everything inefficient).
template <typename StorageTag>
struct ArrayExtractComponentImpl<vtkm::cont::StorageTagReverse<StorageTag>>
: vtkm::cont::internal::ArrayExtractComponentImpl<StorageTag>
{
template <typename T>
using StrideArrayType =

@ -179,7 +179,7 @@ public:
vtkm::Id adjustedEndIndex = (endIndex < indices.NumberOfValues)
? endIndex + indices.StartIndex
: indices.NumberOfValues + indices.StartIndex;
SourceStorage::Fill(buffers, fillValue, adjustedStartIndex, adjustedEndIndex, token);
SourceStorage::Fill(buffers + 1, fillValue, adjustedStartIndex, adjustedEndIndex, token);
}
VTKM_CONT static WritePortalType CreateWritePortal(vtkm::cont::internal::Buffer* buffers,
@ -258,8 +258,11 @@ ArrayHandleView<ArrayHandleType> make_ArrayHandleView(const ArrayHandleType& arr
namespace internal
{
// Superclass will inherit the ArrayExtractComponentImplInefficient property if
// the sub-storage is inefficient (thus making everything inefficient).
template <typename StorageTag>
struct ArrayExtractComponentImpl<StorageTagView<StorageTag>>
: vtkm::cont::internal::ArrayExtractComponentImpl<StorageTag>
{
template <typename T>
using StrideArrayType =

@ -208,6 +208,15 @@ public:
FirstStorage::CreateWritePortal(FirstArrayBuffers(buffers), device, token),
SecondStorage::CreateWritePortal(SecondArrayBuffers(buffers), device, token));
}
vtkm::cont::ArrayHandle<T1, ST1> GetFirstArray(const vtkm::cont::internal::Buffer* buffers)
{
return { FirstArrayBuffers(buffers) };
}
vtkm::cont::ArrayHandle<T2, ST2> GetSecondArray(const vtkm::cont::internal::Buffer* buffers)
{
return { SecondArrayBuffers(buffers) };
}
};
} // namespace internal
@ -238,6 +247,15 @@ public:
: Superclass(vtkm::cont::internal::CreateBuffers(firstArray, secondArray))
{
}
FirstHandleType GetFirstArray() const
{
return this->GetStorage().GetFirstArray(this->GetBuffers());
}
SecondHandleType GetSecondArray() const
{
return this->GetStorage().GetSecondArray(this->GetBuffers());
}
};
/// A convenience function for creating an ArrayHandleZip. It takes the two

@ -11,6 +11,7 @@
set(headers
Algorithm.h
ArrayCopy.h
ArrayCopyDevice.h
ArrayExtractComponent.h
ArrayGetValues.h
ArrayHandle.h
@ -192,7 +193,9 @@ set(device_sources
ColorTable.cxx
ConvertNumComponentsToOffsets.cxx
Field.cxx
internal/ArrayCopyUnknown.cxx
internal/Buffer.cxx
internal/MapArrayPermutation.cxx
MergePartitionedDataSet.cxx
PointLocatorSparseGrid.cxx
RuntimeDeviceInformation.cxx

@ -10,6 +10,7 @@
#ifndef vtk_m_cont_DataSetBuilderRectilinear_h
#define vtk_m_cont_DataSetBuilderRectilinear_h
#include <vtkm/cont/ArrayCopy.h>
#include <vtkm/cont/ArrayHandleCartesianProduct.h>
#include <vtkm/cont/ArrayPortalToIterators.h>
#include <vtkm/cont/CoordinateSystem.h>
@ -34,7 +35,7 @@ class VTKM_CONT_EXPORT DataSetBuilderRectilinear
VTKM_CONT static void CopyInto(const vtkm::cont::ArrayHandle<T>& input,
vtkm::cont::ArrayHandle<U>& output)
{
vtkm::cont::UnknownArrayHandle(output).DeepCopyFrom(input);
vtkm::cont::ArrayCopy(input, output);
}
template <typename T, typename U>

@ -9,6 +9,7 @@
//============================================================================
#include <vtkm/cont/MergePartitionedDataSet.h>
#include <vtkm/cont/Algorithm.h>
#include <vtkm/cont/ArrayCopy.h>
#include <vtkm/cont/ArrayHandleGroupVecVariable.h>
#include <vtkm/cont/ArrayHandleView.h>

@ -12,7 +12,6 @@
#define vtk_m_cont_ParticleArrayCopy_hxx
#include <vtkm/cont/Algorithm.h>
#include <vtkm/cont/ArrayCopy.h>
#include <vtkm/cont/ArrayHandleTransform.h>
#include <vtkm/cont/Invoker.h>
#include <vtkm/cont/ParticleArrayCopy.h>
@ -84,7 +83,7 @@ VTKM_ALWAYS_EXPORT inline void ParticleArrayCopy(
vtkm::cont::Algorithm::CopyIf(posTrn, termTrn, outPos);
}
else
vtkm::cont::ArrayCopy(posTrn, outPos);
vtkm::cont::Algorithm::Copy(posTrn, outPos);
}

@ -21,7 +21,7 @@
#include <vtkm/cont/Algorithm.h>
#include <vtkm/cont/ArrayCopy.h>
#include <vtkm/cont/ArrayHandleCounting.h>
#include <vtkm/cont/ArrayHandleIndex.h>
#include <vtkm/cont/Invoker.h>
#include <vtkm/worklet/WorkletMapField.h>
@ -82,9 +82,8 @@ void PointLocatorSparseGrid::Build()
static_cast<vtkm::FloatDefault>(this->Range[2].Max));
// generate unique id for each input point
vtkm::cont::ArrayHandleCounting<vtkm::Id> pointCounting(
0, 1, this->GetCoordinates().GetNumberOfValues());
vtkm::cont::ArrayCopy(pointCounting, this->PointIds);
vtkm::cont::ArrayHandleIndex pointIndex(this->GetCoordinates().GetNumberOfValues());
vtkm::cont::ArrayCopy(pointIndex, this->PointIds);
using internal::BinPointsWorklet;

@ -275,12 +275,32 @@ VTKM_CONT void UnknownArrayHandle::Allocate(vtkm::Id numValues, vtkm::CopyFlag p
VTKM_CONT void UnknownArrayHandle::DeepCopyFrom(const vtkm::cont::UnknownArrayHandle& source)
{
vtkm::cont::internal::ArrayCopyUnknown(source, *this);
if (!this->IsValid())
{
*this = source.NewInstance();
}
const_cast<const UnknownArrayHandle*>(this)->DeepCopyFrom(source);
}
VTKM_CONT void UnknownArrayHandle::DeepCopyFrom(const vtkm::cont::UnknownArrayHandle& source) const
{
vtkm::cont::internal::ArrayCopyUnknown(source, *this);
if (!this->IsValid())
{
throw vtkm::cont::ErrorBadValue(
"Attempty to copy to a constant UnknownArrayHandle with no valid array.");
}
if (source.IsValueTypeImpl(this->Container->ValueType) &&
source.IsStorageTypeImpl(this->Container->StorageType))
{
this->Container->DeepCopy(source.Container->ArrayHandlePointer,
this->Container->ArrayHandlePointer);
}
else
{
vtkm::cont::internal::ArrayCopyUnknown(source, *this);
}
}
VTKM_CONT
@ -290,8 +310,10 @@ void UnknownArrayHandle::CopyShallowIfPossible(const vtkm::cont::UnknownArrayHan
{
*this = source;
}
const_cast<const UnknownArrayHandle*>(this)->CopyShallowIfPossible(source);
else
{
const_cast<const UnknownArrayHandle*>(this)->CopyShallowIfPossible(source);
}
}
VTKM_CONT
@ -311,7 +333,7 @@ void UnknownArrayHandle::CopyShallowIfPossible(const vtkm::cont::UnknownArrayHan
}
else
{
this->DeepCopyFrom(source);
vtkm::cont::internal::ArrayCopyUnknown(source, *this);
}
}

@ -113,6 +113,15 @@ void UnknownAHShallowCopy(const void* sourceMem, void* destinationMem)
*destination = *source;
}
template <typename T, typename S>
void UnknownAHDeepCopy(const void* sourceMem, void* destinationMem)
{
using AH = vtkm::cont::ArrayHandle<T, S>;
const AH* source = reinterpret_cast<const AH*>(sourceMem);
AH* destination = reinterpret_cast<AH*>(destinationMem);
destination->DeepCopyFrom(*source);
}
template <typename T, typename S>
std::vector<vtkm::cont::internal::Buffer>
UnknownAHExtractComponent(void* mem, vtkm::IdComponent componentIndex, vtkm::CopyFlag allowCopy)
@ -224,6 +233,9 @@ struct VTKM_CONT_EXPORT UnknownAHContainer
using ShallowCopyType = void(const void*, void*);
ShallowCopyType* ShallowCopy;
using DeepCopyType = void(const void*, void*);
DeepCopyType* DeepCopy;
using ExtractComponentType = std::vector<vtkm::cont::internal::Buffer>(void*,
vtkm::IdComponent,
vtkm::CopyFlag);
@ -331,6 +343,7 @@ inline UnknownAHContainer::UnknownAHContainer(const vtkm::cont::ArrayHandle<T, S
, NumberOfComponentsFlat(detail::UnknownAHNumberOfComponentsFlat<T>)
, Allocate(detail::UnknownAHAllocate<T, S>)
, ShallowCopy(detail::UnknownAHShallowCopy<T, S>)
, DeepCopy(detail::UnknownAHDeepCopy<T, S>)
, ExtractComponent(detail::UnknownAHExtractComponent<T, S>)
, ReleaseResources(detail::UnknownAHReleaseResources<T, S>)
, ReleaseResourcesExecution(detail::UnknownAHReleaseResourcesExecution<T, S>)

@ -0,0 +1,254 @@
//============================================================================
// 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.
//============================================================================
#include <vtkm/cont/ArrayCopy.h>
#include <vtkm/cont/ArrayCopyDevice.h>
#include <vtkm/cont/ArrayHandleIndex.h>
#include <vtkm/cont/DeviceAdapterList.h>
#include <vtkm/cont/Invoker.h>
#include <vtkm/cont/internal/ArrayCopyUnknown.h>
#include <vtkm/worklet/WorkletMapField.h>
namespace
{
// Use a worklet because device adapter copies often have an issue with casting the values from the
// `ArrayHandleRecomineVec` that comes from `UnknownArrayHandle::CastAndCallWithExtractedArray`.
struct CopyWorklet : vtkm::worklet::WorkletMapField
{
using ControlSignature = void(FieldIn, FieldOut);
using ExecutionSignature = void(_1, _2);
using InputDomain = _1;
template <typename InType, typename OutType>
VTKM_EXEC void operator()(const InType& in, OutType& out) const
{
out = in;
}
};
struct UnknownCopyOnDevice
{
bool Called = false;
template <typename InType, typename OutType>
void operator()(vtkm::cont::DeviceAdapterId device,
const vtkm::cont::ArrayHandleRecombineVec<InType>& in,
const vtkm::cont::ArrayHandleRecombineVec<OutType>& out)
{
// Note: ArrayHandleRecombineVec returns the wrong value for IsOnDevice (always true).
// This is one of the consequences of ArrayHandleRecombineVec breaking assumptions of
// ArrayHandle. It does this by stuffing Buffer objects in another Buffer's meta data
// rather than listing them explicitly (where they can be queried). We get around this
// by pulling out one of the component arrays and querying that.
if (!this->Called &&
((device == vtkm::cont::DeviceAdapterTagAny{}) ||
(in.GetComponentArray(0).IsOnDevice(device))))
{
vtkm::cont::Invoker invoke(device);
invoke(CopyWorklet{}, in, out);
this->Called = true;
}
}
};
struct UnknownCopyFunctor2
{
template <typename OutType, typename InType>
void operator()(const vtkm::cont::ArrayHandleRecombineVec<OutType>& out,
const vtkm::cont::ArrayHandleRecombineVec<InType>& in) const
{
UnknownCopyOnDevice doCopy;
// Try to copy on a device that the data are already on.
vtkm::ListForEach(doCopy, VTKM_DEFAULT_DEVICE_ADAPTER_LIST{}, in, out);
// If it was not on any device, call one more time with any adapter to copy wherever.
doCopy(vtkm::cont::DeviceAdapterTagAny{}, in, out);
}
};
struct UnknownCopyFunctor1
{
template <typename InType>
void operator()(const vtkm::cont::ArrayHandleRecombineVec<InType>& in,
const vtkm::cont::UnknownArrayHandle& out) const
{
out.Allocate(in.GetNumberOfValues());
this->DoIt(in, out, typename std::is_same<vtkm::FloatDefault, InType>::type{});
}
template <typename InType>
void DoIt(const vtkm::cont::ArrayHandleRecombineVec<InType>& in,
const vtkm::cont::UnknownArrayHandle& out,
std::false_type) const
{
// Source is not float.
if (out.IsBaseComponentType<InType>())
{
// Arrays have the same base component type. Copy directly.
try
{
UnknownCopyFunctor2{}(out.ExtractArrayFromComponents<InType>(vtkm::CopyFlag::Off), in);
}
catch (vtkm::cont::Error& error)
{
throw vtkm::cont::ErrorBadType(
"Unable to copy to an array of type " + out.GetArrayTypeName() +
" using anonymous methods. Try using vtkm::cont::ArrayCopyDevice. "
"(Original error: `" +
error.GetMessage() + "')");
}
}
else if (out.IsBaseComponentType<vtkm::FloatDefault>())
{
// Can copy anything to default float.
try
{
UnknownCopyFunctor2{}(
out.ExtractArrayFromComponents<vtkm::FloatDefault>(vtkm::CopyFlag::Off), in);
}
catch (vtkm::cont::Error& error)
{
throw vtkm::cont::ErrorBadType(
"Unable to copy to an array of type " + out.GetArrayTypeName() +
" using anonymous methods. Try using vtkm::cont::ArrayCopyDevice. "
"(Original error: `" +
error.GetMessage() + "')");
}
}
else
{
// Arrays have different base types. To reduce the number of template paths from nxn to 3n,
// copy first to a temp array of default float.
vtkm::cont::UnknownArrayHandle temp = out.NewInstanceFloatBasic();
(*this)(in, temp);
vtkm::cont::ArrayCopy(temp, out);
}
}
template <typename InType>
void DoIt(const vtkm::cont::ArrayHandleRecombineVec<InType>& in,
const vtkm::cont::UnknownArrayHandle& out,
std::true_type) const
{
// Source array is FloatDefault. That should be copiable to anything.
out.CastAndCallWithExtractedArray(UnknownCopyFunctor2{}, in);
}
};
void ArrayCopySpecialCase(const vtkm::cont::ArrayHandleIndex& source,
const vtkm::cont::UnknownArrayHandle& destination)
{
if (destination.CanConvert<vtkm::cont::ArrayHandleIndex>())
{
// Unlikely, but we'll check.
destination.AsArrayHandle<vtkm::cont::ArrayHandleIndex>().DeepCopyFrom(source);
}
else if (destination.IsBaseComponentType<vtkm::Id>())
{
destination.Allocate(source.GetNumberOfValues());
auto dest = destination.ExtractComponent<vtkm::Id>(0, vtkm::CopyFlag::Off);
vtkm::cont::ArrayCopyDevice(source, dest);
}
else if (destination.IsBaseComponentType<vtkm::IdComponent>())
{
destination.Allocate(source.GetNumberOfValues());
auto dest = destination.ExtractComponent<vtkm::IdComponent>(0, vtkm::CopyFlag::Off);
vtkm::cont::ArrayCopyDevice(source, dest);
}
else if (destination.CanConvert<vtkm::cont::ArrayHandle<vtkm::FloatDefault>>())
{
vtkm::cont::ArrayHandle<vtkm::FloatDefault> dest;
destination.AsArrayHandle(dest);
vtkm::cont::ArrayCopyDevice(source, dest);
}
else
{
// Initializing something that is probably not really an index. Rather than trace down every
// unlikely possibility, just copy to float and then to the final array.
vtkm::cont::ArrayHandle<vtkm::FloatDefault> dest;
vtkm::cont::ArrayCopyDevice(source, dest);
vtkm::cont::ArrayCopy(dest, destination);
}
}
template <typename ArrayHandleType>
bool TryArrayCopySpecialCase(const vtkm::cont::UnknownArrayHandle& source,
const vtkm::cont::UnknownArrayHandle& destination)
{
if (source.CanConvert<ArrayHandleType>())
{
ArrayCopySpecialCase(source.AsArrayHandle<ArrayHandleType>(), destination);
return true;
}
else
{
return false;
}
}
void DoUnknownArrayCopy(const vtkm::cont::UnknownArrayHandle& source,
const vtkm::cont::UnknownArrayHandle& destination)
{
if (source.GetNumberOfValues() > 0)
{
// Try known special cases.
if (TryArrayCopySpecialCase<vtkm::cont::ArrayHandleIndex>(source, destination))
{
return;
}
source.CastAndCallWithExtractedArray(UnknownCopyFunctor1{}, destination);
}
else
{
destination.ReleaseResources();
}
}
} // anonymous namespace
namespace vtkm
{
namespace cont
{
namespace internal
{
void ArrayCopyUnknown(const vtkm::cont::UnknownArrayHandle& source,
vtkm::cont::UnknownArrayHandle& destination)
{
if (!destination.IsValid())
{
destination = source.NewInstanceBasic();
}
DoUnknownArrayCopy(source, destination);
}
void ArrayCopyUnknown(const vtkm::cont::UnknownArrayHandle& source,
const vtkm::cont::UnknownArrayHandle& destination)
{
if (!destination.IsValid())
{
throw vtkm::cont::ErrorBadValue(
"Attempty to copy to a constant UnknownArrayHandle with no valid array.");
}
DoUnknownArrayCopy(source, destination);
}
} // namespace vtkm::cont::internal
} // namespace vtkm::cont
} // namespace vtkm

@ -28,6 +28,7 @@ set(headers
FunctorsGeneral.h
IteratorFromArrayPortal.h
KXSort.h
MapArrayPermutation.h
OptionParser.h
OptionParserArguments.h
ParallelRadixSort.h

@ -0,0 +1,100 @@
//============================================================================
// 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.
//============================================================================
#include <vtkm/cont/internal/CastInvalidValue.h>
#include <vtkm/cont/internal/MapArrayPermutation.h>
#include <vtkm/cont/ErrorBadType.h>
#include <vtkm/worklet/WorkletMapField.h>
namespace
{
template <typename T>
struct MapPermutationWorklet : vtkm::worklet::WorkletMapField
{
T InvalidValue;
explicit MapPermutationWorklet(T invalidValue)
: InvalidValue(invalidValue)
{
}
using ControlSignature = void(FieldIn permutationIndex, WholeArrayIn input, FieldOut output);
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);
}
else
{
output = this->InvalidValue;
}
}
};
struct DoMapFieldPermutation
{
template <typename InputArrayType, typename PermutationArrayType>
void operator()(const InputArrayType& input,
const PermutationArrayType& permutation,
vtkm::cont::UnknownArrayHandle& output,
vtkm::Float64 invalidValue) const
{
using BaseComponentType = typename InputArrayType::ValueType::ComponentType;
MapPermutationWorklet<BaseComponentType> worklet(
vtkm::cont::internal::CastInvalidValue<BaseComponentType>(invalidValue));
vtkm::cont::Invoker{}(
worklet,
permutation,
input,
output.ExtractArrayFromComponents<BaseComponentType>(vtkm::CopyFlag::Off));
}
};
} // anonymous namespace
namespace vtkm
{
namespace cont
{
namespace internal
{
vtkm::cont::UnknownArrayHandle MapArrayPermutation(
const vtkm::cont::UnknownArrayHandle& inputArray,
const vtkm::cont::UnknownArrayHandle& permutation,
vtkm::Float64 invalidValue)
{
if (!permutation.IsBaseComponentType<vtkm::Id>())
{
throw vtkm::cont::ErrorBadType("Permutation array input to MapArrayPermutation must have "
"values of vtkm::Id. Reported type is " +
permutation.GetBaseComponentTypeName());
}
vtkm::cont::UnknownArrayHandle outputArray = inputArray.NewInstanceBasic();
outputArray.Allocate(permutation.GetNumberOfValues());
inputArray.CastAndCallWithExtractedArray(
DoMapFieldPermutation{}, permutation.ExtractComponent<vtkm::Id>(0), outputArray, invalidValue);
return outputArray;
}
}
}
} // namespace vtkm::cont::internal

@ -0,0 +1,51 @@
//============================================================================
// 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_MapArrayPermutation_h
#define vtk_m_cont_internal_MapArrayPermutation_h
#include <vtkm/cont/ArrayHandlePermutation.h>
#include <vtkm/cont/UnknownArrayHandle.h>
#include <vtkm/cont/vtkm_cont_export.h>
namespace vtkm
{
namespace cont
{
namespace internal
{
/// Used to map a permutation like that found in an ArrayHandlePermutation.
///
VTKM_CONT_EXPORT vtkm::cont::UnknownArrayHandle MapArrayPermutation(
const vtkm::cont::UnknownArrayHandle& inputArray,
const vtkm::cont::UnknownArrayHandle& permutation,
vtkm::Float64 invalidValue = vtkm::Nan64());
/// Used to map a permutation array.
///
template <typename T, typename S>
vtkm::cont::UnknownArrayHandle MapArrayPermutation(
const vtkm::cont::ArrayHandle<T,
vtkm::cont::StorageTagPermutation<vtkm::cont::StorageTagBasic, S>>&
inputArray,
vtkm::Float64 invalidValue = vtkm::Nan64())
{
vtkm::cont::ArrayHandlePermutation<vtkm::cont::ArrayHandle<vtkm::Id>,
vtkm::cont::ArrayHandle<T, S>>
input = inputArray;
return MapArrayPermutation(input.GetValueArray(), input.GetIndexArray(), invalidValue);
}
}
}
} // namespace vtkm::cont::internal
#endif //vtk_m_cont_internal_MapArrayPermutation_h

@ -426,7 +426,7 @@ private:
SetPortal(basicArray.WritePortal());
vtkm::cont::ArrayHandleSOA<ValueType> soaArray;
vtkm::cont::ArrayCopy(basicArray, soaArray);
vtkm::cont::Invoker{}(PassThrough{}, basicArray, soaArray);
VTKM_TEST_ASSERT(soaArray.GetNumberOfValues() == ARRAY_SIZE);
for (vtkm::IdComponent componentIndex = 0; componentIndex < NUM_COMPONENTS; ++componentIndex)
@ -1085,13 +1085,13 @@ private:
VTKM_EXEC void operator()(const InputType& input, vtkm::Id workIndex, vtkm::Id& dummyOut) const
{
using ComponentType = typename InputType::ComponentType;
vtkm::IdComponent expectedSize = static_cast<vtkm::IdComponent>(workIndex + 1);
vtkm::IdComponent expectedSize = static_cast<vtkm::IdComponent>(workIndex);
if (expectedSize != input.GetNumberOfComponents())
{
this->RaiseError("Got unexpected number of components.");
}
vtkm::Id valueIndex = workIndex * (workIndex + 1) / 2;
vtkm::Id valueIndex = workIndex * (workIndex - 1) / 2;
dummyOut = valueIndex;
for (vtkm::IdComponent componentIndex = 0; componentIndex < expectedSize; componentIndex++)
{
@ -1113,8 +1113,7 @@ private:
vtkm::Id sourceArraySize;
vtkm::cont::ArrayHandle<vtkm::Id> numComponentsArray;
vtkm::cont::ArrayCopy(vtkm::cont::ArrayHandleCounting<vtkm::IdComponent>(1, 1, ARRAY_SIZE),
numComponentsArray);
vtkm::cont::ArrayCopy(vtkm::cont::ArrayHandleIndex(ARRAY_SIZE), numComponentsArray);
vtkm::cont::ArrayHandle<vtkm::Id> offsetsArray =
vtkm::cont::ConvertNumComponentsToOffsets(numComponentsArray, sourceArraySize);
@ -1147,13 +1146,13 @@ private:
VTKM_EXEC void operator()(OutputType& output, vtkm::Id workIndex) const
{
using ComponentType = typename OutputType::ComponentType;
vtkm::IdComponent expectedSize = static_cast<vtkm::IdComponent>(workIndex + 1);
vtkm::IdComponent expectedSize = static_cast<vtkm::IdComponent>(workIndex);
if (expectedSize != output.GetNumberOfComponents())
{
this->RaiseError("Got unexpected number of components.");
}
vtkm::Id valueIndex = workIndex * (workIndex + 1) / 2;
vtkm::Id valueIndex = workIndex * (workIndex - 1) / 2;
for (vtkm::IdComponent componentIndex = 0; componentIndex < expectedSize; componentIndex++)
{
output[componentIndex] = TestValue(valueIndex, ComponentType());
@ -1170,8 +1169,7 @@ private:
vtkm::Id sourceArraySize;
vtkm::cont::ArrayHandle<vtkm::Id> numComponentsArray;
vtkm::cont::ArrayCopy(vtkm::cont::ArrayHandleCounting<vtkm::IdComponent>(1, 1, ARRAY_SIZE),
numComponentsArray);
vtkm::cont::ArrayCopy(vtkm::cont::ArrayHandleIndex(ARRAY_SIZE), numComponentsArray);
vtkm::cont::ArrayHandle<vtkm::Id> offsetsArray = vtkm::cont::ConvertNumComponentsToOffsets(
numComponentsArray, sourceArraySize, DeviceAdapterTag());
@ -1364,6 +1362,15 @@ private:
//verify that the control portal works
CheckPortal(view.ReadPortal());
//verify that filling works
const ValueType expected = TestValue(20, ValueType{});
view.Fill(expected);
auto valuesPortal = values.ReadPortal();
for (vtkm::Id index = length; index < 2 * length; ++index)
{
VTKM_TEST_ASSERT(valuesPortal.Get(index) == expected);
}
}
};

@ -9,12 +9,18 @@
//============================================================================
#include <vtkm/cont/ArrayCopy.h>
#include <vtkm/cont/ArrayCopyDevice.h>
#include <vtkm/cont/ArrayHandleConcatenate.h>
#include <vtkm/cont/ArrayHandleConstant.h>
#include <vtkm/cont/ArrayHandleCounting.h>
#include <vtkm/cont/ArrayHandleIndex.h>
#include <vtkm/cont/ArrayHandlePermutation.h>
#include <vtkm/cont/ArrayHandleView.h>
#include <vtkm/cont/UncertainArrayHandle.h>
#include <vtkm/cont/UnknownArrayHandle.h>
#include <vtkm/TypeTraits.h>
#include <vtkm/VecTraits.h>
#include <vtkm/cont/testing/Testing.h>
@ -23,13 +29,43 @@ namespace
static constexpr vtkm::Id ARRAY_SIZE = 10;
template <typename RefArrayType, typename TestArrayType>
void TestValues(const RefArrayType& refArray, const TestArrayType& testArray)
vtkm::cont::UnknownArrayHandle MakeComparable(const vtkm::cont::UnknownArrayHandle& array,
std::false_type)
{
return array;
}
template <typename T>
vtkm::cont::UnknownArrayHandle MakeComparable(const vtkm::cont::ArrayHandle<T>& array,
std::true_type)
{
return array;
}
template <typename ArrayType>
vtkm::cont::UnknownArrayHandle MakeComparable(const ArrayType& array, std::true_type)
{
vtkm::cont::ArrayHandle<typename ArrayType::ValueType> simpleArray;
vtkm::cont::ArrayCopyDevice(array, simpleArray);
return simpleArray;
}
void TestValuesImpl(const vtkm::cont::UnknownArrayHandle& refArray,
const vtkm::cont::UnknownArrayHandle& testArray)
{
auto result = test_equal_ArrayHandles(refArray, testArray);
VTKM_TEST_ASSERT(result, result.GetMergedMessage());
}
template <typename RefArrayType, typename TestArrayType>
void TestValues(const RefArrayType& refArray, const TestArrayType& testArray)
{
TestValuesImpl(
MakeComparable(refArray, typename vtkm::cont::internal::ArrayHandleCheck<RefArrayType>::type{}),
MakeComparable(testArray,
typename vtkm::cont::internal::ArrayHandleCheck<TestArrayType>::type{}));
}
template <typename ValueType>
vtkm::cont::ArrayHandle<ValueType> MakeInputArray()
{
@ -44,18 +80,20 @@ void TryCopy()
{
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
"Trying type: " << vtkm::testing::TypeName<ValueType>::Name());
using VTraits = vtkm::VecTraits<ValueType>;
{
std::cout << "implicit -> basic" << std::endl;
vtkm::cont::ArrayHandleIndex input(ARRAY_SIZE);
vtkm::cont::ArrayHandle<ValueType> output;
vtkm::cont::ArrayHandle<typename VTraits::BaseComponentType> output;
vtkm::cont::ArrayCopy(input, output);
TestValues(input, output);
}
{
std::cout << "basic -> basic" << std::endl;
vtkm::cont::ArrayHandle<vtkm::Id> input = MakeInputArray<vtkm::Id>();
using SourceType = typename VTraits::template ReplaceComponentType<vtkm::Id>;
vtkm::cont::ArrayHandle<SourceType> input = MakeInputArray<SourceType>();
vtkm::cont::ArrayHandle<ValueType> output;
vtkm::cont::ArrayCopy(input, output);
TestValues(input, output);
@ -90,30 +128,72 @@ void TryCopy()
TestValues(input, output);
}
using TypeList = vtkm::ListAppend<vtkm::TypeListField, vtkm::List<ValueType, vtkm::UInt8>>;
using StorageList = VTKM_DEFAULT_STORAGE_LIST;
using UnknownArray = vtkm::cont::UnknownArrayHandle;
using UncertainArray = vtkm::cont::UncertainArrayHandle<TypeList, StorageList>;
{
std::cout << "unknown -> unknown" << std::endl;
UnknownArray input = MakeInputArray<ValueType>();
UnknownArray output;
vtkm::cont::ArrayCopy(input, output);
TestValues(input, output);
}
{
std::cout << "uncertain -> basic (same type)" << std::endl;
UncertainArray input = MakeInputArray<ValueType>();
std::cout << "constant -> basic" << std::endl;
vtkm::cont::ArrayHandleConstant<ValueType> input(TestValue(2, ValueType{}), ARRAY_SIZE);
vtkm::cont::ArrayHandle<ValueType> output;
vtkm::cont::ArrayCopy(input, output);
TestValues(input, output);
}
{
std::cout << "uncertain -> basic (different type)" << std::endl;
UncertainArray input = MakeInputArray<vtkm::UInt8>();
std::cout << "counting -> basic" << std::endl;
vtkm::cont::ArrayHandleCounting<ValueType> input(ValueType(-4), ValueType(3), ARRAY_SIZE);
vtkm::cont::ArrayHandle<ValueType> output;
vtkm::cont::ArrayCopy(input, output);
TestValues(input, output);
}
{
std::cout << "view -> basic" << std::endl;
vtkm::cont::ArrayHandle<ValueType> input = MakeInputArray<ValueType>();
auto viewInput = vtkm::cont::make_ArrayHandleView(input, 1, ARRAY_SIZE / 2);
vtkm::cont::ArrayHandle<ValueType> output;
vtkm::cont::ArrayCopy(input, output);
TestValues(input, output);
}
{
std::cout << "concatinate -> basic" << std::endl;
vtkm::cont::ArrayHandle<ValueType> input1 = MakeInputArray<ValueType>();
vtkm::cont::ArrayHandleConstant<ValueType> input2(TestValue(6, ValueType{}), ARRAY_SIZE / 2);
auto concatInput = vtkm::cont::make_ArrayHandleConcatenate(input1, input2);
vtkm::cont::ArrayHandle<ValueType> output;
vtkm::cont::ArrayCopy(concatInput, output);
TestValues(concatInput, output);
}
{
std::cout << "permutation -> basic" << std::endl;
vtkm::cont::ArrayHandle<vtkm::Id> indices;
vtkm::cont::ArrayCopy(vtkm::cont::make_ArrayHandleCounting<vtkm::Id>(0, 2, ARRAY_SIZE / 2),
indices);
auto input = vtkm::cont::make_ArrayHandlePermutation(indices, MakeInputArray<ValueType>());
vtkm::cont::ArrayHandle<ValueType> output;
vtkm::cont::ArrayCopy(input, output);
TestValues(input, output);
}
{
std::cout << "unknown -> unknown" << std::endl;
vtkm::cont::UnknownArrayHandle input = MakeInputArray<ValueType>();
vtkm::cont::UnknownArrayHandle output;
vtkm::cont::ArrayCopy(input, output);
TestValues(input, output);
}
{
std::cout << "unknown -> basic (same type)" << std::endl;
vtkm::cont::UnknownArrayHandle input = MakeInputArray<ValueType>();
vtkm::cont::ArrayHandle<ValueType> output;
vtkm::cont::ArrayCopy(input, output);
TestValues(input, output);
}
{
std::cout << "unknown -> basic (different type)" << std::endl;
using SourceType = typename VTraits::template ReplaceComponentType<vtkm::UInt8>;
vtkm::cont::UnknownArrayHandle input = MakeInputArray<SourceType>();
vtkm::cont::ArrayHandle<ValueType> output;
vtkm::cont::ArrayCopy(input, output);
TestValues(input, output);
@ -139,7 +219,8 @@ void TryCopy()
{
std::cout << "unknown.DeepCopyFrom(different type)" << std::endl;
vtkm::cont::ArrayHandle<vtkm::UInt8> input = MakeInputArray<vtkm::UInt8>();
using SourceType = typename VTraits::template ReplaceComponentType<vtkm::UInt8>;
vtkm::cont::ArrayHandle<SourceType> input = MakeInputArray<SourceType>();
vtkm::cont::ArrayHandle<ValueType> outputArray;
vtkm::cont::UnknownArrayHandle(outputArray).DeepCopyFrom(input);
TestValues(input, outputArray);
@ -166,7 +247,8 @@ void TryCopy()
{
std::cout << "unknown.CopyShallowIfPossible(different type)" << std::endl;
vtkm::cont::ArrayHandle<vtkm::UInt8> input = MakeInputArray<vtkm::UInt8>();
using SourceType = typename VTraits::template ReplaceComponentType<vtkm::UInt8>;
vtkm::cont::ArrayHandle<SourceType> input = MakeInputArray<SourceType>();
vtkm::cont::ArrayHandle<ValueType> outputArray;
vtkm::cont::UnknownArrayHandle(outputArray).CopyShallowIfPossible(input);
TestValues(input, outputArray);
@ -203,6 +285,8 @@ void TestArrayCopy()
TryCopy<vtkm::Id>();
TryCopy<vtkm::IdComponent>();
TryCopy<vtkm::Float32>();
TryCopy<vtkm::Vec3f>();
TryCopy<vtkm::Vec4i_16>();
TryArrayCopyShallowIfPossible();
}

@ -12,6 +12,7 @@
#include <vtkm/cont/Algorithm.h>
#include <vtkm/cont/ArrayCopy.h>
#include <vtkm/cont/ArrayCopyDevice.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ArrayHandleConstant.h>
#include <vtkm/cont/ArrayHandleCounting.h>
@ -331,8 +332,8 @@ struct DecoratorTests
}
// Copy a constant array into the decorator. This should modify ah3Copy.
vtkm::cont::ArrayCopy(vtkm::cont::make_ArrayHandleConstant(ValueType{ 25 }, ARRAY_SIZE),
ahDecor);
vtkm::cont::ArrayCopyDevice(vtkm::cont::make_ArrayHandleConstant(ValueType{ 25 }, ARRAY_SIZE),
ahDecor);
{ // Accessing portal should give all 25s:
auto portalDecor = ahDecor.ReadPortal();
@ -390,7 +391,7 @@ struct DecoratorTests
}
vtkm::cont::ArrayHandle<ValueType> copiedInExec;
vtkm::cont::ArrayCopy(decorArray, copiedInExec);
vtkm::cont::ArrayCopyDevice(decorArray, copiedInExec);
{
auto copiedPortal = copiedInExec.ReadPortal();
auto countPortal = ahCount.ReadPortal();

@ -8,7 +8,7 @@
// PURPOSE. See the above copyright notice for more information.
//============================================================================
#include <vtkm/cont/ArrayCopy.h>
#include <vtkm/cont/ArrayCopyDevice.h>
#include <vtkm/cont/ArrayHandleBasic.h>
#include <vtkm/cont/ArrayHandleCartesianProduct.h>
#include <vtkm/cont/ArrayHandleCompositeVector.h>
@ -84,13 +84,13 @@ void FillArray(vtkm::cont::ArrayHandle<T, S>& array)
using Traits = vtkm::VecTraits<T>;
vtkm::IdComponent numComponents = Traits::NUM_COMPONENTS;
vtkm::cont::ArrayCopy(vtkm::cont::make_ArrayHandleConstant(T{}, ARRAY_SIZE), array);
array.AllocateAndFill(ARRAY_SIZE, vtkm::TypeTraits<T>::ZeroInitialization());
for (vtkm::IdComponent component = 0; component < numComponents; ++component)
{
vtkm::cont::ArrayHandleRandomUniformReal<vtkm::Float64> randomArray(ARRAY_SIZE);
auto dest = vtkm::cont::make_ArrayHandleExtractComponent(array, component);
vtkm::cont::ArrayCopy(randomArray, dest);
vtkm::cont::ArrayCopyDevice(randomArray, dest);
}
}

@ -7,7 +7,7 @@
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//============================================================================
#include <vtkm/cont/ArrayCopy.h>
#include <vtkm/cont/ArrayCopyDevice.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ArrayHandleConstant.h>
#include <vtkm/cont/ArrayHandleCounting.h>
@ -143,16 +143,13 @@ auto PermutationArray = vtkm::cont::ArrayHandleCounting<vtkm::Id>(0, 2, BaseLine
vtkm::cont::CellSetExplicit<> MakeCellSetExplicit()
{
vtkm::cont::ArrayHandle<vtkm::UInt8> shapes;
vtkm::cont::ArrayCopy(vtkm::cont::ArrayHandleConstant<vtkm::UInt8>{ vtkm::CELL_SHAPE_HEXAHEDRON,
BaseLineNumberOfCells },
shapes);
shapes.AllocateAndFill(BaseLineNumberOfCells, vtkm::CELL_SHAPE_HEXAHEDRON);
vtkm::cont::ArrayHandle<vtkm::IdComponent> numIndices;
vtkm::cont::ArrayCopy(
vtkm::cont::ArrayHandleConstant<vtkm::IdComponent>{ 8, BaseLineNumberOfCells }, numIndices);
numIndices.AllocateAndFill(BaseLineNumberOfCells, 8);
vtkm::cont::ArrayHandle<vtkm::Id> connectivity;
vtkm::cont::ArrayCopy(BaseLineConnectivity, connectivity);
vtkm::cont::ArrayCopyDevice(BaseLineConnectivity, connectivity);
auto offsets = vtkm::cont::ConvertNumComponentsToOffsets(numIndices);

@ -24,6 +24,7 @@ vtkm_add_instantiations(ClipWithImplicitFunctionInstantiations
set(deprecated_headers
CellSetConnectivity.h
CleanGrid.h
CrossProduct.h
DotProduct.h
Entropy.h
ExternalFaces.h
@ -88,7 +89,6 @@ set(extra_headers
ComputeMoments.h
CoordinateSystemTransform.h
CreateResult.h
CrossProduct.h
FieldSelection.h
FieldToColors.h
GhostCellClassify.h
@ -133,7 +133,6 @@ set(extra_header_template_sources
ClipWithImplicitFunctionExternInstantiations.h
ComputeMoments.hxx
CoordinateSystemTransform.hxx
CrossProduct.hxx
FieldToColors.hxx
GhostCellClassify.hxx
ImageDifference.hxx

@ -11,133 +11,31 @@
#ifndef vtk_m_filter_CrossProduct_h
#define vtk_m_filter_CrossProduct_h
#include <vtkm/filter/FilterField.h>
#include <vtkm/worklet/CrossProduct.h>
#include <vtkm/Deprecated.h>
#include <vtkm/filter/vector_calculus/CrossProduct.h>
namespace vtkm
{
namespace filter
{
class CrossProduct : public vtkm::filter::FilterField<CrossProduct>
VTKM_DEPRECATED(
1.8,
"Use vtkm/filter/vector_calculus/CrossProduct.h instead of vtkm/filter/CrossProduct.h.")
inline void CrossProduct_deprecated() {}
inline void CrossProduct_deprecated_warning()
{
public:
//CrossProduct filter only works on vec3 data.
using SupportedTypes = vtkm::TypeListFieldVec3;
CrossProduct_deprecated();
}
VTKM_CONT
CrossProduct();
//@{
/// Choose the primary field to operate on. In the cross product operation A x B, A is
/// the primary field.
VTKM_CONT
void SetPrimaryField(
const std::string& name,
vtkm::cont::Field::Association association = vtkm::cont::Field::Association::ANY)
{
this->SetActiveField(name, association);
}
VTKM_CONT const std::string& GetPrimaryFieldName() const { return this->GetActiveFieldName(); }
VTKM_CONT vtkm::cont::Field::Association GetPrimaryFieldAssociation() const
{
return this->GetActiveFieldAssociation();
}
//@}
//@{
/// When set to true, uses a coordinate system as the primary field instead of the one selected
/// by name. Use SetPrimaryCoordinateSystem to select which coordinate system.
VTKM_CONT
void SetUseCoordinateSystemAsPrimaryField(bool flag)
{
this->SetUseCoordinateSystemAsField(flag);
}
VTKM_CONT
bool GetUseCoordinateSystemAsPrimaryField() const
{
return this->GetUseCoordinateSystemAsField();
}
//@}
//@{
/// Select the coordinate system index to use as the primary field. This only has an effect when
/// UseCoordinateSystemAsPrimaryField is true.
VTKM_CONT
void SetPrimaryCoordinateSystem(vtkm::Id index) { this->SetActiveCoordinateSystem(index); }
VTKM_CONT
vtkm::Id GetPrimaryCoordinateSystemIndex() const
{
return this->GetActiveCoordinateSystemIndex();
}
//@}
//@{
/// Choose the secondary field to operate on. In the cross product operation A x B, B is
/// the secondary field.
VTKM_CONT
void SetSecondaryField(
const std::string& name,
vtkm::cont::Field::Association association = vtkm::cont::Field::Association::ANY)
{
this->SecondaryFieldName = name;
this->SecondaryFieldAssociation = association;
}
VTKM_CONT const std::string& GetSecondaryFieldName() const { return this->SecondaryFieldName; }
VTKM_CONT vtkm::cont::Field::Association GetSecondaryFieldAssociation() const
{
return this->SecondaryFieldAssociation;
}
//@}
//@{
/// When set to true, uses a coordinate system as the primary field instead of the one selected
/// by name. Use SetPrimaryCoordinateSystem to select which coordinate system.
VTKM_CONT
void SetUseCoordinateSystemAsSecondaryField(bool flag)
{
this->UseCoordinateSystemAsSecondaryField = flag;
}
VTKM_CONT
bool GetUseCoordinateSystemAsSecondaryField() const
{
return this->UseCoordinateSystemAsSecondaryField;
}
//@}
//@{
/// Select the coordinate system index to use as the primary field. This only has an effect when
/// UseCoordinateSystemAsPrimaryField is true.
VTKM_CONT
void SetSecondaryCoordinateSystem(vtkm::Id index)
{
this->SecondaryCoordinateSystemIndex = index;
}
VTKM_CONT
vtkm::Id GetSecondaryCoordinateSystemIndex() const
{
return this->SecondaryCoordinateSystemIndex;
}
//@}
template <typename T, typename StorageType, typename DerivedPolicy>
VTKM_CONT vtkm::cont::DataSet DoExecute(
const vtkm::cont::DataSet& input,
const vtkm::cont::ArrayHandle<vtkm::Vec<T, 3>, StorageType>& field,
const vtkm::filter::FieldMetadata& fieldMeta,
vtkm::filter::PolicyBase<DerivedPolicy> policy);
private:
std::string SecondaryFieldName;
vtkm::cont::Field::Association SecondaryFieldAssociation;
bool UseCoordinateSystemAsSecondaryField;
vtkm::Id SecondaryCoordinateSystemIndex;
class VTKM_DEPRECATED(1.8, "Use vtkm::filter::vector_calculus::CrossProduct.") CrossProduct
: public vtkm::filter::vector_calculus::CrossProduct
{
using vector_calculus::CrossProduct::CrossProduct;
};
}
} // namespace vtkm::filter
#include <vtkm/filter/CrossProduct.hxx>
#endif // vtk_m_filter_CrossProduct_h

@ -1,62 +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_filter_CrossProduct_hxx
#define vtk_m_filter_CrossProduct_hxx
#include <vtkm/cont/ArrayHandleCast.h>
#include <vtkm/worklet/DispatcherMapField.h>
namespace vtkm
{
namespace filter
{
//-----------------------------------------------------------------------------
inline VTKM_CONT CrossProduct::CrossProduct()
: vtkm::filter::FilterField<CrossProduct>()
, SecondaryFieldName()
, SecondaryFieldAssociation(vtkm::cont::Field::Association::ANY)
, UseCoordinateSystemAsSecondaryField(false)
, SecondaryCoordinateSystemIndex(0)
{
this->SetOutputFieldName("crossproduct");
}
//-----------------------------------------------------------------------------
template <typename T, typename StorageType, typename DerivedPolicy>
inline VTKM_CONT vtkm::cont::DataSet CrossProduct::DoExecute(
const vtkm::cont::DataSet& inDataSet,
const vtkm::cont::ArrayHandle<vtkm::Vec<T, 3>, StorageType>& primary,
const vtkm::filter::FieldMetadata& fieldMetadata,
vtkm::filter::PolicyBase<DerivedPolicy> policy)
{
vtkm::cont::Field secondaryField;
if (this->UseCoordinateSystemAsSecondaryField)
{
secondaryField = inDataSet.GetCoordinateSystem(this->GetSecondaryCoordinateSystemIndex());
}
else
{
secondaryField = inDataSet.GetField(this->SecondaryFieldName, this->SecondaryFieldAssociation);
}
auto secondary =
vtkm::filter::ApplyPolicyFieldOfType<vtkm::Vec<T, 3>>(secondaryField, policy, *this);
vtkm::cont::ArrayHandle<vtkm::Vec<T, 3>> output;
this->Invoke(vtkm::worklet::CrossProduct{}, primary, secondary, output);
return CreateResult(inDataSet, output, this->GetOutputFieldName(), fieldMetadata);
}
}
} // namespace vtkm::filter
#endif

@ -8,65 +8,11 @@
// PURPOSE. See the above copyright notice for more information.
//============================================================================
#include <vtkm/VecTraits.h>
#include <vtkm/cont/Logging.h>
#include <vtkm/cont/internal/CastInvalidValue.h>
#include <vtkm/cont/internal/MapArrayPermutation.h>
#include <vtkm/filter/MapFieldPermutation.h>
#include <vtkm/worklet/WorkletMapField.h>
namespace
{
template <typename T>
struct MapPermutationWorklet : vtkm::worklet::WorkletMapField
{
T InvalidValue;
explicit MapPermutationWorklet(T invalidValue)
: InvalidValue(invalidValue)
{
}
using ControlSignature = void(FieldIn permutationIndex, WholeArrayIn input, FieldOut output);
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);
}
else
{
output = this->InvalidValue;
}
}
};
struct DoMapFieldPermutation
{
template <typename InputArrayType>
void operator()(const InputArrayType& input,
const vtkm::cont::ArrayHandle<vtkm::Id>& permutation,
vtkm::cont::UnknownArrayHandle& output,
vtkm::Float64 invalidValue) const
{
using BaseComponentType = typename InputArrayType::ValueType::ComponentType;
MapPermutationWorklet<BaseComponentType> worklet(
vtkm::cont::internal::CastInvalidValue<BaseComponentType>(invalidValue));
vtkm::cont::Invoker{}(
worklet,
permutation,
input,
output.ExtractArrayFromComponents<BaseComponentType>(vtkm::CopyFlag::Off));
}
};
} // anonymous namespace
VTKM_FILTER_CORE_EXPORT VTKM_CONT bool vtkm::filter::MapFieldPermutation(
const vtkm::cont::Field& inputField,
@ -76,12 +22,10 @@ VTKM_FILTER_CORE_EXPORT VTKM_CONT bool vtkm::filter::MapFieldPermutation(
{
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
vtkm::cont::UnknownArrayHandle outputArray = inputField.GetData().NewInstanceBasic();
outputArray.Allocate(permutation.GetNumberOfValues());
try
{
inputField.GetData().CastAndCallWithExtractedArray(
DoMapFieldPermutation{}, permutation, outputArray, invalidValue);
vtkm::cont::UnknownArrayHandle outputArray =
vtkm::cont::internal::MapArrayPermutation(inputField.GetData(), permutation, invalidValue);
outputField = vtkm::cont::Field(inputField.GetName(), inputField.GetAssociation(), outputArray);
return true;
}

@ -142,6 +142,54 @@ protected:
}
}
template <typename Functor, typename... Args>
VTKM_CONT void CastAndCallScalarField(const vtkm::cont::UnknownArrayHandle& fieldArray,
Functor&& functor,
Args&&... args) const
{
fieldArray
.CastAndCallForTypesWithFloatFallback<vtkm::TypeListFieldScalar, VTKM_DEFAULT_STORAGE_LIST>(
std::forward<Functor>(functor), std::forward<Args>(args)...);
}
template <typename Functor, typename... Args>
VTKM_CONT void CastAndCallScalarField(const vtkm::cont::Field& field,
Functor&& functor,
Args&&... args) const
{
this->CastAndCallScalarField(
field.GetData(), std::forward<Functor>(functor), std::forward<Args>(args)...);
}
private:
template <vtkm::IdComponent VecSize>
struct ScalarToVec
{
template <typename T>
using type = vtkm::Vec<T, VecSize>;
};
protected:
template <vtkm::IdComponent VecSize, typename Functor, typename... Args>
VTKM_CONT void CastAndCallVecField(const vtkm::cont::UnknownArrayHandle& fieldArray,
Functor&& functor,
Args&&... args) const
{
using VecList =
vtkm::ListTransform<vtkm::TypeListFieldScalar, ScalarToVec<VecSize>::template type>;
fieldArray.CastAndCallForTypesWithFloatFallback<VecList, VTKM_DEFAULT_STORAGE_LIST>(
std::forward<Functor>(functor), std::forward<Args>(args)...);
}
template <vtkm::IdComponent VecSize, typename Functor, typename... Args>
VTKM_CONT void CastAndCallVecField(const vtkm::cont::Field& field,
Functor&& functor,
Args&&... args) const
{
this->CastAndCallVecField<VecSize>(
field.GetData(), std::forward<Functor>(functor), std::forward<Args>(args)...);
}
private:
void ResizeIfNeeded(size_t index_st);

@ -10,7 +10,7 @@
#ifndef vtk_m_worklet_RemoveUnusedPoints_h
#define vtk_m_worklet_RemoveUnusedPoints_h
#include <vtkm/cont/ArrayCopy.h>
#include <vtkm/cont/ArrayCopyDevice.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ArrayHandleConstant.h>
#include <vtkm/cont/ArrayHandlePermutation.h>
@ -102,9 +102,7 @@ public:
if (this->MaskArray.GetNumberOfValues() < 1)
{
// Initialize mask array to 0.
vtkm::cont::ArrayCopy(
vtkm::cont::ArrayHandleConstant<vtkm::IdComponent>(0, inCellSet.GetNumberOfPoints()),
this->MaskArray);
this->MaskArray.AllocateAndFill(inCellSet.GetNumberOfPoints(), 0);
}
VTKM_ASSERT(this->MaskArray.GetNumberOfValues() == inCellSet.GetNumberOfPoints());
@ -257,7 +255,7 @@ public:
VTKM_CONT void MapPointFieldDeep(const vtkm::cont::ArrayHandle<InT, InS>& inArray,
vtkm::cont::ArrayHandle<OutT, OutS>& outArray) const
{
vtkm::cont::ArrayCopy(this->MapPointFieldShallow(inArray), outArray);
vtkm::cont::ArrayCopyDevice(this->MapPointFieldShallow(inArray), outArray);
}
template <typename T, typename S>

@ -11,6 +11,7 @@
#ifndef vtk_m_worklet_connectivity_InnerJoin_h
#define vtk_m_worklet_connectivity_InnerJoin_h
#include <vtkm/cont/Algorithm.h>
#include <vtkm/cont/ArrayHandleIndex.h>
#include <vtkm/worklet/DispatcherMapField.h>
#include <vtkm/worklet/ScatterCounting.h>

@ -23,6 +23,6 @@ set(libraries
vtkm_unit_tests(
SOURCES ${unit_tests}
LIBRARIES ${libraries}
ALL_BACKENDS # use ArrayCopy
ALL_BACKENDS # UnitTestParticleDensity.cxx uses DescriptiveStatistcs worklet
USE_VTKM_JOB_POOL
)

@ -8,6 +8,8 @@
// PURPOSE. See the above copyright notice for more information.
//============================================================================
#include <vtkm/cont/ArrayCopy.h>
#include <vtkm/cont/ArrayCopyDevice.h>
#include <vtkm/cont/ArrayHandleRandomUniformReal.h>
#include <vtkm/cont/DataSetBuilderExplicit.h>
#include <vtkm/cont/testing/Testing.h>
@ -27,7 +29,7 @@ void TestNGP()
vtkm::cont::ArrayHandleRandomUniformReal<vtkm::Float32>(N, 0xdeed),
vtkm::cont::ArrayHandleRandomUniformReal<vtkm::Float32>(N, 0xabba));
vtkm::cont::ArrayHandle<vtkm::Vec3f> positions;
vtkm::cont::ArrayCopy(composite, positions);
vtkm::cont::ArrayCopyDevice(composite, positions);
vtkm::cont::ArrayHandle<vtkm::Id> connectivity;
vtkm::cont::ArrayCopy(vtkm::cont::make_ArrayHandleIndex(N), connectivity);
@ -36,8 +38,8 @@ void TestNGP()
positions, vtkm::CellShapeTagVertex{}, 1, connectivity);
vtkm::cont::ArrayHandle<vtkm::FloatDefault> mass;
vtkm::cont::ArrayCopy(vtkm::cont::ArrayHandleRandomUniformReal<vtkm::FloatDefault>(N, 0xd1ce),
mass);
vtkm::cont::ArrayCopyDevice(
vtkm::cont::ArrayHandleRandomUniformReal<vtkm::FloatDefault>(N, 0xd1ce), mass);
dataSet.AddCellField("mass", mass);
auto cellDims = vtkm::Id3{ 3, 3, 3 };
@ -78,7 +80,7 @@ void TestCIC()
vtkm::cont::ArrayHandleRandomUniformReal<vtkm::Float32>(N, 0xdeed),
vtkm::cont::ArrayHandleRandomUniformReal<vtkm::Float32>(N, 0xabba));
vtkm::cont::ArrayHandle<vtkm::Vec3f> positions;
vtkm::cont::ArrayCopy(composite, positions);
vtkm::cont::ArrayCopyDevice(composite, positions);
vtkm::cont::ArrayHandle<vtkm::Id> connectivity;
vtkm::cont::ArrayCopy(vtkm::cont::make_ArrayHandleIndex(N), connectivity);
@ -87,7 +89,8 @@ void TestCIC()
positions, vtkm::CellShapeTagVertex{}, 1, connectivity);
vtkm::cont::ArrayHandle<vtkm::Float32> mass;
vtkm::cont::ArrayCopy(vtkm::cont::ArrayHandleRandomUniformReal<vtkm::Float32>(N, 0xd1ce), mass);
vtkm::cont::ArrayCopyDevice(vtkm::cont::ArrayHandleRandomUniformReal<vtkm::Float32>(N, 0xd1ce),
mass);
dataSet.AddCellField("mass", mass);
auto cellDims = vtkm::Id3{ 3, 3, 3 };

@ -147,7 +147,7 @@ VTKM_CONT vtkm::cont::DataSet ThresholdPoints::DoExecute(const vtkm::cont::DataS
vtkm::cont::CellSetSingleType<> outCellSet;
vtkm::worklet::ThresholdPoints worklet;
auto ResolveType = [&, this](const auto& concrete) {
auto resolveType = [&, this](const auto& concrete) {
switch (this->ThresholdType)
{
case THRESHOLD_BELOW:
@ -170,8 +170,7 @@ VTKM_CONT vtkm::cont::DataSet ThresholdPoints::DoExecute(const vtkm::cont::DataS
}
};
const auto& fieldArray = field.GetData();
fieldArray.CastAndCallForTypes<vtkm::TypeListScalarAll, VTKM_DEFAULT_STORAGE_LIST>(ResolveType);
this->CastAndCallScalarField(field, resolveType);
// create the output dataset
vtkm::cont::DataSet output;

@ -18,6 +18,7 @@
#include <vtkm/cont/Algorithm.h>
#include <vtkm/cont/ArrayCopy.h>
#include <vtkm/cont/ArrayCopyDevice.h>
#include <vtkm/cont/ArrayGetValues.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ArrayHandleConcatenate.h>
@ -940,7 +941,9 @@ public:
auto offsetsArray =
vtkm::cont::make_ArrayHandleConcatenate(faceOffsetsTrim, adjustedPolyDataOffsets);
OffsetsArrayType joinedOffsets;
vtkm::cont::ArrayCopy(offsetsArray, joinedOffsets);
// Need to compile a special device copy because the precompiled ArrayCopy does not
// know how to copy the ArrayHandleTransform.
vtkm::cont::ArrayCopyDevice(offsetsArray, joinedOffsets);
vtkm::cont::ArrayHandleConcatenate<vtkm::cont::ArrayHandle<vtkm::Id>,
vtkm::cont::ArrayHandle<vtkm::Id>>

@ -9,13 +9,13 @@
##============================================================================
set(field_transform_headers
GenerateIds.h)
set(field_transform_sources_device
set(field_transform_sources
GenerateIds.cxx)
vtkm_library(
NAME vtkm_filter_field_transform
HEADERS ${field_transform_headers}
DEVICE_SOURCES ${field_transform_sources_device}
SOURCES ${field_transform_sources}
USE_VTKM_JOB_POOL
)

@ -23,7 +23,6 @@ set(unit_tests
UnitTestContourTreeUniformAugmentedFilter.cxx
UnitTestContourTreeUniformDistributedFilter.cxx
UnitTestCoordinateSystemTransform.cxx
UnitTestCrossProductFilter.cxx
UnitTestFieldMetadata.cxx
UnitTestFieldSelection.cxx
UnitTestFieldToColors.cxx

@ -8,9 +8,13 @@
## PURPOSE. See the above copyright notice for more information.
##============================================================================
set(vector_calculus_headers
DotProduct.h)
CrossProduct.h
DotProduct.h
)
set(vector_calculus_sources_device
DotProduct.cxx)
CrossProduct.cxx
DotProduct.cxx
)
vtkm_library(
NAME vtkm_filter_vector_calculus

@ -0,0 +1,91 @@
//============================================================================
// 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.
//============================================================================
#include <vtkm/filter/vector_calculus/CrossProduct.h>
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/cont/ArrayCopy.h>
#include <vtkm/VectorAnalysis.h>
namespace
{
class CrossProductWorklet : public vtkm::worklet::WorkletMapField
{
public:
using ControlSignature = void(FieldIn, FieldIn, FieldOut);
template <typename T>
VTKM_EXEC void operator()(const vtkm::Vec<T, 3>& vec1,
const vtkm::Vec<T, 3>& vec2,
vtkm::Vec<T, 3>& outVec) const
{
outVec = vtkm::Cross(vec1, vec2);
}
};
} // anonymous namespace
namespace vtkm
{
namespace filter
{
namespace vector_calculus
{
//-----------------------------------------------------------------------------
VTKM_CONT CrossProduct::CrossProduct()
{
this->SetOutputFieldName("crossproduct");
}
//-----------------------------------------------------------------------------
VTKM_CONT vtkm::cont::DataSet CrossProduct::DoExecute(const vtkm::cont::DataSet& inDataSet)
{
vtkm::cont::Field primaryField = this->GetFieldFromDataSet(0, inDataSet);
vtkm::cont::UnknownArrayHandle primaryArray = primaryField.GetData();
vtkm::cont::UnknownArrayHandle outArray;
// We are using a C++14 auto lambda here. The advantage over a Functor is obvious, we don't
// need to explicitly pass filter, input/output DataSets etc. thus reduce the impact to
// the legacy code. The lambda can also access the private part of the filter thus reducing
// filter's public interface profile. CastAndCall tries to cast primaryArray of unknown value
// type and storage to a concrete ArrayHandle<T, S> with T from the `TypeList` and S from
// `StorageList`. It then passes the concrete array to the lambda as the first argument.
// We can later recover the concrete ValueType, T, from the concrete array.
auto resolveType = [&, this](const auto& concrete) {
// use std::decay to remove const ref from the decltype of concrete.
using T = typename std::decay_t<decltype(concrete)>::ValueType;
const auto& secondaryField = this->GetFieldFromDataSet(1, inDataSet);
vtkm::cont::ArrayHandle<T> secondaryArray;
vtkm::cont::ArrayCopyShallowIfPossible(secondaryField.GetData(), secondaryArray);
vtkm::cont::ArrayHandle<T> result;
this->Invoke(CrossProductWorklet{}, concrete, secondaryArray, result);
outArray = result;
};
this->CastAndCallVecField<3>(primaryArray, resolveType);
vtkm::cont::DataSet outDataSet;
outDataSet.CopyStructure(inDataSet);
outDataSet.AddField({ this->GetOutputFieldName(), primaryField.GetAssociation(), outArray });
this->MapFieldsOntoOutput(inDataSet, outDataSet);
return outDataSet;
}
}
}
} // namespace vtkm::filter::vector_calculus

@ -0,0 +1,129 @@
//============================================================================
// 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_filter_vector_calculus_CrossProduct_h
#define vtk_m_filter_vector_calculus_CrossProduct_h
#include <vtkm/filter/NewFilterField.h>
#include <vtkm/filter/vector_calculus/vtkm_filter_vector_calculus_export.h>
namespace vtkm
{
namespace filter
{
namespace vector_calculus
{
class VTKM_FILTER_VECTOR_CALCULUS_EXPORT CrossProduct : public vtkm::filter::NewFilterField
{
public:
VTKM_CONT
CrossProduct();
//@{
/// Choose the primary field to operate on. In the cross product operation A x B, A is
/// the primary field.
VTKM_CONT
void SetPrimaryField(
const std::string& name,
vtkm::cont::Field::Association association = vtkm::cont::Field::Association::ANY)
{
this->SetActiveField(name, association);
}
VTKM_CONT const std::string& GetPrimaryFieldName() const { return this->GetActiveFieldName(); }
VTKM_CONT vtkm::cont::Field::Association GetPrimaryFieldAssociation() const
{
return this->GetActiveFieldAssociation();
}
//@}
//@{
/// When set to true, uses a coordinate system as the primary field instead of the one selected
/// by name. Use SetPrimaryCoordinateSystem to select which coordinate system.
VTKM_CONT
void SetUseCoordinateSystemAsPrimaryField(bool flag)
{
this->SetUseCoordinateSystemAsField(flag);
}
VTKM_CONT
bool GetUseCoordinateSystemAsPrimaryField() const
{
return this->GetUseCoordinateSystemAsField();
}
//@}
//@{
/// Select the coordinate system index to use as the primary field. This only has an effect when
/// UseCoordinateSystemAsPrimaryField is true.
VTKM_CONT
void SetPrimaryCoordinateSystem(vtkm::Id index) { this->SetActiveCoordinateSystem(index); }
VTKM_CONT
vtkm::Id GetPrimaryCoordinateSystemIndex() const
{
return this->GetActiveCoordinateSystemIndex();
}
//@}
//@{
/// Choose the secondary field to operate on. In the dot product operation A . B, B is
/// the secondary field.
VTKM_CONT
void SetSecondaryField(
const std::string& name,
vtkm::cont::Field::Association association = vtkm::cont::Field::Association::ANY)
{
this->SetActiveField(1, name, association);
}
VTKM_CONT const std::string& GetSecondaryFieldName() const { return this->GetActiveFieldName(1); }
VTKM_CONT vtkm::cont::Field::Association GetSecondaryFieldAssociation() const
{
return this->GetActiveFieldAssociation(1);
}
//@}
//@{
/// When set to true, uses a coordinate system as the secondary field instead of the one selected
/// by name. Use SetSecondaryCoordinateSystem to select which coordinate system.
VTKM_CONT
void SetUseCoordinateSystemAsSecondaryField(bool flag)
{
this->SetUseCoordinateSystemAsField(1, flag);
}
VTKM_CONT
bool GetUseCoordinateSystemAsSecondaryField() const
{
return this->GetUseCoordinateSystemAsField(1);
}
//@}
//@{
/// Select the coordinate system index to use as the secondary field. This only has an effect when
/// UseCoordinateSystemAsSecondaryField is true.
VTKM_CONT
void SetSecondaryCoordinateSystem(vtkm::Id index) { this->SetActiveCoordinateSystem(1, index); }
VTKM_CONT
vtkm::Id GetSecondaryCoordinateSystemIndex() const
{
return this->GetActiveCoordinateSystemIndex(1);
}
//@}
private:
VTKM_CONT vtkm::cont::DataSet DoExecute(const vtkm::cont::DataSet& input) override;
};
}
}
} // namespace vtkm::filter::vector_calculus
#endif // vtk_m_filter_vector_calculus_CrossProduct_h

@ -8,33 +8,59 @@
// PURPOSE. See the above copyright notice for more information.
//============================================================================
#include <vtkm/cont/ErrorFilterExecution.h>
#include <vtkm/filter/vector_calculus/DotProduct.h>
#include <vtkm/worklet/WorkletMapField.h>
namespace // anonymous namespace making worklet::DotProduct internal to this .cxx
{
namespace worklet
struct DotProductWorklet : vtkm::worklet::WorkletMapField
{
class DotProduct : public vtkm::worklet::WorkletMapField
{
public:
using ControlSignature = void(FieldIn, FieldIn, FieldOut);
template <typename T, vtkm::IdComponent Size>
VTKM_EXEC void operator()(const vtkm::Vec<T, Size>& v1,
const vtkm::Vec<T, Size>& v2,
T& outValue) const
template <typename T1, typename T2, typename T3>
VTKM_EXEC void operator()(const T1& v1, const T2& v2, T3& outValue) const
{
outValue = static_cast<T>(vtkm::Dot(v1, v2));
}
template <typename T>
VTKM_EXEC void operator()(T s1, T s2, T& outValue) const
{
outValue = static_cast<T>(s1 * s2);
VTKM_ASSERT(v1.GetNumberOfComponents() == v2.GetNumberOfComponents());
outValue = v1[0] * v2[0];
for (vtkm::IdComponent i = 1; i < v1.GetNumberOfComponents(); ++i)
{
outValue += v1[i] * v2[i];
}
}
};
} // namespace worklet
template <typename PrimaryArrayType>
vtkm::cont::UnknownArrayHandle DoDotProduct(const PrimaryArrayType& primaryArray,
const vtkm::cont::Field& secondaryField)
{
using T = typename PrimaryArrayType::ValueType::ComponentType;
vtkm::cont::Invoker invoke;
vtkm::cont::ArrayHandle<T> outputArray;
if (secondaryField.GetData().IsBaseComponentType<T>())
{
invoke(DotProductWorklet{},
primaryArray,
secondaryField.GetData().ExtractArrayFromComponents<T>(),
outputArray);
}
else
{
// Data types of primary and secondary array do not match. Rather than try to replicate every
// possibility, get the secondary array as a FloatDefault.
vtkm::cont::UnknownArrayHandle castSecondaryArray = secondaryField.GetDataAsDefaultFloat();
invoke(DotProductWorklet{},
primaryArray,
castSecondaryArray.ExtractArrayFromComponents<vtkm::FloatDefault>(),
outputArray);
}
return outputArray;
}
} // anonymous namespace
namespace vtkm
@ -51,37 +77,39 @@ VTKM_CONT DotProduct::DotProduct()
VTKM_CONT vtkm::cont::DataSet DotProduct::DoExecute(const vtkm::cont::DataSet& inDataSet)
{
const auto& primaryArray = this->GetFieldFromDataSet(inDataSet).GetData();
vtkm::cont::Field primaryField = this->GetFieldFromDataSet(0, inDataSet);
vtkm::cont::UnknownArrayHandle primaryArray = primaryField.GetData();
vtkm::cont::Field secondaryField = this->GetFieldFromDataSet(1, inDataSet);
if (primaryArray.GetNumberOfComponentsFlat() !=
secondaryField.GetData().GetNumberOfComponentsFlat())
{
throw vtkm::cont::ErrorFilterExecution(
"Primary and secondary arrays of DotProduct filter have different number of components.");
}
vtkm::cont::UnknownArrayHandle outArray;
// We are using a C++14 auto lambda here. The advantage over a Functor is obvious, we don't
// need to explicitly pass filter, input/output DataSets etc. thus reduce the impact to
// the legacy code. The lambda can also access the private part of the filter thus reducing
// filter's public interface profile. CastAndCall tries to cast primaryArray of unknown value
// type and storage to a concrete ArrayHandle<T, S> with T from the `TypeList` and S from
// `StorageList`. It then passes the concrete array to the lambda as the first argument.
// We can later recover the concrete ValueType, T, from the concrete array.
auto ResolveType = [&, this](const auto& concrete) {
// use std::decay to remove const ref from the decltype of concrete.
using T = typename std::decay_t<decltype(concrete)>::ValueType;
const auto& secondaryField = this->GetFieldFromDataSet(1, inDataSet);
vtkm::cont::UnknownArrayHandle secondary = vtkm::cont::ArrayHandle<T>{};
secondary.CopyShallowIfPossible(secondaryField.GetData());
if (primaryArray.IsBaseComponentType<vtkm::Float32>())
{
outArray =
DoDotProduct(primaryArray.ExtractArrayFromComponents<vtkm::Float32>(), secondaryField);
}
else if (primaryArray.IsBaseComponentType<vtkm::Float64>())
{
outArray =
DoDotProduct(primaryArray.ExtractArrayFromComponents<vtkm::Float64>(), secondaryField);
}
else
{
primaryArray = primaryField.GetDataAsDefaultFloat();
outArray =
DoDotProduct(primaryArray.ExtractArrayFromComponents<vtkm::FloatDefault>(), secondaryField);
}
vtkm::cont::ArrayHandle<typename vtkm::VecTraits<T>::ComponentType> result;
this->Invoke(::worklet::DotProduct{},
concrete,
secondary.template AsArrayHandle<vtkm::cont::ArrayHandle<T>>(),
result);
outArray = result;
};
primaryArray
.CastAndCallForTypesWithFloatFallback<VTKM_DEFAULT_TYPE_LIST, VTKM_DEFAULT_STORAGE_LIST>(
ResolveType);
vtkm::cont::DataSet outDataSet = inDataSet; // copy
vtkm::cont::DataSet outDataSet;
outDataSet.CopyStructure(inDataSet);
outDataSet.AddField({ this->GetOutputFieldName(),
this->GetFieldFromDataSet(inDataSet).GetAssociation(),
outArray });

@ -9,6 +9,7 @@
##============================================================================
set(unit_tests
UnitTestCrossProductFilter.cxx
UnitTestDotProductFilter.cxx
)

@ -10,7 +10,9 @@
#include <vtkm/cont/testing/MakeTestDataSet.h>
#include <vtkm/cont/testing/Testing.h>
#include <vtkm/filter/CrossProduct.h>
#include <vtkm/filter/vector_calculus/CrossProduct.h>
#include <vtkm/VectorAnalysis.h>
#include <random>
#include <vector>
@ -139,7 +141,7 @@ void TestCrossProduct()
{
std::cout << " Both vectors as normal fields" << std::endl;
vtkm::filter::CrossProduct filter;
vtkm::filter::vector_calculus::CrossProduct filter;
filter.SetPrimaryField("vec1");
filter.SetSecondaryField("vec2", vtkm::cont::Field::Association::POINTS);
@ -163,7 +165,7 @@ void TestCrossProduct()
{
std::cout << " First field as coordinates" << std::endl;
vtkm::filter::CrossProduct filter;
vtkm::filter::vector_calculus::CrossProduct filter;
filter.SetUseCoordinateSystemAsPrimaryField(true);
filter.SetPrimaryCoordinateSystem(1);
filter.SetSecondaryField("vec2");
@ -184,7 +186,7 @@ void TestCrossProduct()
{
std::cout << " Second field as coordinates" << std::endl;
vtkm::filter::CrossProduct filter;
vtkm::filter::vector_calculus::CrossProduct filter;
filter.SetPrimaryField("vec1");
filter.SetUseCoordinateSystemAsSecondaryField(true);
filter.SetSecondaryCoordinateSystem(2);

@ -49,19 +49,15 @@ set(sources
ImageWriterPNG.cxx
ImageWriterPNM.cxx
VTKDataSetReader.cxx
VTKDataSetReaderBase.cxx
VTKDataSetWriter.cxx
VTKPolyDataReader.cxx
VTKRectilinearGridReader.cxx
VTKStructuredGridReader.cxx
VTKStructuredPointsReader.cxx
VTKUnstructuredGridReader.cxx
)
# These files use ArrayCopy which uses a WorkletMapField thus are required to be device_sources
set(device_sources
VTKDataSetReaderBase.cxx
VTKRectilinearGridReader.cxx
)
if (VTKm_ENABLE_HDF5_IO)
set(headers
${headers}

@ -297,9 +297,16 @@ void VTKDataSetReaderBase::ReadCells(vtkm::cont::ArrayHandle<vtkm::Id>& connecti
offsets.CastAndCallForTypes<vtkm::List<vtkm::Int64, vtkm::Int32>,
vtkm::List<vtkm::cont::StorageTagBasic>>(
[&](const auto& offsetsAH) {
vtkm::cont::ArrayCopy(vtkm::cont::make_ArrayHandleOffsetsToNumComponents(
vtkm::cont::make_ArrayHandleCast(offsetsAH, vtkm::Id{})),
numIndices);
// Convert on host. There will be several other passes of this array on the host anyway.
numIndices.Allocate(offsetsSize - 1);
auto offsetPortal = offsetsAH.ReadPortal();
auto numIndicesPortal = numIndices.WritePortal();
for (vtkm::Id cellIndex = 0; cellIndex < offsetsSize - 1; ++cellIndex)
{
numIndicesPortal.Set(cellIndex,
static_cast<vtkm::IdComponent>(offsetPortal.Get(cellIndex + 1) -
offsetPortal.Get(cellIndex)));
}
});
this->DataFile->Stream >> tag >> dataType >> std::ws;

@ -11,7 +11,7 @@
#define vtk_m_worklet_AverageByKey_h
#include <vtkm/VecTraits.h>
#include <vtkm/cont/ArrayCopy.h>
#include <vtkm/cont/ArrayCopyDevice.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/worklet/DescriptiveStatistics.h>
#include <vtkm/worklet/Keys.h>
@ -86,23 +86,13 @@ struct AverageByKey
return outAverages;
}
struct ExtractKey
{
template <typename First, typename Second>
VTKM_EXEC First operator()(const vtkm::Pair<First, Second>& pair) const
{
return pair.first;
}
};
struct ExtractMean
{
template <typename KeyType, typename ValueType>
VTKM_EXEC ValueType operator()(
const vtkm::Pair<KeyType, vtkm::worklet::DescriptiveStatistics::StatState<ValueType>>& pair)
const
template <typename ValueType>
VTKM_EXEC ValueType
operator()(const vtkm::worklet::DescriptiveStatistics::StatState<ValueType>& state) const
{
return pair.second.Mean();
return state.Mean();
}
};
@ -131,13 +121,15 @@ struct AverageByKey
VTKM_LOG_SCOPE(vtkm::cont::LogLevel::Perf, "AverageByKey::Run");
auto results = vtkm::worklet::DescriptiveStatistics::Run(keyArray, valueArray);
// Copy/TransformCopy from results to outputKeyArray and outputValueArray
auto results_key = vtkm::cont::make_ArrayHandleTransform(results, ExtractKey{});
auto results_mean = vtkm::cont::make_ArrayHandleTransform(results, ExtractMean{});
vtkm::cont::ArrayCopy(results_key, outputKeyArray);
vtkm::cont::ArrayCopy(results_mean, outputValueArray);
// Extract results to outputKeyArray and outputValueArray
outputKeyArray = results.GetFirstArray();
// TODO: DescriptiveStatistics should write its output to a SOA instead of an AOS.
// An ArrayHandle of a weird struct by itself is not useful in any general algorithm.
// In fact, using DescriptiveStatistics at all seems like way overkill. It computes
// all sorts of statistics, and we then throw them all away except for mean.
auto resultsMean =
vtkm::cont::make_ArrayHandleTransform(results.GetSecondArray(), ExtractMean{});
vtkm::cont::ArrayCopyDevice(resultsMean, outputValueArray);
}
};
}

@ -20,13 +20,11 @@ set(headers
ContourTreeUniformAugmented.h
CoordinateSystemTransform.h
CosmoTools.h
CrossProduct.h
DispatcherMapField.h
DispatcherMapTopology.h
DispatcherCellNeighborhood.h
DispatcherPointNeighborhood.h
DispatcherReduceByKey.h
DotProduct.h
FieldStatistics.h
Gradient.h
ImageDifference.h

@ -1,38 +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_worklet_CrossProduct_h
#define vtk_m_worklet_CrossProduct_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/VectorAnalysis.h>
namespace vtkm
{
namespace worklet
{
class CrossProduct : public vtkm::worklet::WorkletMapField
{
public:
using ControlSignature = void(FieldIn, FieldIn, FieldOut);
template <typename T>
VTKM_EXEC void operator()(const vtkm::Vec<T, 3>& vec1,
const vtkm::Vec<T, 3>& vec2,
vtkm::Vec<T, 3>& outVec) const
{
outVec = vtkm::Cross(vec1, vec2);
}
};
}
} // namespace vtkm::worklet
#endif // vtk_m_worklet_CrossProduct_h

@ -1,45 +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_worklet_DotProduct_h
#define vtk_m_worklet_DotProduct_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/Math.h>
#include <vtkm/VectorAnalysis.h>
namespace vtkm
{
namespace worklet
{
class DotProduct : public vtkm::worklet::WorkletMapField
{
public:
using ControlSignature = void(FieldIn, FieldIn, FieldOut);
template <typename T, vtkm::IdComponent Size>
VTKM_EXEC void operator()(const vtkm::Vec<T, Size>& v1,
const vtkm::Vec<T, Size>& v2,
T& outValue) const
{
outValue = static_cast<T>(vtkm::Dot(v1, v2));
}
template <typename T>
VTKM_EXEC void operator()(T s1, T s2, T& outValue) const
{
outValue = static_cast<T>(s1 * s2);
}
};
}
} // namespace vtkm::worklet
#endif // vtk_m_worklet_Normalize_h

@ -56,7 +56,7 @@
// global libraries
#include <vtkm/cont/Algorithm.h>
#include <vtkm/cont/ArrayCopy.h>
#include <vtkm/cont/ArrayCopyDevice.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ArrayHandlePermutation.h>
#include <vtkm/cont/ArrayHandleTransform.h>
@ -106,7 +106,7 @@ inline void PermuteArray(const ArrayType& input, IdArrayType& permute, ArrayType
// fancy vtkm array so that we do not actually copy any data here
permute_type permutedInput(maskedPermuteIndex, input);
// Finally, copy the permuted values to the output array
vtkm::cont::ArrayCopy(permutedInput, output);
vtkm::cont::ArrayCopyDevice(permutedInput, output);
} // permuteValues()

@ -225,7 +225,7 @@ public:
vtkm::cont::ArrayHandle<vtkm::Id> cellIndex;
vtkm::Id connectivityLen = vtkm::cont::Algorithm::ScanExclusive(numPoints, cellIndex);
vtkm::cont::ArrayHandleCounting<vtkm::Id> connCount(0, 1, connectivityLen);
vtkm::cont::ArrayHandleIndex connCount(connectivityLen);
vtkm::cont::ArrayHandle<vtkm::Id> connectivity;
vtkm::cont::ArrayCopy(connCount, connectivity);

@ -27,9 +27,7 @@ set(unit_tests
UnitTestContourTreeUniformDistributed.cxx
UnitTestCoordinateSystemTransform.cxx
UnitTestCosmoTools.cxx
UnitTestCrossProduct.cxx
UnitTestDescriptiveStatistics.cxx
UnitTestDotProduct.cxx
UnitTestFieldStatistics.cxx
UnitTestKeys.cxx
UnitTestMagnitude.cxx

@ -70,7 +70,8 @@ void TryKeyType(KeyType)
VTKM_TEST_ASSERT(keys.GetInputRange() == NUM_UNIQUE, "Keys has bad input range.");
// Create values array
vtkm::cont::ArrayHandleCounting<vtkm::FloatDefault> valuesArray(0.0f, 1.0f, ARRAY_SIZE);
vtkm::cont::ArrayHandle<vtkm::FloatDefault> valuesArray;
vtkm::cont::ArrayCopy(vtkm::cont::ArrayHandleIndex(ARRAY_SIZE), valuesArray);
std::cout << " Try average with Keys object" << std::endl;
CheckAverageByKey(keys.GetUniqueKeys(), vtkm::worklet::AverageByKey::Run(keys, valuesArray));

@ -152,8 +152,7 @@ inline vtkm::cont::DataSet MakeRadiantDataSet::Make3DRadiantDataSet(vtkm::IdComp
DataArrayHandle distanceToOther(coordinates, EuclideanNorm(CoordType(1., 1., 1.)));
vtkm::cont::ArrayHandle<vtkm::FloatDefault> cellFieldArray;
vtkm::cont::ArrayCopy(vtkm::cont::make_ArrayHandleCounting<vtkm::Id>(0, 1, nCells),
cellFieldArray);
vtkm::cont::ArrayCopy(vtkm::cont::make_ArrayHandleIndex(nCells), cellFieldArray);
ConnectivityArrayHandle connectivity(
vtkm::cont::ArrayHandleCounting<vtkm::Id>(0, 1, nCells * HexTraits::NUM_POINTS),

@ -1,118 +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.
//============================================================================
#include <vtkm/worklet/CrossProduct.h>
#include <vtkm/worklet/DispatcherMapField.h>
#include <random>
#include <vtkm/cont/testing/Testing.h>
namespace
{
std::mt19937 randGenerator;
template <typename T>
void createVectors(std::vector<vtkm::Vec<T, 3>>& vecs1, std::vector<vtkm::Vec<T, 3>>& vecs2)
{
// First, test the standard directions.
// X x Y
vecs1.push_back(vtkm::make_Vec(1, 0, 0));
vecs2.push_back(vtkm::make_Vec(0, 1, 0));
// Y x Z
vecs1.push_back(vtkm::make_Vec(0, 1, 0));
vecs2.push_back(vtkm::make_Vec(0, 0, 1));
// Z x X
vecs1.push_back(vtkm::make_Vec(0, 0, 1));
vecs2.push_back(vtkm::make_Vec(1, 0, 0));
// Y x X
vecs1.push_back(vtkm::make_Vec(0, 1, 0));
vecs2.push_back(vtkm::make_Vec(1, 0, 0));
// Z x Y
vecs1.push_back(vtkm::make_Vec(0, 0, 1));
vecs2.push_back(vtkm::make_Vec(0, 1, 0));
// X x Z
vecs1.push_back(vtkm::make_Vec(1, 0, 0));
vecs2.push_back(vtkm::make_Vec(0, 0, 1));
//Test some other vector combinations
std::uniform_real_distribution<vtkm::Float64> randomDist(-10.0, 10.0);
for (int i = 0; i < 100; i++)
{
vecs1.push_back(vtkm::make_Vec(
randomDist(randGenerator), randomDist(randGenerator), randomDist(randGenerator)));
vecs2.push_back(vtkm::make_Vec(
randomDist(randGenerator), randomDist(randGenerator), randomDist(randGenerator)));
}
}
template <typename T>
void TestCrossProduct()
{
std::vector<vtkm::Vec<T, 3>> inputVecs1, inputVecs2;
createVectors(inputVecs1, inputVecs2);
vtkm::cont::ArrayHandle<vtkm::Vec<T, 3>> inputArray1, inputArray2;
vtkm::cont::ArrayHandle<vtkm::Vec<T, 3>> outputArray;
inputArray1 = vtkm::cont::make_ArrayHandle(inputVecs1, vtkm::CopyFlag::Off);
inputArray2 = vtkm::cont::make_ArrayHandle(inputVecs2, vtkm::CopyFlag::Off);
vtkm::worklet::CrossProduct crossProductWorklet;
vtkm::worklet::DispatcherMapField<vtkm::worklet::CrossProduct> dispatcherCrossProduct(
crossProductWorklet);
dispatcherCrossProduct.Invoke(inputArray1, inputArray2, outputArray);
VTKM_TEST_ASSERT(outputArray.GetNumberOfValues() == inputArray1.GetNumberOfValues(),
"Wrong number of results for CrossProduct worklet");
//Test the canonical cases.
VTKM_TEST_ASSERT(test_equal(outputArray.ReadPortal().Get(0), vtkm::make_Vec(0, 0, 1)) &&
test_equal(outputArray.ReadPortal().Get(1), vtkm::make_Vec(1, 0, 0)) &&
test_equal(outputArray.ReadPortal().Get(2), vtkm::make_Vec(0, 1, 0)) &&
test_equal(outputArray.ReadPortal().Get(3), vtkm::make_Vec(0, 0, -1)) &&
test_equal(outputArray.ReadPortal().Get(4), vtkm::make_Vec(-1, 0, 0)) &&
test_equal(outputArray.ReadPortal().Get(5), vtkm::make_Vec(0, -1, 0)),
"Wrong result for CrossProduct worklet");
for (vtkm::Id i = 0; i < inputArray1.GetNumberOfValues(); i++)
{
vtkm::Vec<T, 3> v1 = inputArray1.ReadPortal().Get(i);
vtkm::Vec<T, 3> v2 = inputArray2.ReadPortal().Get(i);
vtkm::Vec<T, 3> res = outputArray.ReadPortal().Get(i);
//Make sure result is orthogonal each input vector. Need to normalize to compare with zero.
vtkm::Vec<T, 3> v1N(vtkm::Normal(v1)), v2N(vtkm::Normal(v1)), resN(vtkm::Normal(res));
VTKM_TEST_ASSERT(test_equal(vtkm::Dot(resN, v1N), T(0.0)), "Wrong result for cross product");
VTKM_TEST_ASSERT(test_equal(vtkm::Dot(resN, v2N), T(0.0)), "Wrong result for cross product");
T sinAngle = vtkm::Magnitude(res) * vtkm::RMagnitude(v1) * vtkm::RMagnitude(v2);
T cosAngle = vtkm::Dot(v1, v2) * vtkm::RMagnitude(v1) * vtkm::RMagnitude(v2);
VTKM_TEST_ASSERT(test_equal(sinAngle * sinAngle + cosAngle * cosAngle, T(1.0)),
"Bad cross product length.");
}
}
void TestCrossProductWorklets()
{
std::cout << "Testing CrossProduct Worklet" << std::endl;
TestCrossProduct<vtkm::Float32>();
TestCrossProduct<vtkm::Float64>();
}
}
int UnitTestCrossProduct(int argc, char* argv[])
{
return vtkm::cont::testing::Testing::Run(TestCrossProductWorklets, argc, argv);
}

@ -1,105 +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.
//============================================================================
#include <vtkm/worklet/DispatcherMapField.h>
#include <vtkm/worklet/DotProduct.h>
#include <vtkm/cont/testing/Testing.h>
namespace
{
template <typename T>
T normalizedVector(T v)
{
T vN = vtkm::Normal(v);
return vN;
}
template <typename T>
void createVectors(std::vector<vtkm::Vec<T, 3>>& vecs1,
std::vector<vtkm::Vec<T, 3>>& vecs2,
std::vector<T>& result)
{
vecs1.push_back(normalizedVector(vtkm::make_Vec(T(1), T(0), T(0))));
vecs2.push_back(normalizedVector(vtkm::make_Vec(T(1), T(0), T(0))));
result.push_back(1);
vecs1.push_back(normalizedVector(vtkm::make_Vec(T(1), T(0), T(0))));
vecs2.push_back(normalizedVector(vtkm::make_Vec(T(-1), T(0), T(0))));
result.push_back(-1);
vecs1.push_back(normalizedVector(vtkm::make_Vec(T(1), T(0), T(0))));
vecs2.push_back(normalizedVector(vtkm::make_Vec(T(0), T(1), T(0))));
result.push_back(0);
vecs1.push_back(normalizedVector(vtkm::make_Vec(T(1), T(0), T(0))));
vecs2.push_back(normalizedVector(vtkm::make_Vec(T(0), T(-1), T(0))));
result.push_back(0);
vecs1.push_back(normalizedVector(vtkm::make_Vec(T(1), T(0), T(0))));
vecs2.push_back(normalizedVector(vtkm::make_Vec(T(1), T(1), T(0))));
result.push_back(T(1.0 / vtkm::Sqrt(2.0)));
vecs1.push_back(normalizedVector(vtkm::make_Vec(T(1), T(1), T(0))));
vecs2.push_back(normalizedVector(vtkm::make_Vec(T(1), T(0), T(0))));
result.push_back(T(1.0 / vtkm::Sqrt(2.0)));
vecs1.push_back(normalizedVector(vtkm::make_Vec(T(-1), T(0), T(0))));
vecs2.push_back(normalizedVector(vtkm::make_Vec(T(1), T(1), T(0))));
result.push_back(-T(1.0 / vtkm::Sqrt(2.0)));
vecs1.push_back(normalizedVector(vtkm::make_Vec(T(0), T(1), T(0))));
vecs2.push_back(normalizedVector(vtkm::make_Vec(T(1), T(1), T(0))));
result.push_back(T(1.0 / vtkm::Sqrt(2.0)));
}
template <typename T>
void TestDotProduct()
{
std::vector<vtkm::Vec<T, 3>> inputVecs1, inputVecs2;
std::vector<T> answer;
createVectors(inputVecs1, inputVecs2, answer);
vtkm::cont::ArrayHandle<vtkm::Vec<T, 3>> inputArray1, inputArray2;
vtkm::cont::ArrayHandle<T> outputArray;
inputArray1 = vtkm::cont::make_ArrayHandle(inputVecs1, vtkm::CopyFlag::Off);
inputArray2 = vtkm::cont::make_ArrayHandle(inputVecs2, vtkm::CopyFlag::Off);
vtkm::worklet::DotProduct dotProductWorklet;
vtkm::worklet::DispatcherMapField<vtkm::worklet::DotProduct> dispatcherDotProduct(
dotProductWorklet);
dispatcherDotProduct.Invoke(inputArray1, inputArray2, outputArray);
VTKM_TEST_ASSERT(outputArray.GetNumberOfValues() == inputArray1.GetNumberOfValues(),
"Wrong number of results for DotProduct worklet");
for (vtkm::Id i = 0; i < inputArray1.GetNumberOfValues(); i++)
{
vtkm::Vec<T, 3> v1 = inputArray1.ReadPortal().Get(i);
vtkm::Vec<T, 3> v2 = inputArray2.ReadPortal().Get(i);
T ans = answer[static_cast<std::size_t>(i)];
VTKM_TEST_ASSERT(test_equal(ans, vtkm::Dot(v1, v2)), "Wrong result for dot product");
}
}
void TestDotProductWorklets()
{
std::cout << "Testing DotProduct Worklet" << std::endl;
TestDotProduct<vtkm::Float32>();
// TestDotProduct<vtkm::Float64>();
}
}
int UnitTestDotProduct(int argc, char* argv[])
{
return vtkm::cont::testing::Testing::Run(TestDotProductWorklets, argc, argv);
}