mirror of
https://gitlab.kitware.com/vtk/vtk-m
synced 2024-10-05 01:49:02 +00:00
Merge topic 'guide-memory-layout'
8e570c8b6 Add user guide chapter on memory layout in ArrayHandles Acked-by: Kitware Robot <kwrobot@kitware.com> Acked-by: Vicente Bolea <vicente.bolea@kitware.com> Merge-request: !3219
This commit is contained in:
commit
98168fc2ff
@ -2,11 +2,11 @@
|
||||
Basic Array Handles
|
||||
==============================
|
||||
|
||||
.. index:: array handle
|
||||
.. index:: array handle; basic
|
||||
|
||||
:chapref:`dataset:Data Sets` describes the basic data sets used by |VTKm|.
|
||||
This chapter dives deeper into how |VTKm| represents data.
|
||||
Ultimately, data structures like \vtkmcont{DataSet} can be broken down into arrays of numbers.
|
||||
Ultimately, data structures like :class:`vtkm::cont::DataSet` can be broken down into arrays of numbers.
|
||||
Arrays in |VTKm| are managed by a unit called an *array handle*.
|
||||
|
||||
An array handle, which is implemented with the :class:`vtkm::cont::ArrayHandle` class, manages an array of data that can be accessed or manipulated by |VTKm| algorithms.
|
||||
@ -43,6 +43,8 @@ This is convenient for creating arrays used as the output for algorithms.
|
||||
Chapter \ref{chap:AccessingAllocatingArrays} describes in detail how to allocate memory and access data in an :class:`vtkm::cont::ArrayHandle`.
|
||||
However, you can use the :func:`vtkm::cont::make_ArrayHandle` function for a simplified way to create an :class:`vtkm::cont::ArrayHandle` with data.
|
||||
|
||||
.. todo:: Update chapter reference above. Also consider moving the access/allocation chapter earlier.
|
||||
|
||||
:func:`vtkm::cont::make_ArrayHandle` has many forms.
|
||||
An easy form to use takes an initializer list and creates a basic :class:`vtkm::cont::ArrayHandle` with it.
|
||||
This allows you to create a short :class:`vtkm::cont::ArrayHandle` from literals.
|
||||
@ -156,7 +158,7 @@ The Hidden Second Template Parameter
|
||||
double: array handle; storage
|
||||
|
||||
We have already seen that :class:`vtkm::cont::ArrayHandle` is a templated class with the template parameter indicating the type of values stored in the array.
|
||||
However, :class:`vtkm::cont::ArrayHandle` has a second hidden parameter that indicates the \keyterm{storage} of the array.
|
||||
However, :class:`vtkm::cont::ArrayHandle` has a second hidden parameter that indicates the _storage_ of the array.
|
||||
We have so far been able to ignore this second template parameter because |VTKm| will assign a default storage for us that will store the data in a basic array.
|
||||
|
||||
Changing the storage of an :class:`vtkm::cont::ArrayHandle` lets us do many weird and wonderful things.
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
set(examples
|
||||
GuideExampleArrayHandle.cxx
|
||||
GuideExampleArrayHandleRuntimeVec.cxx
|
||||
GuideExampleCellShapes.cxx
|
||||
GuideExampleColorTables.cxx
|
||||
GuideExampleCoreDataTypes.cxx
|
||||
@ -35,6 +36,7 @@ set(examples_device
|
||||
GuideExampleFilterDataSetWithField.cxx
|
||||
GuideExampleGenerateMeshConstantShape.cxx
|
||||
GuideExampleSimpleAlgorithm.cxx
|
||||
GuideExampleUnknownArrayHandle.cxx
|
||||
GuideExampleUseWorkletMapField.cxx
|
||||
GuideExampleUseWorkletPointNeighborhood.cxx
|
||||
GuideExampleUseWorkletReduceByKey.cxx
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
#include <vtkm/cont/Algorithm.h>
|
||||
#include <vtkm/cont/ArrayHandle.h>
|
||||
#include <vtkm/cont/ArrayHandleSOA.h>
|
||||
#include <vtkm/cont/ArrayPortalToIterators.h>
|
||||
#include <vtkm/cont/ArrayRangeCompute.h>
|
||||
#include <vtkm/cont/DeviceAdapter.h>
|
||||
@ -517,6 +518,64 @@ void TestExecutionPortalsExample()
|
||||
CheckArrayValues(outputArray, 2);
|
||||
}
|
||||
|
||||
////
|
||||
//// BEGIN-EXAMPLE GetArrayPointer
|
||||
////
|
||||
void LegacyFunction(const int* data);
|
||||
|
||||
void UseArrayWithLegacy(const vtkm::cont::ArrayHandle<vtkm::Int32> array)
|
||||
{
|
||||
vtkm::cont::ArrayHandleBasic<vtkm::Int32> basicArray = array;
|
||||
vtkm::cont::Token token; // Token prevents array from changing while in scope.
|
||||
const int* cArray = basicArray.GetReadPointer(token);
|
||||
LegacyFunction(cArray);
|
||||
// When function returns, token goes out of scope and array can be modified.
|
||||
}
|
||||
////
|
||||
//// END-EXAMPLE GetArrayPointer
|
||||
////
|
||||
|
||||
void LegacyFunction(const int* data)
|
||||
{
|
||||
std::cout << "Got data: " << data[0] << std::endl;
|
||||
}
|
||||
|
||||
void TryUseArrayWithLegacy()
|
||||
{
|
||||
vtkm::cont::ArrayHandle<vtkm::Int32> array;
|
||||
array.Allocate(50);
|
||||
SetPortal(array.WritePortal());
|
||||
UseArrayWithLegacy(array);
|
||||
}
|
||||
|
||||
void ArrayHandleFromComponents()
|
||||
{
|
||||
////
|
||||
//// BEGIN-EXAMPLE ArrayHandleSOAFromComponentArrays
|
||||
////
|
||||
vtkm::cont::ArrayHandle<vtkm::FloatDefault> component1;
|
||||
vtkm::cont::ArrayHandle<vtkm::FloatDefault> component2;
|
||||
vtkm::cont::ArrayHandle<vtkm::FloatDefault> component3;
|
||||
// Fill component arrays...
|
||||
//// PAUSE-EXAMPLE
|
||||
component1.AllocateAndFill(50, 0);
|
||||
component2.AllocateAndFill(50, 1);
|
||||
component3.AllocateAndFill(50, 2);
|
||||
//// RESUME-EXAMPLE
|
||||
|
||||
vtkm::cont::ArrayHandleSOA<vtkm::Vec3f> soaArray =
|
||||
vtkm::cont::make_ArrayHandleSOA(component1, component2, component3);
|
||||
////
|
||||
//// END-EXAMPLE ArrayHandleSOAFromComponentArrays
|
||||
////
|
||||
|
||||
auto portal = soaArray.ReadPortal();
|
||||
for (vtkm::Id index = 0; index < portal.GetNumberOfValues(); ++index)
|
||||
{
|
||||
VTKM_TEST_ASSERT(portal.Get(index) == vtkm::Vec3f{ 0, 1, 2 });
|
||||
}
|
||||
}
|
||||
|
||||
void Test()
|
||||
{
|
||||
BasicConstruction();
|
||||
@ -528,6 +587,8 @@ void Test()
|
||||
TestArrayPortalVectors();
|
||||
TestControlPortalsExample();
|
||||
TestExecutionPortalsExample();
|
||||
TryUseArrayWithLegacy();
|
||||
ArrayHandleFromComponents();
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
139
docs/users-guide/examples/GuideExampleArrayHandleRuntimeVec.cxx
Normal file
139
docs/users-guide/examples/GuideExampleArrayHandleRuntimeVec.cxx
Normal file
@ -0,0 +1,139 @@
|
||||
//============================================================================
|
||||
// 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/ArrayHandleRuntimeVec.h>
|
||||
#include <vtkm/cont/ErrorBadType.h>
|
||||
#include <vtkm/cont/UnknownArrayHandle.h>
|
||||
|
||||
#include <vtkm/TypeList.h>
|
||||
|
||||
#include <vtkm/cont/testing/Testing.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
constexpr vtkm::Id ARRAY_SIZE = 10;
|
||||
|
||||
void ReadArray(std::vector<float>& data, int& numComponents)
|
||||
{
|
||||
numComponents = 3;
|
||||
data.resize(static_cast<std::size_t>(ARRAY_SIZE * numComponents));
|
||||
std::fill(data.begin(), data.end(), 1.23f);
|
||||
}
|
||||
|
||||
////
|
||||
//// BEGIN-EXAMPLE GroupWithRuntimeVec
|
||||
////
|
||||
void ReadArray(std::vector<float>& data, int& numComponents);
|
||||
|
||||
vtkm::cont::UnknownArrayHandle LoadData()
|
||||
{
|
||||
// Read data from some external source where the vector size is determined at runtime.
|
||||
std::vector<vtkm::Float32> data;
|
||||
int numComponents;
|
||||
ReadArray(data, numComponents);
|
||||
|
||||
// Resulting ArrayHandleRuntimeVec gets wrapped in an UnknownArrayHandle
|
||||
return vtkm::cont::make_ArrayHandleRuntimeVecMove(
|
||||
static_cast<vtkm::IdComponent>(numComponents), std::move(data));
|
||||
}
|
||||
|
||||
void UseVecArray(const vtkm::cont::UnknownArrayHandle& array)
|
||||
{
|
||||
using ExpectedArrayType = vtkm::cont::ArrayHandle<vtkm::Vec3f_32>;
|
||||
if (!array.CanConvert<ExpectedArrayType>())
|
||||
{
|
||||
throw vtkm::cont::ErrorBadType("Array unexpected type.");
|
||||
}
|
||||
|
||||
ExpectedArrayType concreteArray = array.AsArrayHandle<ExpectedArrayType>();
|
||||
// Do something with concreteArray...
|
||||
//// PAUSE-EXAMPLE
|
||||
VTKM_TEST_ASSERT(concreteArray.GetNumberOfValues() == ARRAY_SIZE);
|
||||
//// RESUME-EXAMPLE
|
||||
}
|
||||
|
||||
void LoadAndRun()
|
||||
{
|
||||
// Load data in a routine that does not know component size until runtime.
|
||||
vtkm::cont::UnknownArrayHandle array = LoadData();
|
||||
|
||||
// Use the data in a method that requires an array of static size.
|
||||
// This will work as long as the `Vec` size matches correctly (3 in this case).
|
||||
UseVecArray(array);
|
||||
}
|
||||
////
|
||||
//// END-EXAMPLE GroupWithRuntimeVec
|
||||
////
|
||||
|
||||
template<typename T>
|
||||
void WriteData(const T*, std::size_t, int)
|
||||
{
|
||||
// Dummy function for GetRuntimeVec.
|
||||
}
|
||||
|
||||
////
|
||||
//// BEGIN-EXAMPLE GetRuntimeVec
|
||||
////
|
||||
template<typename T>
|
||||
void WriteData(const T* data, std::size_t size, int numComponents);
|
||||
|
||||
void WriteVTKmArray(const vtkm::cont::UnknownArrayHandle& array)
|
||||
{
|
||||
bool writeSuccess = false;
|
||||
auto doWrite = [&](auto componentType) {
|
||||
using ComponentType = decltype(componentType);
|
||||
using VecArrayType = vtkm::cont::ArrayHandleRuntimeVec<ComponentType>;
|
||||
if (array.CanConvert<VecArrayType>())
|
||||
{
|
||||
// Get the array as a runtime Vec.
|
||||
VecArrayType runtimeVecArray = array.AsArrayHandle<VecArrayType>();
|
||||
|
||||
// Get the component array.
|
||||
vtkm::cont::ArrayHandleBasic<ComponentType> componentArray =
|
||||
runtimeVecArray.GetComponentsArray();
|
||||
|
||||
// Use the general function to write the data.
|
||||
WriteData(componentArray.GetReadPointer(),
|
||||
componentArray.GetNumberOfValues(),
|
||||
runtimeVecArray.GetNumberOfComponentsFlat());
|
||||
|
||||
writeSuccess = true;
|
||||
}
|
||||
};
|
||||
|
||||
// Figure out the base component type, retrieve the data (regardless
|
||||
// of vec size), and write out the data.
|
||||
vtkm::ListForEach(doWrite, vtkm::TypeListBaseC{});
|
||||
}
|
||||
////
|
||||
//// END-EXAMPLE GetRuntimeVec
|
||||
////
|
||||
|
||||
void DoWriteTest()
|
||||
{
|
||||
vtkm::cont::ArrayHandle<vtkm::Vec3f> array;
|
||||
array.Allocate(ARRAY_SIZE);
|
||||
SetPortal(array.WritePortal());
|
||||
WriteVTKmArray(array);
|
||||
}
|
||||
|
||||
void Test()
|
||||
{
|
||||
LoadAndRun();
|
||||
DoWriteTest();
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
int GuideExampleArrayHandleRuntimeVec(int argc, char* argv[])
|
||||
{
|
||||
return vtkm::cont::testing::Testing::Run(Test, argc, argv);
|
||||
}
|
515
docs/users-guide/examples/GuideExampleUnknownArrayHandle.cxx
Normal file
515
docs/users-guide/examples/GuideExampleUnknownArrayHandle.cxx
Normal file
@ -0,0 +1,515 @@
|
||||
//============================================================================
|
||||
// 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/Algorithm.h>
|
||||
#include <vtkm/cont/ArrayHandle.h>
|
||||
#include <vtkm/cont/ArrayHandleCast.h>
|
||||
#include <vtkm/cont/ArrayHandleConstant.h>
|
||||
#include <vtkm/cont/ArrayHandleCounting.h>
|
||||
#include <vtkm/cont/ArrayHandleGroupVec.h>
|
||||
#include <vtkm/cont/ArrayHandleIndex.h>
|
||||
#include <vtkm/cont/ArrayHandleMultiplexer.h>
|
||||
#include <vtkm/cont/ArrayRangeCompute.h>
|
||||
#include <vtkm/cont/DeviceAdapter.h>
|
||||
#include <vtkm/cont/Invoker.h>
|
||||
#include <vtkm/cont/UncertainArrayHandle.h>
|
||||
#include <vtkm/cont/UnknownArrayHandle.h>
|
||||
#include <vtkm/cont/internal/StorageError.h>
|
||||
|
||||
#include <vtkm/worklet/WorkletMapField.h>
|
||||
|
||||
#include <vtkm/VecTraits.h>
|
||||
|
||||
#include <vtkm/cont/testing/Testing.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
constexpr vtkm::Id ARRAY_SIZE = 10;
|
||||
|
||||
////
|
||||
//// BEGIN-EXAMPLE CreateUnknownArrayHandle
|
||||
////
|
||||
VTKM_CONT
|
||||
vtkm::cont::UnknownArrayHandle LoadUnknownArray(const void* buffer,
|
||||
vtkm::Id length,
|
||||
std::string type)
|
||||
{
|
||||
vtkm::cont::UnknownArrayHandle handle;
|
||||
if (type == "float")
|
||||
{
|
||||
vtkm::cont::ArrayHandle<vtkm::Float32> concreteArray = vtkm::cont::make_ArrayHandle(
|
||||
reinterpret_cast<const vtkm::Float32*>(buffer), length, vtkm::CopyFlag::On);
|
||||
handle = concreteArray;
|
||||
}
|
||||
else if (type == "int")
|
||||
{
|
||||
vtkm::cont::ArrayHandle<vtkm::Int32> concreteArray = vtkm::cont::make_ArrayHandle(
|
||||
reinterpret_cast<const vtkm::Int32*>(buffer), length, vtkm::CopyFlag::On);
|
||||
handle = concreteArray;
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
////
|
||||
//// END-EXAMPLE CreateUnknownArrayHandle
|
||||
////
|
||||
|
||||
void TryLoadUnknownArray()
|
||||
{
|
||||
vtkm::Float32 scalarBuffer[ARRAY_SIZE];
|
||||
vtkm::cont::UnknownArrayHandle handle =
|
||||
LoadUnknownArray(scalarBuffer, ARRAY_SIZE, "float");
|
||||
VTKM_TEST_ASSERT((handle.IsValueType<vtkm::Float32>()), "Type not right.");
|
||||
VTKM_TEST_ASSERT(!(handle.IsValueType<vtkm::Int32>()), "Type not right.");
|
||||
|
||||
vtkm::Int32 idBuffer[ARRAY_SIZE];
|
||||
handle = LoadUnknownArray(idBuffer, ARRAY_SIZE, "int");
|
||||
VTKM_TEST_ASSERT((handle.IsValueType<vtkm::Int32>()), "Type not right.");
|
||||
VTKM_TEST_ASSERT(!(handle.IsValueType<vtkm::Float32>()), "Type not right.");
|
||||
}
|
||||
|
||||
void NonTypeUnknownArrayHandleAllocate()
|
||||
{
|
||||
vtkm::cont::ArrayHandle<vtkm::Id> concreteArray;
|
||||
concreteArray.Allocate(ARRAY_SIZE);
|
||||
////
|
||||
//// BEGIN-EXAMPLE NonTypeUnknownArrayHandleNewInstance
|
||||
//// BEGIN-EXAMPLE UnknownArrayHandleResize
|
||||
////
|
||||
vtkm::cont::UnknownArrayHandle unknownHandle = // ... some valid array
|
||||
//// PAUSE-EXAMPLE
|
||||
concreteArray;
|
||||
//// RESUME-EXAMPLE
|
||||
|
||||
// Double the size of the array while preserving all the initial values.
|
||||
vtkm::Id originalArraySize = unknownHandle.GetNumberOfValues();
|
||||
unknownHandle.Allocate(originalArraySize * 2, vtkm::CopyFlag::On);
|
||||
////
|
||||
//// END-EXAMPLE UnknownArrayHandleResize
|
||||
////
|
||||
|
||||
// Create a new array of the same type as the original.
|
||||
vtkm::cont::UnknownArrayHandle newArray = unknownHandle.NewInstance();
|
||||
|
||||
newArray.Allocate(originalArraySize);
|
||||
////
|
||||
//// END-EXAMPLE NonTypeUnknownArrayHandleNewInstance
|
||||
////
|
||||
|
||||
VTKM_TEST_ASSERT(originalArraySize == ARRAY_SIZE);
|
||||
VTKM_TEST_ASSERT(unknownHandle.GetNumberOfValues() == (2 * ARRAY_SIZE));
|
||||
VTKM_TEST_ASSERT(concreteArray.GetNumberOfValues() == (2 * ARRAY_SIZE));
|
||||
VTKM_TEST_ASSERT(newArray.GetNumberOfValues() == ARRAY_SIZE);
|
||||
VTKM_TEST_ASSERT(newArray.IsType<decltype(concreteArray)>());
|
||||
|
||||
////
|
||||
//// BEGIN-EXAMPLE UnknownArrayHandleBasicInstance
|
||||
////
|
||||
vtkm::cont::UnknownArrayHandle indexArray = vtkm::cont::ArrayHandleIndex();
|
||||
// Returns an array of type ArrayHandleBasic<vtkm::Id>
|
||||
vtkm::cont::UnknownArrayHandle basicArray = indexArray.NewInstanceBasic();
|
||||
////
|
||||
//// END-EXAMPLE UnknownArrayHandleBasicInstance
|
||||
////
|
||||
|
||||
VTKM_TEST_ASSERT(basicArray.IsType<vtkm::cont::ArrayHandleBasic<vtkm::Id>>());
|
||||
|
||||
////
|
||||
//// BEGIN-EXAMPLE UnknownArrayHandleFloatInstance
|
||||
////
|
||||
vtkm::cont::UnknownArrayHandle intArray = vtkm::cont::ArrayHandleIndex();
|
||||
// Returns an array of type ArrayHandleBasic<vtkm::FloatDefault>
|
||||
vtkm::cont::UnknownArrayHandle floatArray = intArray.NewInstanceFloatBasic();
|
||||
|
||||
vtkm::cont::UnknownArrayHandle id3Array = vtkm::cont::ArrayHandle<vtkm::Id3>();
|
||||
// Returns an array of type ArrayHandleBasic<vtkm::Vec3f>
|
||||
vtkm::cont::UnknownArrayHandle float3Array = id3Array.NewInstanceFloatBasic();
|
||||
////
|
||||
//// END-EXAMPLE UnknownArrayHandleFloatInstance
|
||||
////
|
||||
|
||||
VTKM_TEST_ASSERT(
|
||||
floatArray.IsType<vtkm::cont::ArrayHandleBasic<vtkm::FloatDefault>>());
|
||||
VTKM_TEST_ASSERT(float3Array.IsType<vtkm::cont::ArrayHandleBasic<vtkm::Vec3f>>());
|
||||
}
|
||||
|
||||
////
|
||||
//// BEGIN-EXAMPLE UnknownArrayHandleCanConvert
|
||||
////
|
||||
VTKM_CONT vtkm::FloatDefault GetMiddleValue(
|
||||
const vtkm::cont::UnknownArrayHandle& unknownArray)
|
||||
{
|
||||
if (unknownArray.CanConvert<vtkm::cont::ArrayHandleConstant<vtkm::FloatDefault>>())
|
||||
{
|
||||
// Fast path for known array
|
||||
vtkm::cont::ArrayHandleConstant<vtkm::FloatDefault> constantArray;
|
||||
unknownArray.AsArrayHandle(constantArray);
|
||||
return constantArray.GetValue();
|
||||
}
|
||||
else
|
||||
{
|
||||
// General path
|
||||
auto ranges = vtkm::cont::ArrayRangeCompute(unknownArray);
|
||||
vtkm::Range range = ranges.ReadPortal().Get(0);
|
||||
return static_cast<vtkm::FloatDefault>((range.Min + range.Max) / 2);
|
||||
}
|
||||
}
|
||||
////
|
||||
//// END-EXAMPLE UnknownArrayHandleCanConvert
|
||||
////
|
||||
|
||||
////
|
||||
//// BEGIN-EXAMPLE UnknownArrayHandleDeepCopy
|
||||
////
|
||||
VTKM_CONT vtkm::cont::ArrayHandle<vtkm::FloatDefault> CopyToDefaultArray(
|
||||
const vtkm::cont::UnknownArrayHandle& unknownArray)
|
||||
{
|
||||
// Initialize the output UnknownArrayHandle with the array type we want to copy to.
|
||||
vtkm::cont::UnknownArrayHandle output = vtkm::cont::ArrayHandle<vtkm::FloatDefault>{};
|
||||
output.DeepCopyFrom(unknownArray);
|
||||
return output.AsArrayHandle<vtkm::cont::ArrayHandle<vtkm::FloatDefault>>();
|
||||
}
|
||||
////
|
||||
//// END-EXAMPLE UnknownArrayHandleDeepCopy
|
||||
////
|
||||
|
||||
////
|
||||
//// BEGIN-EXAMPLE UnknownArrayHandleShallowCopy
|
||||
////
|
||||
VTKM_CONT vtkm::cont::ArrayHandle<vtkm::FloatDefault> GetAsDefaultArray(
|
||||
const vtkm::cont::UnknownArrayHandle& unknownArray)
|
||||
{
|
||||
// Initialize the output UnknownArrayHandle with the array type we want to copy to.
|
||||
vtkm::cont::UnknownArrayHandle output = vtkm::cont::ArrayHandle<vtkm::FloatDefault>{};
|
||||
output.CopyShallowIfPossible(unknownArray);
|
||||
return output.AsArrayHandle<vtkm::cont::ArrayHandle<vtkm::FloatDefault>>();
|
||||
}
|
||||
////
|
||||
//// END-EXAMPLE UnknownArrayHandleShallowCopy
|
||||
////
|
||||
|
||||
void CastUnknownArrayHandle()
|
||||
{
|
||||
////
|
||||
//// BEGIN-EXAMPLE UnknownArrayHandleAsCastArray
|
||||
////
|
||||
vtkm::cont::ArrayHandle<vtkm::Float32> originalArray;
|
||||
vtkm::cont::UnknownArrayHandle unknownArray = originalArray;
|
||||
|
||||
vtkm::cont::ArrayHandleCast<vtkm::Float64, decltype(originalArray)> castArray;
|
||||
unknownArray.AsArrayHandle(castArray);
|
||||
////
|
||||
//// END-EXAMPLE UnknownArrayHandleAsCastArray
|
||||
////
|
||||
|
||||
////
|
||||
//// BEGIN-EXAMPLE UnknownArrayHandleAsArrayHandle1
|
||||
////
|
||||
vtkm::cont::ArrayHandle<vtkm::Float32> knownArray =
|
||||
unknownArray.AsArrayHandle<vtkm::cont::ArrayHandle<vtkm::Float32>>();
|
||||
////
|
||||
//// END-EXAMPLE UnknownArrayHandleAsArrayHandle1
|
||||
////
|
||||
|
||||
////
|
||||
//// BEGIN-EXAMPLE UnknownArrayHandleAsArrayHandle2
|
||||
////
|
||||
unknownArray.AsArrayHandle(knownArray);
|
||||
////
|
||||
//// END-EXAMPLE UnknownArrayHandleAsArrayHandle2
|
||||
////
|
||||
|
||||
originalArray.Allocate(ARRAY_SIZE);
|
||||
SetPortal(originalArray.WritePortal());
|
||||
|
||||
GetMiddleValue(unknownArray);
|
||||
CopyToDefaultArray(unknownArray);
|
||||
GetAsDefaultArray(unknownArray);
|
||||
}
|
||||
|
||||
////
|
||||
//// BEGIN-EXAMPLE UsingCastAndCallForTypes
|
||||
////
|
||||
struct PrintArrayContentsFunctor
|
||||
{
|
||||
template<typename T, typename S>
|
||||
VTKM_CONT void operator()(const vtkm::cont::ArrayHandle<T, S>& array) const
|
||||
{
|
||||
this->PrintArrayPortal(array.ReadPortal());
|
||||
}
|
||||
|
||||
private:
|
||||
template<typename PortalType>
|
||||
VTKM_CONT void PrintArrayPortal(const PortalType& portal) const
|
||||
{
|
||||
for (vtkm::Id index = 0; index < portal.GetNumberOfValues(); index++)
|
||||
{
|
||||
// All ArrayPortal objects have ValueType for the type of each value.
|
||||
using ValueType = typename PortalType::ValueType;
|
||||
using VTraits = vtkm::VecTraits<ValueType>;
|
||||
|
||||
ValueType value = portal.Get(index);
|
||||
|
||||
vtkm::IdComponent numComponents = VTraits::GetNumberOfComponents(value);
|
||||
for (vtkm::IdComponent componentIndex = 0; componentIndex < numComponents;
|
||||
componentIndex++)
|
||||
{
|
||||
std::cout << " " << VTraits::GetComponent(value, componentIndex);
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void PrintArrayContents(const vtkm::cont::UnknownArrayHandle& array)
|
||||
{
|
||||
array.CastAndCallForTypes<VTKM_DEFAULT_TYPE_LIST, VTKM_DEFAULT_STORAGE_LIST>(
|
||||
PrintArrayContentsFunctor{});
|
||||
}
|
||||
////
|
||||
//// END-EXAMPLE UsingCastAndCallForTypes
|
||||
////
|
||||
|
||||
struct MyWorklet : vtkm::worklet::WorkletMapField
|
||||
{
|
||||
using ControlSignature = void(FieldIn, FieldOut);
|
||||
|
||||
template<typename T1, typename T2>
|
||||
VTKM_EXEC void operator()(const T1& in, T2& out) const
|
||||
{
|
||||
using VTraitsIn = vtkm::VecTraits<T1>;
|
||||
using VTraitsOut = vtkm::VecTraits<T2>;
|
||||
const vtkm::IdComponent numComponents = VTraitsIn::GetNumberOfComponents(in);
|
||||
VTKM_ASSERT(numComponents == VTraitsOut::GetNumberOfComponents(out));
|
||||
for (vtkm::IdComponent index = 0; index < numComponents; ++index)
|
||||
{
|
||||
VTraitsOut::SetComponent(out,
|
||||
index,
|
||||
static_cast<typename VTraitsOut::ComponentType>(
|
||||
VTraitsIn::GetComponent(in, index)));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void TryPrintArrayContents()
|
||||
{
|
||||
vtkm::cont::ArrayHandleIndex implicitArray(ARRAY_SIZE);
|
||||
|
||||
vtkm::cont::ArrayHandle<vtkm::FloatDefault> concreteArray;
|
||||
vtkm::cont::Algorithm::Copy(implicitArray, concreteArray);
|
||||
|
||||
vtkm::cont::UnknownArrayHandle unknownArray = concreteArray;
|
||||
|
||||
PrintArrayContents(unknownArray);
|
||||
|
||||
////
|
||||
//// BEGIN-EXAMPLE UncertainArrayHandle
|
||||
////
|
||||
vtkm::cont::UncertainArrayHandle<vtkm::TypeListScalarAll, vtkm::cont::StorageListBasic>
|
||||
uncertainArray(unknownArray);
|
||||
uncertainArray.CastAndCall(PrintArrayContentsFunctor{});
|
||||
////
|
||||
//// END-EXAMPLE UncertainArrayHandle
|
||||
////
|
||||
|
||||
vtkm::cont::ArrayHandle<vtkm::FloatDefault> outArray;
|
||||
////
|
||||
//// BEGIN-EXAMPLE UnknownArrayResetTypes
|
||||
////
|
||||
vtkm::cont::Invoker invoke;
|
||||
invoke(
|
||||
MyWorklet{},
|
||||
unknownArray.ResetTypes<vtkm::TypeListScalarAll, vtkm::cont::StorageListBasic>(),
|
||||
outArray);
|
||||
////
|
||||
//// END-EXAMPLE UnknownArrayResetTypes
|
||||
////
|
||||
|
||||
////
|
||||
//// BEGIN-EXAMPLE CastAndCallForTypesWithFloatFallback
|
||||
////
|
||||
unknownArray.CastAndCallForTypesWithFloatFallback<vtkm::TypeListField,
|
||||
VTKM_DEFAULT_STORAGE_LIST>(
|
||||
PrintArrayContentsFunctor{});
|
||||
////
|
||||
//// END-EXAMPLE CastAndCallForTypesWithFloatFallback
|
||||
////
|
||||
|
||||
////
|
||||
//// BEGIN-EXAMPLE CastAndCallWithFloatFallback
|
||||
////
|
||||
uncertainArray.CastAndCall(PrintArrayContentsFunctor{});
|
||||
////
|
||||
//// END-EXAMPLE CastAndCallWithFloatFallback
|
||||
////
|
||||
}
|
||||
|
||||
void ExtractUnknownComponent()
|
||||
{
|
||||
////
|
||||
//// BEGIN-EXAMPLE UnknownArrayExtractComponent
|
||||
////
|
||||
vtkm::cont::ArrayHandleBasic<vtkm::Vec3f> concreteArray =
|
||||
vtkm::cont::make_ArrayHandle<vtkm::Vec3f>({ { 0, 1, 2 },
|
||||
{ 3, 4, 5 },
|
||||
{ 6, 7, 8 },
|
||||
{ 9, 10, 11 },
|
||||
{ 12, 13, 14 },
|
||||
{ 15, 16, 17 } });
|
||||
|
||||
vtkm::cont::UnknownArrayHandle unknownArray(concreteArray);
|
||||
|
||||
//// LABEL Call
|
||||
auto componentArray = unknownArray.ExtractComponent<vtkm::FloatDefault>(0);
|
||||
// componentArray contains [ 0, 3, 6, 9, 12, 15 ].
|
||||
////
|
||||
//// END-EXAMPLE UnknownArrayExtractComponent
|
||||
////
|
||||
VTKM_TEST_ASSERT(componentArray.GetNumberOfValues() ==
|
||||
concreteArray.GetNumberOfValues());
|
||||
{
|
||||
auto portal = componentArray.ReadPortal();
|
||||
auto expectedPortal = concreteArray.ReadPortal();
|
||||
for (vtkm::IdComponent i = 0; i < componentArray.GetNumberOfValues(); ++i)
|
||||
{
|
||||
VTKM_TEST_ASSERT(test_equal(portal.Get(i), expectedPortal.Get(i)[0]));
|
||||
}
|
||||
}
|
||||
|
||||
VTKM_TEST_ASSERT(
|
||||
////
|
||||
//// BEGIN-EXAMPLE UnknownArrayBaseComponentType
|
||||
////
|
||||
unknownArray.IsBaseComponentType<vtkm::FloatDefault>()
|
||||
////
|
||||
//// END-EXAMPLE UnknownArrayBaseComponentType
|
||||
////
|
||||
);
|
||||
|
||||
auto deepTypeArray = vtkm::cont::make_ArrayHandleGroupVec<2>(concreteArray);
|
||||
|
||||
unknownArray = deepTypeArray;
|
||||
VTKM_TEST_ASSERT(unknownArray.GetNumberOfComponentsFlat() == 6);
|
||||
|
||||
vtkm::cont::ArrayHandle<vtkm::FloatDefault> outputArray;
|
||||
|
||||
vtkm::cont::Invoker invoke;
|
||||
|
||||
////
|
||||
//// BEGIN-EXAMPLE UnknownArrayExtractComponentsMultiple
|
||||
////
|
||||
std::vector<vtkm::cont::ArrayHandle<vtkm::FloatDefault>> outputArrays(
|
||||
static_cast<std::size_t>(unknownArray.GetNumberOfComponentsFlat()));
|
||||
for (vtkm::IdComponent componentIndex = 0;
|
||||
componentIndex < unknownArray.GetNumberOfComponentsFlat();
|
||||
++componentIndex)
|
||||
{
|
||||
invoke(MyWorklet{},
|
||||
unknownArray.ExtractComponent<vtkm::FloatDefault>(componentIndex),
|
||||
outputArrays[static_cast<std::size_t>(componentIndex)]);
|
||||
}
|
||||
////
|
||||
//// END-EXAMPLE UnknownArrayExtractComponentsMultiple
|
||||
////
|
||||
for (std::size_t outIndex = 0; outIndex < outputArrays.size(); ++outIndex)
|
||||
{
|
||||
vtkm::IdComponent vecIndex = static_cast<vtkm::IdComponent>(outIndex % 3);
|
||||
vtkm::IdComponent groupIndex = static_cast<vtkm::IdComponent>(outIndex / 3);
|
||||
auto portal = outputArrays[outIndex].ReadPortal();
|
||||
auto expectedPortal = deepTypeArray.ReadPortal();
|
||||
VTKM_TEST_ASSERT(portal.GetNumberOfValues() ==
|
||||
(concreteArray.GetNumberOfValues() / 2));
|
||||
for (vtkm::IdComponent i = 0; i < portal.GetNumberOfValues(); ++i)
|
||||
{
|
||||
VTKM_TEST_ASSERT(
|
||||
test_equal(portal.Get(i), expectedPortal.Get(i)[groupIndex][vecIndex]));
|
||||
}
|
||||
}
|
||||
|
||||
unknownArray = concreteArray;
|
||||
|
||||
vtkm::cont::ArrayHandle<vtkm::Vec3f> outArray;
|
||||
|
||||
////
|
||||
//// BEGIN-EXAMPLE UnknownArrayExtractArrayFromComponents
|
||||
////
|
||||
invoke(MyWorklet{},
|
||||
unknownArray.ExtractArrayFromComponents<vtkm::FloatDefault>(),
|
||||
outArray);
|
||||
////
|
||||
//// END-EXAMPLE UnknownArrayExtractArrayFromComponents
|
||||
////
|
||||
VTKM_TEST_ASSERT(test_equal_ArrayHandles(outArray, concreteArray));
|
||||
|
||||
////
|
||||
//// BEGIN-EXAMPLE UnknownArrayCallWithExtractedArray
|
||||
////
|
||||
unknownArray.CastAndCallWithExtractedArray(PrintArrayContentsFunctor{});
|
||||
////
|
||||
//// END-EXAMPLE UnknownArrayCallWithExtractedArray
|
||||
////
|
||||
}
|
||||
|
||||
////
|
||||
//// BEGIN-EXAMPLE UnknownArrayConstOutput
|
||||
////
|
||||
void IndexInitialize(vtkm::Id size, const vtkm::cont::UnknownArrayHandle& output)
|
||||
{
|
||||
vtkm::cont::ArrayHandleIndex input(size);
|
||||
output.DeepCopyFrom(input);
|
||||
}
|
||||
////
|
||||
//// END-EXAMPLE UnknownArrayConstOutput
|
||||
////
|
||||
|
||||
////
|
||||
//// BEGIN-EXAMPLE UseUnknownArrayConstOutput
|
||||
////
|
||||
template<typename T>
|
||||
void Foo(const vtkm::cont::ArrayHandle<T>& input, vtkm::cont::ArrayHandle<T>& output)
|
||||
{
|
||||
IndexInitialize(input.GetNumberOfValues(), output);
|
||||
// ...
|
||||
////
|
||||
//// END-EXAMPLE UseUnknownArrayConstOutput
|
||||
////
|
||||
|
||||
VTKM_TEST_ASSERT(output.GetNumberOfValues() == input.GetNumberOfValues());
|
||||
auto portal = output.ReadPortal();
|
||||
for (vtkm::Id index = 0; index < portal.GetNumberOfValues(); ++index)
|
||||
{
|
||||
VTKM_TEST_ASSERT(portal.Get(index) == index);
|
||||
}
|
||||
}
|
||||
|
||||
void TryConstOutput()
|
||||
{
|
||||
vtkm::cont::ArrayHandle<vtkm::Id> input =
|
||||
vtkm::cont::make_ArrayHandle<vtkm::Id>({ 3, 6, 1, 4 });
|
||||
vtkm::cont::ArrayHandle<vtkm::Id> output;
|
||||
Foo(input, output);
|
||||
}
|
||||
|
||||
void Test()
|
||||
{
|
||||
TryLoadUnknownArray();
|
||||
NonTypeUnknownArrayHandleAllocate();
|
||||
CastUnknownArrayHandle();
|
||||
TryPrintArrayContents();
|
||||
ExtractUnknownComponent();
|
||||
TryConstOutput();
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
int GuideExampleUnknownArrayHandle(int argc, char* argv[])
|
||||
{
|
||||
return vtkm::cont::testing::Testing::Run(Test, argc, argv);
|
||||
}
|
165
docs/users-guide/memory-layout.rst
Normal file
165
docs/users-guide/memory-layout.rst
Normal file
@ -0,0 +1,165 @@
|
||||
==============================
|
||||
Memory Layout of Array Handles
|
||||
==============================
|
||||
|
||||
.. index:: array handle; memory layout
|
||||
|
||||
:chapref:`basic-array-handles:Basic Array Handles` describes the basics of the :class:`vtkm::cont::ArrayHandle` class, which is the interface to the arrays of data that |VTKm| operates on.
|
||||
Recall that :class:`vtkm::cont::ArrayHandle` is a templated class with two template parameters.
|
||||
The first template argument is the type of each item in the array.
|
||||
The second parameter, which is optional, determines how the array is stored in memory.
|
||||
This can be used in a variety of different ways, but its primary purpose is to provide a strategy for laying the data out in memory.
|
||||
This chapter documents the ways in which |VTKm| can store and access arrays of data in different layouts.
|
||||
|
||||
------------------------------
|
||||
Basic Memory Layout
|
||||
------------------------------
|
||||
|
||||
.. index::
|
||||
single: array handle; basic
|
||||
single: basic array handle
|
||||
|
||||
If the second storage template parameter of :class:`vtkm::cont::ArrayHandle` is not specified, it defaults to the basic memory layout.
|
||||
This is roughly synonymous with a wrapper around a standard C array, much like ``std::vector``.
|
||||
In fact, :secref:`basic-array-handles:Creating Array Handles` provides examples of wrapping a default :class:`vtkm::cont::ArrayHandle` around either a basic C array or a ``std::vector``.
|
||||
|
||||
|VTKm| provides :class:`vtkm::cont::ArrayHandleBasic` as a convenience class for working with basic array handles.
|
||||
:class:`vtkm::cont::ArrayHandleBasic` is a simple subclass of :class:`vtkm::cont::ArrayHandle` with the default storage in the second template argument (which is :class:`vtkm::cont::StorageTagBasic`).
|
||||
:class:`vtkm::cont::ArrayHandleBasic` and its superclass can be used more or less interchangeably.
|
||||
|
||||
.. doxygenclass:: vtkm::cont::ArrayHandleBasic
|
||||
:members:
|
||||
|
||||
Because a :class:`vtkm::cont::ArrayHandleBasic` represents arrays as a standard C array, it is possible to get a pointer to this array using either :func:`vtkm::cont::ArrayHandleBasic::GetReadPointer` or :func:`vtkm::cont::ArrayHandleBasic::GetWritePointer`.
|
||||
|
||||
.. load-example:: GetArrayPointer
|
||||
:file: GuideExampleArrayHandle.cxx
|
||||
:caption: Getting a standard C array from a basic array handle.
|
||||
|
||||
.. didyouknow::
|
||||
When you get an array pointer this way, the :class:`vtkm::cont::ArrayHandle` still has a reference to it.
|
||||
If using multiple threads, you can use a :class:`vtkm::cont::Token` object to lock the array.
|
||||
When the token is used to get a pointer, it will lock the array as long as the token exists.
|
||||
:numref:`ex:GetArrayPointer` demonstrates using a :class:`vtkm::cont::Token`.
|
||||
|
||||
--------------------
|
||||
Structure of Arrays
|
||||
--------------------
|
||||
|
||||
.. index::
|
||||
single: AOS
|
||||
single: SOA
|
||||
|
||||
The basic :class:`vtkm::cont::ArrayHandle` stores :class:`vtkm::Vec` objects in sequence.
|
||||
In this sense, a basic array is an *Array of Structures* (AOS).
|
||||
Another approach is to store each component of the structure (i.e., the :class:`vtkm::Vec`) in a separate array.
|
||||
This is known as a *Structure of Arrays* (SOA).
|
||||
There are advantages to this approach including potentially better cache performance and the ability to combine arrays already represented as separate components without copying them.
|
||||
Arrays of this nature are represented with a :class:`vtkm::cont::ArrayHandleSOA`, which is a subclass of :class:`vtkm::cont::StorageTagSOA`.
|
||||
|
||||
.. doxygenclass:: vtkm::cont::ArrayHandleSOA
|
||||
:members:
|
||||
|
||||
:class:`vtkm::cont::ArrayHandleSOA` can be constructed and allocated just as a basic array handle.
|
||||
Additionally, you can use its constructors or the :func:`vtkm::cont::make_ArrayHandleSOA` functions to build a :class:`vtkm::cont::ArrayHandleSOA` from basic :class:`vtkm::cont::ArrayHandle`'s that hold the components.
|
||||
|
||||
.. doxygenfunction:: vtkm::cont::make_ArrayHandleSOA(std::initializer_list<vtkm::cont::ArrayHandle<typename vtkm::VecTraits<ValueType>::ComponentType, vtkm::cont::StorageTagBasic>> &&)
|
||||
.. doxygenfunction:: vtkm::cont::make_ArrayHandleSOA(const vtkm::cont::ArrayHandle<ComponentType, vtkm::cont::StorageTagBasic>&, const RemainingArrays&...)
|
||||
.. doxygenfunction:: vtkm::cont::make_ArrayHandleSOA(std::initializer_list<std::vector<typename vtkm::VecTraits<ValueType>::ComponentType>>&&)
|
||||
.. doxygenfunction:: vtkm::cont::make_ArrayHandleSOA(vtkm::CopyFlag, const std::vector<ComponentType>&, RemainingVectors&&...)
|
||||
.. doxygenfunction:: vtkm::cont::make_ArrayHandleSOA(vtkm::CopyFlag, std::vector<ComponentType>&&, RemainingVectors&&...)
|
||||
.. doxygenfunction:: vtkm::cont::make_ArrayHandleSOAMove(std::vector<ComponentType>&&, RemainingVectors&&...)
|
||||
.. doxygenfunction:: vtkm::cont::make_ArrayHandleSOA(std::initializer_list<const typename vtkm::VecTraits<ValueType>::ComponentType*>&&, vtkm::Id, vtkm::CopyFlag)
|
||||
.. doxygenfunction:: vtkm::cont::make_ArrayHandleSOA(vtkm::Id, vtkm::CopyFlag, const ComponentType*, const RemainingArrays*...)
|
||||
|
||||
.. load-example:: ArrayHandleSOAFromComponentArrays
|
||||
:file: GuideExampleArrayHandle.cxx
|
||||
:caption: Creating an SOA array handle from component arrays.
|
||||
|
||||
.. didyouknow::
|
||||
In addition to constructing a :class:`vtkm::cont::ArrayHandleSOA` from its component arrays, you can get the component arrays back out using the :func:`vtkm::cont::ArrayHandleSOA::GetArray` method.
|
||||
|
||||
--------------------
|
||||
Strided Arrays
|
||||
--------------------
|
||||
|
||||
.. todo:: Should this be moved to the chapter/section on transformed arrays?
|
||||
|
||||
.. index::
|
||||
double: array handle; stride
|
||||
double: array handle; offset
|
||||
double: array handle; modulo
|
||||
double: array handle; divisor
|
||||
|
||||
:class:`vtkm::cont::ArrayHandleBasic` operates on a tightly packed array.
|
||||
That is, each value follows immediately after the proceeding value in memory.
|
||||
However, it is often convenient to access values at different strides or offsets.
|
||||
This allows representations of data that are not tightly packed in memory.
|
||||
The :class:`vtkm::cont::ArrayHandleStride` class allows arrays with different data packing.
|
||||
|
||||
.. doxygenclass:: vtkm::cont::ArrayHandleStride
|
||||
:members:
|
||||
|
||||
The most common use of :class:`vtkm::cont::ArrayHandleStride` is to pull components out of arrays.
|
||||
:class:`vtkm::cont::ArrayHandleStride` is seldom constructed directly.
|
||||
Rather, |VTKm| has mechanisms to extract a component from an array.
|
||||
To extract a component directly from a :class:`vtkm::cont::ArrayHandle`, use :func:`vtkm::cont::ArrayExtractComponent`.
|
||||
|
||||
.. doxygenfunction:: vtkm::cont::ArrayExtractComponent
|
||||
|
||||
The main advantage of extracting components this way is to convert data represented in different types of arrays into an array of a single type.
|
||||
For example, :class:`vtkm::cont::ArrayHandleStride` can represent a component from either a :class:`vtkm::cont::ArrayHandleBasic` or a :class:`vtkm::cont::ArrayHandleSOA` by just using different stride values.
|
||||
This is used by :func:`vtkm::cont::UnknownArrayHandle::ExtractComponent` and elsewhere to create a concrete array handle class without knowing the actual class.
|
||||
|
||||
.. commonerrors::
|
||||
Many, but not all, of |VTKm|'s arrays can be represented by a :class:`vtkm::cont::ArrayHandleStride` directly without copying.
|
||||
If |VTKm| cannot easily create a :class:`vtkm::cont::ArrayHandleStride` when attempting such an operation, it will use a slow copying fallback.
|
||||
A warning will be issued whenever this happens.
|
||||
Be on the lookout for such warnings and consider changing the data representation when that happens.
|
||||
|
||||
--------------------
|
||||
Runtime Vec Arrays
|
||||
--------------------
|
||||
|
||||
Because many of the devices |VTKm| runs on cannot efficiently allocate memory while an algorithm is running, the data held in :class:`vtkm::cont::ArrayHandle`'s are usually required to be a static size.
|
||||
For example, the :class:`vtkm::Vec` object often used as the value type for :class:`vtkm::cont::ArrayHandle` has a number of components that must be defined at compile time.
|
||||
|
||||
This is a problem in cases where the size of a vector object cannot be determined at compile time.
|
||||
One class to help alleviate this problem is :class:`vtkm::cont::ArrayHandleRuntimeVec`.
|
||||
This array handle stores data in the same way as :class:`vtkm::cont::ArrayHandleBasic` with a :class:`vtkm::Vec` value type, but the size of the ``Vec`` can be set at runtime.
|
||||
|
||||
.. doxygenclass:: vtkm::cont::ArrayHandleRuntimeVec
|
||||
:members:
|
||||
|
||||
A :class:`vtkm::cont::ArrayHandleRuntimeVec` is easily created from existing data using one of the :func:`vtkm::cont::make_ArrayHandleRuntimeVec` functions.
|
||||
|
||||
.. doxygenfunction:: vtkm::cont::make_ArrayHandleRuntimeVec(vtkm::IdComponent, const vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagBasic>&)
|
||||
.. doxygenfunction:: vtkm::cont::make_ArrayHandleRuntimeVec(const vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagBasic>&)
|
||||
|
||||
|VTKm| also provides several convenience functions to convert a basic C array or ``std::vector`` to a :class:`vtkm::cont::ArrayHandleRuntimeVec`.
|
||||
|
||||
.. doxygenfunction:: vtkm::cont::make_ArrayHandleRuntimeVec(vtkm::IdComponent, const T*, vtkm::Id, vtkm::CopyFlag)
|
||||
.. doxygenfunction:: vtkm::cont::make_ArrayHandleRuntimeVecMove(vtkm::IdComponent, T*&, vtkm::Id, vtkm::cont::internal::BufferInfo::Deleter, vtkm::cont::internal::BufferInfo::Reallocater)
|
||||
.. doxygenfunction:: vtkm::cont::make_ArrayHandleRuntimeVec(vtkm::IdComponent, const std::vector<T, Allocator>&, vtkm::CopyFlag)
|
||||
.. doxygenfunction:: vtkm::cont::make_ArrayHandleRuntimeVecMove(vtkm::IdComponent, std::vector<T, Allocator>&&)
|
||||
|
||||
The advantage of this class is that a :class:`vtkm::cont::ArrayHandleRuntimeVec` can be created in a routine that does not know the number of components at runtime and then later retrieved as a basic :class:`vtkm::cont::ArrayHandle` with a :class:`vtkm::Vec` of the correct size.
|
||||
This often consists of a file reader or other data ingestion creating :class:`vtkm::cont::ArrayHandleRuntimeVec` objects and storing them in :class:`vtkm::cont::UnknownArrayHandle`, which is used as an array container for :class:`vtkm::cont::DataSet`.
|
||||
Filters that then subsequently operate on the :class:`vtkm::cont::DataSet` can retrieve the data as a :class:`vtkm::cont::ArrayHandle` of the appropriate :class:`vtkm::Vec` size.
|
||||
|
||||
.. load-example:: GroupWithRuntimeVec
|
||||
:file: GuideExampleArrayHandleRuntimeVec.cxx
|
||||
:caption: Loading a data with runtime component size and using with a static sized filter.
|
||||
|
||||
.. didyouknow::
|
||||
Wrapping a basic array in a :class:`vtkm::cont::ArrayHandleRuntimeVec` has a similar effect as wrapping the array in a :class:`vtkm::cont::ArrayHandleGroupVec`.
|
||||
The difference is in the context in which they are used.
|
||||
If the size of the ``Vec`` is known at compile time *and* the array is going to immediately be used (such as operated on by a worklet), then :class:`vtkm::cont::ArrayHandleGroupVec` should be used.
|
||||
However, if the ``Vec`` size is not known or the array will be stored in an object like :class:`vtkm::cont::UnknownArrayHandle`, then :class:`vtkm::cont::ArrayHandleRuntimeVec` is a better choice.
|
||||
|
||||
It is also possible to get a :class:`vtkm::cont::ArrayHandleRuntimeVec` from a :class:`vtkm::cont::UnknownArrayHandle` that was originally stored as a basic array.
|
||||
This is convenient for operations that want to operate on arrays with an unknown ``Vec`` size.
|
||||
|
||||
.. load-example:: GetRuntimeVec
|
||||
:file: GuideExampleArrayHandleRuntimeVec.cxx
|
||||
:caption: Using :class:`vtkm::cont::ArrayHandleRuntimeVec` to get an array regardless of the size of the contained :class:`vtkm::Vec` values.
|
@ -12,3 +12,4 @@ Advanced Development
|
||||
worklet-error-handling.rst
|
||||
math.rst
|
||||
working-with-cells.rst
|
||||
memory-layout.rst
|
||||
|
@ -101,6 +101,12 @@ public:
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/// @brief Basic array storage for an array handle.
|
||||
///
|
||||
/// This array handle references a standard C array. It provides a level
|
||||
/// of safety and management across devices.
|
||||
/// This is the default used when no storage is specified. Using this subclass
|
||||
/// allows access to the underlying raw array.
|
||||
template <typename T>
|
||||
class VTKM_ALWAYS_EXPORT ArrayHandleBasic : public ArrayHandle<T, vtkm::cont::StorageTagBasic>
|
||||
{
|
||||
@ -173,50 +179,89 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
/// @{
|
||||
/// \brief Gets raw access to the `ArrayHandle`'s data.
|
||||
/// @brief Gets raw access to the `ArrayHandle`'s data.
|
||||
///
|
||||
/// Note that the returned array may become invalidated by other operations on the ArryHandle
|
||||
/// unless you provide a token.
|
||||
/// Note that the returned array may become invalidated by other operations on the ArryHandle.
|
||||
///
|
||||
const T* GetReadPointer(vtkm::cont::Token& token) const
|
||||
{
|
||||
return reinterpret_cast<const T*>(this->GetBuffers()[0].ReadPointerHost(token));
|
||||
}
|
||||
const T* GetReadPointer() const
|
||||
{
|
||||
vtkm::cont::Token token;
|
||||
return this->GetReadPointer(token);
|
||||
}
|
||||
T* GetWritePointer(vtkm::cont::Token& token) const
|
||||
/// @brief Gets raw access to the `ArrayHandle`'s data.
|
||||
///
|
||||
/// @param token When a `vtkm::cont::Token` is provided, the array is locked
|
||||
/// from being used by any write operations until the token goes out of scope.
|
||||
///
|
||||
const T* GetReadPointer(vtkm::cont::Token& token) const
|
||||
{
|
||||
return reinterpret_cast<T*>(this->GetBuffers()[0].WritePointerHost(token));
|
||||
return reinterpret_cast<const T*>(this->GetBuffers()[0].ReadPointerHost(token));
|
||||
}
|
||||
/// @brief Gets raw write access to the `ArrayHandle`'s data.
|
||||
///
|
||||
/// Note that the returned array may become invalidated by other operations on the ArryHandle.
|
||||
///
|
||||
T* GetWritePointer() const
|
||||
{
|
||||
vtkm::cont::Token token;
|
||||
return this->GetWritePointer(token);
|
||||
}
|
||||
|
||||
const T* GetReadPointer(vtkm::cont::DeviceAdapterId device, vtkm::cont::Token& token) const
|
||||
/// @brief Gets raw write access to the `ArrayHandle`'s data.
|
||||
///
|
||||
/// @param token When a `vtkm::cont::Token` is provided, the array is locked
|
||||
/// from being used by any read or write operations until the token goes out of scope.
|
||||
///
|
||||
T* GetWritePointer(vtkm::cont::Token& token) const
|
||||
{
|
||||
return reinterpret_cast<const T*>(this->GetBuffers()[0].ReadPointerDevice(device, token));
|
||||
return reinterpret_cast<T*>(this->GetBuffers()[0].WritePointerHost(token));
|
||||
}
|
||||
|
||||
/// @brief Gets raw access to the `ArrayHandle`'s data on a particular device.
|
||||
///
|
||||
/// Note that the returned array may become invalidated by other operations on the ArryHandle.
|
||||
///
|
||||
/// @param device The device ID or device tag specifying on which device the array will
|
||||
/// be valid on.
|
||||
///
|
||||
const T* GetReadPointer(vtkm::cont::DeviceAdapterId device) const
|
||||
{
|
||||
vtkm::cont::Token token;
|
||||
return this->GetReadPointer(device, token);
|
||||
}
|
||||
T* GetWritePointer(vtkm::cont::DeviceAdapterId device, vtkm::cont::Token& token) const
|
||||
/// @brief Gets raw access to the `ArrayHandle`'s data.
|
||||
///
|
||||
/// @param device The device ID or device tag specifying on which device the array will
|
||||
/// be valid on.
|
||||
/// @param token When a `vtkm::cont::Token` is provided, the array is locked
|
||||
/// from being used by any write operations until the token goes out of scope.
|
||||
///
|
||||
const T* GetReadPointer(vtkm::cont::DeviceAdapterId device, vtkm::cont::Token& token) const
|
||||
{
|
||||
return reinterpret_cast<T*>(this->GetBuffers()[0].WritePointerDevice(device, token));
|
||||
return reinterpret_cast<const T*>(this->GetBuffers()[0].ReadPointerDevice(device, token));
|
||||
}
|
||||
/// @brief Gets raw write access to the `ArrayHandle`'s data.
|
||||
///
|
||||
/// Note that the returned array may become invalidated by other operations on the ArryHandle.
|
||||
///
|
||||
/// @param device The device ID or device tag specifying on which device the array will
|
||||
/// be valid on.
|
||||
///
|
||||
T* GetWritePointer(vtkm::cont::DeviceAdapterId device) const
|
||||
{
|
||||
vtkm::cont::Token token;
|
||||
return this->GetWritePointer(device, token);
|
||||
}
|
||||
/// @}
|
||||
/// @brief Gets raw write access to the `ArrayHandle`'s data.
|
||||
///
|
||||
/// @param device The device ID or device tag specifying on which device the array will
|
||||
/// be valid on.
|
||||
/// @param token When a `vtkm::cont::Token` is provided, the array is locked
|
||||
/// from being used by any read or write operations until the token goes out of scope.
|
||||
///
|
||||
T* GetWritePointer(vtkm::cont::DeviceAdapterId device, vtkm::cont::Token& token) const
|
||||
{
|
||||
return reinterpret_cast<T*>(this->GetBuffers()[0].WritePointerDevice(device, token));
|
||||
}
|
||||
};
|
||||
|
||||
/// A convenience function for creating an ArrayHandle from a standard C array.
|
||||
|
@ -296,7 +296,7 @@ public:
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/// \brief Fancy array handle for a basic array with runtime selected vec size.
|
||||
/// @brief Fancy array handle for a basic array with runtime selected vec size.
|
||||
///
|
||||
/// It is sometimes the case that you need to create an array of `Vec`s where
|
||||
/// the number of components is not known until runtime. This is problematic
|
||||
@ -341,6 +341,14 @@ private:
|
||||
using ComponentsArrayType = vtkm::cont::ArrayHandle<ComponentType, StorageTagBasic>;
|
||||
|
||||
public:
|
||||
/// @brief Construct an `ArrayHandleRuntimeVec` with a given number of components.
|
||||
///
|
||||
/// @param numComponents The size of the `Vec`s stored in the array. This must be
|
||||
/// specified at the time of construction.
|
||||
///
|
||||
/// @param componentsArray This optional parameter allows you to supply a basic array
|
||||
/// that holds the components. This provides a mechanism to group consecutive values
|
||||
/// into vectors.
|
||||
VTKM_CONT
|
||||
ArrayHandleRuntimeVec(vtkm::IdComponent numComponents,
|
||||
const ComponentsArrayType& componentsArray = ComponentsArrayType{})
|
||||
@ -348,18 +356,22 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
/// @brief Return the number of components in each vec value.
|
||||
VTKM_CONT vtkm::IdComponent GetNumberOfComponents() const
|
||||
{
|
||||
return StorageType::GetNumberOfComponents(this->GetBuffers());
|
||||
}
|
||||
|
||||
/// @brief Return a basic array containing the components stored in this array.
|
||||
///
|
||||
/// The returned array is shared with this object. Modifying the contents of one array
|
||||
/// will modify the other.
|
||||
VTKM_CONT vtkm::cont::ArrayHandleBasic<ComponentType> GetComponentsArray() const
|
||||
{
|
||||
return StorageType::GetComponentsArray(this->GetBuffers());
|
||||
}
|
||||
|
||||
///@{
|
||||
/// \brief Converts the array to that of a basic array handle.
|
||||
/// @brief Converts the array to that of a basic array handle.
|
||||
///
|
||||
/// This method converts the `ArrayHandleRuntimeVec` to a simple `ArrayHandleBasic`.
|
||||
/// This is useful if the `ArrayHandleRuntimeVec` is passed to a routine that works
|
||||
@ -371,6 +383,7 @@ public:
|
||||
StorageType::AsArrayHandleBasic(this->GetBuffers(), array);
|
||||
}
|
||||
|
||||
/// @copydoc AsArrayHandleBasic
|
||||
template <typename ArrayType>
|
||||
ArrayType AsArrayHandleBasic() const
|
||||
{
|
||||
@ -378,7 +391,6 @@ public:
|
||||
this->AsArrayHandleBasic(array);
|
||||
return array;
|
||||
}
|
||||
///@}
|
||||
};
|
||||
|
||||
/// `make_ArrayHandleRuntimeVec` is convenience function to generate an
|
||||
@ -407,6 +419,8 @@ VTKM_CONT auto make_ArrayHandleRuntimeVec(
|
||||
numComponents * UnrolledVec::NUM_COMPONENTS, flatComponents);
|
||||
}
|
||||
|
||||
/// Converts a basic array handle into an `ArrayHandleRuntimeVec` with 1 component. The
|
||||
/// constructed array is essentially equivalent but of a different type.
|
||||
template <typename T>
|
||||
VTKM_CONT auto make_ArrayHandleRuntimeVec(
|
||||
const vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagBasic>& componentsArray)
|
||||
|
@ -229,7 +229,7 @@ public:
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/// \brief An `ArrayHandle` that for Vecs stores each component in a separate physical array.
|
||||
/// @brief An `ArrayHandle` that for Vecs stores each component in a separate physical array.
|
||||
///
|
||||
/// `ArrayHandleSOA` behaves like a regular `ArrayHandle` (with a basic storage) except that
|
||||
/// if you specify a `ValueType` of a `Vec` or a `Vec-like`, it will actually store each
|
||||
@ -264,6 +264,17 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
/// @brief Construct an `ArrayHandleSOA` from a collection of component arrays.
|
||||
///
|
||||
/// @code{.cpp}
|
||||
/// vtkm::cont::ArrayHandle<T> components1;
|
||||
/// vtkm::cont::ArrayHandle<T> components2;
|
||||
/// vtkm::cont::ArrayHandle<T> components3;
|
||||
/// // Fill arrays...
|
||||
///
|
||||
/// std::array<T, 3> allComponents{ components1, components2, components3 };
|
||||
/// vtkm::cont::make_ArrayHandleSOA<vtkm::Vec<T, 3>vecarray(allComponents);
|
||||
/// @endcode
|
||||
ArrayHandleSOA(const std::array<ComponentArrayType, NUM_COMPONENTS>& componentArrays)
|
||||
{
|
||||
for (vtkm::IdComponent componentIndex = 0; componentIndex < NUM_COMPONENTS; ++componentIndex)
|
||||
@ -272,6 +283,17 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Construct an `ArrayHandleSOA` from a collection of component arrays.
|
||||
///
|
||||
/// @code{.cpp}
|
||||
/// vtkm::cont::ArrayHandle<T> components1;
|
||||
/// vtkm::cont::ArrayHandle<T> components2;
|
||||
/// vtkm::cont::ArrayHandle<T> components3;
|
||||
/// // Fill arrays...
|
||||
///
|
||||
/// std::vector<T> allComponents{ components1, components2, components3 };
|
||||
/// vtkm::cont::make_ArrayHandleSOA<vtkm::Vec<T, 3>vecarray(allComponents);
|
||||
/// @endcode
|
||||
ArrayHandleSOA(const std::vector<ComponentArrayType>& componentArrays)
|
||||
{
|
||||
VTKM_ASSERT(componentArrays.size() == NUM_COMPONENTS);
|
||||
@ -281,6 +303,17 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Construct an `ArrayHandleSOA` from a collection of component arrays.
|
||||
///
|
||||
/// @code{.cpp}
|
||||
/// vtkm::cont::ArrayHandle<T> components1;
|
||||
/// vtkm::cont::ArrayHandle<T> components2;
|
||||
/// vtkm::cont::ArrayHandle<T> components3;
|
||||
/// // Fill arrays...
|
||||
///
|
||||
/// vtkm::cont::make_ArrayHandleSOA<vtkm::Vec<T, 3> vecarray(
|
||||
/// { components1, components2, components3 });
|
||||
/// @endcode
|
||||
ArrayHandleSOA(std::initializer_list<ComponentArrayType>&& componentArrays)
|
||||
{
|
||||
VTKM_ASSERT(componentArrays.size() == NUM_COMPONENTS);
|
||||
@ -292,6 +325,19 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Construct an `ArrayHandleSOA` from a collection of component arrays.
|
||||
///
|
||||
/// The data is copied from the `std::vector`s to the array handle.
|
||||
///
|
||||
/// @code{.cpp}
|
||||
/// std::vector<T> components1;
|
||||
/// std::vector<T> components2;
|
||||
/// std::vector<T> components3;
|
||||
/// // Fill arrays...
|
||||
///
|
||||
/// vtkm::cont::ArrayHandleSOA<vtkm::Vec<T, 3>> vecarray(
|
||||
/// { components1, components2, components3 });
|
||||
/// @endcode
|
||||
ArrayHandleSOA(std::initializer_list<std::vector<ComponentType>>&& componentVectors)
|
||||
{
|
||||
VTKM_ASSERT(componentVectors.size() == NUM_COMPONENTS);
|
||||
@ -305,7 +351,22 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// This only works if all the templated arguments are of type std::vector<ComponentType>.
|
||||
/// @brief Construct an `ArrayHandleSOA` from a collection of component arrays.
|
||||
///
|
||||
/// The first argument is a `vtkm::CopyFlag` to determine whether the input arrays
|
||||
/// should be copied.
|
||||
/// The component arrays are listed as arguments.
|
||||
/// This only works if all the templated arguments are of type `std::vector<ComponentType>`.
|
||||
///
|
||||
/// @code{.cpp}
|
||||
/// std::vector<T> components1;
|
||||
/// std::vector<T> components2;
|
||||
/// std::vector<T> components3;
|
||||
/// // Fill arrays...
|
||||
///
|
||||
/// vtkm::cont::ArrayHandleSOA<vtkm::Vec<T, 3>> vecarray(
|
||||
/// vtkm::CopyFlag::On, components1, components2, components3);
|
||||
/// @endcode
|
||||
template <typename Allocator, typename... RemainingVectors>
|
||||
ArrayHandleSOA(vtkm::CopyFlag copy,
|
||||
const std::vector<ComponentType, Allocator>& vector0,
|
||||
@ -318,7 +379,25 @@ public:
|
||||
VTKM_STATIC_ASSERT(sizeof...(RemainingVectors) + 1 == NUM_COMPONENTS);
|
||||
}
|
||||
|
||||
// This only works if all the templated arguments are of type std::vector<ComponentType>.
|
||||
/// @brief Construct an `ArrayHandleSOA` from a collection of component arrays.
|
||||
///
|
||||
/// The first argument is a `vtkm::CopyFlag` to determine whether the input arrays
|
||||
/// should be copied.
|
||||
/// The component arrays are listed as arguments.
|
||||
/// This only works if all the templated arguments are rvalues of type
|
||||
/// `std::vector<ComponentType>`.
|
||||
///
|
||||
/// @code{.cpp}
|
||||
/// std::vector<T> components1;
|
||||
/// std::vector<T> components2;
|
||||
/// std::vector<T> components3;
|
||||
/// // Fill arrays...
|
||||
///
|
||||
/// vtkm::cont::ArrayHandleSOA<vtkm::Vec<T, N> vecarray(vtkm::CopyFlag::Off,
|
||||
/// std::move(components1),
|
||||
/// std::move(components2),
|
||||
/// std::move(components3);
|
||||
/// @endcode
|
||||
template <typename... RemainingVectors>
|
||||
ArrayHandleSOA(vtkm::CopyFlag copy,
|
||||
std::vector<ComponentType>&& vector0,
|
||||
@ -331,6 +410,17 @@ public:
|
||||
VTKM_STATIC_ASSERT(sizeof...(RemainingVectors) + 1 == NUM_COMPONENTS);
|
||||
}
|
||||
|
||||
/// @brief Construct an `ArrayHandleSOA` from a collection of component arrays.
|
||||
///
|
||||
/// @code{.cpp}
|
||||
/// T* components1;
|
||||
/// T* components2;
|
||||
/// T* components3;
|
||||
/// // Fill arrays...
|
||||
///
|
||||
/// vtkm::cont::ArrayHandleSOA<vtkm::Vec<T, 3>>(
|
||||
/// { components1, components2, components3 }, size, vtkm::CopyFlag::On);
|
||||
/// @endcode
|
||||
ArrayHandleSOA(std::initializer_list<const ComponentType*> componentArrays,
|
||||
vtkm::Id length,
|
||||
vtkm::CopyFlag copy)
|
||||
@ -345,7 +435,20 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// This only works if all the templated arguments are of type std::vector<ComponentType>.
|
||||
/// @brief Construct an `ArrayHandleSOA` from a collection of component arrays.
|
||||
///
|
||||
/// The component arrays are listed as arguments.
|
||||
/// This only works if all the templated arguments are of type `ComponentType*`.
|
||||
///
|
||||
/// @code{.cpp}
|
||||
/// T* components1;
|
||||
/// T* components2;
|
||||
/// T* components3;
|
||||
/// // Fill arrays...
|
||||
///
|
||||
/// vtkm::cont::ArrayHandleSOA<vtkm::Vec<T, 3>> vecarray(
|
||||
/// size, vtkm::CopyFlag::On, components1, components2, components3);
|
||||
/// @endcode
|
||||
template <typename... RemainingArrays>
|
||||
ArrayHandleSOA(vtkm::Id length,
|
||||
vtkm::CopyFlag copy,
|
||||
@ -358,17 +461,39 @@ public:
|
||||
VTKM_STATIC_ASSERT(sizeof...(RemainingArrays) + 1 == NUM_COMPONENTS);
|
||||
}
|
||||
|
||||
/// @brief Get a basic array representing the component for the given index.
|
||||
VTKM_CONT vtkm::cont::ArrayHandleBasic<ComponentType> GetArray(vtkm::IdComponent index) const
|
||||
{
|
||||
return ComponentArrayType({ this->GetBuffers()[index] });
|
||||
}
|
||||
|
||||
/// @brief Replace a component array.
|
||||
VTKM_CONT void SetArray(vtkm::IdComponent index, const ComponentArrayType& array)
|
||||
{
|
||||
this->SetBuffer(index, array.GetBuffers()[0]);
|
||||
}
|
||||
};
|
||||
|
||||
namespace internal
|
||||
{
|
||||
|
||||
template <typename... Remaining>
|
||||
using VecSizeFromRemaining =
|
||||
std::integral_constant<vtkm::IdComponent, vtkm::IdComponent(sizeof...(Remaining) + 1)>;
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/// @brief Create a `vtkm::cont::ArrayHandleSOA` with an initializer list of array handles.
|
||||
///
|
||||
/// @code{.cpp}
|
||||
/// vtkm::cont::ArrayHandle<T> components1;
|
||||
/// vtkm::cont::ArrayHandle<T> components2;
|
||||
/// vtkm::cont::ArrayHandle<T> components3;
|
||||
/// // Fill arrays...
|
||||
///
|
||||
/// auto vecarray = vtkm::cont::make_ArrayHandleSOA<vtkm::Vec<T, 3>>(
|
||||
/// { components1, components2, components3 });
|
||||
/// @endcode
|
||||
template <typename ValueType>
|
||||
VTKM_CONT ArrayHandleSOA<ValueType> make_ArrayHandleSOA(
|
||||
std::initializer_list<vtkm::cont::ArrayHandle<typename vtkm::VecTraits<ValueType>::ComponentType,
|
||||
@ -377,16 +502,43 @@ VTKM_CONT ArrayHandleSOA<ValueType> make_ArrayHandleSOA(
|
||||
return ArrayHandleSOA<ValueType>(std::move(componentArrays));
|
||||
}
|
||||
|
||||
/// @brief Create a `vtkm::cont::ArrayHandleSOA` with a number of array handles.
|
||||
///
|
||||
/// This only works if all the templated arguments are of type
|
||||
/// `vtkm::cont::ArrayHandle<ComponentType>`.
|
||||
///
|
||||
/// @code{.cpp}
|
||||
/// vtkm::cont::ArrayHandle<T> components1;
|
||||
/// vtkm::cont::ArrayHandle<T> components2;
|
||||
/// vtkm::cont::ArrayHandle<T> components3;
|
||||
/// // Fill arrays...
|
||||
///
|
||||
/// auto vecarray =
|
||||
/// vtkm::cont::make_ArrayHandleSOA(components1, components2, components3);
|
||||
/// @endcode
|
||||
template <typename ComponentType, typename... RemainingArrays>
|
||||
VTKM_CONT
|
||||
ArrayHandleSOA<vtkm::Vec<ComponentType, vtkm::IdComponent(sizeof...(RemainingArrays) + 1)>>
|
||||
make_ArrayHandleSOA(
|
||||
VTKM_CONT ArrayHandleSOA<
|
||||
vtkm::Vec<ComponentType, internal::VecSizeFromRemaining<RemainingArrays...>::value>>
|
||||
make_ArrayHandleSOA(
|
||||
const vtkm::cont::ArrayHandle<ComponentType, vtkm::cont::StorageTagBasic>& componentArray0,
|
||||
const RemainingArrays&... componentArrays)
|
||||
{
|
||||
return { componentArray0, componentArrays... };
|
||||
}
|
||||
|
||||
/// @brief Create a `vtkm::cont::ArrayHandleSOA` with an initializer list of `std::vector`.
|
||||
///
|
||||
/// The data is copied from the `std::vector`s to the array handle.
|
||||
///
|
||||
/// @code{.cpp}
|
||||
/// std::vector<T> components1;
|
||||
/// std::vector<T> components2;
|
||||
/// std::vector<T> components3;
|
||||
/// // Fill arrays...
|
||||
///
|
||||
/// auto vecarray = vtkm::cont::make_ArrayHandleSOA<vtkm::Vec<T, 3>>(
|
||||
/// { components1, components2, components3 });
|
||||
/// @endcode
|
||||
template <typename ValueType>
|
||||
VTKM_CONT ArrayHandleSOA<ValueType> make_ArrayHandleSOA(
|
||||
std::initializer_list<std::vector<typename vtkm::VecTraits<ValueType>::ComponentType>>&&
|
||||
@ -395,11 +547,26 @@ VTKM_CONT ArrayHandleSOA<ValueType> make_ArrayHandleSOA(
|
||||
return ArrayHandleSOA<ValueType>(std::move(componentVectors));
|
||||
}
|
||||
|
||||
// This only works if all the templated arguments are of type std::vector<ComponentType>.
|
||||
/// @brief Create a `vtkm::cont::ArrayHandleSOA` with a number of `std::vector`.
|
||||
///
|
||||
/// The first argument is a `vtkm::CopyFlag` to determine whether the input arrays
|
||||
/// should be copied.
|
||||
/// The component arrays are listed as arguments.
|
||||
/// This only works if all the templated arguments are of type `std::vector<ComponentType>`.
|
||||
///
|
||||
/// @code{.cpp}
|
||||
/// std::vector<T> components1;
|
||||
/// std::vector<T> components2;
|
||||
/// std::vector<T> components3;
|
||||
/// // Fill arrays...
|
||||
///
|
||||
/// auto vecarray = vtkm::cont::make_ArrayHandleSOA(
|
||||
/// vtkm::CopyFlag::On, components1, components2, components3);
|
||||
/// @endcode
|
||||
template <typename ComponentType, typename... RemainingVectors>
|
||||
VTKM_CONT
|
||||
ArrayHandleSOA<vtkm::Vec<ComponentType, vtkm::IdComponent(sizeof...(RemainingVectors) + 1)>>
|
||||
make_ArrayHandleSOA(vtkm::CopyFlag copy,
|
||||
VTKM_CONT ArrayHandleSOA<
|
||||
vtkm::Vec<ComponentType, internal::VecSizeFromRemaining<RemainingVectors...>::value>>
|
||||
make_ArrayHandleSOA(vtkm::CopyFlag copy,
|
||||
const std::vector<ComponentType>& vector0,
|
||||
RemainingVectors&&... componentVectors)
|
||||
{
|
||||
@ -409,32 +576,74 @@ VTKM_CONT
|
||||
copy)... };
|
||||
}
|
||||
|
||||
// This only works if all the templated arguments are of type std::vector<ComponentType>.
|
||||
/// @brief Create a `vtkm::cont::ArrayHandleSOA` with a number of `std::vector`.
|
||||
///
|
||||
/// The first argument is a `vtkm::CopyFlag` to determine whether the input arrays
|
||||
/// should be copied.
|
||||
/// The component arrays are listed as arguments.
|
||||
/// This only works if all the templated arguments are rvalues of type
|
||||
/// `std::vector<ComponentType>`.
|
||||
///
|
||||
/// @code{.cpp}
|
||||
/// std::vector<T> components1;
|
||||
/// std::vector<T> components2;
|
||||
/// std::vector<T> components3;
|
||||
/// // Fill arrays...
|
||||
///
|
||||
/// auto vecarray = vtkm::cont::make_ArrayHandleSOA(vtkm::CopyFlag::Off,
|
||||
/// std::move(components1),
|
||||
/// std::move(components2),
|
||||
/// std::move(components3);
|
||||
/// @endcode
|
||||
template <typename ComponentType, typename... RemainingVectors>
|
||||
VTKM_CONT
|
||||
ArrayHandleSOA<vtkm::Vec<ComponentType, vtkm::IdComponent(sizeof...(RemainingVectors) + 1)>>
|
||||
make_ArrayHandleSOA(vtkm::CopyFlag copy,
|
||||
VTKM_CONT ArrayHandleSOA<
|
||||
vtkm::Vec<ComponentType, internal::VecSizeFromRemaining<RemainingVectors...>::value>>
|
||||
make_ArrayHandleSOA(vtkm::CopyFlag copy,
|
||||
std::vector<ComponentType>&& vector0,
|
||||
RemainingVectors&&... componentVectors)
|
||||
{
|
||||
// Convert std::vector to ArrayHandle first so that it correctly handles a mix of rvalue args.
|
||||
return ArrayHandleSOA<
|
||||
vtkm::Vec<ComponentType, vtkm::IdComponent(sizeof...(RemainingVectors) + 1)>>(
|
||||
vtkm::Vec<ComponentType, internal::VecSizeFromRemaining<RemainingVectors...>::value>>(
|
||||
vtkm::cont::make_ArrayHandle(std::move(vector0), copy),
|
||||
vtkm::cont::make_ArrayHandle(std::forward<RemainingVectors>(componentVectors), copy)...);
|
||||
}
|
||||
|
||||
// This only works if all the templated arguments are rvalues of std::vector<ComponentType>.
|
||||
/// @brief Create a `vtkm::cont::ArrayHandleSOA` with a number of `std::vector`.
|
||||
///
|
||||
/// This only works if all the templated arguments are rvalues of type
|
||||
/// `std::vector<ComponentType>`.
|
||||
///
|
||||
/// @code{.cpp}
|
||||
/// std::vector<T> components1;
|
||||
/// std::vector<T> components2;
|
||||
/// std::vector<T> components3;
|
||||
/// // Fill arrays...
|
||||
///
|
||||
/// auto vecarray = vtkm::cont::make_ArrayHandleSOAMove(
|
||||
/// std::move(components1), std::move(components2), std::move(components3));
|
||||
/// @endcode
|
||||
template <typename ComponentType, typename... RemainingVectors>
|
||||
VTKM_CONT
|
||||
ArrayHandleSOA<vtkm::Vec<ComponentType, vtkm::IdComponent(sizeof...(RemainingVectors) + 1)>>
|
||||
make_ArrayHandleSOAMove(std::vector<ComponentType>&& vector0,
|
||||
VTKM_CONT ArrayHandleSOA<
|
||||
vtkm::Vec<ComponentType, internal::VecSizeFromRemaining<RemainingVectors...>::value>>
|
||||
make_ArrayHandleSOAMove(std::vector<ComponentType>&& vector0,
|
||||
RemainingVectors&&... componentVectors)
|
||||
{
|
||||
return { vtkm::cont::make_ArrayHandleMove(std::move(vector0)),
|
||||
vtkm::cont::make_ArrayHandleMove(std::forward<RemainingVectors>(componentVectors))... };
|
||||
}
|
||||
|
||||
/// @brief Create a `vtkm::cont::ArrayHandleSOA` with an initializer list of C arrays.
|
||||
///
|
||||
/// @code{.cpp}
|
||||
/// T* components1;
|
||||
/// T* components2;
|
||||
/// T* components3;
|
||||
/// // Fill arrays...
|
||||
///
|
||||
/// auto vecarray = vtkm::cont::make_ArrayHandleSOA<vtkm::Vec<T, 3>>(
|
||||
/// { components1, components2, components3 }, size, vtkm::CopyFlag::On);
|
||||
/// @endcode
|
||||
template <typename ValueType>
|
||||
VTKM_CONT ArrayHandleSOA<ValueType> make_ArrayHandleSOA(
|
||||
std::initializer_list<const typename vtkm::VecTraits<ValueType>::ComponentType*>&&
|
||||
@ -445,11 +654,23 @@ VTKM_CONT ArrayHandleSOA<ValueType> make_ArrayHandleSOA(
|
||||
return ArrayHandleSOA<ValueType>(std::move(componentVectors), length, copy);
|
||||
}
|
||||
|
||||
// This only works if all the templated arguments are of type std::vector<ComponentType>.
|
||||
/// @brief Create a `vtkm::cont::ArrayHandleSOA` with a number of C arrays.
|
||||
///
|
||||
/// This only works if all the templated arguments are of type `ComponentType*`.
|
||||
///
|
||||
/// @code{.cpp}
|
||||
/// T* components1;
|
||||
/// T* components2;
|
||||
/// T* components3;
|
||||
/// // Fill arrays...
|
||||
///
|
||||
/// auto vecarray = vtkm::cont::make_ArrayHandleSOA(
|
||||
/// size, vtkm::CopyFlag::On, components1, components2, components3);
|
||||
/// @endcode
|
||||
template <typename ComponentType, typename... RemainingArrays>
|
||||
VTKM_CONT
|
||||
ArrayHandleSOA<vtkm::Vec<ComponentType, vtkm::IdComponent(sizeof...(RemainingArrays) + 1)>>
|
||||
make_ArrayHandleSOA(vtkm::Id length,
|
||||
VTKM_CONT ArrayHandleSOA<
|
||||
vtkm::Vec<ComponentType, internal::VecSizeFromRemaining<RemainingArrays...>::value>>
|
||||
make_ArrayHandleSOA(vtkm::Id length,
|
||||
vtkm::CopyFlag copy,
|
||||
const ComponentType* array0,
|
||||
const RemainingArrays*... componentArrays)
|
||||
|
@ -344,6 +344,7 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
/// @brief Construct an `ArrayHandleStride` from a basic array with specified access patterns.
|
||||
ArrayHandleStride(const vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagBasic>& array,
|
||||
vtkm::Id numValues,
|
||||
vtkm::Id stride,
|
||||
@ -368,11 +369,44 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
/// @brief Get the stride that values are accessed.
|
||||
///
|
||||
/// The stride is the spacing between consecutive values. The stride is measured
|
||||
/// in terms of the number of values. A stride of 1 means a fully packed array.
|
||||
/// A stride of 2 means selecting every other values.
|
||||
vtkm::Id GetStride() const { return StorageType::GetInfo(this->GetBuffers()).Stride; }
|
||||
|
||||
/// @brief Get the offset to start reading values.
|
||||
///
|
||||
/// The offset is the number of values to skip before the first value. The offset
|
||||
/// is measured in terms of the number of values. An offset of 0 means the first value
|
||||
/// at the beginning of the array.
|
||||
///
|
||||
/// The offset is unaffected by the stride and dictates where the strides starts
|
||||
/// counting. For example, given an array with size 3 vectors packed into an array,
|
||||
/// a strided array referencing the middle component will have offset 1 and stride 3.
|
||||
vtkm::Id GetOffset() const { return StorageType::GetInfo(this->GetBuffers()).Offset; }
|
||||
|
||||
/// @brief Get the modulus of the array index.
|
||||
///
|
||||
/// When the index is modulo a value, it becomes the remainder after dividing by that
|
||||
/// value. The effect of the modulus is to cause the index to repeat over the values
|
||||
/// in the array.
|
||||
///
|
||||
/// If the modulo is set to 0, then it is ignored.
|
||||
vtkm::Id GetModulo() const { return StorageType::GetInfo(this->GetBuffers()).Modulo; }
|
||||
|
||||
/// @brief Get the divisor of the array index.
|
||||
///
|
||||
/// The index is divided by the divisor before the other effects. The default divisor of
|
||||
/// 1 will have no effect on the indexing. Setting the divisor to a value greater than 1
|
||||
/// has the effect of repeating each value that many times.
|
||||
vtkm::Id GetDivisor() const { return StorageType::GetInfo(this->GetBuffers()).Divisor; }
|
||||
|
||||
/// @brief Return the underlying data as a basic array handle.
|
||||
///
|
||||
/// It is common for the same basic array to be shared among multiple
|
||||
/// `vtkm::cont::ArrayHandleStride` objects.
|
||||
vtkm::cont::ArrayHandleBasic<T> GetBasicArray() const
|
||||
{
|
||||
return StorageType::GetBasicArray(this->GetBuffers());
|
||||
|
Loading…
Reference in New Issue
Block a user