Advanced Compute Range

Add support for masks, vector magnitude range (L2 norm), and finite values only
range computations.
This commit is contained in:
Sujin Philip 2023-06-02 08:23:03 -04:00
parent bce19a2e4c
commit 01bacbcde0
22 changed files with 1456 additions and 372 deletions

@ -0,0 +1,21 @@
# New features for computing array ranges
ArrayRangeCompute has been update to support more features that are present
in VTK and ParaView.
New overloads for `ArrayRangeCompute` have been added:
1. Takes a boolean parameter, `computeFiniteRange`, that specifies
whether to compute only the finite range by ignoring any non-finite values (+/-inf)
in the array.
2. Takes a `maskArray` parameter of type `vtkm::cont::ArrayHandle<vtkm::UInt8>`.
The mask array must contain the same number of elements as the input array.
A value in the input array is treated as masked off if the
corresponding value in the mask array is non-zero. Masked off values are ignored
in the range computation.
A new function `ArrayRangeComputeMagnitude` has been added. If the input array
has multiple components, this function computes the range of the magnitude of
the values of the array. Nested Vecs are treated as flat. A single `Range` object
is returned containing the result. `ArrayRangeComputMagnitude` also has similar
overloads as `ArrayRangeCompute`.

@ -484,6 +484,13 @@ struct ArrayExtractComponentImpl<vtkm::cont::StorageTagCartesianProduct<STs...>>
}
};
template <typename T, typename S>
vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeComputeGeneric(
const vtkm::cont::ArrayHandle<T, S>& input,
const vtkm::cont::ArrayHandle<vtkm::UInt8>& maskArray,
bool computeFiniteRange,
vtkm::cont::DeviceAdapterId device);
template <typename S>
struct ArrayRangeComputeImpl;
@ -494,63 +501,43 @@ struct VTKM_CONT_EXPORT ArrayRangeComputeImpl<vtkm::cont::StorageTagCartesianPro
VTKM_CONT vtkm::cont::ArrayHandle<vtkm::Range> operator()(
const vtkm::cont::ArrayHandle<vtkm::Vec<T, 3>,
vtkm::cont::StorageTagCartesianProduct<ST1, ST2, ST3>>& input_,
const vtkm::cont::ArrayHandle<vtkm::UInt8>& maskArray,
bool computeFiniteRange,
vtkm::cont::DeviceAdapterId device) const
{
if (maskArray.GetNumberOfValues() != 0)
{
return vtkm::cont::internal::ArrayRangeComputeGeneric(
input_, maskArray, computeFiniteRange, device);
}
const auto& input =
static_cast<const vtkm::cont::ArrayHandleCartesianProduct<vtkm::cont::ArrayHandle<T, ST1>,
vtkm::cont::ArrayHandle<T, ST2>,
vtkm::cont::ArrayHandle<T, ST3>>&>(
input_);
vtkm::cont::ArrayHandle<vtkm::Range> ranges[3];
ranges[0] = vtkm::cont::internal::ArrayRangeComputeImpl<ST1>{}(
input.GetFirstArray(), maskArray, computeFiniteRange, device);
ranges[1] = vtkm::cont::internal::ArrayRangeComputeImpl<ST2>{}(
input.GetSecondArray(), maskArray, computeFiniteRange, device);
ranges[2] = vtkm::cont::internal::ArrayRangeComputeImpl<ST3>{}(
input.GetThirdArray(), maskArray, computeFiniteRange, device);
auto numComponents =
ranges[0].GetNumberOfValues() + ranges[1].GetNumberOfValues() + ranges[2].GetNumberOfValues();
vtkm::cont::ArrayHandle<vtkm::Range> result;
result.Allocate(3);
result.Allocate(numComponents);
auto resultPortal = result.WritePortal();
const vtkm::cont::ArrayHandleCartesianProduct<vtkm::cont::ArrayHandle<T, ST1>,
vtkm::cont::ArrayHandle<T, ST2>,
vtkm::cont::ArrayHandle<T, ST3>>& input = input_;
vtkm::cont::ArrayHandle<vtkm::Range> componentRangeArray;
vtkm::IdComponent index = 0;
vtkm::cont::ArrayHandle<T, ST1> firstArray = input.GetFirstArray();
componentRangeArray = vtkm::cont::internal::ArrayRangeComputeImpl<ST1>{}(firstArray, device);
vtkm::Id numSubComponents = componentRangeArray.GetNumberOfValues();
if (numSubComponents > 1)
for (vtkm::Id i = 0, index = 0; i < 3; ++i)
{
result.Allocate(result.GetNumberOfValues() + numSubComponents - 1, vtkm::CopyFlag::On);
resultPortal = result.WritePortal();
auto rangePortal = ranges[i].ReadPortal();
for (vtkm::Id j = 0; j < rangePortal.GetNumberOfValues(); ++j, ++index)
{
resultPortal.Set(index, rangePortal.Get(j));
}
}
auto componentRangePortal = componentRangeArray.ReadPortal();
for (vtkm::IdComponent subComponent = 0; subComponent < numSubComponents; ++subComponent)
{
resultPortal.Set(index, componentRangePortal.Get(subComponent));
++index;
}
vtkm::cont::ArrayHandle<T, ST2> secondArray = input.GetSecondArray();
componentRangeArray = vtkm::cont::internal::ArrayRangeComputeImpl<ST2>{}(secondArray, device);
numSubComponents = componentRangeArray.GetNumberOfValues();
if (numSubComponents > 1)
{
result.Allocate(result.GetNumberOfValues() + numSubComponents - 1, vtkm::CopyFlag::On);
resultPortal = result.WritePortal();
}
componentRangePortal = componentRangeArray.ReadPortal();
for (vtkm::IdComponent subComponent = 0; subComponent < numSubComponents; ++subComponent)
{
resultPortal.Set(index, componentRangePortal.Get(subComponent));
++index;
}
vtkm::cont::ArrayHandle<T, ST3> thirdArray = input.GetThirdArray();
componentRangeArray = vtkm::cont::internal::ArrayRangeComputeImpl<ST3>{}(thirdArray, device);
numSubComponents = componentRangeArray.GetNumberOfValues();
if (numSubComponents > 1)
{
result.Allocate(result.GetNumberOfValues() + numSubComponents - 1, vtkm::CopyFlag::On);
resultPortal = result.WritePortal();
}
componentRangePortal = componentRangeArray.ReadPortal();
for (vtkm::IdComponent subComponent = 0; subComponent < numSubComponents; ++subComponent)
{
resultPortal.Set(index, componentRangePortal.Get(subComponent));
++index;
}
return result;
}
};

@ -12,8 +12,11 @@
#include <vtkm/cont/ArrayHandleImplicit.h>
#include <vtkm/cont/internal/ArrayRangeComputeUtils.h>
#include <vtkm/Range.h>
#include <vtkm/VecFlat.h>
#include <vtkm/VectorAnalysis.h>
namespace vtkm
{
@ -106,8 +109,18 @@ struct VTKM_CONT_EXPORT ArrayRangeComputeImpl<vtkm::cont::StorageTagConstant>
template <typename T>
VTKM_CONT vtkm::cont::ArrayHandle<vtkm::Range> operator()(
const vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagConstant>& input,
vtkm::cont::DeviceAdapterId) const
const vtkm::cont::ArrayHandle<vtkm::UInt8>& maskArray,
bool computeFiniteRange,
vtkm::cont::DeviceAdapterId devId) const
{
bool allMasked = false;
if (maskArray.GetNumberOfValues() != 0)
{
// Find if there is atleast one value that is not masked
auto ids = GetFirstAndLastUnmaskedIndices(maskArray, devId);
allMasked = (ids[1] < ids[0]);
}
auto value = vtkm::make_VecFlat(input.ReadPortal().Get(0));
vtkm::cont::ArrayHandle<vtkm::Range> result;
@ -115,12 +128,51 @@ struct VTKM_CONT_EXPORT ArrayRangeComputeImpl<vtkm::cont::StorageTagConstant>
auto resultPortal = result.WritePortal();
for (vtkm::IdComponent index = 0; index < value.GetNumberOfComponents(); ++index)
{
resultPortal.Set(index, vtkm::Range{ value[index], value[index] });
auto comp = static_cast<vtkm::Float64>(value[index]);
if (allMasked || (computeFiniteRange && !vtkm::IsFinite(comp)))
{
resultPortal.Set(index, vtkm::Range{});
}
else
{
resultPortal.Set(index, vtkm::Range{ comp, comp });
}
}
return result;
}
};
template <typename S>
struct ArrayRangeComputeMagnitudeImpl;
template <>
struct VTKM_CONT_EXPORT ArrayRangeComputeMagnitudeImpl<vtkm::cont::StorageTagConstant>
{
template <typename T>
VTKM_CONT vtkm::Range operator()(
const vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagConstant>& input,
const vtkm::cont::ArrayHandle<vtkm::UInt8>& maskArray,
bool computeFiniteRange,
vtkm::cont::DeviceAdapterId devId) const
{
if (maskArray.GetNumberOfValues() != 0)
{
// Find if there is atleast one value that is not masked
auto ids = GetFirstAndLastUnmaskedIndices(maskArray, devId);
if (ids[1] < ids[0])
{
return vtkm::Range{};
}
}
auto value = input.ReadPortal().Get(0);
vtkm::Float64 rangeValue = vtkm::Magnitude(vtkm::make_VecFlat(value));
return (computeFiniteRange && !vtkm::IsFinite(rangeValue))
? vtkm::Range{}
: vtkm::Range{ rangeValue, rangeValue };
}
};
} // namespace internal
}

@ -12,8 +12,11 @@
#include <vtkm/cont/ArrayHandleImplicit.h>
#include <vtkm/cont/internal/ArrayRangeComputeUtils.h>
#include <vtkm/Range.h>
#include <vtkm/TypeTraits.h>
#include <vtkm/VecFlat.h>
#include <vtkm/VecTraits.h>
namespace vtkm
@ -156,33 +159,45 @@ struct VTKM_CONT_EXPORT ArrayRangeComputeImpl<vtkm::cont::StorageTagCounting>
template <typename T>
VTKM_CONT vtkm::cont::ArrayHandle<vtkm::Range> operator()(
const vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagCounting>& input,
vtkm::cont::DeviceAdapterId) const
const vtkm::cont::ArrayHandle<vtkm::UInt8>& maskArray,
bool vtkmNotUsed(computeFiniteRange), // assume array produces only finite values
vtkm::cont::DeviceAdapterId device) const
{
using Traits = vtkm::VecTraits<T>;
using Traits = vtkm::VecTraits<vtkm::VecFlat<T>>;
vtkm::cont::ArrayHandle<vtkm::Range> result;
result.Allocate(Traits::NUM_COMPONENTS);
if (input.GetNumberOfValues() <= 0)
{
result.Fill(vtkm::Range{});
return result;
}
vtkm::Id2 firstAndLast{ 0, input.GetNumberOfValues() - 1 };
if (maskArray.GetNumberOfValues() > 0)
{
firstAndLast = GetFirstAndLastUnmaskedIndices(maskArray, device);
}
if (firstAndLast[1] < firstAndLast[0])
{
result.Fill(vtkm::Range{});
return result;
}
auto portal = result.WritePortal();
if (portal.GetNumberOfValues() > 0)
// assume the values to be finite
auto first = make_VecFlat(input.ReadPortal().Get(firstAndLast[0]));
auto last = make_VecFlat(input.ReadPortal().Get(firstAndLast[1]));
for (vtkm::IdComponent cIndex = 0; cIndex < Traits::NUM_COMPONENTS; ++cIndex)
{
T first = input.ReadPortal().Get(0);
T last = input.ReadPortal().Get(input.GetNumberOfValues() - 1);
for (vtkm::IdComponent cIndex = 0; cIndex < Traits::NUM_COMPONENTS; ++cIndex)
{
auto firstComponent = Traits::GetComponent(first, cIndex);
auto lastComponent = Traits::GetComponent(last, cIndex);
portal.Set(cIndex,
vtkm::Range(vtkm::Min(firstComponent, lastComponent),
vtkm::Max(firstComponent, lastComponent)));
}
}
else
{
// Array is empty
for (vtkm::IdComponent cIndex = 0; cIndex < Traits::NUM_COMPONENTS; ++cIndex)
{
portal.Set(cIndex, vtkm::Range{});
}
auto firstComponent = Traits::GetComponent(first, cIndex);
auto lastComponent = Traits::GetComponent(last, cIndex);
portal.Set(cIndex,
vtkm::Range(vtkm::Min(firstComponent, lastComponent),
vtkm::Max(firstComponent, lastComponent)));
}
return result;
}
};

@ -23,7 +23,7 @@
#include <vtkmstd/integer_sequence.h>
#include <array>
#include <numeric>
#include <type_traits>
#include <utility>

