Merge topic 'read-any-vec-size'

bb9e7a0d6 Handle any Vec size in VTKDataSetReader

Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !3061
This commit is contained in:
Kenneth Moreland 2023-05-22 14:56:55 +00:00 committed by Kitware Robot
commit 3fe452662b
5 changed files with 122 additions and 226 deletions

@ -0,0 +1,7 @@
# VTKDataSetReader handles any Vec size.
The legacy VTK file reader previously only supported a specific set of Vec
lengths (i.e., 1, 2, 3, 4, 6, and 9). This is because a basic array handle
has to have the vec length compiled in. However, the new
`ArrayHandleRuntimeVec` feature is capable of reading in any vec-length and
can be leveraged to read in arbitrarily sized vectors in field arrays.

@ -372,10 +372,13 @@ public:
///@}
};
/// \c make_ArrayHandleRuntimeVec is convenience function to generate an
/// ArrayHandleRuntimeVec. It takes in an ArrayHandle of values and an
/// array handle of offsets and returns an array handle with consecutive
/// entries grouped in a Vec.
/// `make_ArrayHandleRuntimeVec` is convenience function to generate an
/// `ArrayHandleRuntimeVec`. It takes the number of components stored in
/// each value's `Vec`, which must be specified on the construction of
/// the `ArrayHandleRuntimeVec`. If not specified, the number of components
/// is set to 1. `make_ArrayHandleRuntimeVec` can also optionally take an
/// existing array of components, which will be grouped into `Vec` values
/// based on the specified number of components.
///
template <typename T>
VTKM_CONT auto make_ArrayHandleRuntimeVec(
@ -402,6 +405,62 @@ VTKM_CONT auto make_ArrayHandleRuntimeVec(
return make_ArrayHandleRuntimeVec(1, componentsArray);
}
/// A convenience function for creating an `ArrayHandleRuntimeVec` from a standard C array.
///
template <typename T>
VTKM_CONT auto make_ArrayHandleRuntimeVec(vtkm::IdComponent numComponents,
const T* array,
vtkm::Id numberOfValues,
vtkm::CopyFlag copy)
{
return make_ArrayHandleRuntimeVec(numComponents,
vtkm::cont::make_ArrayHandle(array, numberOfValues, copy));
}
/// A convenience function to move a user-allocated array into an `ArrayHandleRuntimeVec`.
/// The provided array pointer will be reset to `nullptr`.
/// If the array was not allocated with the `new[]` operator, then deleter and reallocater
/// functions must be provided.
///
template <typename T>
VTKM_CONT auto make_ArrayHandleRuntimeVecMove(
vtkm::IdComponent numComponents,
T*& array,
vtkm::Id numberOfValues,
vtkm::cont::internal::BufferInfo::Deleter deleter = internal::SimpleArrayDeleter<T>,
vtkm::cont::internal::BufferInfo::Reallocater reallocater = internal::SimpleArrayReallocater<T>)
{
return make_ArrayHandleRuntimeVec(
numComponents, vtkm::cont::make_ArrayHandleMove(array, numberOfValues, deleter, reallocater));
}
/// A convenience function for creating an `ArrayHandleRuntimeVec` from an `std::vector`.
///
template <typename T, typename Allocator>
VTKM_CONT auto make_ArrayHandleRuntimeVec(vtkm::IdComponent numComponents,
const std::vector<T, Allocator>& array,
vtkm::CopyFlag copy)
{
return make_ArrayHandleRuntimeVec(numComponents, vtkm::cont::make_ArrayHandle(array, copy));
}
/// Move an `std::vector` into an `ArrayHandleRuntimeVec`.
///
template <typename T, typename Allocator>
VTKM_CONT auto make_ArrayHandleRuntimeVecMove(vtkm::IdComponent numComponents,
std::vector<T, Allocator>&& array)
{
return make_ArrayHandleRuntimeVec(numComponents, make_ArrayHandleMove(std::move(array)));
}
template <typename T, typename Allocator>
VTKM_CONT auto make_ArrayHandleRuntimeVec(vtkm::IdComponent numComponents,
std::vector<T, Allocator>&& array,
vtkm::CopyFlag vtkmNotUsed(copy))
{
return make_ArrayHandleRuntimeVecMove(numComponents, std::move(array));
}
namespace internal
{

@ -14,6 +14,7 @@
#include <vtkm/cont/ArrayCopy.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ArrayHandleOffsetsToNumComponents.h>
#include <vtkm/cont/ArrayHandleRuntimeVec.h>
#include <vtkm/cont/ArrayPortalToIterators.h>
#include <vtkm/cont/Logging.h>
#include <vtkm/cont/UnknownArrayHandle.h>
@ -35,162 +36,6 @@ inline void PrintVTKDataFileSummary(const vtkm::io::internal::VTKDataSetFile& df
<< std::endl;
}
// Since Fields and DataSets store data in the default UnknownArrayHandle, convert
// the data to the closest type supported by default. The following will
// need to be updated if UnknownArrayHandle or TypeListCommon changes.
template <typename T>
struct ClosestCommonType
{
using Type = T;
};
template <>
struct ClosestCommonType<vtkm::Int8>
{
using Type = vtkm::Int32;
};
template <>
struct ClosestCommonType<vtkm::UInt8>
{
using Type = vtkm::Int32;
};
template <>
struct ClosestCommonType<vtkm::Int16>
{
using Type = vtkm::Int32;
};
template <>
struct ClosestCommonType<vtkm::UInt16>
{
using Type = vtkm::Int32;
};
template <>
struct ClosestCommonType<vtkm::UInt32>
{
using Type = vtkm::Int64;
};
template <>
struct ClosestCommonType<vtkm::UInt64>
{
using Type = vtkm::Int64;
};
template <typename T>
struct ClosestFloat
{
using Type = T;
};
template <>
struct ClosestFloat<vtkm::Int8>
{
using Type = vtkm::Float32;
};
template <>
struct ClosestFloat<vtkm::UInt8>
{
using Type = vtkm::Float32;
};
template <>
struct ClosestFloat<vtkm::Int16>
{
using Type = vtkm::Float32;
};
template <>
struct ClosestFloat<vtkm::UInt16>
{
using Type = vtkm::Float32;
};
template <>
struct ClosestFloat<vtkm::Int32>
{
using Type = vtkm::Float64;
};
template <>
struct ClosestFloat<vtkm::UInt32>
{
using Type = vtkm::Float64;
};
template <>
struct ClosestFloat<vtkm::Int64>
{
using Type = vtkm::Float64;
};
template <>
struct ClosestFloat<vtkm::UInt64>
{
using Type = vtkm::Float64;
};
template <typename T>
vtkm::cont::UnknownArrayHandle CreateUnknownArrayHandle(const std::vector<T>& vec)
{
switch (vtkm::VecTraits<T>::NUM_COMPONENTS)
{
case 1:
{
using CommonType = typename ClosestCommonType<T>::Type;
constexpr bool not_same = !std::is_same<T, CommonType>::value;
if (not_same)
{
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
"Type " << vtkm::io::internal::DataTypeName<T>::Name()
<< " is currently unsupported. Converting to "
<< vtkm::io::internal::DataTypeName<CommonType>::Name() << ".");
}
vtkm::cont::ArrayHandle<CommonType> output;
output.Allocate(static_cast<vtkm::Id>(vec.size()));
auto portal = output.WritePortal();
for (vtkm::Id i = 0; i < output.GetNumberOfValues(); ++i)
{
portal.Set(i, static_cast<CommonType>(vec[static_cast<std::size_t>(i)]));
}
return vtkm::cont::UnknownArrayHandle(output);
}
case 2:
case 3:
case 9:
{
constexpr auto numComps = vtkm::VecTraits<T>::NUM_COMPONENTS;
using InComponentType = typename vtkm::VecTraits<T>::ComponentType;
using OutComponentType = typename ClosestFloat<InComponentType>::Type;
using CommonType = vtkm::Vec<OutComponentType, numComps>;
constexpr bool not_same = !std::is_same<T, CommonType>::value;
if (not_same)
{
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
"Type " << vtkm::io::internal::DataTypeName<InComponentType>::Name() << "["
<< vtkm::VecTraits<T>::GetNumberOfComponents(T()) << "] "
<< "is currently unsupported. Converting to "
<< vtkm::io::internal::DataTypeName<OutComponentType>::Name() << "["
<< numComps << "].");
}
vtkm::cont::ArrayHandle<CommonType> output;
output.Allocate(static_cast<vtkm::Id>(vec.size()));
auto portal = output.WritePortal();
for (vtkm::Id i = 0; i < output.GetNumberOfValues(); ++i)
{
CommonType outval = CommonType();
for (vtkm::IdComponent j = 0; j < numComps; ++j)
{
outval[j] = static_cast<OutComponentType>(
vtkm::VecTraits<T>::GetComponent(vec[static_cast<std::size_t>(i)], j));
}
portal.Set(i, outval);
}
return vtkm::cont::UnknownArrayHandle(output);
}
default:
{
VTKM_LOG_S(vtkm::cont::LogLevel::Warn, "Only 1, 2, 3, or 9 components supported. Skipping.");
return vtkm::cont::UnknownArrayHandle(vtkm::cont::ArrayHandle<vtkm::Float32>());
}
}
}
} // anonymous namespace
namespace vtkm
@ -676,27 +521,23 @@ void VTKDataSetReaderBase::ReadGlobalOrPedigreeIds(vtkm::cont::Field::Associatio
class VTKDataSetReaderBase::SkipArrayVariant
{
public:
SkipArrayVariant(VTKDataSetReaderBase* reader, std::size_t numElements)
SkipArrayVariant(VTKDataSetReaderBase* reader,
std::size_t numElements,
vtkm::IdComponent numComponents)
: Reader(reader)
, NumElements(numElements)
, TotalSize(numElements * static_cast<std::size_t>(numComponents))
{
}
template <typename T>
void operator()(T) const
{
this->Reader->SkipArray(this->NumElements, T());
}
template <typename T>
void operator()(vtkm::IdComponent numComponents, T) const
{
this->Reader->SkipArray(this->NumElements * static_cast<std::size_t>(numComponents), T());
this->Reader->SkipArray(this->TotalSize, T());
}
protected:
VTKDataSetReaderBase* Reader;
std::size_t NumElements;
std::size_t TotalSize;
};
class VTKDataSetReaderBase::ReadArrayVariant : public SkipArrayVariant
@ -705,9 +546,11 @@ public:
ReadArrayVariant(VTKDataSetReaderBase* reader,
vtkm::cont::Field::Association association,
std::size_t numElements,
vtkm::IdComponent numComponents,
vtkm::cont::UnknownArrayHandle& data)
: SkipArrayVariant(reader, numElements)
: SkipArrayVariant(reader, numElements, numComponents)
, Association(association)
, NumComponents(numComponents)
, Data(&data)
{
}
@ -715,12 +558,13 @@ public:
template <typename T>
void operator()(T) const
{
std::vector<T> buffer(this->NumElements);
std::vector<T> buffer(this->TotalSize);
this->Reader->ReadArray(buffer);
if ((this->Association != vtkm::cont::Field::Association::Cells) ||
(this->Reader->GetCellsPermutation().GetNumberOfValues() < 1))
{
*this->Data = CreateUnknownArrayHandle(buffer);
*this->Data =
vtkm::cont::make_ArrayHandleRuntimeVecMove(this->NumComponents, std::move(buffer));
}
else
{
@ -734,20 +578,14 @@ public:
std::size_t inIndex = static_cast<std::size_t>(permutation.Get(outIndex));
permutedBuffer[static_cast<std::size_t>(outIndex)] = buffer[inIndex];
}
*this->Data = CreateUnknownArrayHandle(permutedBuffer);
*this->Data =
vtkm::cont::make_ArrayHandleRuntimeVecMove(this->NumComponents, std::move(permutedBuffer));
}
}
template <typename T>
void operator()(vtkm::IdComponent numComponents, T) const
{
VTKM_LOG_S(vtkm::cont::LogLevel::Warn,
"Support for " << numComponents << " components not implemented. Skipping.");
SkipArrayVariant::operator()(numComponents, T());
}
private:
vtkm::cont::Field::Association Association;
vtkm::IdComponent NumComponents;
vtkm::cont::UnknownArrayHandle* Data;
};
@ -764,8 +602,8 @@ void VTKDataSetReaderBase::DoSkipArrayVariant(std::string dataType,
else
{
vtkm::io::internal::DataType typeId = vtkm::io::internal::DataTypeId(dataType);
vtkm::io::internal::SelectTypeAndCall(
typeId, numComponents, SkipArrayVariant(this, numElements));
vtkm::io::internal::SelectTypeAndCall(typeId,
SkipArrayVariant(this, numElements, numComponents));
}
}
@ -791,7 +629,7 @@ vtkm::cont::UnknownArrayHandle VTKDataSetReaderBase::DoReadArrayVariant(
{
vtkm::io::internal::DataType typeId = vtkm::io::internal::DataTypeId(dataType);
vtkm::io::internal::SelectTypeAndCall(
typeId, numComponents, ReadArrayVariant(this, association, numElements, data));
typeId, ReadArrayVariant(this, association, numElements, numComponents, data));
}
return data;

