Create ArrayHandleOffsetsToNumComponents
This is a fancy array that takes an array of offsets and converts it to an array of the number of components for each packed entry. This replaces the use of `ArrayHandleDecorator` in `CellSetExplicit`. The two implementation should do the same thing, but the new `ArrayHandleOffsetsToNumComponents` should be less complex for compilers.
This commit is contained in:
parent
3aa2c7521a
commit
b9430c52e6
29
docs/changelog/array-handle-offsets-to-num-components.md
Normal file
29
docs/changelog/array-handle-offsets-to-num-components.md
Normal file
@ -0,0 +1,29 @@
|
||||
# Create `ArrayHandleOffsetsToNumComponents`
|
||||
|
||||
`ArrayHandleOffsetsToNumComponents` is a fancy array that takes an array of
|
||||
offsets and converts it to an array of the number of components for each
|
||||
packed entry.
|
||||
|
||||
It is common in VTK-m to pack small vectors of variable sizes into a single
|
||||
contiguous array. For example, cells in an explicit cell set can each have
|
||||
a different amount of vertices (triangles = 3, quads = 4, tetra = 4, hexa =
|
||||
8, etc.). Generally, to access items in this list, you need an array of
|
||||
components in each entry and the offset for each entry. However, if you
|
||||
have just the array of offsets in sorted order, you can easily derive the
|
||||
number of components for each entry by subtracting adjacent entries. This
|
||||
works best if the offsets array has a size that is one more than the number
|
||||
of packed vectors with the first entry set to 0 and the last entry set to
|
||||
the total size of the packed array (the offset to the end).
|
||||
|
||||
When packing data of this nature, it is common to start with an array that
|
||||
is the number of components. You can convert that to an offsets array using
|
||||
the `vtkm::cont::ConvertNumComponentsToOffsets` function. This will create
|
||||
an offsets array with one extra entry as previously described. You can then
|
||||
throw out the original number of components array and use the offsets with
|
||||
`ArrayHandleOffsetsToNumComponents` to represent both the offsets and num
|
||||
components while storing only one array.
|
||||
|
||||
This replaces the use of `ArrayHandleDecorator` in `CellSetExplicit`.
|
||||
The two implementation should do the same thing, but the new
|
||||
`ArrayHandleOffsetsToNumComponents` should be less complex for
|
||||
compilers.
|
186
vtkm/cont/ArrayHandleOffsetsToNumComponents.h
Normal file
186
vtkm/cont/ArrayHandleOffsetsToNumComponents.h
Normal file
@ -0,0 +1,186 @@
|
||||
//============================================================================
|
||||
// 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_ArrayHandleOffsetsToNumComponents_h
|
||||
#define vtk_m_cont_ArrayHandleOffsetsToNumComponents_h
|
||||
|
||||
#include <vtkm/cont/ArrayHandle.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace internal
|
||||
{
|
||||
|
||||
// Note that `ArrayPortalOffsetsToNumComponents` requires a source portal with +1 entry
|
||||
// to avoid branching. See `ArrayHandleOffsetsToNumComponents` for details.
|
||||
template <typename OffsetsPortal>
|
||||
class VTKM_ALWAYS_EXPORT ArrayPortalOffsetsToNumComponents
|
||||
{
|
||||
OffsetsPortal Portal;
|
||||
|
||||
public:
|
||||
ArrayPortalOffsetsToNumComponents() = default;
|
||||
|
||||
ArrayPortalOffsetsToNumComponents(const OffsetsPortal& portal)
|
||||
: Portal(portal)
|
||||
{
|
||||
}
|
||||
|
||||
using ValueType = vtkm::IdComponent;
|
||||
|
||||
VTKM_EXEC_CONT vtkm::Id GetNumberOfValues() const { return this->Portal.GetNumberOfValues() - 1; }
|
||||
|
||||
VTKM_EXEC_CONT vtkm::IdComponent Get(vtkm::Id index) const
|
||||
{
|
||||
return static_cast<vtkm::IdComponent>(this->Portal.Get(index + 1) - this->Portal.Get(index));
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace vtkm::internal
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace cont
|
||||
{
|
||||
|
||||
template <typename OffsetsStorageTag>
|
||||
struct VTKM_ALWAYS_EXPORT StorageTagOffsetsToNumComponents
|
||||
{
|
||||
};
|
||||
|
||||
namespace internal
|
||||
{
|
||||
|
||||
template <typename OffsetsStorageTag>
|
||||
class VTKM_ALWAYS_EXPORT
|
||||
Storage<vtkm::IdComponent, vtkm::cont::StorageTagOffsetsToNumComponents<OffsetsStorageTag>>
|
||||
{
|
||||
using OffsetsStorage = vtkm::cont::internal::Storage<vtkm::Id, OffsetsStorageTag>;
|
||||
|
||||
public:
|
||||
using ReadPortalType =
|
||||
vtkm::internal::ArrayPortalOffsetsToNumComponents<typename OffsetsStorage::ReadPortalType>;
|
||||
// Writing to ArrayHandleOffsetsToNumComponents not really supported, but we need to define this.
|
||||
using WritePortalType = ReadPortalType;
|
||||
|
||||
VTKM_CONT static constexpr vtkm::IdComponent GetNumberOfBuffers()
|
||||
{
|
||||
return OffsetsStorage::GetNumberOfBuffers();
|
||||
}
|
||||
|
||||
VTKM_CONT static vtkm::Id GetNumberOfValues(const vtkm::cont::internal::Buffer* buffers)
|
||||
{
|
||||
vtkm::Id numOffsets = OffsetsStorage::GetNumberOfValues(buffers);
|
||||
if (numOffsets < 1)
|
||||
{
|
||||
throw vtkm::cont::ErrorBadValue(
|
||||
"ArrayHandleOffsetsToNumComponents requires an offsets array with at least one value.");
|
||||
}
|
||||
return numOffsets - 1;
|
||||
}
|
||||
|
||||
VTKM_CONT static void ResizeBuffers(vtkm::Id numValues,
|
||||
vtkm::cont::internal::Buffer* buffers,
|
||||
vtkm::CopyFlag,
|
||||
vtkm::cont::Token&)
|
||||
{
|
||||
if (numValues == GetNumberOfValues(buffers))
|
||||
{
|
||||
// In general, we don't allow resizing of the array, but if it was "allocated" to the
|
||||
// correct size, we will allow that.
|
||||
}
|
||||
else
|
||||
{
|
||||
throw vtkm::cont::ErrorBadAllocation(
|
||||
"Cannot allocate/resize ArrayHandleOffsetsToNumComponents.");
|
||||
}
|
||||
}
|
||||
|
||||
VTKM_CONT static ReadPortalType CreateReadPortal(const vtkm::cont::internal::Buffer* buffers,
|
||||
vtkm::cont::DeviceAdapterId device,
|
||||
vtkm::cont::Token& token)
|
||||
{
|
||||
VTKM_ASSERT(OffsetsStorage::GetNumberOfValues(buffers) > 0);
|
||||
return ReadPortalType(OffsetsStorage::CreateReadPortal(buffers, device, token));
|
||||
}
|
||||
|
||||
VTKM_CONT static WritePortalType CreateWritePortal(const vtkm::cont::internal::Buffer*,
|
||||
vtkm::cont::DeviceAdapterId,
|
||||
vtkm::cont::Token&)
|
||||
{
|
||||
throw vtkm::cont::ErrorBadAllocation("Cannot write to implicit arrays.");
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/// \brief An `ArrayHandle` that converts an array of offsets to an array of `Vec` sizes.
|
||||
///
|
||||
/// It is common in VTK-m to pack small vectors of variable sizes into a single contiguous
|
||||
/// array. For example, cells in an explicit cell set can each have a different amount of
|
||||
/// vertices (triangles = 3, quads = 4, tetra = 4, hexa = 8, etc.). Generally, to access
|
||||
/// items in this list, you need an array of components in each entry and the offset for
|
||||
/// each entry. However, if you have just the array of offsets in sorted order, you can
|
||||
/// easily derive the number of components for each entry by subtracting adjacent entries.
|
||||
/// This works best if the offsets array has a size that is one more than the number of
|
||||
/// packed vectors with the first entry set to 0 and the last entry set to the total size
|
||||
/// of the packed array (the offset to the end).
|
||||
///
|
||||
/// `ArrayHandleOffsetsToNumComponents` decorates an array in exactly this manner. It
|
||||
/// takes an offsets array and makes it behave like an array of counts. Note that the
|
||||
/// offsets array must conform to the conditions described above: the offsets are in
|
||||
/// sorted order and there is one additional entry in the offsets (ending in an offset
|
||||
/// pointing past the end of the array).
|
||||
///
|
||||
/// When packing data of this nature, it is common to start with an array that is the
|
||||
/// number of components. You can convert that to an offsets array using the
|
||||
/// `vtkm::cont::ConvertNumComponentsToOffsets` function. This will create an offsets array
|
||||
/// with one extra entry as previously described. You can then throw out the original
|
||||
/// number of components array and use the offsets with `ArrayHandleOffsetsToNumComponents`
|
||||
/// to represent both the offsets and num components while storing only one array.
|
||||
///
|
||||
template <class OffsetsArray>
|
||||
class VTKM_ALWAYS_EXPORT ArrayHandleOffsetsToNumComponents
|
||||
: public vtkm::cont::ArrayHandle<
|
||||
vtkm::IdComponent,
|
||||
vtkm::cont::StorageTagOffsetsToNumComponents<typename OffsetsArray::StorageTag>>
|
||||
{
|
||||
VTKM_IS_ARRAY_HANDLE(OffsetsArray);
|
||||
VTKM_STATIC_ASSERT_MSG((std::is_same<typename OffsetsArray::ValueType, vtkm::Id>::value),
|
||||
"Offsets array must have a value type of vtkm::Id.");
|
||||
|
||||
public:
|
||||
VTKM_ARRAY_HANDLE_SUBCLASS(
|
||||
ArrayHandleOffsetsToNumComponents,
|
||||
(ArrayHandleOffsetsToNumComponents<OffsetsArray>),
|
||||
(vtkm::cont::ArrayHandle<
|
||||
vtkm::IdComponent,
|
||||
vtkm::cont::StorageTagOffsetsToNumComponents<typename OffsetsArray::StorageTag>>));
|
||||
|
||||
VTKM_CONT ArrayHandleOffsetsToNumComponents(const OffsetsArray& array)
|
||||
: Superclass(array.GetBuffers())
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
template <typename OffsetsStorageTag>
|
||||
VTKM_CONT vtkm::cont::ArrayHandleOffsetsToNumComponents<
|
||||
vtkm::cont::ArrayHandle<vtkm::Id, OffsetsStorageTag>>
|
||||
make_ArrayHandleOffsetsToNumComponents(
|
||||
const vtkm::cont::ArrayHandle<vtkm::Id, OffsetsStorageTag>& array)
|
||||
{
|
||||
// Converts to correct type.
|
||||
return array;
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace vtkm::cont
|
||||
|
||||
#endif //vtk_m_cont_ArrayHandleOffsetsToNumComponents_h
|
@ -30,6 +30,7 @@ set(headers
|
||||
ArrayHandleImplicit.h
|
||||
ArrayHandleIndex.h
|
||||
ArrayHandleMultiplexer.h
|
||||
ArrayHandleOffsetsToNumComponents.h
|
||||
ArrayHandlePermutation.h
|
||||
ArrayHandleRecombineVec.h
|
||||
ArrayHandleReverse.h
|
||||
|
@ -16,7 +16,7 @@
|
||||
#include <vtkm/cont/ArrayHandleCast.h>
|
||||
#include <vtkm/cont/ArrayHandleConstant.h>
|
||||
#include <vtkm/cont/ArrayHandleCounting.h>
|
||||
#include <vtkm/cont/ArrayHandleDecorator.h>
|
||||
#include <vtkm/cont/ArrayHandleOffsetsToNumComponents.h>
|
||||
#include <vtkm/cont/CellSet.h>
|
||||
#include <vtkm/cont/internal/ConnectivityExplicitInternals.h>
|
||||
#include <vtkm/exec/ConnectivityExplicit.h>
|
||||
@ -37,32 +37,6 @@ struct CellSetExplicitConnectivityChooser
|
||||
using ConnectivityType = vtkm::cont::internal::ConnectivityExplicitInternals<>;
|
||||
};
|
||||
|
||||
// Used with ArrayHandleDecorator to recover the NumIndices array from the
|
||||
// offsets.
|
||||
struct NumIndicesDecorator
|
||||
{
|
||||
template <typename OffsetsPortal>
|
||||
struct Functor
|
||||
{
|
||||
OffsetsPortal Offsets;
|
||||
|
||||
VTKM_SUPPRESS_EXEC_WARNINGS
|
||||
VTKM_EXEC_CONT
|
||||
vtkm::IdComponent operator()(vtkm::Id cellId) const
|
||||
{
|
||||
return static_cast<vtkm::IdComponent>(this->Offsets.Get(cellId + 1) -
|
||||
this->Offsets.Get(cellId));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename OffsetsPortal>
|
||||
static VTKM_CONT Functor<typename std::decay<OffsetsPortal>::type> CreateFunctor(
|
||||
OffsetsPortal&& portal)
|
||||
{
|
||||
return { std::forward<OffsetsPortal>(portal) };
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
#ifndef VTKM_DEFAULT_SHAPES_STORAGE_TAG
|
||||
@ -142,8 +116,7 @@ class VTKM_ALWAYS_EXPORT CellSetExplicit : public CellSet
|
||||
using ConnectivityArrayType = typename ConnectivityType::ConnectivityArrayType;
|
||||
using OffsetsArrayType = typename ConnectivityType::OffsetsArrayType;
|
||||
|
||||
using NumIndicesArrayType =
|
||||
vtkm::cont::ArrayHandleDecorator<detail::NumIndicesDecorator, OffsetsArrayType>;
|
||||
using NumIndicesArrayType = vtkm::cont::ArrayHandleOffsetsToNumComponents<OffsetsArrayType>;
|
||||
|
||||
using ExecConnectivityType =
|
||||
vtkm::exec::ConnectivityExplicit<typename ShapesArrayType::ReadPortalType,
|
||||
|
@ -14,7 +14,6 @@
|
||||
|
||||
#include <vtkm/cont/Algorithm.h>
|
||||
#include <vtkm/cont/ArrayGetValues.h>
|
||||
#include <vtkm/cont/ArrayHandleDecorator.h>
|
||||
#include <vtkm/cont/Logging.h>
|
||||
#include <vtkm/cont/RuntimeDeviceTracker.h>
|
||||
#include <vtkm/cont/TryExecute.h>
|
||||
@ -442,11 +441,8 @@ auto CellSetExplicit<SST, CST, OST>
|
||||
-> typename ConnectivityChooser<VisitTopology,
|
||||
IncidentTopology>::NumIndicesArrayType
|
||||
{
|
||||
auto offsets = this->GetOffsetsArray(visited, incident);
|
||||
const vtkm::Id numVals = offsets.GetNumberOfValues() - 1;
|
||||
return vtkm::cont::make_ArrayHandleDecorator(numVals,
|
||||
detail::NumIndicesDecorator{},
|
||||
std::move(offsets));
|
||||
// Converts to NumIndicesArrayType (which is an ArrayHandleOffsetsToNumComponents)
|
||||
return this->GetOffsetsArray(visited, incident);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
@ -43,11 +43,12 @@ set(unit_tests
|
||||
UnitTestArrayHandleExtractComponent.cxx
|
||||
UnitTestArrayHandleImplicit.cxx
|
||||
UnitTestArrayHandleIndex.cxx
|
||||
UnitTestArrayHandleReverse.cxx
|
||||
UnitTestArrayHandleOffsetsToNumComponents.cxx
|
||||
UnitTestArrayHandlePermutation.cxx
|
||||
UnitTestArrayHandleRandomStandardNormal.cxx
|
||||
UnitTestArrayHandleRandomUniformBits.cxx
|
||||
UnitTestArrayHandleRandomUniformReal.cxx
|
||||
UnitTestArrayHandleReverse.cxx
|
||||
UnitTestArrayHandleSwizzle.cxx
|
||||
UnitTestArrayHandleThreadSafety.cxx
|
||||
UnitTestArrayHandleTransform.cxx
|
||||
|
@ -0,0 +1,72 @@
|
||||
//============================================================================
|
||||
// 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/ArrayHandleOffsetsToNumComponents.h>
|
||||
|
||||
#include <vtkm/cont/ArrayHandleConstant.h>
|
||||
#include <vtkm/cont/ArrayHandleCounting.h>
|
||||
#include <vtkm/cont/CellSetExplicit.h>
|
||||
|
||||
#include <vtkm/cont/testing/Testing.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
constexpr vtkm::Id ARRAY_SIZE = 20;
|
||||
|
||||
template <typename OffsetsArray, typename ExpectedNumComponents>
|
||||
void TestOffsetsToNumComponents(const OffsetsArray& offsetsArray,
|
||||
const ExpectedNumComponents& expectedNumComponents)
|
||||
{
|
||||
VTKM_TEST_ASSERT(offsetsArray.GetNumberOfValues() ==
|
||||
expectedNumComponents.GetNumberOfValues() + 1);
|
||||
|
||||
auto numComponents = vtkm::cont::make_ArrayHandleOffsetsToNumComponents(offsetsArray);
|
||||
VTKM_TEST_ASSERT(numComponents.GetNumberOfValues() == expectedNumComponents.GetNumberOfValues());
|
||||
VTKM_TEST_ASSERT(
|
||||
test_equal_portals(numComponents.ReadPortal(), expectedNumComponents.ReadPortal()));
|
||||
}
|
||||
|
||||
void TryNormalOffsets()
|
||||
{
|
||||
std::cout << "Normal offset array." << std::endl;
|
||||
|
||||
vtkm::cont::ArrayHandle<vtkm::IdComponent> numComponents;
|
||||
numComponents.Allocate(ARRAY_SIZE);
|
||||
auto numComponentsPortal = numComponents.WritePortal();
|
||||
for (vtkm::IdComponent i = 0; i < ARRAY_SIZE; ++i)
|
||||
{
|
||||
numComponentsPortal.Set(i, i % 5);
|
||||
}
|
||||
|
||||
auto offsets = vtkm::cont::ConvertNumIndicesToOffsets(numComponents);
|
||||
TestOffsetsToNumComponents(offsets, numComponents);
|
||||
}
|
||||
|
||||
void TryFancyOffsets()
|
||||
{
|
||||
std::cout << "Fancy offset array." << std::endl;
|
||||
vtkm::cont::ArrayHandleCounting<vtkm::Id> offsets(0, 3, ARRAY_SIZE + 1);
|
||||
TestOffsetsToNumComponents(offsets,
|
||||
vtkm::cont::ArrayHandleConstant<vtkm::IdComponent>(3, ARRAY_SIZE));
|
||||
}
|
||||
|
||||
void Run()
|
||||
{
|
||||
TryNormalOffsets();
|
||||
TryFancyOffsets();
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
int UnitTestArrayHandleOffsetsToNumComponents(int argc, char* argv[])
|
||||
{
|
||||
return vtkm::cont::testing::Testing::Run(Run, argc, argv);
|
||||
}
|
Loading…
Reference in New Issue
Block a user