@ -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.
//============================================================================
#include <vtkm/cont/ArrayHandleIndex.h>
#include <vtkm/cont/internal/ArrayRangeComputeUtils.h>
namespace vtkm
{
namespace cont
{
namespace internal
{
VTKM_CONT vtkm::cont::ArrayHandle<vtkm::Range>
ArrayRangeComputeImpl<vtkm::cont::StorageTagIndex>::operator()(
const vtkm::cont::ArrayHandle<vtkm::Id, vtkm::cont::StorageTagIndex>& input,
const vtkm::cont::ArrayHandle<vtkm::UInt8>& maskArray,
bool vtkmNotUsed(computeFiniteRange), // assume array produces only finite values
vtkm::cont::DeviceAdapterId device) const
{
vtkm::Range range{};
if (input.GetNumberOfValues() > 0)
{
vtkm::Id2 firstAndLast{ 0, input.GetNumberOfValues() - 1 };
if (maskArray.GetNumberOfValues() > 0)
{
firstAndLast = vtkm::cont::internal::GetFirstAndLastUnmaskedIndices(maskArray, device);
}
if (firstAndLast[0] < firstAndLast[1])
{
range = vtkm::Range(firstAndLast[0], firstAndLast[1]);
}
}
vtkm::cont::ArrayHandle<vtkm::Range> result;
result.Allocate(1);
result.WritePortal().Set(0, range);
return result;
}
}
}
} // vtkm::cont::internal

@ -84,12 +84,26 @@ struct VTKM_CONT_EXPORT ArrayRangeComputeImpl<vtkm::cont::StorageTagIndex>
{
VTKM_CONT vtkm::cont::ArrayHandle<vtkm::Range> operator()(
const vtkm::cont::ArrayHandle<vtkm::Id, vtkm::cont::StorageTagIndex>& input,
vtkm::cont::DeviceAdapterId) const
const vtkm::cont::ArrayHandle<vtkm::UInt8>& maskArray,
bool computeFiniteRange,
vtkm::cont::DeviceAdapterId device) const;
};
template <typename S>
struct ArrayRangeComputeMagnitudeImpl;
template <>
struct VTKM_CONT_EXPORT ArrayRangeComputeMagnitudeImpl<vtkm::cont::StorageTagIndex>
{
VTKM_CONT vtkm::Range operator()(
const vtkm::cont::ArrayHandle<vtkm::Id, vtkm::cont::StorageTagIndex>& input,
const vtkm::cont::ArrayHandle<vtkm::UInt8>& maskArray,
bool computeFiniteRange,
vtkm::cont::DeviceAdapterId device) const
{
vtkm::cont::ArrayHandle<vtkm::Range> result;
result.Allocate(1);
result.WritePortal().Set(0, vtkm::Range(0, input.GetNumberOfValues() - 1));
return result;
auto rangeAH = ArrayRangeComputeImpl<vtkm::cont::StorageTagIndex>{}(
input, maskArray, computeFiniteRange, device);
return rangeAH.ReadPortal().Get(0);
}
};

@ -13,8 +13,11 @@
#include <vtkm/cont/ArrayExtractComponent.h>
#include <vtkm/cont/ArrayHandleMultiplexer.h>
#include <vtkm/cont/ArrayHandleStride.h>
#include <vtkm/cont/ArrayHandleTransform.h>
#include <vtkm/cont/DeviceAdapterTag.h>
#include <vtkm/cont/internal/ArrayRangeComputeUtils.h>
#include <vtkm/internal/ArrayPortalValueReference.h>
namespace vtkm
@ -648,6 +651,110 @@ struct ArrayExtractComponentImpl<vtkm::cont::internal::StorageTagRecombineVec>
}
};
//-------------------------------------------------------------------------------------------------
template <typename S>
struct ArrayRangeComputeImpl;
template <typename S>
struct ArrayRangeComputeMagnitudeImpl;
template <typename T, typename S>
inline vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeComputeImplCaller(
const vtkm::cont::ArrayHandle<T, S>& input,
const vtkm::cont::ArrayHandle<vtkm::UInt8>& maskArray,
bool computeFiniteRange,
vtkm::cont::DeviceAdapterId device)
{
return vtkm::cont::internal::ArrayRangeComputeImpl<S>{}(
input, maskArray, computeFiniteRange, device);
}
template <typename T, typename S>
inline vtkm::Range ArrayRangeComputeMagnitudeImplCaller(
const vtkm::cont::ArrayHandle<T, S>& input,
const vtkm::cont::ArrayHandle<vtkm::UInt8>& maskArray,
bool computeFiniteRange,
vtkm::cont::DeviceAdapterId device)
{
return vtkm::cont::internal::ArrayRangeComputeMagnitudeImpl<S>{}(
input, maskArray, computeFiniteRange, device);
}
template <>
struct VTKM_CONT_EXPORT ArrayRangeComputeImpl<vtkm::cont::internal::StorageTagRecombineVec>
{
template <typename RecombineVecType>
VTKM_CONT vtkm::cont::ArrayHandle<vtkm::Range> operator()(
const vtkm::cont::ArrayHandle<RecombineVecType, vtkm::cont::internal::StorageTagRecombineVec>&
input_,
const vtkm::cont::ArrayHandle<vtkm::UInt8>& maskArray,
bool computeFiniteRange,
vtkm::cont::DeviceAdapterId device) const
{
auto input =
static_cast<vtkm::cont::ArrayHandleRecombineVec<typename RecombineVecType::ComponentType>>(
input_);
vtkm::cont::ArrayHandle<vtkm::Range> result;
result.Allocate(input.GetNumberOfComponents());
if (input.GetNumberOfValues() < 1)
{
result.Fill(vtkm::Range{});
return result;
}
auto resultPortal = result.WritePortal();
for (vtkm::IdComponent i = 0; i < input.GetNumberOfComponents(); ++i)
{
auto rangeAH = ArrayRangeComputeImplCaller(
input.GetComponentArray(i), maskArray, computeFiniteRange, device);
resultPortal.Set(i, rangeAH.ReadPortal().Get(0));
}
return result;
}
};
template <typename ArrayHandleType>
struct ArrayValueIsNested;
template <typename RecombineVecType>
struct ArrayValueIsNested<
vtkm::cont::ArrayHandle<RecombineVecType, vtkm::cont::internal::StorageTagRecombineVec>>
{
static constexpr bool Value = false;
};
template <>
struct VTKM_CONT_EXPORT ArrayRangeComputeMagnitudeImpl<vtkm::cont::internal::StorageTagRecombineVec>
{
template <typename RecombineVecType>
VTKM_CONT vtkm::Range operator()(
const vtkm::cont::ArrayHandle<RecombineVecType, vtkm::cont::internal::StorageTagRecombineVec>&
input_,
const vtkm::cont::ArrayHandle<vtkm::UInt8>& maskArray,
bool computeFiniteRange,
vtkm::cont::DeviceAdapterId device) const
{
auto input =
static_cast<vtkm::cont::ArrayHandleRecombineVec<typename RecombineVecType::ComponentType>>(
input_);
if (input.GetNumberOfValues() < 1)
{
return vtkm::Range{};
}
if (input.GetNumberOfComponents() == 1)
{
return ArrayRangeComputeMagnitudeImplCaller(
input.GetComponentArray(0), maskArray, computeFiniteRange, device);
}
return ArrayRangeComputeMagnitudeGeneric(input_, maskArray, computeFiniteRange, device);
}
};
} // namespace internal
}

@ -226,7 +226,7 @@ struct TransformFunctorManager
}
template <typename ValueType>
using TransformedValueType = decltype(std::declval<FunctorType>()(ValueType{}));
using TransformedValueType = decltype(std::declval<FunctorType>()(std::declval<ValueType>()));
};
template <typename ArrayHandleType,