@ -170,73 +170,45 @@ struct DataTypeName<vtkm::Float64>
static const char* Name() { return "double"; }
};
template <typename T, typename Functor>
inline void SelectVecTypeAndCall(T, vtkm::IdComponent numComponents, const Functor& functor)
{
switch (numComponents)
{
case 1:
functor(T());
break;
case 2:
functor(vtkm::Vec<T, 2>());
break;
case 3:
functor(vtkm::Vec<T, 3>());
break;
case 4:
functor(vtkm::Vec<T, 4>());
break;
case 9:
functor(vtkm::Vec<T, 9>());
break;
default:
functor(numComponents, T());
break;
}
}
template <typename Functor>
inline void SelectTypeAndCall(DataType dtype,
vtkm::IdComponent numComponents,
const Functor& functor)
inline void SelectTypeAndCall(DataType dtype, Functor&& functor)
{
switch (dtype)
{
case DTYPE_BIT:
SelectVecTypeAndCall(DummyBitType(), numComponents, functor);
functor(DummyBitType());
break;
case DTYPE_UNSIGNED_CHAR:
SelectVecTypeAndCall(vtkm::UInt8(), numComponents, functor);
functor(vtkm::UInt8());
break;
case DTYPE_CHAR:
SelectVecTypeAndCall(vtkm::Int8(), numComponents, functor);
functor(vtkm::Int8());
break;
case DTYPE_UNSIGNED_SHORT:
SelectVecTypeAndCall(vtkm::UInt16(), numComponents, functor);
functor(vtkm::UInt16());
break;
case DTYPE_SHORT:
SelectVecTypeAndCall(vtkm::Int16(), numComponents, functor);
functor(vtkm::Int16());
break;
case DTYPE_UNSIGNED_INT:
SelectVecTypeAndCall(vtkm::UInt32(), numComponents, functor);
functor(vtkm::UInt32());
break;
case DTYPE_INT:
SelectVecTypeAndCall(vtkm::Int32(), numComponents, functor);
functor(vtkm::Int32());
break;
case DTYPE_UNSIGNED_LONG:
case DTYPE_UNSIGNED_LONG_LONG:
SelectVecTypeAndCall(vtkm::UInt64(), numComponents, functor);
functor(vtkm::UInt64());
break;
case DTYPE_LONG:
case DTYPE_LONG_LONG:
SelectVecTypeAndCall(vtkm::Int64(), numComponents, functor);
functor(vtkm::Int64());
break;
case DTYPE_FLOAT:
SelectVecTypeAndCall(vtkm::Float32(), numComponents, functor);
functor(vtkm::Float32());
break;
case DTYPE_DOUBLE:
SelectVecTypeAndCall(vtkm::Float64(), numComponents, functor);
functor(vtkm::Float64());
break;
default:
assert(false);

@ -12,6 +12,7 @@
#include <cstdio>
#include <vector>
#include <vtkm/cont/ArrayHandleSOA.h>
#include <vtkm/cont/DataSetBuilderUniform.h>
#include <vtkm/io/VTKDataSetReader.h>
#include <vtkm/io/VTKDataSetWriter.h>
@ -122,7 +123,7 @@ void CheckWrittenReadData(const vtkm::cont::DataSet& originalData,
VTKM_TEST_ASSERT(fileData.HasField(originalField.GetName(), originalField.GetAssociation()));
vtkm::cont::Field fileField =
fileData.GetField(originalField.GetName(), originalField.GetAssociation());
vtkm::cont::CastAndCall(originalField, CheckSameField{}, fileField);
VTKM_TEST_ASSERT(test_equal_ArrayHandles(originalField.GetData(), fileField.GetData()));
}
VTKM_TEST_ASSERT(fileData.GetNumberOfCoordinateSystems() > 0);
@ -261,12 +262,31 @@ void TestVTKCompoundWrite()
std::remove("chirp.vtk");
}
void TestVTKOddVecSizes()
{
vtkm::cont::DataSetBuilderUniform dsb;
vtkm::cont::DataSet dataSet = dsb.Create({ 2, 2, 2 });
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::FloatDefault, 5>> vec5Array;
vec5Array.Allocate(dataSet.GetNumberOfPoints());
SetPortal(vec5Array.WritePortal());
dataSet.AddPointField("vec5", vec5Array);
vtkm::cont::ArrayHandleSOA<vtkm::Vec<vtkm::FloatDefault, 13>> vec13Array;
vec13Array.Allocate(dataSet.GetNumberOfPoints());
SetPortal(vec13Array.WritePortal());
dataSet.AddPointField("vec13", vec13Array);
TestVTKWriteTestData("OddVecSizes", dataSet);
}
void TestVTKWrite()
{
TestVTKExplicitWrite();
TestVTKUniformWrite();
TestVTKRectilinearWrite();
TestVTKCompoundWrite();
TestVTKOddVecSizes();
}
} //Anonymous namespace