2014-02-11 17:34:56 +00:00
|
|
|
//============================================================================
|
|
|
|
// Copyright (c) Kitware, Inc.
|
|
|
|
// All rights reserved.
|
|
|
|
// See LICENSE.txt for details.
|
2019-04-15 23:24:21 +00:00
|
|
|
//
|
2014-02-11 17:34:56 +00:00
|
|
|
// 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.
|
|
|
|
//============================================================================
|
2016-09-15 23:46:09 +00:00
|
|
|
|
2014-03-07 15:19:09 +00:00
|
|
|
#ifndef vtk_m_cont_internal_DeviceAdapterAlgorithmGeneral_h
|
|
|
|
#define vtk_m_cont_internal_DeviceAdapterAlgorithmGeneral_h
|
2014-02-11 17:34:56 +00:00
|
|
|
|
|
|
|
#include <vtkm/cont/ArrayHandle.h>
|
2017-08-24 14:22:35 +00:00
|
|
|
#include <vtkm/cont/ArrayHandleDiscard.h>
|
2015-04-28 13:31:50 +00:00
|
|
|
#include <vtkm/cont/ArrayHandleImplicit.h>
|
2015-09-15 04:11:09 +00:00
|
|
|
#include <vtkm/cont/ArrayHandleIndex.h>
|
2019-09-03 15:53:14 +00:00
|
|
|
#include <vtkm/cont/ArrayHandleView.h>
|
2015-04-23 17:25:37 +00:00
|
|
|
#include <vtkm/cont/ArrayHandleZip.h>
|
2019-03-05 21:47:09 +00:00
|
|
|
#include <vtkm/cont/BitField.h>
|
2018-08-30 17:29:36 +00:00
|
|
|
#include <vtkm/cont/Logging.h>
|
2015-07-16 19:40:22 +00:00
|
|
|
#include <vtkm/cont/internal/FunctorsGeneral.h>
|
2014-06-10 17:35:13 +00:00
|
|
|
|
2014-02-11 17:34:56 +00:00
|
|
|
#include <vtkm/exec/internal/ErrorMessageBuffer.h>
|
2016-09-12 14:30:03 +00:00
|
|
|
#include <vtkm/exec/internal/TaskSingular.h>
|
2014-02-11 17:34:56 +00:00
|
|
|
|
2017-10-24 22:53:09 +00:00
|
|
|
#include <vtkm/BinaryPredicates.h>
|
2017-03-09 00:05:28 +00:00
|
|
|
#include <vtkm/TypeTraits.h>
|
|
|
|
|
2016-11-23 21:14:56 +00:00
|
|
|
#include <vtkm/internal/Windows.h>
|
2016-03-14 13:51:17 +00:00
|
|
|
|
2017-08-24 14:22:35 +00:00
|
|
|
#include <type_traits>
|
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
namespace vtkm
|
|
|
|
{
|
|
|
|
namespace cont
|
|
|
|
{
|
|
|
|
namespace internal
|
|
|
|
{
|
2014-02-11 17:34:56 +00:00
|
|
|
|
2020-01-22 23:54:00 +00:00
|
|
|
/// \brief General implementations of device adapter algorithms.
|
2014-02-11 17:34:56 +00:00
|
|
|
///
|
|
|
|
/// This struct provides algorithms that implement "general" device adapter
|
|
|
|
/// algorithms. If a device adapter provides implementations for Schedule,
|
|
|
|
/// and Synchronize, the rest of the algorithms can be implemented by calling
|
|
|
|
/// these functions.
|
|
|
|
///
|
|
|
|
/// It should be noted that we recommend that you also implement Sort,
|
|
|
|
/// ScanInclusive, and ScanExclusive for improved performance.
|
|
|
|
///
|
|
|
|
/// An easy way to implement the DeviceAdapterAlgorithm specialization is to
|
|
|
|
/// subclass this and override the implementation of methods as necessary.
|
|
|
|
/// As an example, the code would look something like this.
|
|
|
|
///
|
|
|
|
/// \code{.cpp}
|
|
|
|
/// template<>
|
|
|
|
/// struct DeviceAdapterAlgorithm<DeviceAdapterTagFoo>
|
|
|
|
/// : DeviceAdapterAlgorithmGeneral<DeviceAdapterAlgorithm<DeviceAdapterTagFoo>,
|
|
|
|
/// DeviceAdapterTagFoo>
|
|
|
|
/// {
|
|
|
|
/// template<class Functor>
|
2016-10-19 22:42:58 +00:00
|
|
|
/// VTKM_CONT static void Schedule(Functor functor,
|
2014-02-11 17:34:56 +00:00
|
|
|
/// vtkm::Id numInstances)
|
|
|
|
/// {
|
|
|
|
/// ...
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// template<class Functor>
|
2016-10-19 22:42:58 +00:00
|
|
|
/// VTKM_CONT static void Schedule(Functor functor,
|
2014-02-11 17:34:56 +00:00
|
|
|
/// vtkm::Id3 maxRange)
|
|
|
|
/// {
|
|
|
|
/// ...
|
|
|
|
/// }
|
|
|
|
///
|
2016-10-19 22:42:58 +00:00
|
|
|
/// VTKM_CONT static void Synchronize()
|
2014-02-11 17:34:56 +00:00
|
|
|
/// {
|
|
|
|
/// ...
|
|
|
|
/// }
|
|
|
|
/// };
|
|
|
|
/// \endcode
|
|
|
|
///
|
|
|
|
/// You might note that DeviceAdapterAlgorithmGeneral has two template
|
|
|
|
/// parameters that are redundant. Although the first parameter, the class for
|
|
|
|
/// the actual DeviceAdapterAlgorithm class containing Schedule, and
|
|
|
|
/// Synchronize is the same as DeviceAdapterAlgorithm<DeviceAdapterTag>, it is
|
|
|
|
/// made a separate template parameter to avoid a recursive dependence between
|
|
|
|
/// DeviceAdapterAlgorithmGeneral.h and DeviceAdapterAlgorithm.h
|
|
|
|
///
|
2017-05-18 14:29:41 +00:00
|
|
|
template <class DerivedAlgorithm, class DeviceAdapterTag>
|
2014-02-11 17:34:56 +00:00
|
|
|
struct DeviceAdapterAlgorithmGeneral
|
|
|
|
{
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
// Get Execution Value
|
|
|
|
// This method is used internally to get a single element from the execution
|
2020-01-22 23:54:00 +00:00
|
|
|
// array. Normally you would just use ArrayGetValue, but that functionality
|
|
|
|
// relies on the device adapter algorithm and would create a circular
|
|
|
|
// dependency.
|
2014-02-11 17:34:56 +00:00
|
|
|
private:
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename T, class CIn>
|
|
|
|
VTKM_CONT static T GetExecutionValue(const vtkm::cont::ArrayHandle<T, CIn>& input, vtkm::Id index)
|
2014-02-11 17:34:56 +00:00
|
|
|
{
|
2020-01-22 23:54:00 +00:00
|
|
|
vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagBasic> output;
|
2014-02-11 17:34:56 +00:00
|
|
|
|
2020-01-22 23:54:00 +00:00
|
|
|
{
|
|
|
|
vtkm::cont::Token token;
|
2020-01-21 20:18:03 +00:00
|
|
|
|
2020-01-22 23:54:00 +00:00
|
|
|
auto inputPortal = input.PrepareForInput(DeviceAdapterTag(), token);
|
|
|
|
auto outputPortal = output.PrepareForOutput(1, DeviceAdapterTag(), token);
|
2014-02-11 17:34:56 +00:00
|
|
|
|
2020-01-22 23:54:00 +00:00
|
|
|
CopyKernel<decltype(inputPortal), decltype(outputPortal)> kernel(
|
|
|
|
inputPortal, outputPortal, index);
|
2014-02-11 17:34:56 +00:00
|
|
|
|
2020-01-22 23:54:00 +00:00
|
|
|
DerivedAlgorithm::Schedule(kernel, 1);
|
|
|
|
}
|
2014-02-11 17:34:56 +00:00
|
|
|
|
2020-01-28 19:14:32 +00:00
|
|
|
return output.ReadPortal().Get(0);
|
2014-02-11 17:34:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
2019-03-05 21:47:09 +00:00
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
// BitFieldToUnorderedSet
|
|
|
|
template <typename IndicesStorage>
|
|
|
|
VTKM_CONT static vtkm::Id BitFieldToUnorderedSet(
|
|
|
|
const vtkm::cont::BitField& bits,
|
|
|
|
vtkm::cont::ArrayHandle<Id, IndicesStorage>& indices)
|
|
|
|
{
|
|
|
|
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
|
|
|
|
|
|
|
vtkm::Id numBits = bits.GetNumberOfBits();
|
|
|
|
|
2020-01-21 20:18:03 +00:00
|
|
|
vtkm::cont::Token token;
|
|
|
|
|
|
|
|
auto bitsPortal = bits.PrepareForInput(DeviceAdapterTag{}, token);
|
|
|
|
auto indicesPortal = indices.PrepareForOutput(numBits, DeviceAdapterTag{}, token);
|
2019-03-05 21:47:09 +00:00
|
|
|
|
|
|
|
std::atomic<vtkm::UInt64> popCount;
|
|
|
|
popCount.store(0, std::memory_order_seq_cst);
|
|
|
|
|
|
|
|
using Functor = BitFieldToUnorderedSetFunctor<decltype(bitsPortal), decltype(indicesPortal)>;
|
|
|
|
Functor functor{ bitsPortal, indicesPortal, popCount };
|
|
|
|
|
|
|
|
DerivedAlgorithm::Schedule(functor, functor.GetNumberOfInstances());
|
|
|
|
DerivedAlgorithm::Synchronize();
|
|
|
|
|
2020-01-21 20:18:03 +00:00
|
|
|
token.DetachFromAll();
|
|
|
|
|
2019-03-05 21:47:09 +00:00
|
|
|
numBits = static_cast<vtkm::Id>(popCount.load(std::memory_order_seq_cst));
|
|
|
|
|
|
|
|
indices.Shrink(numBits);
|
|
|
|
return numBits;
|
|
|
|
}
|
|
|
|
|
2015-07-16 19:40:22 +00:00
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
// Copy
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename T, typename U, class CIn, class COut>
|
|
|
|
VTKM_CONT static void Copy(const vtkm::cont::ArrayHandle<T, CIn>& input,
|
|
|
|
vtkm::cont::ArrayHandle<U, COut>& output)
|
2014-02-11 17:34:56 +00:00
|
|
|
{
|
2018-08-30 17:29:36 +00:00
|
|
|
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
|
|
|
|
2020-01-21 20:18:03 +00:00
|
|
|
vtkm::cont::Token token;
|
|
|
|
|
2016-08-12 16:39:42 +00:00
|
|
|
const vtkm::Id inSize = input.GetNumberOfValues();
|
2020-01-21 20:18:03 +00:00
|
|
|
auto inputPortal = input.PrepareForInput(DeviceAdapterTag(), token);
|
|
|
|
auto outputPortal = output.PrepareForOutput(inSize, DeviceAdapterTag(), token);
|
2016-08-12 16:39:42 +00:00
|
|
|
|
2017-08-10 20:13:55 +00:00
|
|
|
CopyKernel<decltype(inputPortal), decltype(outputPortal)> kernel(inputPortal, outputPortal);
|
2016-08-12 16:39:42 +00:00
|
|
|
DerivedAlgorithm::Schedule(kernel, inSize);
|
|
|
|
}
|
2014-02-11 17:34:56 +00:00
|
|
|
|
2017-03-03 22:17:43 +00:00
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
// CopyIf
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename T, typename U, class CIn, class CStencil, class COut, class UnaryPredicate>
|
|
|
|
VTKM_CONT static void CopyIf(const vtkm::cont::ArrayHandle<T, CIn>& input,
|
|
|
|
const vtkm::cont::ArrayHandle<U, CStencil>& stencil,
|
|
|
|
vtkm::cont::ArrayHandle<T, COut>& output,
|
|
|
|
UnaryPredicate unary_predicate)
|
2017-03-03 22:17:43 +00:00
|
|
|
{
|
2018-08-30 17:29:36 +00:00
|
|
|
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
|
|
|
|
2017-03-03 22:17:43 +00:00
|
|
|
VTKM_ASSERT(input.GetNumberOfValues() == stencil.GetNumberOfValues());
|
|
|
|
vtkm::Id arrayLength = stencil.GetNumberOfValues();
|
|
|
|
|
2017-08-10 19:26:05 +00:00
|
|
|
using IndexArrayType = vtkm::cont::ArrayHandle<vtkm::Id, vtkm::cont::StorageTagBasic>;
|
2017-03-03 22:17:43 +00:00
|
|
|
IndexArrayType indices;
|
|
|
|
|
2020-01-21 20:18:03 +00:00
|
|
|
{
|
|
|
|
vtkm::cont::Token token;
|
2017-03-03 22:17:43 +00:00
|
|
|
|
2020-01-21 20:18:03 +00:00
|
|
|
auto stencilPortal = stencil.PrepareForInput(DeviceAdapterTag(), token);
|
|
|
|
auto indexPortal = indices.PrepareForOutput(arrayLength, DeviceAdapterTag(), token);
|
2017-03-03 22:17:43 +00:00
|
|
|
|
2020-01-21 20:18:03 +00:00
|
|
|
StencilToIndexFlagKernel<decltype(stencilPortal), decltype(indexPortal), UnaryPredicate>
|
|
|
|
indexKernel(stencilPortal, indexPortal, unary_predicate);
|
2017-03-03 22:17:43 +00:00
|
|
|
|
2020-01-21 20:18:03 +00:00
|
|
|
DerivedAlgorithm::Schedule(indexKernel, arrayLength);
|
|
|
|
}
|
2017-03-03 22:17:43 +00:00
|
|
|
|
2020-01-21 20:18:03 +00:00
|
|
|
vtkm::Id outArrayLength = DerivedAlgorithm::ScanExclusive(indices, indices);
|
2017-05-18 14:29:41 +00:00
|
|
|
|
2020-01-21 20:18:03 +00:00
|
|
|
{
|
|
|
|
vtkm::cont::Token token;
|
|
|
|
|
|
|
|
auto inputPortal = input.PrepareForInput(DeviceAdapterTag(), token);
|
|
|
|
auto stencilPortal = stencil.PrepareForInput(DeviceAdapterTag(), token);
|
|
|
|
auto indexPortal = indices.PrepareForOutput(arrayLength, DeviceAdapterTag(), token);
|
|
|
|
auto outputPortal = output.PrepareForOutput(outArrayLength, DeviceAdapterTag(), token);
|
|
|
|
|
|
|
|
CopyIfKernel<decltype(inputPortal),
|
|
|
|
decltype(stencilPortal),
|
|
|
|
decltype(indexPortal),
|
|
|
|
decltype(outputPortal),
|
|
|
|
UnaryPredicate>
|
|
|
|
copyKernel(inputPortal, stencilPortal, indexPortal, outputPortal, unary_predicate);
|
|
|
|
DerivedAlgorithm::Schedule(copyKernel, arrayLength);
|
|
|
|
}
|
2017-03-03 22:17:43 +00:00
|
|
|
}
|
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename T, typename U, class CIn, class CStencil, class COut>
|
|
|
|
VTKM_CONT static void CopyIf(const vtkm::cont::ArrayHandle<T, CIn>& input,
|
|
|
|
const vtkm::cont::ArrayHandle<U, CStencil>& stencil,
|
|
|
|
vtkm::cont::ArrayHandle<T, COut>& output)
|
2017-03-03 22:17:43 +00:00
|
|
|
{
|
2018-08-30 17:29:36 +00:00
|
|
|
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
|
|
|
|
2017-03-03 22:17:43 +00:00
|
|
|
::vtkm::NotZeroInitialized unary_predicate;
|
|
|
|
DerivedAlgorithm::CopyIf(input, stencil, output, unary_predicate);
|
|
|
|
}
|
|
|
|
|
2016-08-12 16:39:42 +00:00
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
// CopySubRange
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename T, typename U, class CIn, class COut>
|
|
|
|
VTKM_CONT static bool CopySubRange(const vtkm::cont::ArrayHandle<T, CIn>& input,
|
2017-05-26 17:53:28 +00:00
|
|
|
vtkm::Id inputStartIndex,
|
|
|
|
vtkm::Id numberOfElementsToCopy,
|
2017-05-18 14:29:41 +00:00
|
|
|
vtkm::cont::ArrayHandle<U, COut>& output,
|
|
|
|
vtkm::Id outputIndex = 0)
|
2016-08-12 16:39:42 +00:00
|
|
|
{
|
2018-08-30 17:29:36 +00:00
|
|
|
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
|
|
|
|
2016-08-12 16:39:42 +00:00
|
|
|
const vtkm::Id inSize = input.GetNumberOfValues();
|
2017-10-10 19:30:49 +00:00
|
|
|
|
|
|
|
// Check if the ranges overlap and fail if they do.
|
2020-08-17 14:18:24 +00:00
|
|
|
if (input == output &&
|
|
|
|
((outputIndex >= inputStartIndex &&
|
|
|
|
outputIndex < inputStartIndex + numberOfElementsToCopy) ||
|
|
|
|
(inputStartIndex >= outputIndex &&
|
|
|
|
inputStartIndex < outputIndex + numberOfElementsToCopy)))
|
2017-10-10 19:30:49 +00:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
if (inputStartIndex < 0 || numberOfElementsToCopy < 0 || outputIndex < 0 ||
|
|
|
|
inputStartIndex >= inSize)
|
|
|
|
{ //invalid parameters
|
2016-08-12 16:39:42 +00:00
|
|
|
return false;
|
|
|
|
}
|
2014-02-11 17:34:56 +00:00
|
|
|
|
2016-08-12 16:39:42 +00:00
|
|
|
//determine if the numberOfElementsToCopy needs to be reduced
|
2017-05-18 14:29:41 +00:00
|
|
|
if (inSize < (inputStartIndex + numberOfElementsToCopy))
|
|
|
|
{ //adjust the size
|
2016-08-12 16:39:42 +00:00
|
|
|
numberOfElementsToCopy = (inSize - inputStartIndex);
|
2017-05-18 14:29:41 +00:00
|
|
|
}
|
2016-08-12 16:39:42 +00:00
|
|
|
|
|
|
|
const vtkm::Id outSize = output.GetNumberOfValues();
|
|
|
|
const vtkm::Id copyOutEnd = outputIndex + numberOfElementsToCopy;
|
2017-05-18 14:29:41 +00:00
|
|
|
if (outSize < copyOutEnd)
|
2016-08-12 16:39:42 +00:00
|
|
|
{ //output is not large enough
|
2017-05-18 14:29:41 +00:00
|
|
|
if (outSize == 0)
|
2016-08-12 16:39:42 +00:00
|
|
|
{ //since output has nothing, just need to allocate to correct length
|
|
|
|
output.Allocate(copyOutEnd);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{ //we currently have data in this array, so preserve it in the new
|
|
|
|
//resized array
|
|
|
|
vtkm::cont::ArrayHandle<U, COut> temp;
|
|
|
|
temp.Allocate(copyOutEnd);
|
|
|
|
DerivedAlgorithm::CopySubRange(output, 0, outSize, temp);
|
|
|
|
output = temp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-21 20:18:03 +00:00
|
|
|
vtkm::cont::Token token;
|
|
|
|
|
|
|
|
auto inputPortal = input.PrepareForInput(DeviceAdapterTag(), token);
|
|
|
|
auto outputPortal = output.PrepareForInPlace(DeviceAdapterTag(), token);
|
2017-08-10 20:13:55 +00:00
|
|
|
|
|
|
|
CopyKernel<decltype(inputPortal), decltype(outputPortal)> kernel(
|
|
|
|
inputPortal, outputPortal, inputStartIndex, outputIndex);
|
2016-08-12 16:39:42 +00:00
|
|
|
DerivedAlgorithm::Schedule(kernel, numberOfElementsToCopy);
|
|
|
|
return true;
|
2014-02-11 17:34:56 +00:00
|
|
|
}
|
|
|
|
|
2019-06-13 14:04:28 +00:00
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
// Count Set Bits
|
|
|
|
VTKM_CONT static vtkm::Id CountSetBits(const vtkm::cont::BitField& bits)
|
|
|
|
{
|
|
|
|
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
|
|
|
|
2020-01-21 20:18:03 +00:00
|
|
|
vtkm::cont::Token token;
|
|
|
|
|
|
|
|
auto bitsPortal = bits.PrepareForInput(DeviceAdapterTag{}, token);
|
2019-06-13 14:04:28 +00:00
|
|
|
|
|
|
|
std::atomic<vtkm::UInt64> popCount;
|
|
|
|
popCount.store(0, std::memory_order_relaxed);
|
|
|
|
|
|
|
|
using Functor = CountSetBitsFunctor<decltype(bitsPortal)>;
|
|
|
|
Functor functor{ bitsPortal, popCount };
|
|
|
|
|
|
|
|
DerivedAlgorithm::Schedule(functor, functor.GetNumberOfInstances());
|
|
|
|
DerivedAlgorithm::Synchronize();
|
|
|
|
|
|
|
|
return static_cast<vtkm::Id>(popCount.load(std::memory_order_seq_cst));
|
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
// Fill Bit Field (bool, resize)
|
|
|
|
VTKM_CONT static void Fill(vtkm::cont::BitField& bits, bool value, vtkm::Id numBits)
|
|
|
|
{
|
|
|
|
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
|
|
|
|
|
|
|
if (numBits == 0)
|
|
|
|
{
|
2020-08-24 21:26:57 +00:00
|
|
|
bits.Allocate(0);
|
2019-06-13 14:04:28 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-01-21 20:18:03 +00:00
|
|
|
vtkm::cont::Token token;
|
|
|
|
|
|
|
|
auto portal = bits.PrepareForOutput(numBits, DeviceAdapterTag{}, token);
|
2019-06-13 14:04:28 +00:00
|
|
|
|
|
|
|
using WordType =
|
|
|
|
typename vtkm::cont::BitField::template ExecutionTypes<DeviceAdapterTag>::WordTypePreferred;
|
|
|
|
|
|
|
|
using Functor = FillBitFieldFunctor<decltype(portal), WordType>;
|
|
|
|
Functor functor{ portal, value ? ~WordType{ 0 } : WordType{ 0 } };
|
|
|
|
|
|
|
|
const vtkm::Id numWords = portal.template GetNumberOfWords<WordType>();
|
|
|
|
DerivedAlgorithm::Schedule(functor, numWords);
|
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
// Fill Bit Field (bool)
|
|
|
|
VTKM_CONT static void Fill(vtkm::cont::BitField& bits, bool value)
|
|
|
|
{
|
|
|
|
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
|
|
|
|
|
|
|
const vtkm::Id numBits = bits.GetNumberOfBits();
|
|
|
|
if (numBits == 0)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-01-21 20:18:03 +00:00
|
|
|
vtkm::cont::Token token;
|
|
|
|
|
|
|
|
auto portal = bits.PrepareForOutput(numBits, DeviceAdapterTag{}, token);
|
2019-06-13 14:04:28 +00:00
|
|
|
|
|
|
|
using WordType =
|
|
|
|
typename vtkm::cont::BitField::template ExecutionTypes<DeviceAdapterTag>::WordTypePreferred;
|
|
|
|
|
|
|
|
using Functor = FillBitFieldFunctor<decltype(portal), WordType>;
|
|
|
|
Functor functor{ portal, value ? ~WordType{ 0 } : WordType{ 0 } };
|
|
|
|
|
|
|
|
const vtkm::Id numWords = portal.template GetNumberOfWords<WordType>();
|
|
|
|
DerivedAlgorithm::Schedule(functor, numWords);
|
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
// Fill Bit Field (mask, resize)
|
|
|
|
template <typename WordType>
|
|
|
|
VTKM_CONT static void Fill(vtkm::cont::BitField& bits, WordType word, vtkm::Id numBits)
|
|
|
|
{
|
|
|
|
VTKM_STATIC_ASSERT_MSG(vtkm::cont::BitField::IsValidWordType<WordType>{}, "Invalid word type.");
|
|
|
|
|
|
|
|
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
|
|
|
|
|
|
|
if (numBits == 0)
|
|
|
|
{
|
2020-08-24 21:26:57 +00:00
|
|
|
bits.Allocate(0);
|
2019-06-13 14:04:28 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-01-21 20:18:03 +00:00
|
|
|
vtkm::cont::Token token;
|
|
|
|
|
|
|
|
auto portal = bits.PrepareForOutput(numBits, DeviceAdapterTag{}, token);
|
2019-06-13 14:04:28 +00:00
|
|
|
|
|
|
|
// If less than 32 bits, repeat the word until we get a 32 bit pattern.
|
|
|
|
// Using this for the pattern prevents races while writing small numbers
|
|
|
|
// to adjacent memory locations.
|
|
|
|
auto repWord = RepeatTo32BitsIfNeeded(word);
|
|
|
|
using RepWordType = decltype(repWord);
|
|
|
|
|
|
|
|
using Functor = FillBitFieldFunctor<decltype(portal), RepWordType>;
|
|
|
|
Functor functor{ portal, repWord };
|
|
|
|
|
|
|
|
const vtkm::Id numWords = portal.template GetNumberOfWords<RepWordType>();
|
|
|
|
DerivedAlgorithm::Schedule(functor, numWords);
|
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
// Fill Bit Field (mask)
|
|
|
|
template <typename WordType>
|
|
|
|
VTKM_CONT static void Fill(vtkm::cont::BitField& bits, WordType word)
|
|
|
|
{
|
|
|
|
VTKM_STATIC_ASSERT_MSG(vtkm::cont::BitField::IsValidWordType<WordType>{}, "Invalid word type.");
|
|
|
|
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
|
|
|
|
|
|
|
const vtkm::Id numBits = bits.GetNumberOfBits();
|
|
|
|
if (numBits == 0)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-01-21 20:18:03 +00:00
|
|
|
vtkm::cont::Token token;
|
|
|
|
|
|
|
|
auto portal = bits.PrepareForOutput(numBits, DeviceAdapterTag{}, token);
|
2019-06-13 14:04:28 +00:00
|
|
|
|
|
|
|
// If less than 32 bits, repeat the word until we get a 32 bit pattern.
|
|
|
|
// Using this for the pattern prevents races while writing small numbers
|
|
|
|
// to adjacent memory locations.
|
|
|
|
auto repWord = RepeatTo32BitsIfNeeded(word);
|
|
|
|
using RepWordType = decltype(repWord);
|
|
|
|
|
|
|
|
using Functor = FillBitFieldFunctor<decltype(portal), RepWordType>;
|
|
|
|
Functor functor{ portal, repWord };
|
|
|
|
|
|
|
|
const vtkm::Id numWords = portal.template GetNumberOfWords<RepWordType>();
|
|
|
|
DerivedAlgorithm::Schedule(functor, numWords);
|
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
// Fill ArrayHandle
|
|
|
|
template <typename T, typename S>
|
|
|
|
VTKM_CONT static void Fill(vtkm::cont::ArrayHandle<T, S>& handle, const T& value)
|
|
|
|
{
|
|
|
|
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
|
|
|
|
|
|
|
const vtkm::Id numValues = handle.GetNumberOfValues();
|
|
|
|
if (numValues == 0)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-01-21 20:18:03 +00:00
|
|
|
vtkm::cont::Token token;
|
|
|
|
|
|
|
|
auto portal = handle.PrepareForOutput(numValues, DeviceAdapterTag{}, token);
|
2019-06-13 14:04:28 +00:00
|
|
|
FillArrayHandleFunctor<decltype(portal)> functor{ portal, value };
|
|
|
|
DerivedAlgorithm::Schedule(functor, numValues);
|
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
// Fill ArrayHandle (resize)
|
|
|
|
template <typename T, typename S>
|
|
|
|
VTKM_CONT static void Fill(vtkm::cont::ArrayHandle<T, S>& handle,
|
|
|
|
const T& value,
|
|
|
|
const vtkm::Id numValues)
|
|
|
|
{
|
|
|
|
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
|
|
|
if (numValues == 0)
|
|
|
|
{
|
|
|
|
handle.Shrink(0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-01-21 20:18:03 +00:00
|
|
|
vtkm::cont::Token token;
|
|
|
|
|
|
|
|
auto portal = handle.PrepareForOutput(numValues, DeviceAdapterTag{}, token);
|
2019-06-13 14:04:28 +00:00
|
|
|
FillArrayHandleFunctor<decltype(portal)> functor{ portal, value };
|
|
|
|
DerivedAlgorithm::Schedule(functor, numValues);
|
|
|
|
}
|
|
|
|
|
2014-02-11 17:34:56 +00:00
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
// Lower Bounds
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename T, class CIn, class CVal, class COut>
|
|
|
|
VTKM_CONT static void LowerBounds(const vtkm::cont::ArrayHandle<T, CIn>& input,
|
|
|
|
const vtkm::cont::ArrayHandle<T, CVal>& values,
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::Id, COut>& output)
|
2014-02-11 17:34:56 +00:00
|
|
|
{
|
2018-08-30 17:29:36 +00:00
|
|
|
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
|
|
|
|
2014-02-11 17:34:56 +00:00
|
|
|
vtkm::Id arraySize = values.GetNumberOfValues();
|
|
|
|
|
2020-01-21 20:18:03 +00:00
|
|
|
vtkm::cont::Token token;
|
|
|
|
|
|
|
|
auto inputPortal = input.PrepareForInput(DeviceAdapterTag(), token);
|
|
|
|
auto valuesPortal = values.PrepareForInput(DeviceAdapterTag(), token);
|
|
|
|
auto outputPortal = output.PrepareForOutput(arraySize, DeviceAdapterTag(), token);
|
2017-08-10 20:13:55 +00:00
|
|
|
|
|
|
|
LowerBoundsKernel<decltype(inputPortal), decltype(valuesPortal), decltype(outputPortal)> kernel(
|
|
|
|
inputPortal, valuesPortal, outputPortal);
|
2014-02-11 17:34:56 +00:00
|
|
|
|
|
|
|
DerivedAlgorithm::Schedule(kernel, arraySize);
|
|
|
|
}
|
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename T, class CIn, class CVal, class COut, class BinaryCompare>
|
|
|
|
VTKM_CONT static void LowerBounds(const vtkm::cont::ArrayHandle<T, CIn>& input,
|
|
|
|
const vtkm::cont::ArrayHandle<T, CVal>& values,
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::Id, COut>& output,
|
|
|
|
BinaryCompare binary_compare)
|
2014-02-11 17:34:56 +00:00
|
|
|
{
|
2018-08-30 17:29:36 +00:00
|
|
|
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
|
|
|
|
2014-02-11 17:34:56 +00:00
|
|
|
vtkm::Id arraySize = values.GetNumberOfValues();
|
|
|
|
|
2020-01-21 20:18:03 +00:00
|
|
|
vtkm::cont::Token token;
|
|
|
|
|
|
|
|
auto inputPortal = input.PrepareForInput(DeviceAdapterTag(), token);
|
|
|
|
auto valuesPortal = values.PrepareForInput(DeviceAdapterTag(), token);
|
|
|
|
auto outputPortal = output.PrepareForOutput(arraySize, DeviceAdapterTag(), token);
|
2017-08-10 20:13:55 +00:00
|
|
|
|
|
|
|
LowerBoundsComparisonKernel<decltype(inputPortal),
|
|
|
|
decltype(valuesPortal),
|
|
|
|
decltype(outputPortal),
|
|
|
|
BinaryCompare>
|
|
|
|
kernel(inputPortal, valuesPortal, outputPortal, binary_compare);
|
2014-02-11 17:34:56 +00:00
|
|
|
|
|
|
|
DerivedAlgorithm::Schedule(kernel, arraySize);
|
|
|
|
}
|
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
template <class CIn, class COut>
|
|
|
|
VTKM_CONT static void LowerBounds(const vtkm::cont::ArrayHandle<vtkm::Id, CIn>& input,
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::Id, COut>& values_output)
|
2014-02-11 17:34:56 +00:00
|
|
|
{
|
2018-08-30 17:29:36 +00:00
|
|
|
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
DeviceAdapterAlgorithmGeneral<DerivedAlgorithm, DeviceAdapterTag>::LowerBounds(
|
|
|
|
input, values_output, values_output);
|
2014-02-11 17:34:56 +00:00
|
|
|
}
|
|
|
|
|
2015-04-28 13:31:50 +00:00
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
// Reduce
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename T, typename U, class CIn>
|
|
|
|
VTKM_CONT static U Reduce(const vtkm::cont::ArrayHandle<T, CIn>& input, U initialValue)
|
2015-04-30 13:01:52 +00:00
|
|
|
{
|
2018-08-30 17:29:36 +00:00
|
|
|
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
return DerivedAlgorithm::Reduce(input, initialValue, vtkm::Add());
|
2015-04-30 13:01:52 +00:00
|
|
|
}
|
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename T, typename U, class CIn, class BinaryFunctor>
|
2017-05-26 17:53:28 +00:00
|
|
|
VTKM_CONT static U Reduce(const vtkm::cont::ArrayHandle<T, CIn>& input,
|
|
|
|
U initialValue,
|
2017-05-18 14:29:41 +00:00
|
|
|
BinaryFunctor binary_functor)
|
2015-04-28 13:31:50 +00:00
|
|
|
{
|
2018-08-30 17:29:36 +00:00
|
|
|
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
|
|
|
|
2020-01-21 20:18:03 +00:00
|
|
|
vtkm::cont::Token token;
|
|
|
|
|
2015-04-28 13:31:50 +00:00
|
|
|
//Crazy Idea:
|
|
|
|
//We create a implicit array handle that wraps the input
|
|
|
|
//array handle. The implicit functor is passed the input array handle, and
|
|
|
|
//the number of elements it needs to sum. This way the implicit handle
|
|
|
|
//acts as the first level reduction. Say for example reducing 16 values
|
|
|
|
//at a time.
|
|
|
|
//
|
|
|
|
//Now that we have an implicit array that is 1/16 the length of full array
|
|
|
|
//we can use scan inclusive to compute the final sum
|
2020-01-21 20:18:03 +00:00
|
|
|
auto inputPortal = input.PrepareForInput(DeviceAdapterTag(), token);
|
2017-08-10 20:13:55 +00:00
|
|
|
ReduceKernel<decltype(inputPortal), U, BinaryFunctor> kernel(
|
|
|
|
inputPortal, initialValue, binary_functor);
|
2015-07-16 19:40:22 +00:00
|
|
|
|
2015-04-28 13:31:50 +00:00
|
|
|
vtkm::Id length = (input.GetNumberOfValues() / 16);
|
|
|
|
length += (input.GetNumberOfValues() % 16 == 0) ? 0 : 1;
|
2017-08-10 20:13:55 +00:00
|
|
|
auto reduced = vtkm::cont::make_ArrayHandleImplicit(kernel, length);
|
2015-04-28 13:31:50 +00:00
|
|
|
|
2017-08-10 20:13:55 +00:00
|
|
|
vtkm::cont::ArrayHandle<U, vtkm::cont::StorageTagBasic> inclusiveScanStorage;
|
2017-05-18 14:29:41 +00:00
|
|
|
const U scanResult =
|
|
|
|
DerivedAlgorithm::ScanInclusive(reduced, inclusiveScanStorage, binary_functor);
|
2016-11-22 23:03:27 +00:00
|
|
|
return scanResult;
|
2015-04-28 13:31:50 +00:00
|
|
|
}
|
|
|
|
|
2015-05-04 19:53:35 +00:00
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
// Reduce By Key
|
2017-05-26 17:53:28 +00:00
|
|
|
template <typename T,
|
|
|
|
typename U,
|
|
|
|
class KIn,
|
|
|
|
class VIn,
|
|
|
|
class KOut,
|
|
|
|
class VOut,
|
2017-05-18 14:29:41 +00:00
|
|
|
class BinaryFunctor>
|
|
|
|
VTKM_CONT static void ReduceByKey(const vtkm::cont::ArrayHandle<T, KIn>& keys,
|
|
|
|
const vtkm::cont::ArrayHandle<U, VIn>& values,
|
|
|
|
vtkm::cont::ArrayHandle<T, KOut>& keys_output,
|
|
|
|
vtkm::cont::ArrayHandle<U, VOut>& values_output,
|
|
|
|
BinaryFunctor binary_functor)
|
2015-05-04 19:53:35 +00:00
|
|
|
{
|
2018-08-30 17:29:36 +00:00
|
|
|
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
|
|
|
|
2017-08-24 14:22:35 +00:00
|
|
|
using KeysOutputType = vtkm::cont::ArrayHandle<U, KOut>;
|
|
|
|
|
2016-04-20 21:41:14 +00:00
|
|
|
VTKM_ASSERT(keys.GetNumberOfValues() == values.GetNumberOfValues());
|
2015-05-04 19:53:35 +00:00
|
|
|
const vtkm::Id numberOfKeys = keys.GetNumberOfValues();
|
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
if (numberOfKeys <= 1)
|
|
|
|
{ //we only have a single key/value so that is our output
|
2015-05-04 19:53:35 +00:00
|
|
|
DerivedAlgorithm::Copy(keys, keys_output);
|
|
|
|
DerivedAlgorithm::Copy(values, values_output);
|
|
|
|
return;
|
2017-05-18 14:29:41 +00:00
|
|
|
}
|
2015-05-04 19:53:35 +00:00
|
|
|
|
|
|
|
//we need to determine based on the keys what is the keystate for
|
|
|
|
//each key. The states are start, middle, end of a series and the special
|
|
|
|
//state start and end of a series
|
2017-05-18 14:29:41 +00:00
|
|
|
vtkm::cont::ArrayHandle<ReduceKeySeriesStates> keystate;
|
2015-05-04 19:53:35 +00:00
|
|
|
|
|
|
|
{
|
2020-01-21 20:18:03 +00:00
|
|
|
vtkm::cont::Token token;
|
|
|
|
auto inputPortal = keys.PrepareForInput(DeviceAdapterTag(), token);
|
|
|
|
auto keyStatePortal = keystate.PrepareForOutput(numberOfKeys, DeviceAdapterTag(), token);
|
2017-08-10 20:13:55 +00:00
|
|
|
ReduceStencilGeneration<decltype(inputPortal), decltype(keyStatePortal)> kernel(
|
|
|
|
inputPortal, keyStatePortal);
|
2017-05-18 14:29:41 +00:00
|
|
|
DerivedAlgorithm::Schedule(kernel, numberOfKeys);
|
2015-05-04 19:53:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//next step is we need to reduce the values for each key. This is done
|
|
|
|
//by running an inclusive scan over the values array using the stencil.
|
|
|
|
//
|
|
|
|
// this inclusive scan will write out two values, the first being
|
|
|
|
// the value summed currently, the second being 0 or 1, with 1 being used
|
|
|
|
// when this is a value of a key we need to write ( END or START_AND_END)
|
|
|
|
{
|
2017-08-10 20:13:55 +00:00
|
|
|
vtkm::cont::ArrayHandle<ReduceKeySeriesStates> stencil;
|
2020-04-16 20:18:34 +00:00
|
|
|
vtkm::cont::ArrayHandle<U> reducedValues;
|
2015-05-04 19:53:35 +00:00
|
|
|
|
2017-08-10 20:13:55 +00:00
|
|
|
auto scanInput = vtkm::cont::make_ArrayHandleZip(values, keystate);
|
|
|
|
auto scanOutput = vtkm::cont::make_ArrayHandleZip(reducedValues, stencil);
|
2017-05-18 14:29:41 +00:00
|
|
|
|
2017-05-26 17:53:28 +00:00
|
|
|
DerivedAlgorithm::ScanInclusive(
|
|
|
|
scanInput, scanOutput, ReduceByKeyAdd<BinaryFunctor>(binary_functor));
|
2017-05-18 14:29:41 +00:00
|
|
|
|
|
|
|
//at this point we are done with keystate, so free the memory
|
|
|
|
keystate.ReleaseResources();
|
|
|
|
|
|
|
|
// all we need know is an efficient way of doing the write back to the
|
|
|
|
// reduced global memory. this is done by using CopyIf with the
|
|
|
|
// stencil and values we just created with the inclusive scan
|
|
|
|
DerivedAlgorithm::CopyIf(reducedValues, stencil, values_output, ReduceByKeyUnaryStencilOp());
|
|
|
|
|
|
|
|
} //release all temporary memory
|
2015-05-04 19:53:35 +00:00
|
|
|
|
2017-08-24 14:22:35 +00:00
|
|
|
// Don't bother with the keys_output if it's an ArrayHandleDiscard -- there
|
|
|
|
// will be a runtime exception in Unique() otherwise:
|
2018-02-27 14:25:25 +00:00
|
|
|
if (!vtkm::cont::IsArrayHandleDiscard<KeysOutputType>::value)
|
2017-08-24 14:22:35 +00:00
|
|
|
{
|
|
|
|
//find all the unique keys
|
|
|
|
DerivedAlgorithm::Copy(keys, keys_output);
|
|
|
|
DerivedAlgorithm::Unique(keys_output);
|
|
|
|
}
|
2015-05-04 19:53:35 +00:00
|
|
|
}
|
|
|
|
|
2014-02-11 17:34:56 +00:00
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
// Scan Exclusive
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename T, class CIn, class COut, class BinaryFunctor>
|
|
|
|
VTKM_CONT static T ScanExclusive(const vtkm::cont::ArrayHandle<T, CIn>& input,
|
|
|
|
vtkm::cont::ArrayHandle<T, COut>& output,
|
2017-05-26 17:53:28 +00:00
|
|
|
BinaryFunctor binaryFunctor,
|
|
|
|
const T& initialValue)
|
2014-02-11 17:34:56 +00:00
|
|
|
{
|
2018-08-30 17:29:36 +00:00
|
|
|
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
|
|
|
|
2015-08-27 17:50:32 +00:00
|
|
|
vtkm::Id numValues = input.GetNumberOfValues();
|
|
|
|
if (numValues <= 0)
|
2014-02-11 21:20:30 +00:00
|
|
|
{
|
2019-09-03 15:53:14 +00:00
|
|
|
output.Shrink(0);
|
2015-08-27 17:50:32 +00:00
|
|
|
return initialValue;
|
2014-02-11 21:20:30 +00:00
|
|
|
}
|
2014-02-11 17:34:56 +00:00
|
|
|
|
2017-08-10 20:13:55 +00:00
|
|
|
vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagBasic> inclusiveScan;
|
2015-08-27 17:50:32 +00:00
|
|
|
T result = DerivedAlgorithm::ScanInclusive(input, inclusiveScan, binaryFunctor);
|
2014-02-11 17:34:56 +00:00
|
|
|
|
2020-01-21 20:18:03 +00:00
|
|
|
vtkm::cont::Token token;
|
|
|
|
|
|
|
|
auto inputPortal = inclusiveScan.PrepareForInput(DeviceAdapterTag(), token);
|
|
|
|
auto outputPortal = output.PrepareForOutput(numValues, DeviceAdapterTag(), token);
|
2017-08-10 20:13:55 +00:00
|
|
|
|
|
|
|
InclusiveToExclusiveKernel<decltype(inputPortal), decltype(outputPortal), BinaryFunctor>
|
|
|
|
inclusiveToExclusive(inputPortal, outputPortal, binaryFunctor, initialValue);
|
2015-08-27 17:50:32 +00:00
|
|
|
|
|
|
|
DerivedAlgorithm::Schedule(inclusiveToExclusive, numValues);
|
|
|
|
|
|
|
|
return binaryFunctor(initialValue, result);
|
|
|
|
}
|
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename T, class CIn, class COut>
|
|
|
|
VTKM_CONT static T ScanExclusive(const vtkm::cont::ArrayHandle<T, CIn>& input,
|
|
|
|
vtkm::cont::ArrayHandle<T, COut>& output)
|
2015-08-27 17:50:32 +00:00
|
|
|
{
|
2018-08-30 17:29:36 +00:00
|
|
|
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
|
|
|
|
2017-05-26 17:53:28 +00:00
|
|
|
return DerivedAlgorithm::ScanExclusive(
|
|
|
|
input, output, vtkm::Sum(), vtkm::TypeTraits<T>::ZeroInitialization());
|
2014-02-11 17:34:56 +00:00
|
|
|
}
|
2016-10-23 13:24:28 +00:00
|
|
|
|
2019-09-03 15:53:14 +00:00
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
// Scan Exclusive Extend
|
|
|
|
template <typename T, class CIn, class COut, class BinaryFunctor>
|
|
|
|
VTKM_CONT static void ScanExtended(const vtkm::cont::ArrayHandle<T, CIn>& input,
|
|
|
|
vtkm::cont::ArrayHandle<T, COut>& output,
|
|
|
|
BinaryFunctor binaryFunctor,
|
|
|
|
const T& initialValue)
|
|
|
|
{
|
|
|
|
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
|
|
|
|
|
|
|
vtkm::Id numValues = input.GetNumberOfValues();
|
|
|
|
if (numValues <= 0)
|
|
|
|
{
|
|
|
|
output.Allocate(1);
|
2020-01-28 19:14:32 +00:00
|
|
|
output.WritePortal().Set(0, initialValue);
|
2019-09-03 15:53:14 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagBasic> inclusiveScan;
|
|
|
|
T result = DerivedAlgorithm::ScanInclusive(input, inclusiveScan, binaryFunctor);
|
|
|
|
|
2020-01-21 20:18:03 +00:00
|
|
|
vtkm::cont::Token token;
|
|
|
|
|
|
|
|
auto inputPortal = inclusiveScan.PrepareForInput(DeviceAdapterTag(), token);
|
|
|
|
auto outputPortal = output.PrepareForOutput(numValues + 1, DeviceAdapterTag(), token);
|
2019-09-03 15:53:14 +00:00
|
|
|
|
|
|
|
InclusiveToExtendedKernel<decltype(inputPortal), decltype(outputPortal), BinaryFunctor>
|
|
|
|
inclusiveToExtended(inputPortal,
|
|
|
|
outputPortal,
|
|
|
|
binaryFunctor,
|
|
|
|
initialValue,
|
|
|
|
binaryFunctor(initialValue, result));
|
|
|
|
|
|
|
|
DerivedAlgorithm::Schedule(inclusiveToExtended, numValues + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T, class CIn, class COut>
|
|
|
|
VTKM_CONT static void ScanExtended(const vtkm::cont::ArrayHandle<T, CIn>& input,
|
|
|
|
vtkm::cont::ArrayHandle<T, COut>& output)
|
|
|
|
{
|
|
|
|
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
|
|
|
|
|
|
|
DerivedAlgorithm::ScanExtended(
|
|
|
|
input, output, vtkm::Sum(), vtkm::TypeTraits<T>::ZeroInitialization());
|
|
|
|
}
|
|
|
|
|
2017-04-13 17:50:56 +00:00
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
// Scan Exclusive By Key
|
2017-10-24 22:12:30 +00:00
|
|
|
template <typename KeyT,
|
|
|
|
typename ValueT,
|
|
|
|
typename KIn,
|
|
|
|
typename VIn,
|
|
|
|
typename VOut,
|
|
|
|
class BinaryFunctor>
|
|
|
|
VTKM_CONT static void ScanExclusiveByKey(const vtkm::cont::ArrayHandle<KeyT, KIn>& keys,
|
|
|
|
const vtkm::cont::ArrayHandle<ValueT, VIn>& values,
|
|
|
|
vtkm::cont::ArrayHandle<ValueT, VOut>& output,
|
|
|
|
const ValueT& initialValue,
|
2017-05-26 17:53:28 +00:00
|
|
|
BinaryFunctor binaryFunctor)
|
2017-04-13 17:50:56 +00:00
|
|
|
{
|
2018-08-30 17:29:36 +00:00
|
|
|
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
|
|
|
|
2017-04-18 19:26:15 +00:00
|
|
|
VTKM_ASSERT(keys.GetNumberOfValues() == values.GetNumberOfValues());
|
|
|
|
|
|
|
|
// 0. Special case for 0 and 1 element input
|
2017-04-17 21:03:49 +00:00
|
|
|
vtkm::Id numberOfKeys = keys.GetNumberOfValues();
|
|
|
|
|
2017-04-18 19:26:15 +00:00
|
|
|
if (numberOfKeys == 0)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else if (numberOfKeys == 1)
|
|
|
|
{
|
2020-01-21 20:18:03 +00:00
|
|
|
output.Allocate(1);
|
2020-01-28 19:14:32 +00:00
|
|
|
output.WritePortal().Set(0, initialValue);
|
2017-04-18 19:26:15 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-04-17 21:03:49 +00:00
|
|
|
// 1. Create head flags
|
|
|
|
//we need to determine based on the keys what is the keystate for
|
|
|
|
//each key. The states are start, middle, end of a series and the special
|
|
|
|
//state start and end of a series
|
2017-05-18 14:29:41 +00:00
|
|
|
vtkm::cont::ArrayHandle<ReduceKeySeriesStates> keystate;
|
2017-04-17 21:03:49 +00:00
|
|
|
|
|
|
|
{
|
2020-01-21 20:18:03 +00:00
|
|
|
vtkm::cont::Token token;
|
|
|
|
auto inputPortal = keys.PrepareForInput(DeviceAdapterTag(), token);
|
|
|
|
auto keyStatePortal = keystate.PrepareForOutput(numberOfKeys, DeviceAdapterTag(), token);
|
2017-08-10 20:13:55 +00:00
|
|
|
ReduceStencilGeneration<decltype(inputPortal), decltype(keyStatePortal)> kernel(
|
|
|
|
inputPortal, keyStatePortal);
|
2017-04-17 21:03:49 +00:00
|
|
|
DerivedAlgorithm::Schedule(kernel, numberOfKeys);
|
|
|
|
}
|
|
|
|
|
|
|
|
// 2. Shift input and initialize elements at head flags position to initValue
|
2017-10-24 22:12:30 +00:00
|
|
|
vtkm::cont::ArrayHandle<ValueT, vtkm::cont::StorageTagBasic> temp;
|
2017-04-17 21:03:49 +00:00
|
|
|
{
|
2020-01-21 20:18:03 +00:00
|
|
|
vtkm::cont::Token token;
|
|
|
|
auto inputPortal = values.PrepareForInput(DeviceAdapterTag(), token);
|
|
|
|
auto keyStatePortal = keystate.PrepareForInput(DeviceAdapterTag(), token);
|
|
|
|
auto tempPortal = temp.PrepareForOutput(numberOfKeys, DeviceAdapterTag(), token);
|
2017-04-17 21:03:49 +00:00
|
|
|
|
2017-10-24 22:12:30 +00:00
|
|
|
ShiftCopyAndInit<ValueT,
|
|
|
|
decltype(inputPortal),
|
|
|
|
decltype(keyStatePortal),
|
|
|
|
decltype(tempPortal)>
|
2017-08-10 20:13:55 +00:00
|
|
|
kernel(inputPortal, keyStatePortal, tempPortal, initialValue);
|
2017-04-17 21:03:49 +00:00
|
|
|
DerivedAlgorithm::Schedule(kernel, numberOfKeys);
|
|
|
|
}
|
2017-04-17 22:11:02 +00:00
|
|
|
// 3. Perform a ScanInclusiveByKey
|
2017-04-17 21:03:49 +00:00
|
|
|
DerivedAlgorithm::ScanInclusiveByKey(keys, temp, output, binaryFunctor);
|
2017-04-13 17:50:56 +00:00
|
|
|
}
|
|
|
|
|
2017-10-24 22:12:30 +00:00
|
|
|
template <typename KeyT, typename ValueT, class KIn, typename VIn, typename VOut>
|
|
|
|
VTKM_CONT static void ScanExclusiveByKey(const vtkm::cont::ArrayHandle<KeyT, KIn>& keys,
|
|
|
|
const vtkm::cont::ArrayHandle<ValueT, VIn>& values,
|
|
|
|
vtkm::cont::ArrayHandle<ValueT, VOut>& output)
|
2017-04-13 17:50:56 +00:00
|
|
|
{
|
2018-08-30 17:29:36 +00:00
|
|
|
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
|
|
|
|
2017-05-26 17:53:28 +00:00
|
|
|
DerivedAlgorithm::ScanExclusiveByKey(
|
2017-10-24 22:12:30 +00:00
|
|
|
keys, values, output, vtkm::TypeTraits<ValueT>::ZeroInitialization(), vtkm::Sum());
|
2017-04-13 17:50:56 +00:00
|
|
|
}
|
|
|
|
|
2014-02-11 17:34:56 +00:00
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
// Scan Inclusive
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename T, class CIn, class COut>
|
|
|
|
VTKM_CONT static T ScanInclusive(const vtkm::cont::ArrayHandle<T, CIn>& input,
|
|
|
|
vtkm::cont::ArrayHandle<T, COut>& output)
|
2015-04-29 19:48:25 +00:00
|
|
|
{
|
2018-08-30 17:29:36 +00:00
|
|
|
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
return DerivedAlgorithm::ScanInclusive(input, output, vtkm::Add());
|
2015-04-29 19:48:25 +00:00
|
|
|
}
|
|
|
|
|
2020-06-16 12:54:01 +00:00
|
|
|
private:
|
|
|
|
template <typename T1, typename S1, typename T2, typename S2>
|
|
|
|
VTKM_CONT static bool ArrayHandlesAreSame(const vtkm::cont::ArrayHandle<T1, S1>&,
|
|
|
|
const vtkm::cont::ArrayHandle<T2, S2>&)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T, typename S>
|
|
|
|
VTKM_CONT static bool ArrayHandlesAreSame(const vtkm::cont::ArrayHandle<T, S>& a1,
|
|
|
|
const vtkm::cont::ArrayHandle<T, S>& a2)
|
|
|
|
{
|
|
|
|
return a1 == a2;
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename T, class CIn, class COut, class BinaryFunctor>
|
|
|
|
VTKM_CONT static T ScanInclusive(const vtkm::cont::ArrayHandle<T, CIn>& input,
|
|
|
|
vtkm::cont::ArrayHandle<T, COut>& output,
|
|
|
|
BinaryFunctor binary_functor)
|
2014-02-11 17:34:56 +00:00
|
|
|
{
|
2018-08-30 17:29:36 +00:00
|
|
|
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
|
|
|
|
2020-06-16 12:54:01 +00:00
|
|
|
if (!ArrayHandlesAreSame(input, output))
|
|
|
|
{
|
|
|
|
DerivedAlgorithm::Copy(input, output);
|
|
|
|
}
|
2014-02-11 17:34:56 +00:00
|
|
|
|
|
|
|
vtkm::Id numValues = output.GetNumberOfValues();
|
|
|
|
if (numValues < 1)
|
2017-03-09 00:05:28 +00:00
|
|
|
{
|
|
|
|
return vtkm::TypeTraits<T>::ZeroInitialization();
|
|
|
|
}
|
2014-02-11 17:34:56 +00:00
|
|
|
|
2020-01-22 23:54:00 +00:00
|
|
|
{
|
|
|
|
vtkm::cont::Token token;
|
2020-01-21 20:18:03 +00:00
|
|
|
|
2020-01-22 23:54:00 +00:00
|
|
|
auto portal = output.PrepareForInPlace(DeviceAdapterTag(), token);
|
|
|
|
using ScanKernelType = ScanKernel<decltype(portal), BinaryFunctor>;
|
2017-08-10 20:13:55 +00:00
|
|
|
|
2014-02-11 17:34:56 +00:00
|
|
|
|
2020-01-22 23:54:00 +00:00
|
|
|
vtkm::Id stride;
|
|
|
|
for (stride = 2; stride - 1 < numValues; stride *= 2)
|
|
|
|
{
|
|
|
|
ScanKernelType kernel(portal, binary_functor, stride, stride / 2 - 1);
|
|
|
|
DerivedAlgorithm::Schedule(kernel, numValues / stride);
|
|
|
|
}
|
2014-02-11 17:34:56 +00:00
|
|
|
|
2020-01-22 23:54:00 +00:00
|
|
|
// Do reverse operation on odd indices. Start at stride we were just at.
|
|
|
|
for (stride /= 2; stride > 1; stride /= 2)
|
|
|
|
{
|
|
|
|
ScanKernelType kernel(portal, binary_functor, stride, stride - 1);
|
|
|
|
DerivedAlgorithm::Schedule(kernel, numValues / stride);
|
|
|
|
}
|
2014-02-11 21:20:30 +00:00
|
|
|
}
|
2014-02-11 17:34:56 +00:00
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
return GetExecutionValue(output, numValues - 1);
|
2014-02-11 17:34:56 +00:00
|
|
|
}
|
2016-10-23 13:24:28 +00:00
|
|
|
|
2017-10-24 22:12:30 +00:00
|
|
|
template <typename KeyT, typename ValueT, class KIn, class VIn, class VOut>
|
|
|
|
VTKM_CONT static void ScanInclusiveByKey(const vtkm::cont::ArrayHandle<KeyT, KIn>& keys,
|
|
|
|
const vtkm::cont::ArrayHandle<ValueT, VIn>& values,
|
|
|
|
vtkm::cont::ArrayHandle<ValueT, VOut>& values_output)
|
2017-03-29 15:29:11 +00:00
|
|
|
{
|
2018-08-30 17:29:36 +00:00
|
|
|
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
return DerivedAlgorithm::ScanInclusiveByKey(keys, values, values_output, vtkm::Add());
|
2017-03-29 15:29:11 +00:00
|
|
|
}
|
|
|
|
|
2017-10-24 22:12:30 +00:00
|
|
|
template <typename KeyT, typename ValueT, class KIn, class VIn, class VOut, class BinaryFunctor>
|
|
|
|
VTKM_CONT static void ScanInclusiveByKey(const vtkm::cont::ArrayHandle<KeyT, KIn>& keys,
|
|
|
|
const vtkm::cont::ArrayHandle<ValueT, VIn>& values,
|
|
|
|
vtkm::cont::ArrayHandle<ValueT, VOut>& values_output,
|
2017-05-18 14:29:41 +00:00
|
|
|
BinaryFunctor binary_functor)
|
2017-03-29 15:29:11 +00:00
|
|
|
{
|
2018-08-30 17:29:36 +00:00
|
|
|
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
|
|
|
|
2017-03-29 15:29:11 +00:00
|
|
|
VTKM_ASSERT(keys.GetNumberOfValues() == values.GetNumberOfValues());
|
|
|
|
const vtkm::Id numberOfKeys = keys.GetNumberOfValues();
|
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
if (numberOfKeys <= 1)
|
2017-03-29 15:29:11 +00:00
|
|
|
{ //we only have a single key/value so that is our output
|
|
|
|
DerivedAlgorithm::Copy(values, values_output);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
//we need to determine based on the keys what is the keystate for
|
|
|
|
//each key. The states are start, middle, end of a series and the special
|
|
|
|
//state start and end of a series
|
2017-05-18 14:29:41 +00:00
|
|
|
vtkm::cont::ArrayHandle<ReduceKeySeriesStates> keystate;
|
2017-03-29 15:29:11 +00:00
|
|
|
|
|
|
|
{
|
2020-01-21 20:18:03 +00:00
|
|
|
vtkm::cont::Token token;
|
|
|
|
auto inputPortal = keys.PrepareForInput(DeviceAdapterTag(), token);
|
|
|
|
auto keyStatePortal = keystate.PrepareForOutput(numberOfKeys, DeviceAdapterTag(), token);
|
2017-08-10 20:13:55 +00:00
|
|
|
ReduceStencilGeneration<decltype(inputPortal), decltype(keyStatePortal)> kernel(
|
|
|
|
inputPortal, keyStatePortal);
|
2017-03-29 15:29:11 +00:00
|
|
|
DerivedAlgorithm::Schedule(kernel, numberOfKeys);
|
|
|
|
}
|
|
|
|
|
|
|
|
//next step is we need to reduce the values for each key. This is done
|
|
|
|
//by running an inclusive scan over the values array using the stencil.
|
|
|
|
//
|
|
|
|
// this inclusive scan will write out two values, the first being
|
|
|
|
// the value summed currently, the second being 0 or 1, with 1 being used
|
|
|
|
// when this is a value of a key we need to write ( END or START_AND_END)
|
|
|
|
{
|
2020-04-16 16:37:44 +00:00
|
|
|
vtkm::cont::ArrayHandle<ValueT> reducedValues;
|
2017-08-10 20:13:55 +00:00
|
|
|
vtkm::cont::ArrayHandle<ReduceKeySeriesStates> stencil;
|
|
|
|
auto scanInput = vtkm::cont::make_ArrayHandleZip(values, keystate);
|
|
|
|
auto scanOutput = vtkm::cont::make_ArrayHandleZip(reducedValues, stencil);
|
2017-03-29 15:29:11 +00:00
|
|
|
|
2017-05-26 17:53:28 +00:00
|
|
|
DerivedAlgorithm::ScanInclusive(
|
|
|
|
scanInput, scanOutput, ReduceByKeyAdd<BinaryFunctor>(binary_functor));
|
2017-03-29 15:29:11 +00:00
|
|
|
//at this point we are done with keystate, so free the memory
|
|
|
|
keystate.ReleaseResources();
|
|
|
|
DerivedAlgorithm::Copy(reducedValues, values_output);
|
|
|
|
}
|
|
|
|
}
|
2017-04-13 17:50:56 +00:00
|
|
|
|
2016-09-15 23:46:09 +00:00
|
|
|
//--------------------------------------------------------------------------
|
2014-02-11 17:34:56 +00:00
|
|
|
// Sort
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename T, class Storage, class BinaryCompare>
|
|
|
|
VTKM_CONT static void Sort(vtkm::cont::ArrayHandle<T, Storage>& values,
|
|
|
|
BinaryCompare binary_compare)
|
2014-02-11 17:34:56 +00:00
|
|
|
{
|
2018-08-30 17:29:36 +00:00
|
|
|
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
|
|
|
|
2014-02-11 17:34:56 +00:00
|
|
|
vtkm::Id numValues = values.GetNumberOfValues();
|
2017-05-18 14:29:41 +00:00
|
|
|
if (numValues < 2)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2014-02-11 17:34:56 +00:00
|
|
|
vtkm::Id numThreads = 1;
|
2017-05-18 14:29:41 +00:00
|
|
|
while (numThreads < numValues)
|
|
|
|
{
|
|
|
|
numThreads *= 2;
|
|
|
|
}
|
2014-02-11 17:34:56 +00:00
|
|
|
numThreads /= 2;
|
|
|
|
|
2020-01-21 20:18:03 +00:00
|
|
|
vtkm::cont::Token token;
|
|
|
|
|
|
|
|
auto portal = values.PrepareForInPlace(DeviceAdapterTag(), token);
|
2017-08-10 20:13:55 +00:00
|
|
|
using MergeKernel = BitonicSortMergeKernel<decltype(portal), BinaryCompare>;
|
|
|
|
using CrossoverKernel = BitonicSortCrossoverKernel<decltype(portal), BinaryCompare>;
|
2014-02-11 17:34:56 +00:00
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
for (vtkm::Id crossoverSize = 1; crossoverSize < numValues; crossoverSize *= 2)
|
2014-02-11 21:20:30 +00:00
|
|
|
{
|
2017-05-18 14:29:41 +00:00
|
|
|
DerivedAlgorithm::Schedule(CrossoverKernel(portal, binary_compare, crossoverSize),
|
2014-02-11 17:34:56 +00:00
|
|
|
numThreads);
|
2017-05-18 14:29:41 +00:00
|
|
|
for (vtkm::Id mergeSize = crossoverSize / 2; mergeSize > 0; mergeSize /= 2)
|
2014-02-11 21:20:30 +00:00
|
|
|
{
|
2017-05-18 14:29:41 +00:00
|
|
|
DerivedAlgorithm::Schedule(MergeKernel(portal, binary_compare, mergeSize), numThreads);
|
2014-02-11 17:34:56 +00:00
|
|
|
}
|
2014-02-11 21:20:30 +00:00
|
|
|
}
|
2014-02-11 17:34:56 +00:00
|
|
|
}
|
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename T, class Storage>
|
|
|
|
VTKM_CONT static void Sort(vtkm::cont::ArrayHandle<T, Storage>& values)
|
2014-02-11 17:34:56 +00:00
|
|
|
{
|
2018-08-30 17:29:36 +00:00
|
|
|
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
|
|
|
|
2014-02-11 17:34:56 +00:00
|
|
|
DerivedAlgorithm::Sort(values, DefaultCompareFunctor());
|
2015-04-23 17:25:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
// Sort by Key
|
|
|
|
public:
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename T, typename U, class StorageT, class StorageU>
|
|
|
|
VTKM_CONT static void SortByKey(vtkm::cont::ArrayHandle<T, StorageT>& keys,
|
|
|
|
vtkm::cont::ArrayHandle<U, StorageU>& values)
|
2015-04-23 17:25:37 +00:00
|
|
|
{
|
2018-08-30 17:29:36 +00:00
|
|
|
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
|
|
|
|
2015-04-23 17:25:37 +00:00
|
|
|
//combine the keys and values into a ZipArrayHandle
|
|
|
|
//we than need to specify a custom compare function wrapper
|
|
|
|
//that only checks for key side of the pair, using a custom compare functor.
|
2017-08-10 20:13:55 +00:00
|
|
|
auto zipHandle = vtkm::cont::make_ArrayHandleZip(keys, values);
|
2017-05-18 14:29:41 +00:00
|
|
|
DerivedAlgorithm::Sort(zipHandle, internal::KeyCompare<T, U>());
|
2015-04-23 17:25:37 +00:00
|
|
|
}
|
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename T, typename U, class StorageT, class StorageU, class BinaryCompare>
|
|
|
|
VTKM_CONT static void SortByKey(vtkm::cont::ArrayHandle<T, StorageT>& keys,
|
|
|
|
vtkm::cont::ArrayHandle<U, StorageU>& values,
|
|
|
|
BinaryCompare binary_compare)
|
2015-04-23 17:25:37 +00:00
|
|
|
{
|
2018-08-30 17:29:36 +00:00
|
|
|
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
|
|
|
|
2015-04-23 17:25:37 +00:00
|
|
|
//combine the keys and values into a ZipArrayHandle
|
|
|
|
//we than need to specify a custom compare function wrapper
|
|
|
|
//that only checks for key side of the pair, using the custom compare
|
|
|
|
//functor that the user passed in
|
2017-08-10 20:13:55 +00:00
|
|
|
auto zipHandle = vtkm::cont::make_ArrayHandleZip(keys, values);
|
2017-05-18 14:29:41 +00:00
|
|
|
DerivedAlgorithm::Sort(zipHandle, internal::KeyCompare<T, U, BinaryCompare>(binary_compare));
|
2014-02-11 17:34:56 +00:00
|
|
|
}
|
|
|
|
|
2018-01-16 21:43:31 +00:00
|
|
|
template <typename T,
|
|
|
|
typename U,
|
|
|
|
typename V,
|
|
|
|
typename StorageT,
|
|
|
|
typename StorageU,
|
|
|
|
typename StorageV,
|
|
|
|
typename BinaryFunctor>
|
|
|
|
VTKM_CONT static void Transform(const vtkm::cont::ArrayHandle<T, StorageT>& input1,
|
|
|
|
const vtkm::cont::ArrayHandle<U, StorageU>& input2,
|
|
|
|
vtkm::cont::ArrayHandle<V, StorageV>& output,
|
2017-12-22 17:31:02 +00:00
|
|
|
BinaryFunctor binaryFunctor)
|
|
|
|
{
|
2018-08-30 17:29:36 +00:00
|
|
|
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
|
|
|
|
2017-12-22 17:31:02 +00:00
|
|
|
vtkm::Id numValues = vtkm::Min(input1.GetNumberOfValues(), input2.GetNumberOfValues());
|
|
|
|
if (numValues <= 0)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-01-21 20:18:03 +00:00
|
|
|
vtkm::cont::Token token;
|
|
|
|
|
|
|
|
auto input1Portal = input1.PrepareForInput(DeviceAdapterTag(), token);
|
|
|
|
auto input2Portal = input2.PrepareForInput(DeviceAdapterTag(), token);
|
|
|
|
auto outputPortal = output.PrepareForOutput(numValues, DeviceAdapterTag(), token);
|
2017-12-22 17:31:02 +00:00
|
|
|
|
2018-01-16 21:43:31 +00:00
|
|
|
BinaryTransformKernel<decltype(input1Portal),
|
|
|
|
decltype(input2Portal),
|
|
|
|
decltype(outputPortal),
|
|
|
|
BinaryFunctor>
|
2017-12-22 17:31:02 +00:00
|
|
|
binaryKernel(input1Portal, input2Portal, outputPortal, binaryFunctor);
|
|
|
|
DerivedAlgorithm::Schedule(binaryKernel, numValues);
|
|
|
|
}
|
|
|
|
|
|
|
|
//};
|
2014-02-11 17:34:56 +00:00
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
// Unique
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename T, class Storage>
|
|
|
|
VTKM_CONT static void Unique(vtkm::cont::ArrayHandle<T, Storage>& values)
|
2014-02-11 17:34:56 +00:00
|
|
|
{
|
2018-08-30 17:29:36 +00:00
|
|
|
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
|
|
|
|
2017-10-24 22:53:09 +00:00
|
|
|
DerivedAlgorithm::Unique(values, vtkm::Equal());
|
2014-02-11 17:34:56 +00:00
|
|
|
}
|
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename T, class Storage, class BinaryCompare>
|
|
|
|
VTKM_CONT static void Unique(vtkm::cont::ArrayHandle<T, Storage>& values,
|
|
|
|
BinaryCompare binary_compare)
|
2014-02-11 17:34:56 +00:00
|
|
|
{
|
2018-08-30 17:29:36 +00:00
|
|
|
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
vtkm::cont::ArrayHandle<vtkm::Id, vtkm::cont::StorageTagBasic> stencilArray;
|
2014-02-11 17:34:56 +00:00
|
|
|
vtkm::Id inputSize = values.GetNumberOfValues();
|
|
|
|
|
2017-08-10 19:26:05 +00:00
|
|
|
using WrappedBOpType = internal::WrappedBinaryOperator<bool, BinaryCompare>;
|
2016-03-18 20:39:21 +00:00
|
|
|
WrappedBOpType wrappedCompare(binary_compare);
|
|
|
|
|
2020-01-21 20:18:03 +00:00
|
|
|
{
|
|
|
|
vtkm::cont::Token token;
|
|
|
|
auto valuesPortal = values.PrepareForInput(DeviceAdapterTag(), token);
|
|
|
|
auto stencilPortal = stencilArray.PrepareForOutput(inputSize, DeviceAdapterTag(), token);
|
|
|
|
ClassifyUniqueComparisonKernel<decltype(valuesPortal),
|
|
|
|
decltype(stencilPortal),
|
|
|
|
WrappedBOpType>
|
|
|
|
classifyKernel(valuesPortal, stencilPortal, wrappedCompare);
|
|
|
|
|
|
|
|
DerivedAlgorithm::Schedule(classifyKernel, inputSize);
|
|
|
|
}
|
2014-02-11 17:34:56 +00:00
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagBasic> outputArray;
|
2014-02-11 17:34:56 +00:00
|
|
|
|
2017-03-03 22:17:43 +00:00
|
|
|
DerivedAlgorithm::CopyIf(values, stencilArray, outputArray);
|
2014-02-11 17:34:56 +00:00
|
|
|
|
2016-08-12 16:39:42 +00:00
|
|
|
values.Allocate(outputArray.GetNumberOfValues());
|
2014-02-11 17:34:56 +00:00
|
|
|
DerivedAlgorithm::Copy(outputArray, values);
|
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
// Upper bounds
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename T, class CIn, class CVal, class COut>
|
|
|
|
VTKM_CONT static void UpperBounds(const vtkm::cont::ArrayHandle<T, CIn>& input,
|
|
|
|
const vtkm::cont::ArrayHandle<T, CVal>& values,
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::Id, COut>& output)
|
2014-02-11 17:34:56 +00:00
|
|
|
{
|
2018-08-30 17:29:36 +00:00
|
|
|
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
|
|
|
|
2014-02-11 17:34:56 +00:00
|
|
|
vtkm::Id arraySize = values.GetNumberOfValues();
|
|
|
|
|
2020-01-21 20:18:03 +00:00
|
|
|
vtkm::cont::Token token;
|
|
|
|
|
|
|
|
auto inputPortal = input.PrepareForInput(DeviceAdapterTag(), token);
|
|
|
|
auto valuesPortal = values.PrepareForInput(DeviceAdapterTag(), token);
|
|
|
|
auto outputPortal = output.PrepareForOutput(arraySize, DeviceAdapterTag(), token);
|
2014-02-11 17:34:56 +00:00
|
|
|
|
2017-08-10 20:13:55 +00:00
|
|
|
UpperBoundsKernel<decltype(inputPortal), decltype(valuesPortal), decltype(outputPortal)> kernel(
|
|
|
|
inputPortal, valuesPortal, outputPortal);
|
2014-02-11 17:34:56 +00:00
|
|
|
DerivedAlgorithm::Schedule(kernel, arraySize);
|
|
|
|
}
|
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename T, class CIn, class CVal, class COut, class BinaryCompare>
|
|
|
|
VTKM_CONT static void UpperBounds(const vtkm::cont::ArrayHandle<T, CIn>& input,
|
|
|
|
const vtkm::cont::ArrayHandle<T, CVal>& values,
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::Id, COut>& output,
|
|
|
|
BinaryCompare binary_compare)
|
2014-02-11 17:34:56 +00:00
|
|
|
{
|
2018-08-30 17:29:36 +00:00
|
|
|
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
|
|
|
|
2014-02-11 17:34:56 +00:00
|
|
|
vtkm::Id arraySize = values.GetNumberOfValues();
|
|
|
|
|
2020-01-21 20:18:03 +00:00
|
|
|
vtkm::cont::Token token;
|
|
|
|
|
|
|
|
auto inputPortal = input.PrepareForInput(DeviceAdapterTag(), token);
|
|
|
|
auto valuesPortal = values.PrepareForInput(DeviceAdapterTag(), token);
|
|
|
|
auto outputPortal = output.PrepareForOutput(arraySize, DeviceAdapterTag(), token);
|
2017-08-10 20:13:55 +00:00
|
|
|
|
|
|
|
UpperBoundsKernelComparisonKernel<decltype(inputPortal),
|
|
|
|
decltype(valuesPortal),
|
|
|
|
decltype(outputPortal),
|
|
|
|
BinaryCompare>
|
|
|
|
kernel(inputPortal, valuesPortal, outputPortal, binary_compare);
|
2014-02-11 17:34:56 +00:00
|
|
|
|
|
|
|
DerivedAlgorithm::Schedule(kernel, arraySize);
|
|
|
|
}
|
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
template <class CIn, class COut>
|
|
|
|
VTKM_CONT static void UpperBounds(const vtkm::cont::ArrayHandle<vtkm::Id, CIn>& input,
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::Id, COut>& values_output)
|
2014-02-11 17:34:56 +00:00
|
|
|
{
|
2018-08-30 17:29:36 +00:00
|
|
|
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
DeviceAdapterAlgorithmGeneral<DerivedAlgorithm, DeviceAdapterTag>::UpperBounds(
|
|
|
|
input, values_output, values_output);
|
2014-02-11 17:34:56 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-05-25 17:35:34 +00:00
|
|
|
} // namespace internal
|
2016-09-12 14:30:03 +00:00
|
|
|
|
|
|
|
/// \brief Class providing a device-specific support for selecting the optimal
|
|
|
|
/// Task type for a given worklet.
|
|
|
|
///
|
2018-01-30 00:24:31 +00:00
|
|
|
/// When worklets are launched inside the execution environment we need to
|
2016-09-12 14:30:03 +00:00
|
|
|
/// ask the device adapter what is the preferred execution style, be it
|
|
|
|
/// a tiled iteration pattern, or strided. This class
|
|
|
|
///
|
|
|
|
/// By default if not specialized for a device adapter the default
|
|
|
|
/// is to use vtkm::exec::internal::TaskSingular
|
|
|
|
///
|
|
|
|
template <typename DeviceTag>
|
|
|
|
class DeviceTaskTypes
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
template <typename WorkletType, typename InvocationType>
|
|
|
|
static vtkm::exec::internal::TaskSingular<WorkletType, InvocationType> MakeTask(
|
2018-01-18 18:51:30 +00:00
|
|
|
WorkletType& worklet,
|
|
|
|
InvocationType& invocation,
|
2017-05-26 17:53:28 +00:00
|
|
|
vtkm::Id,
|
2016-09-12 14:30:03 +00:00
|
|
|
vtkm::Id globalIndexOffset = 0)
|
|
|
|
{
|
|
|
|
using Task = vtkm::exec::internal::TaskSingular<WorkletType, InvocationType>;
|
|
|
|
return Task(worklet, invocation, globalIndexOffset);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename WorkletType, typename InvocationType>
|
|
|
|
static vtkm::exec::internal::TaskSingular<WorkletType, InvocationType> MakeTask(
|
2018-01-18 18:51:30 +00:00
|
|
|
WorkletType& worklet,
|
|
|
|
InvocationType& invocation,
|
2017-05-26 17:53:28 +00:00
|
|
|
vtkm::Id3,
|
2016-09-12 14:30:03 +00:00
|
|
|
vtkm::Id globalIndexOffset = 0)
|
|
|
|
{
|
|
|
|
using Task = vtkm::exec::internal::TaskSingular<WorkletType, InvocationType>;
|
|
|
|
return Task(worklet, invocation, globalIndexOffset);
|
|
|
|
}
|
|
|
|
};
|
2016-02-10 16:21:38 +00:00
|
|
|
}
|
|
|
|
} // namespace vtkm::cont
|
|
|
|
|
2014-06-11 16:43:36 +00:00
|
|
|
#endif //vtk_m_cont_internal_DeviceAdapterAlgorithmGeneral_h
|