@ -10,6 +10,10 @@
#include <vtkm/cont/ArrayHandleUniformPointCoordinates.h>
#include <vtkm/cont/ArrayRangeComputeTemplate.h>
#include <vtkm/VectorAnalysis.h>
namespace vtkm
{
namespace cont
@ -89,8 +93,16 @@ ArrayExtractComponentImpl<vtkm::cont::StorageTagUniformPoints>::operator()(
VTKM_CONT vtkm::cont::ArrayHandle<vtkm::Range>
ArrayRangeComputeImpl<vtkm::cont::StorageTagUniformPoints>::operator()(
const vtkm::cont::ArrayHandleUniformPointCoordinates& input,
vtkm::cont::DeviceAdapterId vtkmNotUsed(device)) const
const vtkm::cont::ArrayHandle<vtkm::UInt8>& maskArray,
bool computeFiniteRange,
vtkm::cont::DeviceAdapterId device) const
{
if (maskArray.GetNumberOfValues() != 0)
{
return vtkm::cont::internal::ArrayRangeComputeGeneric(
input, maskArray, computeFiniteRange, device);
}
vtkm::internal::ArrayPortalUniformPointCoordinates portal = input.ReadPortal();
// In this portal we know that the min value is the first entry and the

@ -88,6 +88,8 @@ struct VTKM_CONT_EXPORT ArrayRangeComputeImpl<vtkm::cont::StorageTagUniformPoint
{
VTKM_CONT vtkm::cont::ArrayHandle<vtkm::Range> operator()(
const vtkm::cont::ArrayHandleUniformPointCoordinates& input,
const vtkm::cont::ArrayHandle<vtkm::UInt8>& maskArray,
bool computeFiniteRange,
vtkm::cont::DeviceAdapterId device) const;
};

@ -8,13 +8,13 @@
// PURPOSE. See the above copyright notice for more information.
//============================================================================
#include <vtkm/cont/ArrayRangeCompute.h>
#include <vtkm/cont/ArrayRangeComputeTemplate.h>
#include <vtkm/TypeList.h>
#include <vtkm/cont/ArrayHandleBasic.h>
#include <vtkm/cont/ArrayHandleCartesianProduct.h>
#include <vtkm/cont/ArrayHandleCompositeVector.h>
#include <vtkm/cont/ArrayHandleConstant.h>
#include <vtkm/cont/ArrayHandleCounting.h>
#include <vtkm/cont/ArrayHandleIndex.h>
@ -42,50 +42,39 @@ using AllVec = vtkm::ListAppend<AllVecOfSize<2>, AllVecOfSize<3>, AllVecOfSize<4
using AllTypes = vtkm::ListAppend<AllScalars, AllVec>;
struct ComputeRangeFunctor
{
// Used with UnknownArrayHandle::CastAndCallForTypes
template <typename T, typename S>
void operator()(const vtkm::cont::ArrayHandle<T, S>& array,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::ArrayHandle<vtkm::Range>& ranges) const
{
ranges = vtkm::cont::ArrayRangeComputeTemplate(array, device);
using CartesianProductStorage = vtkm::cont::StorageTagCartesianProduct<vtkm::cont::StorageTagBasic,
vtkm::cont::StorageTagBasic,
vtkm::cont::StorageTagBasic>;
using StorageTagsList = vtkm::List<vtkm::cont::StorageTagBasic,
vtkm::cont::StorageTagSOA,
vtkm::cont::StorageTagXGCCoordinates,
vtkm::cont::StorageTagUniformPoints,
CartesianProductStorage,
vtkm::cont::StorageTagConstant,
vtkm::cont::StorageTagCounting,
vtkm::cont::StorageTagIndex>;
template <typename StorageTag>
struct StorageTagToValueTypesMap;
#define MAP_STORAGE_TAG_VALUE_TYPES(StorageTag, ValueTypesList) \
template <> \
struct StorageTagToValueTypesMap<StorageTag> \
{ \
using TypeList = ValueTypesList; \
}
// Used with vtkm::ListForEach to get components
template <typename T>
void operator()(T,
const vtkm::cont::UnknownArrayHandle& array,
vtkm::cont::DeviceAdapterId device,
vtkm::cont::ArrayHandle<vtkm::Range>& ranges,
bool& success) const
{
if (!success && array.IsBaseComponentType<T>())
{
vtkm::IdComponent numComponents = array.GetNumberOfComponentsFlat();
ranges.Allocate(numComponents);
auto rangePortal = ranges.WritePortal();
for (vtkm::IdComponent componentI = 0; componentI < numComponents; ++componentI)
{
vtkm::cont::ArrayHandleStride<T> componentArray = array.ExtractComponent<T>(componentI);
vtkm::cont::ArrayHandle<vtkm::Range> componentRange =
vtkm::cont::ArrayRangeComputeTemplate(componentArray, device);
rangePortal.Set(componentI, componentRange.ReadPortal().Get(0));
}
success = true;
}
}
};
MAP_STORAGE_TAG_VALUE_TYPES(vtkm::cont::StorageTagBasic, AllTypes);
MAP_STORAGE_TAG_VALUE_TYPES(vtkm::cont::StorageTagSOA, AllVec);
MAP_STORAGE_TAG_VALUE_TYPES(vtkm::cont::StorageTagXGCCoordinates, vtkm::TypeListFieldVec3);
MAP_STORAGE_TAG_VALUE_TYPES(vtkm::cont::StorageTagUniformPoints, vtkm::List<vtkm::Vec3f>);
MAP_STORAGE_TAG_VALUE_TYPES(CartesianProductStorage, vtkm::TypeListFieldVec3);
MAP_STORAGE_TAG_VALUE_TYPES(vtkm::cont::StorageTagConstant, AllTypes);
MAP_STORAGE_TAG_VALUE_TYPES(vtkm::cont::StorageTagCounting, AllTypes);
MAP_STORAGE_TAG_VALUE_TYPES(vtkm::cont::StorageTagIndex, vtkm::List<vtkm::Id>);
template <typename TList, typename Storage>
vtkm::cont::ArrayHandle<vtkm::Range> ComputeForStorage(const vtkm::cont::UnknownArrayHandle& array,
vtkm::cont::DeviceAdapterId device)
{
vtkm::cont::ArrayHandle<vtkm::Range> ranges;
array.CastAndCallForTypes<TList, vtkm::List<Storage>>(ComputeRangeFunctor{}, device, ranges);
return ranges;
}
#undef MAP_STORAGE_TAG_VALUE_TYPES
} // anonymous namespace
@ -105,49 +94,44 @@ void ThrowArrayRangeComputeFailed()
} // namespace internal
vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(const vtkm::cont::UnknownArrayHandle& array,
bool computeFiniteRange,
vtkm::cont::DeviceAdapterId device)
{
// First, try fast-paths of precompiled array types common(ish) in fields.
return ArrayRangeCompute(
array, vtkm::cont::ArrayHandle<vtkm::UInt8>{}, computeFiniteRange, device);
}
vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(
const vtkm::cont::UnknownArrayHandle& array,
const vtkm::cont::ArrayHandle<vtkm::UInt8>& maskArray,
bool computeFiniteRange,
vtkm::cont::DeviceAdapterId device)
{
// First, try (potentially fast-paths) for common(ish) array types.
try
{
if (array.IsStorageType<vtkm::cont::StorageTagBasic>())
vtkm::cont::ArrayHandle<vtkm::Range> ranges;
auto computeForArrayHandle = [&](const auto& input) {
ranges = vtkm::cont::ArrayRangeComputeTemplate(input, maskArray, computeFiniteRange, device);
};
bool success = false;
auto computeForStorage = [&](auto storageTag) {
using STag = decltype(storageTag);
using VTypes = typename StorageTagToValueTypesMap<STag>::TypeList;
if (array.IsStorageType<STag>())
{
array.CastAndCallForTypes<VTypes, vtkm::List<STag>>(computeForArrayHandle);
success = true;
}
};
vtkm::ListForEach(computeForStorage, StorageTagsList{});
if (success)
{
return ComputeForStorage<AllTypes, vtkm::cont::StorageTagBasic>(array, device);
}
if (array.IsStorageType<vtkm::cont::StorageTagSOA>())
{
return ComputeForStorage<AllVec, vtkm::cont::StorageTagSOA>(array, device);
}
if (array.IsStorageType<vtkm::cont::StorageTagXGCCoordinates>())
{
return ComputeForStorage<vtkm::TypeListFieldVec3, vtkm::cont::StorageTagXGCCoordinates>(
array, device);
}
if (array.IsStorageType<vtkm::cont::ArrayHandleUniformPointCoordinates::StorageTag>())
{
vtkm::cont::ArrayHandleUniformPointCoordinates uniformPoints;
array.AsArrayHandle(uniformPoints);
return vtkm::cont::ArrayRangeComputeTemplate(uniformPoints, device);
}
using CartesianProductStorage =
vtkm::cont::StorageTagCartesianProduct<vtkm::cont::StorageTagBasic,
vtkm::cont::StorageTagBasic,
vtkm::cont::StorageTagBasic>;
if (array.IsStorageType<CartesianProductStorage>())
{
return ComputeForStorage<vtkm::TypeListFieldVec3, CartesianProductStorage>(array, device);
}
if (array.IsStorageType<vtkm::cont::StorageTagConstant>())
{
return ComputeForStorage<AllTypes, vtkm::cont::StorageTagConstant>(array, device);
}
if (array.IsStorageType<vtkm::cont::StorageTagCounting>())
{
return ComputeForStorage<AllTypes, vtkm::cont::StorageTagCounting>(array, device);
}
if (array.IsStorageType<vtkm::cont::StorageTagIndex>())
{
return ArrayRangeComputeTemplate(array.AsArrayHandle<vtkm::cont::ArrayHandleIndex>(), device);
return ranges;
}
}
catch (vtkm::cont::ErrorBadType&)
@ -155,11 +139,104 @@ vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(const vtkm::cont::Unknown
// If a cast/call failed, try falling back to a more general implementation.
}
vtkm::cont::ArrayHandle<vtkm::Range> ranges;
// fallback
bool success = false;
vtkm::ListForEach(ComputeRangeFunctor{}, AllScalars{}, array, device, ranges, success);
vtkm::cont::ArrayHandle<vtkm::Range> ranges;
auto computeForExtractComponent = [&](auto valueTypeObj) {
using VT = decltype(valueTypeObj);
if (!success && array.IsBaseComponentType<VT>())
{
vtkm::IdComponent numComponents = array.GetNumberOfComponentsFlat();
ranges.Allocate(numComponents);
auto rangePortal = ranges.WritePortal();
for (vtkm::IdComponent i = 0; i < numComponents; ++i)
{
auto componentArray = array.ExtractComponent<VT>(i);
auto componentRange = vtkm::cont::ArrayRangeComputeTemplate(
componentArray, maskArray, computeFiniteRange, device);
rangePortal.Set(i, componentRange.ReadPortal().Get(0));
}
success = true;
}
};
vtkm::ListForEach(computeForExtractComponent, AllScalars{});
if (!success)
{
internal::ThrowArrayRangeComputeFailed();
}
return ranges;
}
vtkm::Range ArrayRangeComputeMagnitude(const vtkm::cont::UnknownArrayHandle& array,
bool computeFiniteRange,
vtkm::cont::DeviceAdapterId device)
{
return ArrayRangeComputeMagnitude(
array, vtkm::cont::ArrayHandle<vtkm::UInt8>{}, computeFiniteRange, device);
}
vtkm::Range ArrayRangeComputeMagnitude(const vtkm::cont::UnknownArrayHandle& array,
const vtkm::cont::ArrayHandle<vtkm::UInt8>& maskArray,
bool computeFiniteRange,
vtkm::cont::DeviceAdapterId device)
{
// First, try (potentially fast-paths) for common(ish) array types.
try
{
vtkm::Range range;
auto computeForArrayHandle = [&](const auto& input) {
range = vtkm::cont::ArrayRangeComputeMagnitudeTemplate(
input, maskArray, computeFiniteRange, device);
};
bool success = false;
auto computeForStorage = [&](auto storageTag) {
using STag = decltype(storageTag);
using VTypes = typename StorageTagToValueTypesMap<STag>::TypeList;
if (array.IsStorageType<STag>())
{
array.CastAndCallForTypes<VTypes, vtkm::List<STag>>(computeForArrayHandle);
success = true;
}
};
vtkm::ListForEach(computeForStorage, StorageTagsList{});
if (success)
{
return range;
}
}
catch (vtkm::cont::ErrorBadType&)
{
// If a cast/call failed, try falling back to a more general implementation.
}
// fallback
bool success = false;
vtkm::Range range;
auto computeForExtractArrayFromComponents = [&](auto valueTypeObj) {
using VT = decltype(valueTypeObj);
if (!success && array.IsBaseComponentType<VT>())
{
auto extractedArray = array.ExtractArrayFromComponents<VT>();
range = vtkm::cont::ArrayRangeComputeMagnitudeTemplate(
extractedArray, maskArray, computeFiniteRange, device);
success = true;
}
};
vtkm::ListForEach(computeForExtractArrayFromComponents, AllScalars{});
if (!success)
{
internal::ThrowArrayRangeComputeFailed();
}
return range;
}
}
} // namespace vtkm::cont

@ -11,18 +11,8 @@
#define vtk_m_cont_ArrayRangeCompute_h
#include <vtkm/Range.h>
#include <vtkm/VecTraits.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ArrayHandleCartesianProduct.h>
#include <vtkm/cont/ArrayHandleCompositeVector.h>
#include <vtkm/cont/ArrayHandleConstant.h>
#include <vtkm/cont/ArrayHandleCounting.h>
#include <vtkm/cont/ArrayHandleIndex.h>
#include <vtkm/cont/ArrayHandleSOA.h>
#include <vtkm/cont/ArrayHandleStride.h>
#include <vtkm/cont/ArrayHandleUniformPointCoordinates.h>
#include <vtkm/cont/ArrayHandleXGCCoordinates.h>
#include <vtkm/cont/DeviceAdapterTag.h>
#include <vtkm/cont/UnknownArrayHandle.h>
@ -31,30 +21,116 @@ namespace vtkm
namespace cont
{
/// @{
/// \brief Compute the range of the data in an array handle.
///
/// Given an `ArrayHandle`, this function computes the range (min and max) of
/// the values in the array. For arrays containing Vec values, the range is
/// computed for each component.
/// computed for each component, and in the case of nested Vecs, ranges are computed
/// for each of the leaf components.
///
/// This method optionally takes a `vtkm::cont::DeviceAdapterId` to control which
/// devices to try.
/// \param array The input array as a `vtkm::cont::UnknownArrayHandle`.
/// \param maskArray An array handle of type `vtkm::cont::ArrayHandle<vtkm::UInt8>`.
/// This array should have the same number of elements as the input array
/// with each value representing the masking status of the corresponding
/// value in the input array (masked if 0 else unmasked). Ignored if empty.
/// \param computeFiniteRange Optional boolean parameter to specify if non-finite values in the
/// array should be ignored to compute the finite range of
/// the array. For Vec types, individual component values
/// are considered independantly.
/// \param device This optional parameter can be used to specify a device to run the
/// range computation on. The default value is `vtkm::cont::DeviceAdapterTagAny{}`.
///
/// The result is returned in an `ArrayHandle` of `Range` objects. There is
/// \return The result is returned in an `ArrayHandle` of `Range` objects. There is
/// one value in the returned array for every component of the input's value
/// type.
/// type. For nested Vecs the results are stored in depth-first order.
///
/// Note that the ArrayRangeCompute.h header file contains only precompiled overloads
/// of ArrayRangeCompute. This is so that ArrayRangeCompute.h can be included in
/// code that does not use a device compiler. If you need to compute array ranges
/// for arbitrary `ArrayHandle`s not in this precompiled list, you need to use
/// `ArrayRangeComputeTemplate` (declared in `ArrayRangeComputeTemplate`), which
/// will compile for any `ArrayHandle` type not already handled.
/// \note `ArrayRangeCompute` takes an UnknownArrayHandle as the input.
/// The implementation uses precompiled and specicialized code for several of the
/// most commonly used value and storage types, with a fallback for other cases.
/// This is so that ArrayRangeCompute.h can be included in code that does not use a
/// device compiler. This should be sufficient for most cases, but if you need to
/// compute the range for an array type that is not explicitly handled by
/// `ArrayRangeCompute` and the fallback code is not performant, use the
/// templated version `ArrayRangeComputeTemplate`. Specializations can be
/// implemented by specializing the template class `ArrayRangeComputeImpl`.
/// Please refer to ArrayRangeComputeTemplate.h for details
///
/// \sa ArrayRangeComputeTemplate
///
VTKM_CONT_EXPORT vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(
const vtkm::cont::UnknownArrayHandle& array,
bool computeFiniteRange = false,
vtkm::cont::DeviceAdapterId device = vtkm::cont::DeviceAdapterTagAny{});
VTKM_CONT_EXPORT vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(
const vtkm::cont::UnknownArrayHandle& array,
const vtkm::cont::ArrayHandle<vtkm::UInt8>& maskArray,
bool computeFiniteRange = false,
vtkm::cont::DeviceAdapterId device = vtkm::cont::DeviceAdapterTagAny{});
inline vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(
const vtkm::cont::UnknownArrayHandle& array,
vtkm::cont::DeviceAdapterId device)
{
return ArrayRangeCompute(array, false, device);
}
/// @}
/// @{
/// \brief Compute the range of the magnitude of the Vec data in an array handle.
///
/// Given an `ArrayHandle`, this function computes the range (min and max) of
/// the magnitude of the values in the array.
///
/// \param array The input array as a `vtkm::cont::UnknownArrayHandle`.
/// \param maskArray An array handle of type `vtkm::cont::ArrayHandle<vtkm::UInt8>`.
/// This array should have the same number of elements as the input array
/// with each value representing the masking status of the corresponding
/// value in the input array (masked if 0 else unmasked). Ignored if empty.
/// \param computeFiniteRange Optional boolean value to specify if non-finite values in the
/// array should be ignored to compute the finite range of
/// the array. A Vec with any non-finite component will be
/// ignored.
/// \param device This optional parameter can be used to specify a device to run the
/// range computation on. The default value is `vtkm::cont::DeviceAdapterTagAny{}`.
///
/// \return The result is returned in a single `Range` objects.
///
/// \note `ArrayRangeComputeMagnitude` takes an UnknownArrayHandle as the input.
/// The implementation uses precompiled and specicialized code for several of the
/// most commonly used value and storage types, with a fallback for other cases.
/// This is so that ArrayRangeCompute.h can be included in code that does not use a
/// device compiler. This should be sufficient for most cases, but if you need to
/// compute the range for an array type that is not explicitly handled by
/// `ArrayRangeComputeMagnitude` and the fallback code is not performant, use the
/// templated version `ArrayRangeComputeMagnitudeTemplate`. Specializations can be
/// implemented by specializing the template class `ArrayRangeComputeMagnitudeImpl`.
/// Please refer to ArrayRangeComputeTemplate.h for details
///
/// \sa ArrayRangeComputeMagnitudeTemplate
///
VTKM_CONT_EXPORT vtkm::Range ArrayRangeComputeMagnitude(
const vtkm::cont::UnknownArrayHandle& array,
bool computeFiniteRange = false,
vtkm::cont::DeviceAdapterId device = vtkm::cont::DeviceAdapterTagAny{});
VTKM_CONT_EXPORT vtkm::Range ArrayRangeComputeMagnitude(
const vtkm::cont::UnknownArrayHandle& array,
const vtkm::cont::ArrayHandle<vtkm::UInt8>& maskArray,
bool computeFiniteRange = false,
vtkm::cont::DeviceAdapterId device = vtkm::cont::DeviceAdapterTagAny{});
inline vtkm::Range ArrayRangeComputeMagnitude(const vtkm::cont::UnknownArrayHandle& array,
vtkm::cont::DeviceAdapterId device)
{
return ArrayRangeComputeMagnitude(array, false, device);
}
/// @}
namespace internal
{

@ -10,257 +10,531 @@
#ifndef vtk_m_cont_ArrayRangeComputeTemplate_h
#define vtk_m_cont_ArrayRangeComputeTemplate_h
#include <vtkm/cont/ArrayRangeCompute.h>
#include <vtkm/cont/Algorithm.h>
#include <vtkm/cont/ArrayHandleCast.h>
#include <vtkm/cont/ArrayHandleDecorator.h>
#include <vtkm/cont/ArrayHandleTransform.h>
#include <vtkm/cont/internal/ArrayRangeComputeUtils.h>
#include <vtkm/BinaryOperators.h>
#include <vtkm/Deprecated.h>
#include <vtkm/VecFlat.h>
#include <vtkm/VecTraits.h>
#include <vtkm/VectorAnalysis.h>
#include <vtkm/internal/Instantiations.h>
#include <vtkm/cont/Algorithm.h>
#include <limits>
namespace vtkm
{
namespace cont
{
namespace detail
{
struct ArrayRangeComputeFunctor
{
template <typename Device, typename T, typename S>
VTKM_CONT bool operator()(Device,
const vtkm::cont::ArrayHandle<T, S>& handle,
const vtkm::Vec<T, 2>& initialValue,
vtkm::Vec<T, 2>& result) const
{
VTKM_IS_DEVICE_ADAPTER_TAG(Device);
using Algorithm = vtkm::cont::DeviceAdapterAlgorithm<Device>;
result = Algorithm::Reduce(handle, initialValue, vtkm::MinAndMax<T>());
return true;
}
};
} // namespace detail
namespace internal
{
//-------------------------------------------------------------------------------------------------
struct ComputeRangeOptionsDecorator
{
bool IgnoreInf = false;
template <typename SrcPortal, typename MaskPortal>
struct Functor
{
SrcPortal Src;
MaskPortal Mask;
bool IgnoreInf;
using InValueType = typename SrcPortal::ValueType;
using InVecTraits = vtkm::VecTraits<InValueType>;
using ResultType = vtkm::Vec<vtkm::Vec<vtkm::Float64, InVecTraits::NUM_COMPONENTS>, 2>;
VTKM_EXEC_CONT
ResultType operator()(vtkm::Id idx) const
{
if ((this->Mask.GetNumberOfValues() != 0) && (this->Mask.Get(idx) == 0))
{
return { { vtkm::Range{}.Min }, { vtkm::Range{}.Max } };
}
const auto& inVal = this->Src.Get(idx);
ResultType outVal;
for (vtkm::IdComponent i = 0; i < InVecTraits::NUM_COMPONENTS; ++i)
{
auto val = static_cast<vtkm::Float64>(InVecTraits::GetComponent(inVal, i));
if (vtkm::IsNan(val) || (this->IgnoreInf && !vtkm::IsFinite(val)))
{
outVal[0][i] = vtkm::Range{}.Min;
outVal[1][i] = vtkm::Range{}.Max;
}
else
{
outVal[0][i] = outVal[1][i] = val;
}
}
return outVal;
}
};
template <typename SrcPortal, typename GhostPortal>
Functor<SrcPortal, GhostPortal> CreateFunctor(const SrcPortal& sp, const GhostPortal& gp) const
{
return { sp, gp, this->IgnoreInf };
}
};
template <typename ArrayHandleType>
struct ArrayValueIsNested
{
static constexpr bool Value =
!vtkm::internal::IsFlatVec<typename ArrayHandleType::ValueType>::value;
};
template <typename ArrayHandleType, bool IsNested = ArrayValueIsNested<ArrayHandleType>::Value>
struct NestedToFlat;
template <typename ArrayHandleType>
struct NestedToFlat<ArrayHandleType, true>
{
static auto Transform(const ArrayHandleType& in)
{
return vtkm::cont::ArrayHandleCast<vtkm::VecFlat<typename ArrayHandleType::ValueType>,
ArrayHandleType>(in);
}
};
template <typename ArrayHandleType>
struct NestedToFlat<ArrayHandleType, false>
{
static auto Transform(const ArrayHandleType& in) { return in; }
};
template <typename ArrayHandleType>
inline auto NestedToFlatTransform(const ArrayHandleType& input)
{
return NestedToFlat<ArrayHandleType>::Transform(input);
}
//-------------------------------------------------------------------------------------------------
/// \brief A generic implementation of `ArrayRangeCompute`. This is the implementation used
/// when `ArrayRangeComputeImpl` is not specialized.
///
template <typename T, typename S>
inline vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeComputeGeneric(
const vtkm::cont::ArrayHandle<T, S>& input,
const vtkm::cont::ArrayHandle<vtkm::UInt8>& maskArray,
bool computeFiniteRange,
vtkm::cont::DeviceAdapterId device)
{
VTKM_LOG_SCOPE(vtkm::cont::LogLevel::Perf, "ArrayRangeCompute");
using VecTraits = vtkm::VecTraits<T>;
using CT = typename VecTraits::ComponentType;
//We want to minimize the amount of code that we do in try execute as
//it is repeated for each
vtkm::cont::ArrayHandle<vtkm::Range> range;
range.Allocate(VecTraits::NUM_COMPONENTS);
//We want to minimize the amount of code that we do in try execute as
//it is repeated for each
if (input.GetNumberOfValues() < 1)
{
auto portal = range.WritePortal();
for (vtkm::IdComponent i = 0; i < VecTraits::NUM_COMPONENTS; ++i)
{
portal.Set(i, vtkm::Range());
}
range.Fill(vtkm::Range{});
}
else
{
//We used the limits, so that we don't need to sync the array handle
//
vtkm::Vec<T, 2> result;
vtkm::Vec<T, 2> initial;
initial[0] = T(std::numeric_limits<CT>::max());
initial[1] = T(std::numeric_limits<CT>::lowest());
// if input is an array of nested vectors, transform them to `VecFlat` using ArrayHandleCast
auto flattened = NestedToFlatTransform(input);
ComputeRangeOptionsDecorator decorator{ computeFiniteRange };
auto decorated =
make_ArrayHandleDecorator(flattened.GetNumberOfValues(), decorator, flattened, maskArray);
const bool rangeComputed = vtkm::cont::TryExecuteOnDevice(
device, vtkm::cont::detail::ArrayRangeComputeFunctor{}, input, initial, result);
if (!rangeComputed)
using ResultType = vtkm::Vec<vtkm::Vec<vtkm::Float64, VecTraits::NUM_COMPONENTS>, 2>;
using MinAndMaxFunctor = vtkm::MinAndMax<typename ResultType::ComponentType>;
ResultType identity{ { vtkm::Range{}.Min }, { vtkm::Range{}.Max } };
auto result = vtkm::cont::Algorithm::Reduce(device, decorated, identity, MinAndMaxFunctor{});
auto portal = range.WritePortal();
for (vtkm::IdComponent i = 0; i < VecTraits::NUM_COMPONENTS; ++i)
{
ThrowArrayRangeComputeFailed();
portal.Set(i, vtkm::Range(result[0][i], result[1][i]));
}
else
}
return range;
}
//-------------------------------------------------------------------------------------------------
struct ScalarMagnitudeFunctor
{
template <typename T>
VTKM_EXEC_CONT vtkm::Float64 operator()(const T& val) const
{
// spcilization of `vtkm::Magnitude` for scalars should avoid `sqrt` computation by using `abs`
// instead
return static_cast<vtkm::Float64>(vtkm::Magnitude(val));
}
};
struct MagnitudeSquareFunctor
{
template <typename T>
VTKM_EXEC_CONT vtkm::Float64 operator()(const T& val) const
{
using VecTraits = vtkm::VecTraits<T>;
vtkm::Float64 result = 0;
for (vtkm::IdComponent i = 0; i < VecTraits::GetNumberOfComponents(val); ++i)
{
auto portal = range.WritePortal();
for (vtkm::IdComponent i = 0; i < VecTraits::NUM_COMPONENTS; ++i)
{
portal.Set(i,
vtkm::Range(VecTraits::GetComponent(result[0], i),
VecTraits::GetComponent(result[1], i)));
}
auto comp = static_cast<vtkm::Float64>(VecTraits::GetComponent(val, i));
result += comp * comp;
}
return result;
}
};
template <typename ArrayHandleType>
vtkm::Range ArrayRangeComputeMagnitudeGenericImpl(
vtkm::VecTraitsTagSingleComponent,
const ArrayHandleType& input,
const vtkm::cont::ArrayHandle<vtkm::UInt8>& maskArray,
bool computeFiniteRange,
vtkm::cont::DeviceAdapterId device)
{
auto mag = vtkm::cont::make_ArrayHandleTransform(input, ScalarMagnitudeFunctor{});
auto rangeAH = ArrayRangeComputeGeneric(mag, maskArray, computeFiniteRange, device);
return rangeAH.ReadPortal().Get(0);
}
template <typename ArrayHandleType>
vtkm::Range ArrayRangeComputeMagnitudeGenericImpl(
vtkm::VecTraitsTagMultipleComponents,
const ArrayHandleType& input,
const vtkm::cont::ArrayHandle<vtkm::UInt8>& maskArray,
bool computeFiniteRange,
vtkm::cont::DeviceAdapterId device)
{
auto magsqr = vtkm::cont::make_ArrayHandleTransform(input, MagnitudeSquareFunctor{});
auto rangeAH = ArrayRangeComputeGeneric(magsqr, maskArray, computeFiniteRange, device);
auto range = rangeAH.ReadPortal().Get(0);
if (range.IsNonEmpty())
{
range.Min = vtkm::Sqrt(range.Min);
range.Max = vtkm::Sqrt(range.Max);
}
return range;
}
/// \brief A generic implementation of `ArrayRangeComputeMagnitude`. This is the implementation used
/// when `ArrayRangeComputeMagnitudeImpl` is not specialized.
///
template <typename T, typename S>
inline vtkm::Range ArrayRangeComputeMagnitudeGeneric(
const vtkm::cont::ArrayHandle<T, S>& input,
const vtkm::cont::ArrayHandle<vtkm::UInt8>& maskArray,
bool computeFiniteRange,
vtkm::cont::DeviceAdapterId device)
{
VTKM_LOG_SCOPE(vtkm::cont::LogLevel::Perf, "ArrayRangeComputeMagnitude");
using VecTraits = vtkm::VecTraits<T>;
//We want to minimize the amount of code that we do in try execute as
//it is repeated for each
if (input.GetNumberOfValues() < 1)
{
return vtkm::Range{};
}
auto flattened = NestedToFlatTransform(input);
return ArrayRangeComputeMagnitudeGenericImpl(
typename VecTraits::HasMultipleComponents{}, flattened, maskArray, computeFiniteRange, device);
}
//-------------------------------------------------------------------------------------------------
template <typename S>
struct ArrayRangeComputeImpl
{
template <typename T>
vtkm::cont::ArrayHandle<vtkm::Range> operator()(const vtkm::cont::ArrayHandle<T, S>& input,
vtkm::cont::DeviceAdapterId device) const
vtkm::cont::ArrayHandle<vtkm::Range> operator()(
const vtkm::cont::ArrayHandle<T, S>& input,
const vtkm::cont::ArrayHandle<vtkm::UInt8>& maskArray,
bool computeFiniteRange,
vtkm::cont::DeviceAdapterId device) const
{
return vtkm::cont::internal::ArrayRangeComputeGeneric(input, device);
return vtkm::cont::internal::ArrayRangeComputeGeneric(
input, maskArray, computeFiniteRange, device);
}
};
template <typename S>
struct ArrayRangeComputeMagnitudeImpl
{
template <typename T>
vtkm::Range operator()(const vtkm::cont::ArrayHandle<T, S>& input,
const vtkm::cont::ArrayHandle<vtkm::UInt8>& maskArray,
bool computeFiniteRange,
vtkm::cont::DeviceAdapterId device) const
{
return vtkm::cont::internal::ArrayRangeComputeMagnitudeGeneric(
input, maskArray, computeFiniteRange, device);
}
};
} // namespace internal
template <typename ArrayHandleType>
vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeComputeTemplate(
const ArrayHandleType& input,
//-------------------------------------------------------------------------------------------------
/// @{
/// \brief Templated version of ArrayRangeCompute
/// \sa ArrayRangeCompute
///
template <typename T, typename S>
inline vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeComputeTemplate(
const vtkm::cont::ArrayHandle<T, S>& input,
bool computeFiniteRange = false,
vtkm::cont::DeviceAdapterId device = vtkm::cont::DeviceAdapterTagAny{})
{
VTKM_IS_ARRAY_HANDLE(ArrayHandleType);
return internal::ArrayRangeComputeImpl<typename ArrayHandleType::StorageTag>{}(input, device);
return ArrayRangeComputeTemplate(
input, vtkm::cont::ArrayHandle<vtkm::UInt8>{}, computeFiniteRange, device);
}
template <typename T, typename S>
vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeComputeTemplate(
const vtkm::cont::ArrayHandle<T, S>& input,
const vtkm::cont::ArrayHandle<vtkm::UInt8>& maskArray,
bool computeFiniteRange = false,
vtkm::cont::DeviceAdapterId device = vtkm::cont::DeviceAdapterTagAny{})
{
VTKM_ASSERT(maskArray.GetNumberOfValues() == 0 ||
maskArray.GetNumberOfValues() == input.GetNumberOfValues());
return internal::ArrayRangeComputeImpl<S>{}(input, maskArray, computeFiniteRange, device);
}
template <typename T, typename S>
inline vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeComputeTemplate(
const vtkm::cont::ArrayHandle<T, S>& input,
vtkm::cont::DeviceAdapterId device)
{
return ArrayRangeComputeTemplate(input, false, device);
}
/// @}
/// @{
/// \brief Templated version of ArrayRangeComputeMagnitude
/// \sa ArrayRangeComputeMagnitude
///
template <typename T, typename S>
inline vtkm::Range ArrayRangeComputeMagnitudeTemplate(
const vtkm::cont::ArrayHandle<T, S>& input,
bool computeFiniteRange = false,
vtkm::cont::DeviceAdapterId device = vtkm::cont::DeviceAdapterTagAny{})
{
return ArrayRangeComputeMagnitudeTemplate(
input, vtkm::cont::ArrayHandle<vtkm::UInt8>{}, computeFiniteRange, device);
}
template <typename T, typename S>
vtkm::Range ArrayRangeComputeMagnitudeTemplate(
const vtkm::cont::ArrayHandle<T, S>& input,
const vtkm::cont::ArrayHandle<vtkm::UInt8>& maskArray,
bool computeFiniteRange = false,
vtkm::cont::DeviceAdapterId device = vtkm::cont::DeviceAdapterTagAny{})
{
VTKM_ASSERT(maskArray.GetNumberOfValues() == 0 ||
maskArray.GetNumberOfValues() == input.GetNumberOfValues());
return internal::ArrayRangeComputeMagnitudeImpl<S>{}(
input, maskArray, computeFiniteRange, device);
}
template <typename T, typename S>
inline vtkm::Range ArrayRangeComputeMagnitudeTemplate(const vtkm::cont::ArrayHandle<T, S>& input,
vtkm::cont::DeviceAdapterId device)
{
return ArrayRangeComputeMagnitudeTemplate(input, false, device);
}
/// @}
//-----------------------------------------------------------------------------
template <typename ArrayHandleType>
VTKM_DEPRECATED(2.1, "Use precompiled ArrayRangeCompute or ArrayRangeComputeTemplate.")
inline vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(
const ArrayHandleType& input,
vtkm::cont::DeviceAdapterId device = vtkm::cont::DeviceAdapterTagAny{})
{
return ArrayRangeComputeTemplate(input, device);
return ArrayRangeComputeTemplate(input, false, device);
}
}
} // namespace vtkm::cont
#define VTK_M_ARRAY_RANGE_COMPUTE_ALL_SCALARS(modifiers, ...) \
modifiers vtkm::cont::ArrayHandle<vtkm::Range> vtkm::cont::ArrayRangeComputeTemplate( \
const vtkm::cont::ArrayHandle<vtkm::Int8, __VA_ARGS__>& input, \
vtkm::cont::DeviceAdapterId device); \
modifiers vtkm::cont::ArrayHandle<vtkm::Range> vtkm::cont::ArrayRangeComputeTemplate( \
const vtkm::cont::ArrayHandle<vtkm::UInt8, __VA_ARGS__>& input, \
vtkm::cont::DeviceAdapterId device); \
modifiers vtkm::cont::ArrayHandle<vtkm::Range> vtkm::cont::ArrayRangeComputeTemplate( \
const vtkm::cont::ArrayHandle<vtkm::Int16, __VA_ARGS__>& input, \
vtkm::cont::DeviceAdapterId device); \
modifiers vtkm::cont::ArrayHandle<vtkm::Range> vtkm::cont::ArrayRangeComputeTemplate( \
const vtkm::cont::ArrayHandle<vtkm::UInt16, __VA_ARGS__>& input, \
vtkm::cont::DeviceAdapterId device); \
modifiers vtkm::cont::ArrayHandle<vtkm::Range> vtkm::cont::ArrayRangeComputeTemplate( \
const vtkm::cont::ArrayHandle<vtkm::Int32, __VA_ARGS__>& input, \
vtkm::cont::DeviceAdapterId device); \
modifiers vtkm::cont::ArrayHandle<vtkm::Range> vtkm::cont::ArrayRangeComputeTemplate( \
const vtkm::cont::ArrayHandle<vtkm::UInt32, __VA_ARGS__>& input, \
vtkm::cont::DeviceAdapterId device); \
modifiers vtkm::cont::ArrayHandle<vtkm::Range> vtkm::cont::ArrayRangeComputeTemplate( \
const vtkm::cont::ArrayHandle<vtkm::Int64, __VA_ARGS__>& input, \
vtkm::cont::DeviceAdapterId device); \
modifiers vtkm::cont::ArrayHandle<vtkm::Range> vtkm::cont::ArrayRangeComputeTemplate( \
const vtkm::cont::ArrayHandle<vtkm::UInt64, __VA_ARGS__>& input, \
vtkm::cont::DeviceAdapterId device); \
modifiers vtkm::cont::ArrayHandle<vtkm::Range> vtkm::cont::ArrayRangeComputeTemplate( \
const vtkm::cont::ArrayHandle<vtkm::Float32, __VA_ARGS__>& input, \
vtkm::cont::DeviceAdapterId device); \
modifiers vtkm::cont::ArrayHandle<vtkm::Range> vtkm::cont::ArrayRangeComputeTemplate( \
const vtkm::cont::ArrayHandle<vtkm::Float64, __VA_ARGS__>& input, \
vtkm::cont::DeviceAdapterId device); \
modifiers vtkm::cont::ArrayHandle<vtkm::Range> vtkm::cont::ArrayRangeComputeTemplate( \
const vtkm::cont::ArrayHandle<bool, __VA_ARGS__>& input, vtkm::cont::DeviceAdapterId device); \
modifiers vtkm::cont::ArrayHandle<vtkm::Range> vtkm::cont::ArrayRangeComputeTemplate( \
const vtkm::cont::ArrayHandle<char, __VA_ARGS__>& input, vtkm::cont::DeviceAdapterId device); \
modifiers vtkm::cont::ArrayHandle<vtkm::Range> vtkm::cont::ArrayRangeComputeTemplate( \
const vtkm::cont::ArrayHandle<signed VTKM_UNUSED_INT_TYPE, __VA_ARGS__>& input, \
vtkm::cont::DeviceAdapterId device); \
modifiers vtkm::cont::ArrayHandle<vtkm::Range> vtkm::cont::ArrayRangeComputeTemplate( \
const vtkm::cont::ArrayHandle<unsigned VTKM_UNUSED_INT_TYPE, __VA_ARGS__>& input, \
vtkm::cont::DeviceAdapterId device)
#define VTK_M_ARRAY_RANGE_COMPUTE_DCLR(...) \
vtkm::cont::ArrayHandle<vtkm::Range> vtkm::cont::ArrayRangeComputeTemplate( \
const vtkm::cont::ArrayHandle<__VA_ARGS__>&, \
const vtkm::cont::ArrayHandle<vtkm::UInt8>&, \
bool, \
vtkm::cont::DeviceAdapterId)
#define VTK_M_ARRAY_RANGE_COMPUTE_ALL_VECN(modifiers, N, ...) \
modifiers vtkm::cont::ArrayHandle<vtkm::Range> vtkm::cont::ArrayRangeComputeTemplate( \
const vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Int8, N>, __VA_ARGS__>& input, \
vtkm::cont::DeviceAdapterId device); \
modifiers vtkm::cont::ArrayHandle<vtkm::Range> vtkm::cont::ArrayRangeComputeTemplate( \
const vtkm::cont::ArrayHandle<vtkm::Vec<UInt8, N>, __VA_ARGS__>& input, \
vtkm::cont::DeviceAdapterId device); \
modifiers vtkm::cont::ArrayHandle<vtkm::Range> vtkm::cont::ArrayRangeComputeTemplate( \
const vtkm::cont::ArrayHandle<vtkm::Vec<Int16, N>, __VA_ARGS__>& input, \
vtkm::cont::DeviceAdapterId device); \
modifiers vtkm::cont::ArrayHandle<vtkm::Range> vtkm::cont::ArrayRangeComputeTemplate( \
const vtkm::cont::ArrayHandle<vtkm::Vec<UInt16, N>, __VA_ARGS__>& input, \
vtkm::cont::DeviceAdapterId device); \
modifiers vtkm::cont::ArrayHandle<vtkm::Range> vtkm::cont::ArrayRangeComputeTemplate( \
const vtkm::cont::ArrayHandle<vtkm::Vec<Int32, N>, __VA_ARGS__>& input, \
vtkm::cont::DeviceAdapterId device); \
modifiers vtkm::cont::ArrayHandle<vtkm::Range> vtkm::cont::ArrayRangeComputeTemplate( \
const vtkm::cont::ArrayHandle<vtkm::Vec<UInt32, N>, __VA_ARGS__>& input, \
vtkm::cont::DeviceAdapterId device); \
modifiers vtkm::cont::ArrayHandle<vtkm::Range> vtkm::cont::ArrayRangeComputeTemplate( \
const vtkm::cont::ArrayHandle<vtkm::Vec<Int64, N>, __VA_ARGS__>& input, \
vtkm::cont::DeviceAdapterId device); \
modifiers vtkm::cont::ArrayHandle<vtkm::Range> vtkm::cont::ArrayRangeComputeTemplate( \
const vtkm::cont::ArrayHandle<vtkm::Vec<UInt64, N>, __VA_ARGS__>& input, \
vtkm::cont::DeviceAdapterId device); \
modifiers vtkm::cont::ArrayHandle<vtkm::Range> vtkm::cont::ArrayRangeComputeTemplate( \
const vtkm::cont::ArrayHandle<vtkm::Vec<Float32, N>, __VA_ARGS__>& input, \
vtkm::cont::DeviceAdapterId device); \
modifiers vtkm::cont::ArrayHandle<vtkm::Range> vtkm::cont::ArrayRangeComputeTemplate( \
const vtkm::cont::ArrayHandle<vtkm::Vec<Float64, N>, __VA_ARGS__>& input, \
vtkm::cont::DeviceAdapterId device); \
modifiers vtkm::cont::ArrayHandle<vtkm::Range> vtkm::cont::ArrayRangeComputeTemplate( \
const vtkm::cont::ArrayHandle<vtkm::Vec<bool, N>, __VA_ARGS__>& input, \
vtkm::cont::DeviceAdapterId device); \
modifiers vtkm::cont::ArrayHandle<vtkm::Range> vtkm::cont::ArrayRangeComputeTemplate( \
const vtkm::cont::ArrayHandle<vtkm::Vec<char, N>, __VA_ARGS__>& input, \
vtkm::cont::DeviceAdapterId device); \
modifiers vtkm::cont::ArrayHandle<vtkm::Range> vtkm::cont::ArrayRangeComputeTemplate( \
const vtkm::cont::ArrayHandle<vtkm::Vec<signed VTKM_UNUSED_INT_TYPE, N>, __VA_ARGS__>& input, \
vtkm::cont::DeviceAdapterId device); \
modifiers vtkm::cont::ArrayHandle<vtkm::Range> vtkm::cont::ArrayRangeComputeTemplate( \
const vtkm::cont::ArrayHandle<vtkm::Vec<unsigned VTKM_UNUSED_INT_TYPE, N>, __VA_ARGS__>& \
input, \
vtkm::cont::DeviceAdapterId device)
#define VTK_M_ARRAY_RANGE_COMPUTE_MAG_DCLR(...) \
vtkm::Range vtkm::cont::ArrayRangeComputeMagnitudeTemplate( \
const vtkm::cont::ArrayHandle<__VA_ARGS__>&, \
const vtkm::cont::ArrayHandle<vtkm::UInt8>&, \
bool, \
vtkm::cont::DeviceAdapterId)
#define VTK_M_ARRAY_RANGE_COMPUTE_INT_SCALARS(modifiers, ...) \
modifiers VTK_M_ARRAY_RANGE_COMPUTE_DCLR(vtkm::Int8, __VA_ARGS__); \
modifiers VTK_M_ARRAY_RANGE_COMPUTE_MAG_DCLR(vtkm::Int8, __VA_ARGS__); \
modifiers VTK_M_ARRAY_RANGE_COMPUTE_DCLR(vtkm::UInt8, __VA_ARGS__); \
modifiers VTK_M_ARRAY_RANGE_COMPUTE_MAG_DCLR(vtkm::UInt8, __VA_ARGS__); \
modifiers VTK_M_ARRAY_RANGE_COMPUTE_DCLR(vtkm::Int16, __VA_ARGS__); \
modifiers VTK_M_ARRAY_RANGE_COMPUTE_MAG_DCLR(vtkm::Int16, __VA_ARGS__); \
modifiers VTK_M_ARRAY_RANGE_COMPUTE_DCLR(vtkm::UInt16, __VA_ARGS__); \
modifiers VTK_M_ARRAY_RANGE_COMPUTE_MAG_DCLR(vtkm::UInt16, __VA_ARGS__); \
modifiers VTK_M_ARRAY_RANGE_COMPUTE_DCLR(vtkm::Int32, __VA_ARGS__); \
modifiers VTK_M_ARRAY_RANGE_COMPUTE_MAG_DCLR(vtkm::Int32, __VA_ARGS__); \
modifiers VTK_M_ARRAY_RANGE_COMPUTE_DCLR(vtkm::UInt32, __VA_ARGS__); \
modifiers VTK_M_ARRAY_RANGE_COMPUTE_MAG_DCLR(vtkm::UInt32, __VA_ARGS__); \
modifiers VTK_M_ARRAY_RANGE_COMPUTE_DCLR(vtkm::Int64, __VA_ARGS__); \
modifiers VTK_M_ARRAY_RANGE_COMPUTE_MAG_DCLR(vtkm::Int64, __VA_ARGS__); \
modifiers VTK_M_ARRAY_RANGE_COMPUTE_DCLR(vtkm::UInt64, __VA_ARGS__); \
modifiers VTK_M_ARRAY_RANGE_COMPUTE_MAG_DCLR(vtkm::UInt64, __VA_ARGS__)
#define VTK_M_ARRAY_RANGE_COMPUTE_FLOAT_SCALARS(modifiers, ...) \
modifiers VTK_M_ARRAY_RANGE_COMPUTE_DCLR(vtkm::Float32, __VA_ARGS__); \
modifiers VTK_M_ARRAY_RANGE_COMPUTE_MAG_DCLR(vtkm::Float32, __VA_ARGS__); \
modifiers VTK_M_ARRAY_RANGE_COMPUTE_DCLR(vtkm::Float64, __VA_ARGS__); \
modifiers VTK_M_ARRAY_RANGE_COMPUTE_MAG_DCLR(vtkm::Float64, __VA_ARGS__)
#define VTK_M_ARRAY_RANGE_COMPUTE_BOOL_SCALARS(modifiers, ...) \
modifiers VTK_M_ARRAY_RANGE_COMPUTE_DCLR(bool, __VA_ARGS__); \
modifiers VTK_M_ARRAY_RANGE_COMPUTE_MAG_DCLR(bool, __VA_ARGS__)
#define VTK_M_ARRAY_RANGE_COMPUTE_OTHER_SCALARS(modifiers, ...) \
modifiers VTK_M_ARRAY_RANGE_COMPUTE_DCLR(char, __VA_ARGS__); \
modifiers VTK_M_ARRAY_RANGE_COMPUTE_MAG_DCLR(char, __VA_ARGS__); \
modifiers VTK_M_ARRAY_RANGE_COMPUTE_DCLR(signed VTKM_UNUSED_INT_TYPE, __VA_ARGS__); \
modifiers VTK_M_ARRAY_RANGE_COMPUTE_MAG_DCLR(signed VTKM_UNUSED_INT_TYPE, __VA_ARGS__); \
modifiers VTK_M_ARRAY_RANGE_COMPUTE_DCLR(unsigned VTKM_UNUSED_INT_TYPE, __VA_ARGS__); \
modifiers VTK_M_ARRAY_RANGE_COMPUTE_MAG_DCLR(unsigned VTKM_UNUSED_INT_TYPE, __VA_ARGS__)
#define VTK_M_ARRAY_RANGE_COMPUTE_ALL_SCALARS(modifiers, ...) \
VTK_M_ARRAY_RANGE_COMPUTE_INT_SCALARS(modifiers, __VA_ARGS__); \
VTK_M_ARRAY_RANGE_COMPUTE_FLOAT_SCALARS(modifiers, __VA_ARGS__); \
VTK_M_ARRAY_RANGE_COMPUTE_BOOL_SCALARS(modifiers, __VA_ARGS__); \
VTK_M_ARRAY_RANGE_COMPUTE_OTHER_SCALARS(modifiers, __VA_ARGS__)
#define VTK_M_ARRAY_RANGE_COMPUTE_INT_VECN(modifiers, N, ...) \
modifiers VTK_M_ARRAY_RANGE_COMPUTE_DCLR(vtkm::Vec<vtkm::Int8, N>, __VA_ARGS__); \
modifiers VTK_M_ARRAY_RANGE_COMPUTE_MAG_DCLR(vtkm::Vec<vtkm::Int8, N>, __VA_ARGS__); \
modifiers VTK_M_ARRAY_RANGE_COMPUTE_DCLR(vtkm::Vec<vtkm::UInt8, N>, __VA_ARGS__); \
modifiers VTK_M_ARRAY_RANGE_COMPUTE_MAG_DCLR(vtkm::Vec<vtkm::UInt8, N>, __VA_ARGS__); \
modifiers VTK_M_ARRAY_RANGE_COMPUTE_DCLR(vtkm::Vec<vtkm::Int16, N>, __VA_ARGS__); \
modifiers VTK_M_ARRAY_RANGE_COMPUTE_MAG_DCLR(vtkm::Vec<vtkm::Int16, N>, __VA_ARGS__); \
modifiers VTK_M_ARRAY_RANGE_COMPUTE_DCLR(vtkm::Vec<vtkm::UInt16, N>, __VA_ARGS__); \
modifiers VTK_M_ARRAY_RANGE_COMPUTE_MAG_DCLR(vtkm::Vec<vtkm::UInt16, N>, __VA_ARGS__); \
modifiers VTK_M_ARRAY_RANGE_COMPUTE_DCLR(vtkm::Vec<vtkm::Int32, N>, __VA_ARGS__); \
modifiers VTK_M_ARRAY_RANGE_COMPUTE_MAG_DCLR(vtkm::Vec<vtkm::Int32, N>, __VA_ARGS__); \
modifiers VTK_M_ARRAY_RANGE_COMPUTE_DCLR(vtkm::Vec<vtkm::UInt32, N>, __VA_ARGS__); \
modifiers VTK_M_ARRAY_RANGE_COMPUTE_MAG_DCLR(vtkm::Vec<vtkm::UInt32, N>, __VA_ARGS__); \
modifiers VTK_M_ARRAY_RANGE_COMPUTE_DCLR(vtkm::Vec<vtkm::Int64, N>, __VA_ARGS__); \
modifiers VTK_M_ARRAY_RANGE_COMPUTE_MAG_DCLR(vtkm::Vec<vtkm::Int64, N>, __VA_ARGS__); \
modifiers VTK_M_ARRAY_RANGE_COMPUTE_DCLR(vtkm::Vec<vtkm::UInt64, N>, __VA_ARGS__); \
modifiers VTK_M_ARRAY_RANGE_COMPUTE_MAG_DCLR(vtkm::Vec<vtkm::UInt64, N>, __VA_ARGS__)
#define VTK_M_ARRAY_RANGE_COMPUTE_FLOAT_VECN(modifiers, N, ...) \
modifiers VTK_M_ARRAY_RANGE_COMPUTE_DCLR(vtkm::Vec<vtkm::Float32, N>, __VA_ARGS__); \
modifiers VTK_M_ARRAY_RANGE_COMPUTE_MAG_DCLR(vtkm::Vec<vtkm::Float32, N>, __VA_ARGS__); \
modifiers VTK_M_ARRAY_RANGE_COMPUTE_DCLR(vtkm::Vec<vtkm::Float64, N>, __VA_ARGS__); \
modifiers VTK_M_ARRAY_RANGE_COMPUTE_MAG_DCLR(vtkm::Vec<vtkm::Float64, N>, __VA_ARGS__)
#define VTK_M_ARRAY_RANGE_COMPUTE_BOOL_VECN(modifiers, N, ...) \
modifiers VTK_M_ARRAY_RANGE_COMPUTE_DCLR(vtkm::Vec<bool, N>, __VA_ARGS__); \
modifiers VTK_M_ARRAY_RANGE_COMPUTE_MAG_DCLR(vtkm::Vec<bool, N>, __VA_ARGS__)
#define VTK_M_ARRAY_RANGE_COMPUTE_OTHER_VECN(modifiers, N, ...) \
modifiers VTK_M_ARRAY_RANGE_COMPUTE_DCLR(vtkm::Vec<char, N>, __VA_ARGS__); \
modifiers VTK_M_ARRAY_RANGE_COMPUTE_MAG_DCLR(vtkm::Vec<char, N>, __VA_ARGS__); \
modifiers VTK_M_ARRAY_RANGE_COMPUTE_DCLR(vtkm::Vec<signed VTKM_UNUSED_INT_TYPE, N>, \
__VA_ARGS__); \
modifiers VTK_M_ARRAY_RANGE_COMPUTE_MAG_DCLR(vtkm::Vec<signed VTKM_UNUSED_INT_TYPE, N>, \
__VA_ARGS__); \
modifiers VTK_M_ARRAY_RANGE_COMPUTE_DCLR(vtkm::Vec<unsigned VTKM_UNUSED_INT_TYPE, N>, \
__VA_ARGS__); \
modifiers VTK_M_ARRAY_RANGE_COMPUTE_MAG_DCLR(vtkm::Vec<unsigned VTKM_UNUSED_INT_TYPE, N>, \
__VA_ARGS__)
#define VTK_M_ARRAY_RANGE_COMPUTE_ALL_VECN(modifiers, N, ...) \
VTK_M_ARRAY_RANGE_COMPUTE_INT_VECN(modifiers, N, __VA_ARGS__); \
VTK_M_ARRAY_RANGE_COMPUTE_FLOAT_VECN(modifiers, N, __VA_ARGS__); \
VTK_M_ARRAY_RANGE_COMPUTE_BOOL_VECN(modifiers, N, __VA_ARGS__); \
VTK_M_ARRAY_RANGE_COMPUTE_OTHER_VECN(modifiers, N, __VA_ARGS__)
namespace vtkm
{
namespace cont
{
struct StorageTagSOA;
template <typename ST1, typename ST2, typename ST3>
struct StorageTagCartesianProduct;
struct StorageTagConstant;
struct StorageTagCounting;
struct StorageTagXGCCoordinates;
struct StorageTagStride;
}
} // vtkm::cont
//-------------------------------------------------------------------------------------------------
VTKM_INSTANTIATION_BEGIN
VTK_M_ARRAY_RANGE_COMPUTE_ALL_SCALARS(extern template VTKM_CONT_TEMPLATE_EXPORT,
vtkm::cont::StorageTagBasic);
VTKM_INSTANTIATION_END
VTKM_INSTANTIATION_BEGIN
VTK_M_ARRAY_RANGE_COMPUTE_ALL_VECN(extern template VTKM_CONT_TEMPLATE_EXPORT,
2,
vtkm::cont::StorageTagBasic);
VTKM_INSTANTIATION_END
VTKM_INSTANTIATION_BEGIN
VTK_M_ARRAY_RANGE_COMPUTE_ALL_VECN(extern template VTKM_CONT_TEMPLATE_EXPORT,
3,
vtkm::cont::StorageTagBasic);
VTKM_INSTANTIATION_END
VTKM_INSTANTIATION_BEGIN
VTK_M_ARRAY_RANGE_COMPUTE_ALL_VECN(extern template VTKM_CONT_TEMPLATE_EXPORT,
4,
vtkm::cont::StorageTagBasic);
VTKM_INSTANTIATION_END
//-------------------------------------------------------------------------------------------------
VTKM_INSTANTIATION_BEGIN
VTK_M_ARRAY_RANGE_COMPUTE_ALL_VECN(extern template VTKM_CONT_TEMPLATE_EXPORT,
2,
vtkm::cont::StorageTagSOA);
VTKM_INSTANTIATION_END
VTKM_INSTANTIATION_BEGIN
VTK_M_ARRAY_RANGE_COMPUTE_ALL_VECN(extern template VTKM_CONT_TEMPLATE_EXPORT,
3,
vtkm::cont::StorageTagSOA);
VTKM_INSTANTIATION_END
VTKM_INSTANTIATION_BEGIN
VTK_M_ARRAY_RANGE_COMPUTE_ALL_VECN(extern template VTKM_CONT_TEMPLATE_EXPORT,
4,
vtkm::cont::StorageTagSOA);
VTKM_INSTANTIATION_END
//-------------------------------------------------------------------------------------------------
VTKM_INSTANTIATION_BEGIN
VTK_M_ARRAY_RANGE_COMPUTE_ALL_VECN(
VTK_M_ARRAY_RANGE_COMPUTE_FLOAT_VECN(
extern template VTKM_CONT_TEMPLATE_EXPORT,
3,
vtkm::cont::StorageTagCartesianProduct<vtkm::cont::StorageTagBasic,
@ -268,24 +542,87 @@ VTK_M_ARRAY_RANGE_COMPUTE_ALL_VECN(
vtkm::cont::StorageTagBasic>);
VTKM_INSTANTIATION_END
//-------------------------------------------------------------------------------------------------
VTKM_INSTANTIATION_BEGIN
VTK_M_ARRAY_RANGE_COMPUTE_FLOAT_VECN(extern template VTKM_CONT_TEMPLATE_EXPORT,
3,
StorageTagXGCCoordinates);
VTKM_INSTANTIATION_END
//-------------------------------------------------------------------------------------------------
VTKM_INSTANTIATION_BEGIN
VTK_M_ARRAY_RANGE_COMPUTE_ALL_SCALARS(extern template VTKM_CONT_TEMPLATE_EXPORT,
vtkm::cont::StorageTagConstant);
VTKM_INSTANTIATION_END
VTKM_INSTANTIATION_BEGIN
VTK_M_ARRAY_RANGE_COMPUTE_ALL_VECN(extern template VTKM_CONT_TEMPLATE_EXPORT,
2,
vtkm::cont::StorageTagConstant);
VTKM_INSTANTIATION_END
VTKM_INSTANTIATION_BEGIN
VTK_M_ARRAY_RANGE_COMPUTE_ALL_VECN(extern template VTKM_CONT_TEMPLATE_EXPORT,
3,
vtkm::cont::StorageTagConstant);
VTKM_INSTANTIATION_END
VTKM_INSTANTIATION_BEGIN
VTK_M_ARRAY_RANGE_COMPUTE_ALL_VECN(extern template VTKM_CONT_TEMPLATE_EXPORT,
4,
vtkm::cont::StorageTagConstant);
VTKM_INSTANTIATION_END
//-------------------------------------------------------------------------------------------------
VTKM_INSTANTIATION_BEGIN
VTK_M_ARRAY_RANGE_COMPUTE_INT_SCALARS(extern template VTKM_CONT_TEMPLATE_EXPORT,
vtkm::cont::StorageTagCounting);
VTK_M_ARRAY_RANGE_COMPUTE_FLOAT_SCALARS(extern template VTKM_CONT_TEMPLATE_EXPORT,
vtkm::cont::StorageTagCounting);
VTK_M_ARRAY_RANGE_COMPUTE_OTHER_SCALARS(extern template VTKM_CONT_TEMPLATE_EXPORT,
vtkm::cont::StorageTagCounting);
VTKM_INSTANTIATION_END
VTKM_INSTANTIATION_BEGIN
VTK_M_ARRAY_RANGE_COMPUTE_INT_VECN(extern template VTKM_CONT_TEMPLATE_EXPORT,
2,
vtkm::cont::StorageTagCounting);
VTK_M_ARRAY_RANGE_COMPUTE_FLOAT_VECN(extern template VTKM_CONT_TEMPLATE_EXPORT,
2,
vtkm::cont::StorageTagCounting);
VTK_M_ARRAY_RANGE_COMPUTE_OTHER_VECN(extern template VTKM_CONT_TEMPLATE_EXPORT,
2,
vtkm::cont::StorageTagCounting);
VTKM_INSTANTIATION_END
VTKM_INSTANTIATION_BEGIN
VTK_M_ARRAY_RANGE_COMPUTE_INT_VECN(extern template VTKM_CONT_TEMPLATE_EXPORT,
3,
vtkm::cont::StorageTagCounting);
VTK_M_ARRAY_RANGE_COMPUTE_FLOAT_VECN(extern template VTKM_CONT_TEMPLATE_EXPORT,
3,
vtkm::cont::StorageTagCounting);
VTK_M_ARRAY_RANGE_COMPUTE_OTHER_VECN(extern template VTKM_CONT_TEMPLATE_EXPORT,
3,
vtkm::cont::StorageTagCounting);
VTKM_INSTANTIATION_END
VTKM_INSTANTIATION_BEGIN
VTK_M_ARRAY_RANGE_COMPUTE_INT_VECN(extern template VTKM_CONT_TEMPLATE_EXPORT,
4,
vtkm::cont::StorageTagCounting);
VTK_M_ARRAY_RANGE_COMPUTE_FLOAT_VECN(extern template VTKM_CONT_TEMPLATE_EXPORT,
4,
vtkm::cont::StorageTagCounting);
VTK_M_ARRAY_RANGE_COMPUTE_OTHER_VECN(extern template VTKM_CONT_TEMPLATE_EXPORT,
4,
vtkm::cont::StorageTagCounting);
VTKM_INSTANTIATION_END
//-------------------------------------------------------------------------------------------------
VTKM_INSTANTIATION_BEGIN
VTK_M_ARRAY_RANGE_COMPUTE_ALL_SCALARS(extern template VTKM_CONT_TEMPLATE_EXPORT,
vtkm::cont::StorageTagStride);
VTKM_INSTANTIATION_END
#endif //vtk_m_cont_ArrayRangeComputeTemplate_h

@ -0,0 +1,22 @@
//============================================================================
// 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_ArrayRangeComputeTemplateInstantiationsIncludes_h
#define vtk_m_cont_ArrayRangeComputeTemplateInstantiationsIncludes_h
#include <vtkm/cont/ArrayRangeComputeTemplate.h>
#include <vtkm/cont/ArrayHandleCartesianProduct.h>
#include <vtkm/cont/ArrayHandleConstant.h>
#include <vtkm/cont/ArrayHandleCounting.h>
#include <vtkm/cont/ArrayHandleRecombineVec.h>
#include <vtkm/cont/ArrayHandleSOA.h>
#include <vtkm/cont/ArrayHandleXGCCoordinates.h>
#endif // vtk_m_cont_ArrayRangeComputeTemplateInstantiationsIncludes_h

@ -51,6 +51,7 @@ set(headers
ArrayPortalToIterators.h
ArrayRangeCompute.h
ArrayRangeComputeTemplate.h
ArrayRangeComputeTemplateInstantiationsIncludes.h
AssignerPartitionedDataSet.h
AtomicArray.h
BitField.h
@ -135,7 +136,6 @@ set(sources
ArrayHandleBasic.cxx
ArrayHandleSOA.cxx
ArrayHandleStride.cxx
ArrayHandleUniformPointCoordinates.cxx
AssignerPartitionedDataSet.cxx
BitField.cxx
BoundsCompute.cxx
@ -183,6 +183,8 @@ set(sources
set(device_sources
ArrayCopy.cxx
ArrayGetValues.cxx
ArrayHandleIndex.cxx
ArrayHandleUniformPointCoordinates.cxx
ArrayRangeCompute.cxx
CellLocatorBoundingIntervalHierarchy.cxx
CellLocatorUniformBins.cxx
@ -193,6 +195,7 @@ set(device_sources
ConvertNumComponentsToOffsets.cxx
Field.cxx
internal/ArrayCopyUnknown.cxx
internal/ArrayRangeComputeUtils.cxx
internal/Buffer.cxx
internal/MapArrayPermutation.cxx
MergePartitionedDataSet.cxx
@ -268,6 +271,7 @@ vtkm_install_headers(vtkm/cont
# compiles by breaking them up into smaller units.
vtkm_add_instantiations(array_range_instantiations
INSTANTIATIONS_FILE ArrayRangeComputeTemplate.h
TEMPLATE_SOURCE ArrayRangeComputeTemplateInstantiationsIncludes.h
)
list(APPEND device_sources ${array_range_instantiations})

@ -0,0 +1,52 @@
//============================================================================
// 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/ArrayRangeComputeUtils.h>
#include <vtkm/cont/Algorithm.h>
#include <vtkm/cont/ArrayHandleIndex.h>
#include <vtkm/cont/ArrayHandleTransform.h>
#include <vtkm/cont/ArrayHandleZip.h>
#include <vtkm/BinaryOperators.h>
#include <limits>
namespace
{
struct UnmaskedIndicesTransform
{
VTKM_EXEC vtkm::Id2 operator()(vtkm::Pair<vtkm::UInt8, vtkm::Id> in) const
{
if (in.first == 0)
{
return { std::numeric_limits<vtkm::Id>::max(), std::numeric_limits<vtkm::Id>::min() };
}
return { in.second };
}
};
} // namespace
vtkm::Id2 vtkm::cont::internal::GetFirstAndLastUnmaskedIndices(
const vtkm::cont::ArrayHandle<vtkm::UInt8>& maskArray,
vtkm::cont::DeviceAdapterId device)
{
vtkm::Id2 initialValue = { std::numeric_limits<vtkm::Id>::max(),
std::numeric_limits<vtkm::Id>::min() };
auto maskValsAndInds = vtkm::cont::make_ArrayHandleZip(
maskArray, vtkm::cont::ArrayHandleIndex(maskArray.GetNumberOfValues()));
auto unmaskedIndices =
vtkm::cont::make_ArrayHandleTransform(maskValsAndInds, UnmaskedIndicesTransform{});
return vtkm::cont::Algorithm::Reduce(
device, unmaskedIndices, initialValue, vtkm::MinAndMax<vtkm::Id>());
}

@ -0,0 +1,33 @@
//============================================================================
// 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_ArrayRangeComputeUtils_h
#define vtk_m_cont_internal_ArrayRangeComputeUtils_h
#include <vtkm/VecTraits.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/vtkm_cont_export.h>
namespace vtkm
{
namespace cont
{
namespace internal
{
VTKM_CONT_EXPORT vtkm::Id2 GetFirstAndLastUnmaskedIndices(
const vtkm::cont::ArrayHandle<vtkm::UInt8>& maskArray,
vtkm::cont::DeviceAdapterId device = vtkm::cont::DeviceAdapterTagAny{});
}
}
} // vtkm::cont::internal
#endif // vtk_m_cont_internal_ArrayRangeComputeUtils_h

@ -12,6 +12,7 @@ set(headers
ArrayCopyUnknown.h
ArrayHandleExecutionManager.h
ArrayPortalFromIterators.h
ArrayRangeComputeUtils.h
ArrayTransfer.h
Buffer.h
CastInvalidValue.h

@ -36,8 +36,10 @@ namespace
constexpr vtkm::Id ARRAY_SIZE = 20;
template <typename T, typename S>
void VerifyRange(const vtkm::cont::ArrayHandle<T, S>& array,
const vtkm::cont::ArrayHandle<vtkm::Range>& computedRangeArray)
void VerifyRangeScalar(const vtkm::cont::ArrayHandle<T, S>& array,
const vtkm::cont::ArrayHandle<vtkm::Range>& computedRangeArray,
const vtkm::cont::ArrayHandle<vtkm::UInt8>& maskArray,
bool finitesOnly)
{
using Traits = vtkm::VecTraits<T>;
vtkm::IdComponent numComponents = Traits::NUM_COMPONENTS;
@ -46,40 +48,237 @@ void VerifyRange(const vtkm::cont::ArrayHandle<T, S>& array,
auto computedRangePortal = computedRangeArray.ReadPortal();
auto portal = array.ReadPortal();
auto maskPortal = maskArray.ReadPortal();
for (vtkm::IdComponent component = 0; component < numComponents; ++component)
{
vtkm::Range computedRange = computedRangePortal.Get(component);
vtkm::Range expectedRange;
vtkm::Range expectedRange{};
for (vtkm::Id index = 0; index < portal.GetNumberOfValues(); ++index)
{
T value = portal.Get(index);
expectedRange.Include(Traits::GetComponent(value, component));
if (maskPortal.GetNumberOfValues() != 0 && (maskPortal.Get(index) == 0))
{
continue;
}
auto value = static_cast<vtkm::Float64>(Traits::GetComponent(portal.Get(index), component));
if (finitesOnly && !vtkm::IsFinite(value))
{
continue;
}
expectedRange.Include(value);
}
try
{
VTKM_TEST_ASSERT(!vtkm::IsNan(computedRange.Min));
VTKM_TEST_ASSERT(!vtkm::IsNan(computedRange.Max));
VTKM_TEST_ASSERT((!expectedRange.IsNonEmpty() && !computedRange.IsNonEmpty()) ||
(test_equal(expectedRange, computedRange)));
}
catch (const vtkm::testing::Testing::TestFailure&)
{
std::cout << "Test array: \n";
vtkm::cont::printSummary_ArrayHandle(array, std::cout, true);
std::cout << "Mask array: \n";
vtkm::cont::printSummary_ArrayHandle(maskArray, std::cout, true);
std::cout << "Range type: " << (finitesOnly ? "Scalar, Finite" : "Scalar, NonFinite") << "\n";
std::cout << "Computed range: \n";
vtkm::cont::printSummary_ArrayHandle(computedRangeArray, std::cout, true);
std::cout << "Expected range: " << expectedRange << ", component: " << component << "\n";
throw;
}
}
}
template <typename T, typename S>
void VerifyRangeVector(const vtkm::cont::ArrayHandle<T, S>& array,
const vtkm::Range& computedRange,
const vtkm::cont::ArrayHandle<vtkm::UInt8>& maskArray,
bool finitesOnly)
{
auto portal = array.ReadPortal();
auto maskPortal = maskArray.ReadPortal();
vtkm::Range expectedRange{};
for (vtkm::Id index = 0; index < portal.GetNumberOfValues(); ++index)
{
if (maskPortal.GetNumberOfValues() != 0 && (maskPortal.Get(index) == 0))
{
continue;
}
auto value = static_cast<vtkm::Float64>(vtkm::MagnitudeSquared(portal.Get(index)));
if (finitesOnly && !vtkm::IsFinite(value))
{
continue;
}
expectedRange.Include(value);
}
if (expectedRange.IsNonEmpty())
{
expectedRange.Min = vtkm::Sqrt(expectedRange.Min);
expectedRange.Max = vtkm::Sqrt(expectedRange.Max);
}
try
{
VTKM_TEST_ASSERT(!vtkm::IsNan(computedRange.Min));
VTKM_TEST_ASSERT(!vtkm::IsNan(computedRange.Max));
VTKM_TEST_ASSERT(test_equal(expectedRange, computedRange));
VTKM_TEST_ASSERT((!expectedRange.IsNonEmpty() && !computedRange.IsNonEmpty()) ||
(test_equal(expectedRange, computedRange)));
}
catch (const vtkm::testing::Testing::TestFailure&)
{
std::cout << "Test array: \n";
vtkm::cont::printSummary_ArrayHandle(array, std::cout, true);
std::cout << "Mask array: \n";
vtkm::cont::printSummary_ArrayHandle(maskArray, std::cout, true);
std::cout << "Range type: " << (finitesOnly ? "Vector, Finite" : "Vector, NonFinite") << "\n";
std::cout << "Computed range: " << computedRange << "\n";
std::cout << "Expected range: " << expectedRange << "\n";
throw;
}
}
auto FillMaskArray(vtkm::Id length)
{
vtkm::cont::ArrayHandle<vtkm::UInt8> maskArray;
maskArray.Allocate(length);
vtkm::cont::ArrayHandleRandomUniformBits randomBits(length + 1);
auto randomPortal = randomBits.ReadPortal();
switch (randomPortal.Get(length) % 3)
{
case 0: // all masked
maskArray.Fill(0);
break;
case 1: // none masked
maskArray.Fill(1);
break;
case 2: // random masked
default:
{
auto maskPortal = maskArray.WritePortal();
for (vtkm::Id i = 0; i < length; ++i)
{
vtkm::UInt8 maskVal = ((randomPortal.Get(i) % 8) == 0) ? 0 : 1;
maskPortal.Set(i, maskVal);
}
break;
}
}
return maskArray;
}
template <typename T, typename S>
void CheckRange(const vtkm::cont::ArrayHandle<T, S>& array)
{
VerifyRange(array, vtkm::cont::ArrayRangeCompute(array));
auto length = array.GetNumberOfValues();
vtkm::cont::ArrayHandle<vtkm::UInt8> emptyMaskArray;
auto maskArray = FillMaskArray(length);
vtkm::cont::ArrayHandle<vtkm::Range> scalarRange;
std::cout << "\tchecking scalar range without mask\n";
scalarRange = vtkm::cont::ArrayRangeCompute(array);
VerifyRangeScalar(array, scalarRange, emptyMaskArray, false);
std::cout << "\tchecking scalar range with mask\n";
scalarRange = vtkm::cont::ArrayRangeCompute(array, maskArray);
VerifyRangeScalar(array, scalarRange, maskArray, false);
vtkm::Range vectorRange;
std::cout << "\tchecking vector range without mask\n";
vectorRange = vtkm::cont::ArrayRangeComputeMagnitude(array);
VerifyRangeVector(array, vectorRange, emptyMaskArray, false);
std::cout << "\tchecking vector range with mask\n";
vectorRange = vtkm::cont::ArrayRangeComputeMagnitude(array, maskArray);
VerifyRangeVector(array, vectorRange, maskArray, false);
}
template <typename ArrayHandleType>
void CheckRangeFiniteImpl(const ArrayHandleType& array, std::true_type)
{
auto length = array.GetNumberOfValues();
vtkm::cont::ArrayHandle<vtkm::UInt8> emptyMaskArray;
auto maskArray = FillMaskArray(length);
vtkm::cont::ArrayHandle<vtkm::Range> scalarRange;
std::cout << "\tchecking finite scalar range without mask\n";
scalarRange = vtkm::cont::ArrayRangeCompute(array, true);
VerifyRangeScalar(array, scalarRange, emptyMaskArray, true);
std::cout << "\tchecking finite scalar range with mask\n";
scalarRange = vtkm::cont::ArrayRangeCompute(array, maskArray, true);
VerifyRangeScalar(array, scalarRange, maskArray, true);
vtkm::Range vectorRange;
std::cout << "\tchecking finite vector range without mask\n";
vectorRange = vtkm::cont::ArrayRangeComputeMagnitude(array, true);
VerifyRangeVector(array, vectorRange, emptyMaskArray, true);
std::cout << "\tchecking finite vector range with mask\n";
vectorRange = vtkm::cont::ArrayRangeComputeMagnitude(array, maskArray, true);
VerifyRangeVector(array, vectorRange, maskArray, true);
}
template <typename ArrayHandleType>
void CheckRangeFiniteImpl(const ArrayHandleType&, std::false_type)
{
}
template <typename T, typename S>
void FillArray(vtkm::cont::ArrayHandle<T, S>& array)
void CheckRangeFinite(const vtkm::cont::ArrayHandle<T, S>& array)
{
using ComponentType = typename vtkm::VecTraits<T>::ComponentType;
auto tag = std::integral_constant < bool,
std::is_same<ComponentType, vtkm::Float32>::value ||
std::is_same<ComponentType, vtkm::Float64>::value > {};
CheckRangeFiniteImpl(array, tag);
}
// Transform random values in range [0, 1) to the range [From, To).
// If the `AddNonFinites` flag is set, some values are transformed to non-finite values.
struct TransformRange
{
vtkm::Float64 From, To;
bool AddNonFinites = false;
VTKM_EXEC vtkm::Float64 operator()(vtkm::Float64 in) const
{
if (AddNonFinites)
{
if (in >= 0.3 && in <= 0.33)
{
return vtkm::NegativeInfinity64();
}
if (in >= 0.9 && in <= 0.93)
{
return vtkm::Infinity64();
}
}
return (in * (this->To - this->From)) + this->From;
}
};
template <typename T, typename S>
void FillArray(vtkm::cont::ArrayHandle<T, S>& array, bool addNonFinites)
{
using Traits = vtkm::VecTraits<T>;
vtkm::IdComponent numComponents = Traits::NUM_COMPONENTS;
// non-finites only applies to floating point types
addNonFinites = addNonFinites &&
(std::is_same<typename Traits::ComponentType, vtkm::Float32>::value ||
std::is_same<typename Traits::ComponentType, vtkm::Float64>::value);
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::ArrayCopyDevice(randomArray, dest);
auto transformFunctor = std::numeric_limits<typename Traits::BaseComponentType>::is_signed
? TransformRange{ -100.0, 100.0, addNonFinites }
: TransformRange{ 0.0, 200.0, addNonFinites };
vtkm::cont::ArrayCopyDevice(
vtkm::cont::make_ArrayHandleTransform(randomArray, transformFunctor), dest);
}
}
@ -88,8 +287,10 @@ void TestBasicArray()
{
std::cout << "Checking basic array" << std::endl;
vtkm::cont::ArrayHandleBasic<T> array;
FillArray(array);
FillArray(array, false);
CheckRange(array);
FillArray(array, true);
CheckRangeFinite(array);
}
template <typename T>
@ -97,8 +298,10 @@ void TestSOAArray(vtkm::TypeTraitsVectorTag)
{
std::cout << "Checking SOA array" << std::endl;
vtkm::cont::ArrayHandleSOA<T> array;
FillArray(array);
FillArray(array, false);
CheckRange(array);
FillArray(array, true);
CheckRangeFinite(array);
}
template <typename T>
@ -112,8 +315,10 @@ void TestStrideArray()
{
std::cout << "Checking stride array" << std::endl;
vtkm::cont::ArrayHandleBasic<T> array;
FillArray(array);
FillArray(array, false);
CheckRange(vtkm::cont::ArrayHandleStride<T>(array, ARRAY_SIZE / 2, 2, 1));
FillArray(array, true);
CheckRangeFinite(vtkm::cont::ArrayHandleStride<T>(array, ARRAY_SIZE / 2, 2, 1));
}
template <typename T>
@ -122,23 +327,30 @@ void TestCastArray()
std::cout << "Checking cast array" << std::endl;
using CastType = typename vtkm::VecTraits<T>::template ReplaceBaseComponentType<vtkm::Float64>;
vtkm::cont::ArrayHandle<T> array;
FillArray(array);
FillArray(array, false);
CheckRange(vtkm::cont::make_ArrayHandleCast<CastType>(array));
}
template <typename T>
auto FillCartesianProductArray(bool addNonFinites)
{
vtkm::cont::ArrayHandleBasic<T> array0;
FillArray(array0, addNonFinites);
vtkm::cont::ArrayHandleBasic<T> array1;
FillArray(array1, addNonFinites);
vtkm::cont::ArrayHandleBasic<T> array2;
FillArray(array2, addNonFinites);
return vtkm::cont::make_ArrayHandleCartesianProduct(array0, array1, array2);
}
template <typename T>
void TestCartesianProduct(vtkm::TypeTraitsScalarTag)
{
std::cout << "Checking Cartesian product" << std::endl;
vtkm::cont::ArrayHandleBasic<T> array0;
FillArray(array0);
vtkm::cont::ArrayHandleBasic<T> array1;
FillArray(array1);
vtkm::cont::ArrayHandleBasic<T> array2;
FillArray(array2);
CheckRange(vtkm::cont::make_ArrayHandleCartesianProduct(array0, array1, array2));
auto array = FillCartesianProductArray<T>(false);
CheckRange(array);
array = FillCartesianProductArray<T>(true);
CheckRangeFinite(array);
}
template <typename T>
@ -147,19 +359,27 @@ void TestCartesianProduct(vtkm::TypeTraitsVectorTag)
// Skip test.
}
template <typename T>
auto FillCompositeVectorArray(bool addNonFinites)
{
vtkm::cont::ArrayHandleBasic<T> array0;
FillArray(array0, addNonFinites);
vtkm::cont::ArrayHandleBasic<T> array1;
FillArray(array1, addNonFinites);
vtkm::cont::ArrayHandleBasic<T> array2;
FillArray(array2, addNonFinites);
return vtkm::cont::make_ArrayHandleCompositeVector(array0, array1, array2);
}
template <typename T>
void TestComposite(vtkm::TypeTraitsScalarTag)
{
std::cout << "Checking composite vector array" << std::endl;
vtkm::cont::ArrayHandleBasic<T> array0;
FillArray(array0);
vtkm::cont::ArrayHandleBasic<T> array1;
FillArray(array1);
vtkm::cont::ArrayHandleBasic<T> array2;
FillArray(array2);
CheckRange(vtkm::cont::make_ArrayHandleCompositeVector(array0, array1, array2));
auto array = FillCompositeVectorArray<T>(false);
CheckRange(array);
array = FillCompositeVectorArray<T>(true);
CheckRangeFinite(array);
}
template <typename T>
@ -174,8 +394,10 @@ void TestGroup(vtkm::TypeTraitsScalarTag)
std::cout << "Checking group vec array" << std::endl;
vtkm::cont::ArrayHandleBasic<T> array;
FillArray(array);
FillArray(array, false);
CheckRange(vtkm::cont::make_ArrayHandleGroupVec<2>(array));
FillArray(array, true);
CheckRangeFinite(vtkm::cont::make_ArrayHandleGroupVec<2>(array));
}
template <typename T>
@ -190,8 +412,10 @@ void TestView()
std::cout << "Checking view array" << std::endl;
vtkm::cont::ArrayHandleBasic<T> array;
FillArray(array);
FillArray(array, false);
CheckRange(vtkm::cont::make_ArrayHandleView(array, 2, ARRAY_SIZE - 5));
FillArray(array, true);
CheckRangeFinite(vtkm::cont::make_ArrayHandleView(array, 2, ARRAY_SIZE - 5));
}
template <typename T>
@ -234,8 +458,10 @@ void TestXGCCoordinates()
{
std::cout << "Checking XGC coordinates array" << std::endl;
vtkm::cont::ArrayHandle<vtkm::FloatDefault> array;
FillArray(array);
FillArray(array, false);
CheckRange(vtkm::cont::make_ArrayHandleXGCCoordinates(array, 4, true));
FillArray(array, true);
CheckRangeFinite(vtkm::cont::make_ArrayHandleXGCCoordinates(array, 4, true));
}
struct DoTestFunctor

@ -20,7 +20,6 @@
#include <cstdio>
#include <string>
#include <vector>
#include <vtkm/cont/ArrayRangeCompute.h>
#include <vtkm/cont/CellSetSingleType.h>
#include <vtkm/cont/DataSet.h>
#include <vtkm/cont/DataSetBuilderExplicit.h>

@ -73,8 +73,6 @@
#include <vtkm/cont/ArrayHandleIndex.h>
#include <vtkm/cont/ArrayHandlePermutation.h>
#include <vtkm/cont/ArrayPortalToIterators.h>
#include <vtkm/cont/ArrayRangeCompute.h>
#include <vtkm/cont/ArrayRangeComputeTemplate.h>
#include <vtkm/cont/ConvertNumComponentsToOffsets.h>
#include <vtkm/cont/EnvironmentTracker.h>
#include <vtkm/cont/Timer.h>
@ -576,9 +574,7 @@ template <typename FieldType>
inline void ContourTreeMesh<FieldType>::ComputeMaxNeighbors()
{
auto neighborCounts = make_ArrayHandleOffsetsToNumComponents(this->NeighborOffsets);
vtkm::cont::ArrayHandle<vtkm::Range> rangeArray =
vtkm::cont::ArrayRangeComputeTemplate(neighborCounts);
this->MaxNeighbors = static_cast<vtkm::Id>(rangeArray.ReadPortal().Get(0).Max);
this->MaxNeighbors = vtkm::cont::Algorithm::Reduce(neighborCounts, 0, vtkm::Maximum{});
}
// Define the behavior for the execution object generate by the PrepareForExecution function