Merge remote-tracking branch 'upstream/master' into lagrangian_bugfix

This commit is contained in:
Sudhanshu Sane 2020-05-20 10:15:47 -07:00
commit 536249f634
87 changed files with 4153 additions and 2027 deletions

@ -2,8 +2,8 @@
set -e
readonly version="nvcc_v3"
readonly sha256sum="d5b56dd9e7d4597f4a47a90d6327e30a259151b59b897607e1804d6d3513f491"
readonly version="nvcc_v4"
readonly sha256sum="260779b4a740fe8373d251d1e318541a98dd5cd2f8051eedd55227a5a852fdf7"
readonly filename="sccache-0.2.14-$version-x86_64-unknown-linux-musl"
readonly tarball="$filename.tar.gz"

@ -24,7 +24,14 @@ ctest_build(APPEND
RETURN_VALUE build_result)
if(NOT DEFINED ENV{GITLAB_CI_EMULATION})
ctest_submit(PARTS Build)
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.15)
ctest_submit(PARTS Build BUILD_ID build_id)
message(STATUS "Build submission build_id: ${build_id}")
else()
ctest_submit(PARTS Build)
endif()
endif()
if (build_result)

@ -38,8 +38,15 @@ ctest_configure(APPEND
# We can now submit because we've configured.
if(NOT DEFINED ENV{GITLAB_CI_EMULATION})
ctest_submit(PARTS Update)
ctest_submit(PARTS Configure)
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.15)
ctest_submit(PARTS Update BUILD_ID build_id)
message(STATUS "Update submission build_id: ${build_id}")
ctest_submit(PARTS Configure BUILD_ID build_id)
message(STATUS "Configure submission build_id: ${build_id}")
else()
ctest_submit(PARTS Update)
ctest_submit(PARTS Configure)
endif()
endif()
if (configure_result)

@ -48,7 +48,8 @@ ctest_memcheck(
EXCLUDE "${test_exclusions}"
DEFECT_COUNT defects)
ctest_submit(PARTS Memcheck)
ctest_submit(PARTS Memcheck BUILD_ID build_id)
message(STATUS "Memcheck submission build_id: ${build_id}")
if (defects)
message(FATAL_ERROR "Found ${defects} memcheck defects")

@ -35,7 +35,8 @@ ctest_test(APPEND
)
if(NOT DEFINED ENV{GITLAB_CI_EMULATION})
ctest_submit(PARTS Test)
ctest_submit(PARTS Test BUILD_ID build_id)
message(STATUS "Test submission build_id: ${build_id}")
endif()
if (test_result)

@ -378,7 +378,7 @@ function(vtkm_library)
EXTENDS_VTKM
DEVICE_SOURCES ${VTKm_LIB_DEVICE_SOURCES}
)
if(NOT VTKm_USE_DEFAULT_SYMBOL_VISIBILITY)
if(VTKm_HIDE_PRIVATE_SYMBOLS)
set_property(TARGET ${lib_name} PROPERTY CUDA_VISIBILITY_PRESET "hidden")
set_property(TARGET ${lib_name} PROPERTY CXX_VISIBILITY_PRESET "hidden")
endif()

@ -134,7 +134,7 @@ function(vtkm_unit_tests)
endif()
vtkm_add_target_information(${test_prog} DEVICE_SOURCES ${device_sources})
if(NOT VTKm_USE_DEFAULT_SYMBOL_VISIBILITY)
if(VTKm_HIDE_PRIVATE_SYMBOLS)
set_property(TARGET ${test_prog} PROPERTY CUDA_VISIBILITY_PRESET "hidden")
set_property(TARGET ${test_prog} PROPERTY CXX_VISIBILITY_PRESET "hidden")
endif()

@ -118,7 +118,7 @@ vtkm_option(VTKm_INSTALL_ONLY_LIBRARIES "install only vtk-m libraries and no hea
# rather than exporting all symbols. This flag is added so that consumers
# which require static builds can force all symbols on, which is something
# VTK does.
vtkm_option(VTKm_USE_DEFAULT_SYMBOL_VISIBILITY "Don't explicitly hide symbols from libraries." OFF)
vtkm_option(VTKm_HIDE_PRIVATE_SYMBOLS "Hide symbols from libraries." ON)
vtkm_option(BUILD_SHARED_LIBS "Build VTK-m with shared libraries" OFF)
set(VTKm_BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS})
@ -136,7 +136,7 @@ mark_as_advanced(
VTKm_ENABLE_LOGGING
VTKm_NO_ASSERT
VTKm_INSTALL_ONLY_LIBRARIES
VTKm_USE_DEFAULT_SYMBOL_VISIBILITY
VTKm_HIDE_PRIVATE_SYMBOLS
VTKm_ENABLE_DEVELOPER_FLAGS
VTKm_NO_INSTALL_README_LICENSE
)

@ -404,7 +404,7 @@ template <typename ValueType>
void BenchCopy(benchmark::State& state)
{
const vtkm::cont::DeviceAdapterId device = Config.Device;
const vtkm::Id numBytes = state.range(0);
const vtkm::Id numBytes = static_cast<vtkm::Id>(state.range(0));
const vtkm::Id numValues = BytesToWords<ValueType>(numBytes);
state.SetLabel(SizeAndValuesString(numBytes, numValues));
@ -580,7 +580,7 @@ template <typename ValueType>
void BenchFillArrayHandle(benchmark::State& state)
{
const vtkm::cont::DeviceAdapterId device = Config.Device;
const vtkm::Id numBytes = state.range(0);
const vtkm::Id numBytes = static_cast<vtkm::Id>(state.range(0));
const vtkm::Id numValues = BytesToWords<ValueType>(numBytes);
state.SetLabel(SizeAndValuesString(numBytes, numValues));
@ -610,7 +610,7 @@ VTKM_BENCHMARK_TEMPLATES_OPTS(BenchFillArrayHandle,
void BenchFillBitFieldBool(benchmark::State& state)
{
const vtkm::cont::DeviceAdapterId device = Config.Device;
const vtkm::Id numBytes = state.range(0);
const vtkm::Id numBytes = static_cast<vtkm::Id>(state.range(0));
const vtkm::Id numBits = numBytes * CHAR_BIT;
const bool value = state.range(1) != 0;
@ -640,7 +640,7 @@ template <typename WordType>
void BenchFillBitFieldMask(benchmark::State& state)
{
const vtkm::cont::DeviceAdapterId device = Config.Device;
const vtkm::Id numBytes = state.range(0);
const vtkm::Id numBytes = static_cast<vtkm::Id>(state.range(0));
const vtkm::Id numBits = numBytes * CHAR_BIT;
const WordType mask = static_cast<WordType>(0x1);
@ -717,7 +717,7 @@ template <typename ValueType>
void BenchReduce(benchmark::State& state)
{
const vtkm::cont::DeviceAdapterId device = Config.Device;
const vtkm::Id numBytes = state.range(0);
const vtkm::Id numBytes = static_cast<vtkm::Id>(state.range(0));
const vtkm::Id numValues = BytesToWords<ValueType>(numBytes);
state.SetLabel(SizeAndValuesString(numBytes, numValues));
@ -752,10 +752,10 @@ void BenchReduceByKey(benchmark::State& state)
{
const vtkm::cont::DeviceAdapterId device = Config.Device;
const vtkm::Id numBytes = state.range(0);
const vtkm::Id numBytes = static_cast<vtkm::Id>(state.range(0));
const vtkm::Id numValues = BytesToWords<ValueType>(numBytes);
const vtkm::Id percentKeys = state.range(1);
const vtkm::Id percentKeys = static_cast<vtkm::Id>(state.range(1));
const vtkm::Id numKeys = std::max((numValues * percentKeys) / 100, vtkm::Id{ 1 });
{
@ -807,7 +807,7 @@ template <typename ValueType>
void BenchScanExclusive(benchmark::State& state)
{
const vtkm::cont::DeviceAdapterId device = Config.Device;
const vtkm::Id numBytes = state.range(0);
const vtkm::Id numBytes = static_cast<vtkm::Id>(state.range(0));
const vtkm::Id numValues = BytesToWords<ValueType>(numBytes);
state.SetLabel(SizeAndValuesString(numBytes, numValues));
@ -841,7 +841,7 @@ template <typename ValueType>
void BenchScanExtended(benchmark::State& state)
{
const vtkm::cont::DeviceAdapterId device = Config.Device;
const vtkm::Id numBytes = state.range(0);
const vtkm::Id numBytes = static_cast<vtkm::Id>(state.range(0));
const vtkm::Id numValues = BytesToWords<ValueType>(numBytes);
state.SetLabel(SizeAndValuesString(numBytes, numValues));
@ -875,7 +875,7 @@ template <typename ValueType>
void BenchScanInclusive(benchmark::State& state)
{
const vtkm::cont::DeviceAdapterId device = Config.Device;
const vtkm::Id numBytes = state.range(0);
const vtkm::Id numBytes = static_cast<vtkm::Id>(state.range(0));
const vtkm::Id numValues = BytesToWords<ValueType>(numBytes);
state.SetLabel(SizeAndValuesString(numBytes, numValues));
@ -909,7 +909,7 @@ template <typename ValueType>
void BenchSort(benchmark::State& state)
{
const vtkm::cont::DeviceAdapterId device = Config.Device;
const vtkm::Id numBytes = state.range(0);
const vtkm::Id numBytes = static_cast<vtkm::Id>(state.range(0));
const vtkm::Id numValues = BytesToWords<ValueType>(numBytes);
state.SetLabel(SizeAndValuesString(numBytes, numValues));
@ -950,7 +950,7 @@ void BenchSortByKey(benchmark::State& state)
const vtkm::Id numBytes = static_cast<vtkm::Id>(state.range(0));
const vtkm::Id numValues = BytesToWords<ValueType>(numBytes);
const vtkm::Id percentKeys = state.range(1);
const vtkm::Id percentKeys = static_cast<vtkm::Id>(state.range(1));
const vtkm::Id numKeys = std::max((numValues * percentKeys) / 100, vtkm::Id{ 1 });
{
@ -1005,7 +1005,7 @@ template <typename ValueType>
void BenchStableSortIndices(benchmark::State& state)
{
const vtkm::cont::DeviceAdapterId device = Config.Device;
const vtkm::Id numBytes = state.range(0);
const vtkm::Id numBytes = static_cast<vtkm::Id>(state.range(0));
const vtkm::Id numValues = BytesToWords<ValueType>(numBytes);
state.SetLabel(SizeAndValuesString(numBytes, numValues));
@ -1042,10 +1042,10 @@ template <typename ValueType>
void BenchStableSortIndicesUnique(benchmark::State& state)
{
const vtkm::cont::DeviceAdapterId device = Config.Device;
const vtkm::Id numBytes = state.range(0);
const vtkm::Id numBytes = static_cast<vtkm::Id>(state.range(0));
const vtkm::Id numValues = BytesToWords<ValueType>(numBytes);
const vtkm::Id percentUnique = state.range(1);
const vtkm::Id percentUnique = static_cast<vtkm::Id>(state.range(1));
const vtkm::Id numUnique = std::max((numValues * percentUnique) / 100, vtkm::Id{ 1 });
{
@ -1105,10 +1105,10 @@ template <typename ValueType>
void BenchUnique(benchmark::State& state)
{
const vtkm::cont::DeviceAdapterId device = Config.Device;
const vtkm::Id numBytes = state.range(0);
const vtkm::Id numBytes = static_cast<vtkm::Id>(state.range(0));
const vtkm::Id numValues = BytesToWords<ValueType>(numBytes);
const vtkm::Id percentUnique = state.range(1);
const vtkm::Id percentUnique = static_cast<vtkm::Id>(state.range(1));
const vtkm::Id numUnique = std::max((numValues * percentUnique) / 100, vtkm::Id{ 1 });
{

@ -52,7 +52,7 @@ set(VTKm_BENCHS_RANGE_UPPER_BOUNDARY 134217728 CACHE STRING "Biggest sample for
mark_as_advanced(VTKm_BENCHS_RANGE_LOWER_BOUNDARY VTKm_BENCHS_RANGE_UPPER_BOUNDARY)
foreach (benchmark ${benchmarks})
add_benchmark(NAME ${benchmark} FILE ${benchmark}.cxx LIBS vtkm_source vtkm_filter)
add_benchmark(NAME ${benchmark} FILE ${benchmark}.cxx LIBS vtkm_source vtkm_filter vtkm_io)
endforeach ()
target_compile_definitions(BenchmarkDeviceAdapter PUBLIC VTKm_BENCHS_RANGE_LOWER_BOUNDARY=${VTKm_BENCHS_RANGE_LOWER_BOUNDARY})

@ -0,0 +1,13 @@
# Result DataSet of coordinate transform has its CoordinateSystem changed
When you run one of the coordinate transform filters,
`CylindricalCoordinateTransform` or `SphericalCoordinateTransform`, the
transform coordiantes are placed as the first `CoordinateSystem` in the
returned `DataSet`. This means that after running this filter, the data
will be moved to this new coordinate space.
Previously, the result of these filters was just placed in a named `Field`
of the output. This caused some confusion because the filter did not seem
to have any effect (unless you knew to modify the output data). Not using
the result as the coordinate system seems like a dubious use case (and not
hard to work around), so this is much better behavior.

@ -0,0 +1,17 @@
# DataSet now only allows unique field names
When you add a `vtkm::cont::Field` to a `vtkm::cont::DataSet`, it now
requires every `Field` to have a unique name. When you attempt to add a
`Field` to a `DataSet` that already has a `Field` of the same name and
association, the old `Field` is removed and replaced with the new `Field`.
You are allowed, however, to have two `Field`s with the same name but
different associations. For example, you could have a point `Field` named
"normals" and also have a cell `Field` named "normals" in the same
`DataSet`.
This new behavior matches how VTK's data sets manage fields.
The old behavior allowed you to add multiple `Field`s with the same name,
but it would be unclear which one you would get if you asked for a `Field`
by name.

@ -0,0 +1,8 @@
# Filters specify their own field types
Previously, the policy specified which field types the filter should
operate on. The filter could remove some types, but it was not able to
add any types.
This is backward. Instead, the filter should specify what types its
supports and the policy may cull out some of those.

@ -0,0 +1,15 @@
# Flying Edges
Added the flying edges contouring algorithm to VTK-m. This algorithm only
works on structured grids, but operates much faster than the traditional
Marching Cubes algorithm.
The speed of VTK-m's flying edges is comprable to VTK's running on the same
CPUs. VTK-m's implementation also works well on CUDA hardware.
The Flying Edges algorithm was introduced in this paper:
Schroeder, W.; Maynard, R. & Geveci, B.
"Flying edges: A high-performance scalable isocontouring algorithm."
Large Data Analysis and Visualization (LDAV), 2015.
DOI 10.1109/LDAV.2015.7348069

@ -0,0 +1,32 @@
# Implemented PNG/PPM image Readers/Writers
The original implementation of writing image data was only performed as a
proxy through the Canvas rendering class. In order to implement true support
for image-based regression testing, this interface needed to be expanded upon
to support reading/writing arbitrary image data and storing it in a `vtkm::DataSet`.
Using the new `vtkm::io::PNGReader` and `vtkm::io::PPMReader` it is possible
to read data from files and Cavases directly and store them as a point field
in a 2D uniform `vtkm::DataSet`
```cpp
auto reader = vtkm::io::PNGReader();
auto imageDataSet = reader.ReadFromFile("read_image.png");
```
Similarly, the new `vtkm::io::PNGWriter` and `vtkm::io::PPMWriter` make it possible
to write out a 2D uniform `vtkm::DataSet` directly to a file.
```cpp
auto writer = vtkm::io::PNGWriter();
writer.WriteToFile("write_image.png", imageDataSet);
```
If canvas data is to be written out, the reader provides a method for converting
a canvas's data to a `vtkm::DataSet`.
```cpp
auto reader = vtkm::io::PNGReader();
auto dataSet = reader.CreateImageDataSet(canvas);
auto writer = vtkm::io::PNGWriter();
writer.WriteToFile("output.png", dataSet);
```

@ -0,0 +1,72 @@
# Avoid raising errors when operating on cells
Cell operations like interpolate and finding parametric coordinates can
fail under certain conditions. The previous behavior was to call
`RaiseError` on the worklet. By design, this would cause the worklet
execution to fail. However, that makes the worklet unstable for a conditin
that might be relatively common in data. For example, you wouldn't want a
large streamline worklet to fail just because one cell was not found
correctly.
To work around this, many of the cell operations in the execution
environment have been changed to return an error code rather than raise an
error in the worklet.
## Error Codes
To support cell operations efficiently returning errors, a new enum named
`vtkm::ErrorCode` is available. This is the current implementation of
`ErrorCode`.
``` cpp
enum class ErrorCode
{
Success,
InvalidShapeId,
InvalidNumberOfPoints,
WrongShapeIdForTagType,
InvalidPointId,
InvalidEdgeId,
InvalidFaceId,
SolutionDidNotConverge,
MatrixFactorizationFailed,
DegenerateCellDetected,
MalformedCellDetected,
OperationOnEmptyCell,
CellNotFound,
UnknownError
};
```
A convenience function named `ErrorString` is provided to make it easy to
convert the `ErrorCode` to a descriptive string that can be placed in an
error.
## New Calling Specification
Previously, most execution environment functions took as an argument the
worklet calling the function. This made it possible to call `RaiseError` on
the worklet. The result of the operation was typically returned. For
example, here is how the _old_ version of interpolate was called.
``` cpp
FieldType interpolatedValue =
vtkm::exec::CellInterpolate(fieldValues, pcoord, shape, worklet);
```
The worklet is now no longer passed to the function. It is no longer needed
because an error is never directly raised. Instead, an `ErrorCode` is
returned from the function. Because the `ErrorCode` is returned, the
computed result of the function is returned by passing in a reference to a
variable. This is usually placed as the last argument (where the worklet
used to be). here is the _new_ version of how interpolate is called.
``` cpp
FieldType interpolatedValue;
vtkm::ErrorCode result =
vtkm::exec::CellInterpolate(fieldValues, pcoord, shape, interpolatedValue);
```
The success of the operation can be determined by checking that the
returned `ErrorCode` is equal to `vtkm::ErrorCode::Success`.

@ -0,0 +1,13 @@
# Removed OpenGL Rendering Classes
When the rendering library was first built, OpenGL was used to implement
the components (windows, mappers, annotation, etc.). However, as the native
ray casting became viable, the majority of the work has focused on using
that. Since then, the original OpenGL classes have been largely ignored.
It has for many months been determined that it is not work attempting to
maintain two different versions of the rendering libraries as features are
added and changed. Thus, the OpenGL classes have fallen out of date and did
not actually work.
These classes have finally been officially removed.

@ -0,0 +1,13 @@
# Move VTK file readers and writers into vtkm_io
The legacy VTK file reader and writer were created back when VTK-m was a
header-only library. Things have changed and we now compile quite a bit of
code into libraries. At this point, there is no reason why the VTK file
reader/writer should be any different.
Thus, `VTKDataSetReader`, `VTKDataSetWriter`, and several supporting
classes are now compiled into the `vtkm_io` library. Also similarly updated
`BOVDataSetReader` for good measure.
As a side effect, code using VTK-m will need to link to `vtkm_io` if they
are using any readers or writers.

@ -14,7 +14,7 @@ project(Clipping CXX)
find_package(VTKm REQUIRED QUIET)
add_executable(Clipping Clipping.cxx)
target_link_libraries(Clipping PRIVATE vtkm_filter)
target_link_libraries(Clipping PRIVATE vtkm_filter vtkm_io)
vtkm_add_target_information(Clipping
DROP_UNUSED_SYMBOLS MODIFY_CUDA_FLAGS

@ -130,7 +130,7 @@ public:
}
else
{
return (it - this->mCLOptions.begin());
return static_cast<vtkm::Id>(it - this->mCLOptions.begin());
}
}

@ -14,7 +14,7 @@ project(HelloWorklet CXX)
find_package(VTKm REQUIRED QUIET)
add_executable(HelloWorklet HelloWorklet.cxx)
target_link_libraries(HelloWorklet PRIVATE vtkm_filter)
target_link_libraries(HelloWorklet PRIVATE vtkm_filter vtkm_io)
vtkm_add_target_information(HelloWorklet
DROP_UNUSED_SYMBOLS MODIFY_CUDA_FLAGS

@ -26,7 +26,7 @@ project(MeshQuality CXX)
find_package(VTKm REQUIRED QUIET)
add_executable(MeshQuality MeshQuality.cxx)
target_link_libraries(MeshQuality PRIVATE vtkm_filter)
target_link_libraries(MeshQuality PRIVATE vtkm_filter vtkm_io)
if(TARGET vtkm::tbb)
target_compile_definitions(MeshQuality PRIVATE BUILDING_TBB_VERSION)

@ -62,19 +62,19 @@ void process_partition_tbb(RuntimeTaskQueue& queue)
void process_partition_openMP(RuntimeTaskQueue& queue)
{
//Step 1. Set the device adapter to this thread to TBB.
//Step 1. Set the device adapter to this thread to openMP.
//This makes sure that any vtkm::filters used by our
//task operate only on TBB. The "global" thread tracker
//task operate only on openMP. The "global" thread tracker
//is actually thread-local, so we can use that.
//
vtkm::cont::GetRuntimeDeviceTracker().ForceDevice(vtkm::cont::DeviceAdapterTagOpenMP{});
while (queue.hasTasks())
{
//Step 2. Get the task to run on TBB
//Step 2. Get the task to run on openMP
auto task = queue.pop();
//Step 3. Run the task on TBB. We check the validity
//Step 3. Run the task on openMP. We check the validity
//of the task since we could be given an empty task
//when the queue is empty and we are shutting down
if (task != nullptr)
@ -84,7 +84,8 @@ void process_partition_openMP(RuntimeTaskQueue& queue)
//Step 4. Notify the queue that we finished processing this task
queue.completedTask();
std::cout << "finished a partition on tbb (" << std::this_thread::get_id() << ")" << std::endl;
std::cout << "finished a partition on openMP (" << std::this_thread::get_id() << ")"
<< std::endl;
}
}

@ -14,7 +14,7 @@ project(ParticleAdvection CXX)
find_package(VTKm REQUIRED QUIET)
add_executable(Particle_Advection ParticleAdvection.cxx)
target_link_libraries(Particle_Advection PRIVATE vtkm_filter)
target_link_libraries(Particle_Advection PRIVATE vtkm_filter vtkm_io)
vtkm_add_target_information(Particle_Advection
DROP_UNUSED_SYMBOLS MODIFY_CUDA_FLAGS
DEVICE_SOURCES ParticleAdvection.cxx)

@ -13,7 +13,7 @@ project(RedistributePoints CXX)
#Find the VTK-m package
find_package(VTKm REQUIRED QUIET)
add_executable(RedistributePoints RedistributePoints.cxx RedistributePoints.h)
target_link_libraries(RedistributePoints PRIVATE vtkm_filter)
target_link_libraries(RedistributePoints PRIVATE vtkm_filter vtkm_io)
vtkm_add_target_information(RedistributePoints
DROP_UNUSED_SYMBOLS MODIFY_CUDA_FLAGS
DEVICE_SOURCES RedistributePoints.cxx)

@ -19,4 +19,4 @@ add_executable(Temporal_Advection TemporalAdvection.cxx)
vtkm_add_target_information(Temporal_Advection
DROP_UNUSED_SYMBOLS MODIFY_CUDA_FLAGS
DEVICE_SOURCES TemporalAdvection.cxx)
target_link_libraries(Temporal_Advection PRIVATE vtkm_filter)
target_link_libraries(Temporal_Advection PRIVATE vtkm_filter vtkm_io)

@ -14,10 +14,10 @@ project(Tetrahedra CXX)
find_package(VTKm REQUIRED QUIET)
add_executable(Tetrahedralize Tetrahedralize.cxx)
target_link_libraries(Tetrahedralize PRIVATE vtkm_filter)
target_link_libraries(Tetrahedralize PRIVATE vtkm_filter vtkm_io)
add_executable(Triangulate Triangulate.cxx)
target_link_libraries(Triangulate PRIVATE vtkm_filter)
target_link_libraries(Triangulate PRIVATE vtkm_filter vtkm_io)
vtkm_add_target_information(Tetrahedralize Triangulate
DROP_UNUSED_SYMBOLS

@ -60,7 +60,9 @@
// [[deprecated]] is supported, then VTK_M_DEPRECATED_ATTRIBUTE_SUPPORTED will get defined.
#ifndef VTK_M_DEPRECATED_ATTRIBUTE_SUPPORTED
#if __cplusplus >= 201402L && !defined(__NVCC__)
#if defined(__NVCC__)
// Currently nvcc has zero support deprecated attributes
#elif __cplusplus >= 201402L
// C++14 and better supports [[deprecated]]
// Except in these cases:
@ -68,7 +70,6 @@
#define VTK_M_DEPRECATED_ATTRIBUTE_SUPPORTED
#elif defined(VTKM_GCC)
// GCC has supported [[deprecated]] since version 5.0, but using it on enum was not
// supported until 6.0. So we have to make a special case to only use it for high
// enough revisions.
@ -76,14 +77,14 @@
#define VTK_M_DEPRECATED_ATTRIBUTE_SUPPORTED
#endif // Too old GCC
#elif defined(__has_cpp_attribute) && !defined(__NVCC__)
#elif defined(__has_cpp_attribute)
#if __has_cpp_attribute(deprecated)
// Compiler not fully C++14 compliant, but it reports to support [[deprecated]]
#define VTK_M_DEPRECATED_ATTRIBUTE_SUPPORTED
#endif // __has_cpp_attribute(deprecated)
#elif defined(VTKM_MSVC) && (_MSC_VER >= 1900) && !defined(__NVCC__)
#elif defined(VTKM_MSVC) && (_MSC_VER >= 1900)
#define VTK_M_DEPRECATED_ATTRIBUTE_SUPPORTED

@ -54,9 +54,10 @@ void CellLocatorUniformGrid::Build()
}
UniformType uniformCoords = coords.GetData().Cast<UniformType>();
this->Origin = uniformCoords.ReadPortal().GetOrigin();
auto coordsPortal = uniformCoords.ReadPortal();
this->Origin = coordsPortal.GetOrigin();
vtkm::Vec3f spacing = uniformCoords.ReadPortal().GetSpacing();
vtkm::Vec3f spacing = coordsPortal.GetSpacing();
vtkm::Vec3f unitLength;
unitLength[0] = static_cast<vtkm::FloatDefault>(this->PointDims[0] - 1);
unitLength[1] = static_cast<vtkm::FloatDefault>(this->PointDims[1] - 1);

@ -186,6 +186,9 @@ public:
VTKM_CONT vtkm::IdComponent GetNumberOfPointsInCell(vtkm::Id cellid) const override;
VTKM_CONT void GetCellPointIds(vtkm::Id id, vtkm::Id* ptids) const override;
VTKM_CONT typename vtkm::cont::ArrayHandle<vtkm::UInt8, ShapesStorageTag>::ReadPortalType
ShapesReadPortal() const;
VTKM_CONT vtkm::UInt8 GetCellShape(vtkm::Id cellid) const override;
template <vtkm::IdComponent NumIndices>

@ -9,7 +9,7 @@
//============================================================================
#ifndef vtk_m_cont_CellSetExplicit_hxx
#define vtk_m_cont_CellSetExplicit_hxx
#include <vtkm/Deprecated.h>
#include <vtkm/cont/CellSetExplicit.h>
#include <vtkm/cont/ArrayCopy.h>
@ -176,14 +176,22 @@ vtkm::IdComponent CellSetExplicit<SST, CST, OST>
template <typename SST, typename CST, typename OST>
VTKM_CONT
typename vtkm::cont::ArrayHandle<vtkm::UInt8, SST>::ReadPortalType
CellSetExplicit<SST, CST, OST>::ShapesReadPortal() const
{
return this->Data->CellPointIds.Shapes.ReadPortal();
}
template <typename SST, typename CST, typename OST>
VTKM_CONT
VTKM_DEPRECATED(1.6, "Calling GetCellShape(cellid) is a performance bug. Call ShapesReadPortal() and loop over the .Get.")
vtkm::UInt8 CellSetExplicit<SST, CST, OST>
::GetCellShape(vtkm::Id cellid) const
{
// Looping over GetCellShape(cellid) is a performance bug.
// Don't know quite what to do about it right now.
return this->Data->CellPointIds.Shapes.ReadPortal().Get(cellid);
return this->ShapesReadPortal().Get(cellid);
}
template <typename SST, typename CST, typename OST>
template <vtkm::IdComponent NumVecIndices>
VTKM_CONT

@ -204,11 +204,14 @@ void TestCellLocator(const vtkm::Vec<vtkm::Id, DIMENSIONS>& dim, vtkm::Id number
vtkm::worklet::DispatcherMapField<FindCellWorklet> dispatcher;
dispatcher.Invoke(points, locator, cellIds, pcoords);
auto cellIdsPortal = cellIds.ReadPortal();
auto expCellIdsPortal = expCellIds.ReadPortal();
auto pcoordsPortal = pcoords.ReadPortal();
auto expPCoordsPortal = expPCoords.ReadPortal();
for (vtkm::Id i = 0; i < numberOfPoints; ++i)
{
VTKM_TEST_ASSERT(cellIds.ReadPortal().Get(i) == expCellIds.ReadPortal().Get(i),
"Incorrect cell ids");
VTKM_TEST_ASSERT(test_equal(pcoords.ReadPortal().Get(i), expPCoords.ReadPortal().Get(i), 1e-3),
VTKM_TEST_ASSERT(cellIdsPortal.Get(i) == expCellIdsPortal.Get(i), "Incorrect cell ids");
VTKM_TEST_ASSERT(test_equal(pcoordsPortal.Get(i), expPCoordsPortal.Get(i), 1e-3),
"Incorrect parameteric coordinates");
}
}

@ -42,9 +42,10 @@ private:
return false;
}
auto ahPortal = ah.ReadPortal();
for (vtkm::Id i = 0; i < size; ++i)
{
if (ah.ReadPortal().Get(i) != expected[i])
if (ahPortal.Get(i) != expected[i])
{
return false;
}
@ -115,6 +116,7 @@ private:
VTKM_TEST_ASSERT(conn.GetNumberOfValues() == connectivitySize,
"Connectivity array wrong size.");
vtkm::Id connectivityIndex = 0;
auto connPortal = conn.ReadPortal();
for (vtkm::Id pointIndex = 0; pointIndex < numPoints; pointIndex++)
{
vtkm::IdComponent numIncidentCells = correctNumIndices[pointIndex];
@ -125,7 +127,7 @@ private:
}
for (vtkm::IdComponent cellIndex = 0; cellIndex < numIncidentCells; cellIndex++)
{
vtkm::Id expectedCell = conn.ReadPortal().Get(connectivityIndex + cellIndex);
vtkm::Id expectedCell = connPortal.Get(connectivityIndex + cellIndex);
std::set<vtkm::Id>::iterator foundCell = correctIncidentCells.find(expectedCell);
VTKM_TEST_ASSERT(foundCell != correctIncidentCells.end(),
"An incident cell in the connectivity list is wrong or repeated.");

@ -36,9 +36,10 @@ void TestArrayHandleConcatenate()
array5 = vtkm::cont::make_ArrayHandleConcatenate(array3, array4);
}
auto array5Portal = array5.ReadPortal();
for (vtkm::Id index = 0; index < array5.GetNumberOfValues(); index++)
{
std::cout << array5.ReadPortal().Get(index) << std::endl;
std::cout << array5Portal.Get(index) << std::endl;
}
}
@ -59,8 +60,9 @@ void TestConcatenateEmptyArray()
ArrayConcat arrConc(arr2, arr1);
ArrayConcat2 arrConc2(arrConc, arr3);
auto arrConc2Portal = arrConc2.ReadPortal();
for (vtkm::Id i = 0; i < arrConc2.GetNumberOfValues(); i++)
std::cout << arrConc2.ReadPortal().Get(i) << std::endl;
std::cout << arrConc2Portal.Get(i) << std::endl;
}
} // namespace UnitTestArrayHandleIndexNamespace

@ -102,14 +102,17 @@ struct TemplatedTests
"Counting array using raw array handle + tag has wrong size.");
ValueType properValue = startingValue;
auto arrayConstPortal = arrayConst.ReadPortal();
auto arrayMakePortal = arrayMake.ReadPortal();
auto arrayHandlePortal = arrayHandle.ReadPortal();
for (vtkm::Id index = 0; index < ARRAY_SIZE; index++)
{
VTKM_TEST_ASSERT(arrayConst.ReadPortal().Get(index) == properValue,
VTKM_TEST_ASSERT(arrayConstPortal.Get(index) == properValue,
"Counting array using constructor has unexpected value.");
VTKM_TEST_ASSERT(arrayMake.ReadPortal().Get(index) == properValue,
VTKM_TEST_ASSERT(arrayMakePortal.Get(index) == properValue,
"Counting array using make has unexpected value.");
VTKM_TEST_ASSERT(arrayHandle.ReadPortal().Get(index) == properValue,
VTKM_TEST_ASSERT(arrayHandlePortal.Get(index) == properValue,
"Counting array using raw array handle + tag has unexpected value.");
properValue = properValue + step;
}
@ -128,6 +131,7 @@ void TestArrayHandleCounting()
TemplatedTests<StringInt>()(StringInt(10), StringInt(2));
}
} // namespace UnitTestArrayHandleCountingNamespace
int UnitTestArrayHandleCounting(int argc, char* argv[])

@ -42,12 +42,13 @@ struct ImplicitTests
using ImplicitHandle = vtkm::cont::ArrayHandleImplicit<FunctorType>;
ImplicitHandle implict = vtkm::cont::make_ArrayHandleImplicit(functor, ARRAY_SIZE);
ImplicitHandle implicit = vtkm::cont::make_ArrayHandleImplicit(functor, ARRAY_SIZE);
//verify that the control portal works
auto implicitPortal = implicit.ReadPortal();
for (int i = 0; i < ARRAY_SIZE; ++i)
{
const ValueType v = implict.ReadPortal().Get(i);
const ValueType v = implicitPortal.Get(i);
const ValueType correct_value = functor(i);
VTKM_TEST_ASSERT(v == correct_value, "Implicit Handle Failed");
}
@ -56,7 +57,7 @@ struct ImplicitTests
vtkm::cont::Token token;
using Device = vtkm::cont::DeviceAdapterTagSerial;
using CEPortal = typename ImplicitHandle::template ExecutionTypes<Device>::PortalConst;
CEPortal execPortal = implict.PrepareForInput(Device(), token);
CEPortal execPortal = implicit.PrepareForInput(Device(), token);
for (int i = 0; i < ARRAY_SIZE; ++i)
{
const ValueType v = execPortal.Get(i);

@ -188,11 +188,14 @@ void TestWithDataSet(vtkm::cont::CellLocatorGeneral& locator, const vtkm::cont::
// CellLocatorGeneral is non-copyable. Pass it via a pointer.
dispatcher.Invoke(points, &locator, cellIds, pcoords);
auto cellIdPortal = cellIds.ReadPortal();
auto expCellIdsPortal = expCellIds.ReadPortal();
auto pcoordsPortal = pcoords.ReadPortal();
auto expPCoordsPortal = expPCoords.ReadPortal();
for (vtkm::Id i = 0; i < 128; ++i)
{
VTKM_TEST_ASSERT(cellIds.ReadPortal().Get(i) == expCellIds.ReadPortal().Get(i),
"Incorrect cell ids");
VTKM_TEST_ASSERT(test_equal(pcoords.ReadPortal().Get(i), expPCoords.ReadPortal().Get(i), 1e-3),
VTKM_TEST_ASSERT(cellIdPortal.Get(i) == expCellIdsPortal.Get(i), "Incorrect cell ids");
VTKM_TEST_ASSERT(test_equal(pcoordsPortal.Get(i), expPCoordsPortal.Get(i), 1e-3),
"Incorrect parameteric coordinates");
}

@ -117,13 +117,13 @@ void TestAgainstBaseLine(const vtkm::cont::CellSet& cellset,
: PermutationArray.GetNumberOfValues();
VTKM_TEST_ASSERT(numCells == expectedNumCell, "Wrong number of cells");
auto permutationPortal = PermutationArray.ReadPortal();
for (vtkm::Id i = 0; i < numCells; ++i)
{
VTKM_TEST_ASSERT(cellset.GetCellShape(i) == vtkm::CELL_SHAPE_HEXAHEDRON, "Wrong shape");
VTKM_TEST_ASSERT(cellset.GetNumberOfPointsInCell(i) == 8, "Wrong number of points-of-cell");
vtkm::Id baseLineCellId =
(flag == IsPermutationCellSet::YES) ? PermutationArray.ReadPortal().Get(i) : i;
vtkm::Id baseLineCellId = (flag == IsPermutationCellSet::YES) ? permutationPortal.Get(i) : i;
auto baseLinePointIds = baseLineStructure.GetPointsOfCell(baseLineCellId);
vtkm::Id pointIds[8];

@ -32,9 +32,10 @@ bool TestArrayHandle(const vtkm::cont::ArrayHandle<T, Storage>& ah,
return false;
}
auto ahPortal = ah.ReadPortal();
for (vtkm::Id i = 0; i < size; ++i)
{
if (ah.ReadPortal().Get(i) != expected[i])
if (ahPortal.Get(i) != expected[i])
{
return false;
}
@ -110,9 +111,10 @@ void TestDataSet_Explicit()
//iterate same cell 4 times
vtkm::Float32 expected[4] = { 30.1667f, 30.1667f, 30.1667f, 30.1667f };
auto resultPortal = result.ReadPortal();
for (int i = 0; i < 4; ++i)
{
VTKM_TEST_ASSERT(test_equal(result.ReadPortal().Get(i), expected[i]),
VTKM_TEST_ASSERT(test_equal(resultPortal.Get(i), expected[i]),
"Wrong result for CellAverage worklet on explicit subset data");
}
}
@ -145,9 +147,10 @@ void TestDataSet_Structured2D()
dispatcher.Invoke(subset, dataSet.GetField("pointvar"), result);
vtkm::Float32 expected[4] = { 40.1f, 40.1f, 40.1f, 40.1f };
auto resultPortal = result.ReadPortal();
for (int i = 0; i < 4; ++i)
{
VTKM_TEST_ASSERT(test_equal(result.ReadPortal().Get(i), expected[i]),
VTKM_TEST_ASSERT(test_equal(resultPortal.Get(i), expected[i]),
"Wrong result for CellAverage worklet on 2d structured subset data");
}
}
@ -180,9 +183,10 @@ void TestDataSet_Structured3D()
dispatcher.Invoke(subset, dataSet.GetField("pointvar"), result);
vtkm::Float32 expected[4] = { 70.2125f, 70.2125f, 70.2125f, 70.2125f };
auto resultPortal = result.ReadPortal();
for (int i = 0; i < 4; ++i)
{
VTKM_TEST_ASSERT(test_equal(result.ReadPortal().Get(i), expected[i]),
VTKM_TEST_ASSERT(test_equal(resultPortal.Get(i), expected[i]),
"Wrong result for CellAverage worklet on 2d structured subset data");
}
}

@ -97,6 +97,7 @@ void RunTests()
int UnitTestLogging(int, char* [])
{
// Test that parameterless init works:
VTKM_LOG_S(vtkm::cont::LogLevel::Info, "Log before intialize");
vtkm::cont::InitLogging();
RunTests();

@ -23,8 +23,7 @@ namespace
using TimerTestDevices =
vtkm::ListAppend<VTKM_DEFAULT_DEVICE_ADAPTER_LIST, vtkm::List<vtkm::cont::DeviceAdapterTagAny>>;
constexpr long long waitTimeMilliseconds = 100;
constexpr vtkm::Float64 waitTimeSeconds = vtkm::Float64(waitTimeMilliseconds) / 1000;
constexpr long long waitTimeMilliseconds = 5;
struct Waiter
{
@ -44,17 +43,10 @@ struct Waiter
long long millisecondsToSleep = this->ExpectedTimeMilliseconds - elapsedMilliseconds;
std::cout << " Sleeping for " << millisecondsToSleep << "ms (to " << expectedTimeSeconds
<< "s)" << std::endl;
<< "s)\n";
std::this_thread::sleep_for(std::chrono::milliseconds(millisecondsToSleep));
VTKM_TEST_ASSERT(std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::high_resolution_clock::now() - this->Start)
.count() <
(this->ExpectedTimeMilliseconds + ((3 * waitTimeMilliseconds) / 4)),
"Internal test error: Sleep lasted longer than expected. System must be busy. "
"Might need to increase waitTimeMilliseconds.");
return expectedTimeSeconds;
}
};
@ -64,14 +56,11 @@ void CheckTime(const vtkm::cont::Timer& timer, vtkm::Float64 expectedTime)
vtkm::Float64 elapsedTime = timer.GetElapsedTime();
VTKM_TEST_ASSERT(
elapsedTime > (expectedTime - 0.001), "Timer did not capture full wait. ", elapsedTime);
VTKM_TEST_ASSERT(elapsedTime < (expectedTime + waitTimeSeconds),
"Timer counted too far or system really busy. ",
elapsedTime);
}
void DoTimerCheck(vtkm::cont::Timer& timer)
{
std::cout << " Starting timer" << std::endl;
std::cout << " Starting timer\n";
timer.Start();
VTKM_TEST_ASSERT(timer.Started(), "Timer fails to track started status");
VTKM_TEST_ASSERT(!timer.Stopped(), "Timer fails to track non stopped status");
@ -85,14 +74,14 @@ void DoTimerCheck(vtkm::cont::Timer& timer)
CheckTime(timer, expectedTime);
std::cout << " Make sure timer is still running" << std::endl;
std::cout << " Make sure timer is still running\n";
VTKM_TEST_ASSERT(!timer.Stopped(), "Timer fails to track stopped status");
expectedTime = waiter.Wait();
CheckTime(timer, expectedTime);
std::cout << " Stop the timer" << std::endl;
std::cout << " Stop the timer\n";
timer.Stop();
VTKM_TEST_ASSERT(timer.Stopped(), "Timer fails to track stopped status");
@ -100,7 +89,7 @@ void DoTimerCheck(vtkm::cont::Timer& timer)
waiter.Wait(); // Do not advanced expected time
std::cout << " Check that timer legitimately stopped" << std::endl;
std::cout << " Check that timer legitimately stopped\n";
CheckTime(timer, expectedTime);
}
@ -146,7 +135,7 @@ struct TimerCheckFunctor
void DoTimerTest()
{
std::cout << "Check default timer" << std::endl;
std::cout << "Check default timer\n";
vtkm::cont::Timer timer;
DoTimerCheck(timer);

@ -30,10 +30,11 @@ template <typename FetchType, typename ExecObjectType>
struct Fetch<FetchType, vtkm::exec::arg::AspectTagIncidentElementIndices, ExecObjectType>
{
VTKM_SUPPRESS_EXEC_WARNINGS
template <typename Device>
VTKM_EXEC auto Load(const vtkm::exec::arg::ThreadIndicesTopologyMap<
vtkm::exec::ConnectivityExtrude<Device>>& indices,
const ExecObjectType&) const -> vtkm::Vec<vtkm::Id, 6>
template <typename Device, typename ScatterAndMaskMode>
VTKM_EXEC auto Load(
const vtkm::exec::arg::ThreadIndicesTopologyMap<vtkm::exec::ConnectivityExtrude<Device>,
ScatterAndMaskMode>& indices,
const ExecObjectType&) const -> vtkm::Vec<vtkm::Id, 6>
{
// std::cout << "opimized fetch for point ids" << std::endl;
const auto& xgcidx = indices.GetIndicesIncident();
@ -50,9 +51,10 @@ struct Fetch<FetchType, vtkm::exec::arg::AspectTagIncidentElementIndices, ExecOb
}
VTKM_SUPPRESS_EXEC_WARNINGS
template <typename ConnectivityType>
VTKM_EXEC auto Load(const vtkm::exec::arg::ThreadIndicesTopologyMap<ConnectivityType>& indices,
const ExecObjectType&) const -> decltype(indices.GetIndicesIncident())
template <typename ConnectivityType, typename ScatterAndMaskMode>
VTKM_EXEC auto Load(
const vtkm::exec::arg::ThreadIndicesTopologyMap<ConnectivityType, ScatterAndMaskMode>& indices,
const ExecObjectType&) const -> decltype(indices.GetIndicesIncident())
{
return indices.GetIndicesIncident();
}
@ -133,10 +135,11 @@ struct Fetch<vtkm::exec::arg::FetchTagArrayDirectIn,
}
VTKM_SUPPRESS_EXEC_WARNINGS
template <typename Device>
VTKM_EXEC auto Load(const vtkm::exec::arg::ThreadIndicesTopologyMap<
vtkm::exec::ReverseConnectivityExtrude<Device>>& indices,
const vtkm::exec::ArrayPortalExtrude<T>& points)
template <typename Device, typename ScatterAndMaskMode>
VTKM_EXEC auto Load(
const vtkm::exec::arg::ThreadIndicesTopologyMap<vtkm::exec::ReverseConnectivityExtrude<Device>,
ScatterAndMaskMode>& indices,
const vtkm::exec::ArrayPortalExtrude<T>& points)
-> decltype(points.Get(indices.GetIndexLogical()))
{
// std::cout << "optimized fetch for point coordinates" << std::endl;

@ -213,11 +213,11 @@ struct Fetch<vtkm::exec::arg::FetchTagArrayTopologyMapIn,
//Optimized fetch for point arrays when iterating the cells ConnectivityExtrude
VTKM_SUPPRESS_EXEC_WARNINGS
template <typename Device>
VTKM_EXEC auto Load(const vtkm::exec::arg::ThreadIndicesTopologyMap<
vtkm::exec::ConnectivityExtrude<Device>>& indices,
const ExecObjectType& portal)
-> vtkm::Vec<typename ExecObjectType::ValueType, 6>
template <typename Device, typename ScatterAndMaskMode>
VTKM_EXEC auto Load(
const vtkm::exec::arg::ThreadIndicesTopologyMap<vtkm::exec::ConnectivityExtrude<Device>,
ScatterAndMaskMode>& indices,
const ExecObjectType& portal) -> vtkm::Vec<typename ExecObjectType::ValueType, 6>
{
// std::cout << "opimized fetch for point values" << std::endl;
const auto& xgcidx = indices.GetIndicesIncident();

@ -21,8 +21,8 @@ namespace arg
{
// Specialization for extrude types.
template <typename Device>
class ThreadIndicesTopologyMap<vtkm::exec::ConnectivityExtrude<Device>>
template <typename Device, typename ScatterAndMaskMode>
class ThreadIndicesTopologyMap<vtkm::exec::ConnectivityExtrude<Device>, ScatterAndMaskMode>
{
using ConnectivityType = vtkm::exec::ConnectivityExtrude<Device>;
@ -175,8 +175,8 @@ private:
};
// Specialization for extrude types.
template <typename Device>
class ThreadIndicesTopologyMap<vtkm::exec::ReverseConnectivityExtrude<Device>>
template <typename Device, typename ScatterAndMaskMode>
class ThreadIndicesTopologyMap<vtkm::exec::ReverseConnectivityExtrude<Device>, ScatterAndMaskMode>
{
using ConnectivityType = vtkm::exec::ReverseConnectivityExtrude<Device>;

@ -69,6 +69,17 @@ static inline VTKM_EXEC vtkm::Id2 Deflate(const vtkm::Id3& index, vtkm::Id2)
} // namespace detail
/// \brief Uses spaces optimizations when using MaskNone and ScatterIdentity
///
struct DefaultScatterAndMaskTag
{
};
/// \brief Used for when not using MaskNone and ScatterIdentity.
///
struct CustomScatterOrMaskTag
{
};
/// \brief Container for thread indices in a topology map
///
@ -80,7 +91,7 @@ static inline VTKM_EXEC vtkm::Id2 Deflate(const vtkm::Id3& index, vtkm::Id2)
/// This class is templated on the type that stores the connectivity (such
/// as \c ConnectivityExplicit or \c ConnectivityStructured).
///
template <typename ConnectivityType>
template <typename ConnectivityType, typename ScatterAndMaskMode>
class ThreadIndicesTopologyMap : public vtkm::exec::arg::ThreadIndicesBasic
{
using Superclass = vtkm::exec::arg::ThreadIndicesBasic;
@ -144,10 +155,11 @@ private:
CellShapeTag CellShape;
};
// Specialization for structured connectivity types.
/// \brief Specialization for CustomScatterOrMaskTag
template <typename VisitTopology, typename IncidentTopology, vtkm::IdComponent Dimension>
class ThreadIndicesTopologyMap<
vtkm::exec::ConnectivityStructured<VisitTopology, IncidentTopology, Dimension>>
vtkm::exec::ConnectivityStructured<VisitTopology, IncidentTopology, Dimension>,
CustomScatterOrMaskTag>
{
using ConnectivityType =
vtkm::exec::ConnectivityStructured<VisitTopology, IncidentTopology, Dimension>;
@ -160,15 +172,15 @@ public:
vtkm::exec::ConnectivityStructured<VisitTopology, IncidentTopology, Dimension>;
VTKM_EXEC ThreadIndicesTopologyMap(vtkm::Id threadIndex,
vtkm::Id inIndex,
vtkm::Id inputIndex,
vtkm::IdComponent visitIndex,
vtkm::Id outIndex,
vtkm::Id outputIndex,
const ConnectivityType& connectivity)
{
this->ThreadIndex = threadIndex;
this->InputIndex = inIndex;
this->InputIndex = inputIndex;
this->VisitIndex = visitIndex;
this->OutputIndex = outIndex;
this->OutputIndex = outputIndex;
this->LogicalIndex = connectivity.FlatToLogicalToIndex(this->InputIndex);
this->IndicesIncident = connectivity.GetIndices(this->LogicalIndex);
this->CellShape = connectivity.GetCellShape(this->InputIndex);
@ -181,9 +193,6 @@ public:
// This constructor handles multidimensional indices on one-to-one input-to-output
auto logicalIndex = detail::Deflate(threadIndex3D, LogicalIndexType());
this->ThreadIndex = threadIndex1D;
this->InputIndex = threadIndex1D;
this->OutputIndex = threadIndex1D;
this->VisitIndex = 0;
this->LogicalIndex = logicalIndex;
this->IndicesIncident = connectivity.GetIndices(logicalIndex);
this->CellShape = connectivity.GetCellShape(threadIndex1D);
@ -207,6 +216,7 @@ public:
this->CellShape = connectivity.GetCellShape(threadIndex1D);
}
/// \brief The index of the thread or work invocation.
///
/// This index refers to which instance of the worklet is being invoked. Every invocation of the
@ -292,20 +302,176 @@ public:
private:
vtkm::Id ThreadIndex;
vtkm::Id InputIndex;
vtkm::IdComponent VisitIndex;
LogicalIndexType LogicalIndex;
IndicesIncidentType IndicesIncident;
CellShapeTag CellShape;
vtkm::Id InputIndex;
vtkm::Id OutputIndex;
};
/// \brief Specialization for DefaultScatterAndMaskTag
///
/// It does not store VisitIndex, InputIndex and OutputIndex
/// since this is used only when Scatter is set as ScatterIdentity
/// and Mask is set as MaskNone which does not performs any transformation onto the
/// indices.
///
template <typename VisitTopology, typename IncidentTopology, vtkm::IdComponent Dimension>
class ThreadIndicesTopologyMap<
vtkm::exec::ConnectivityStructured<VisitTopology, IncidentTopology, Dimension>,
DefaultScatterAndMaskTag>
{
using ConnectivityType =
vtkm::exec::ConnectivityStructured<VisitTopology, IncidentTopology, Dimension>;
public:
using IndicesIncidentType = typename ConnectivityType::IndicesType;
using CellShapeTag = typename ConnectivityType::CellShapeTag;
using LogicalIndexType = typename ConnectivityType::SchedulingRangeType;
using Connectivity = ConnectivityType;
VTKM_EXEC ThreadIndicesTopologyMap(vtkm::Id threadIndex,
vtkm::Id inputIndex,
vtkm::IdComponent vtkmNotUsed(visitIndex),
vtkm::Id vtkmNotUsed(outputIndex),
const ConnectivityType& connectivity)
{
this->ThreadIndex = threadIndex;
this->LogicalIndex = connectivity.FlatToLogicalToIndex(inputIndex);
this->IndicesIncident = connectivity.GetIndices(this->LogicalIndex);
this->CellShape = connectivity.GetCellShape(inputIndex);
}
VTKM_EXEC ThreadIndicesTopologyMap(const vtkm::Id3& threadIndex3D,
vtkm::Id threadIndex1D,
const ConnectivityType& connectivity)
{
// This constructor handles multidimensional indices on one-to-one input-to-output
auto logicalIndex = detail::Deflate(threadIndex3D, LogicalIndexType());
this->ThreadIndex = threadIndex1D;
this->LogicalIndex = logicalIndex;
this->IndicesIncident = connectivity.GetIndices(logicalIndex);
this->CellShape = connectivity.GetCellShape(threadIndex1D);
}
VTKM_EXEC ThreadIndicesTopologyMap(const vtkm::Id3& threadIndex3D,
vtkm::Id threadIndex1D,
vtkm::Id vtkmNotUsed(inIndex),
vtkm::IdComponent vtkmNotUsed(visitIndex),
vtkm::Id vtkmNotUsed(outIndex),
const ConnectivityType& connectivity)
{
// This constructor handles multidimensional indices on many-to-many input-to-output
auto logicalIndex = detail::Deflate(threadIndex3D, LogicalIndexType());
this->ThreadIndex = threadIndex1D;
this->LogicalIndex = logicalIndex;
this->IndicesIncident = connectivity.GetIndices(logicalIndex);
this->CellShape = connectivity.GetCellShape(threadIndex1D);
}
/// \brief The index of the thread or work invocation.
///
/// This index refers to which instance of the worklet is being invoked. Every invocation of the
/// worklet has a unique thread index. This is also called the work index depending on the
/// context.
///
VTKM_EXEC
vtkm::Id GetThreadIndex() const { return this->ThreadIndex; }
/// \brief The logical index into the input domain.
///
/// This is similar to \c GetIndex3D except the Vec size matches the actual
/// dimensions of the data.
///
VTKM_EXEC
LogicalIndexType GetIndexLogical() const { return this->LogicalIndex; }
/// \brief The index into the input domain.
///
/// This index refers to the input element (array value, cell, etc.) that
/// this thread is being invoked for. This is the typical index used during
/// fetches.
///
VTKM_EXEC
vtkm::Id GetInputIndex() const { return this->ThreadIndex; }
/// \brief The 3D index into the input domain.
///
/// Overloads the implementation in the base class to return the 3D index
/// for the input.
///
VTKM_EXEC
vtkm::Id3 GetInputIndex3D() const { return detail::InflateTo3D(this->GetIndexLogical()); }
/// \brief The index into the output domain.
///
/// This index refers to the output element (array value, cell, etc.) that
/// this thread is creating. This is the typical index used during
/// Fetch::Store.
///
VTKM_EXEC
vtkm::Id GetOutputIndex() const { return this->ThreadIndex; }
/// \brief The visit index.
///
/// When multiple output indices have the same input index, they are
/// distinguished using the visit index.
///
VTKM_EXEC
vtkm::IdComponent GetVisitIndex() const { return 0; }
/// \brief The indices of the incident elements.
///
/// A topology map has "visited" and "incident" elements (e.g. points, cells,
/// etc). For each worklet invocation, there is exactly one visited element,
/// but there can be several incident elements. This method returns a
/// Vec-like object containing the indices to the incident elements.
///
VTKM_EXEC
const IndicesIncidentType& GetIndicesIncident() const { return this->IndicesIncident; }
/// \brief The input indices of the incident elements in pointer form.
///
/// Returns the same object as GetIndicesIncident except that it returns a
/// pointer to the internally held object rather than a reference or copy.
/// Since the from indices can be a sizeable Vec (8 entries is common), it is
/// best not to have a bunch a copies. Thus, you can pass around a pointer
/// instead. However, care should be taken to make sure that this object does
/// not go out of scope, at which time the returned pointer becomes invalid.
///
VTKM_EXEC
const IndicesIncidentType* GetIndicesIncidentPointer() const { return &this->IndicesIncident; }
/// \brief The shape of the input cell.
///
/// In topology maps that map from points to something, the indices make up
/// the structure of a cell. Although the shape tag is not technically and
/// index, it defines the meaning of the indices, so we put it here. (That
/// and this class is the only convenient place to store it.)
///
VTKM_EXEC
CellShapeTag GetCellShape() const { return this->CellShape; }
private:
vtkm::Id ThreadIndex;
LogicalIndexType LogicalIndex;
IndicesIncidentType IndicesIncident;
CellShapeTag CellShape;
};
// Specialization for permuted structured connectivity types.
/// \brief Specialization for permuted structured connectivity types.
template <typename PermutationPortal, vtkm::IdComponent Dimension>
class ThreadIndicesTopologyMap<vtkm::exec::ConnectivityPermutedVisitCellsWithPoints<
PermutationPortal,
vtkm::exec::
ConnectivityStructured<vtkm::TopologyElementTagCell, vtkm::TopologyElementTagPoint, Dimension>>>
PermutationPortal,
vtkm::exec::ConnectivityStructured<vtkm::TopologyElementTagCell,
vtkm::TopologyElementTagPoint,
Dimension>>,
CustomScatterOrMaskTag>
{
using PermutedConnectivityType = vtkm::exec::ConnectivityPermutedVisitCellsWithPoints<
PermutationPortal,

@ -87,7 +87,9 @@ struct FetchArrayTopologyMapInTests
void TryInvocation(const Invocation& invocation) const
{
using ConnectivityType = typename Invocation::InputDomainType;
using ThreadIndicesType = vtkm::exec::arg::ThreadIndicesTopologyMap<ConnectivityType>;
using ThreadIndicesType =
vtkm::exec::arg::ThreadIndicesTopologyMap<ConnectivityType,
vtkm::exec::arg::CustomScatterOrMaskTag>;
using FetchType = vtkm::exec::arg::Fetch<vtkm::exec::arg::FetchTagArrayTopologyMapIn,
vtkm::exec::arg::AspectTagDefault,
@ -166,7 +168,9 @@ template <vtkm::IdComponent NumDimensions, vtkm::IdComponent ParamIndex, typenam
void TryStructuredPointCoordinatesInvocation(const Invocation& invocation)
{
using ConnectivityType = typename Invocation::InputDomainType;
using ThreadIndicesType = vtkm::exec::arg::ThreadIndicesTopologyMap<ConnectivityType>;
using ThreadIndicesType =
vtkm::exec::arg::ThreadIndicesTopologyMap<ConnectivityType,
vtkm::exec::arg::CustomScatterOrMaskTag>;
vtkm::exec::arg::Fetch<vtkm::exec::arg::FetchTagArrayTopologyMapIn,
vtkm::exec::arg::AspectTagDefault,

@ -69,7 +69,7 @@ set(unit_tests
vtkm_unit_tests(
SOURCES ${unit_tests}
LIBRARIES vtkm_filter vtkm_source
LIBRARIES vtkm_filter vtkm_source vtkm_io
ALL_BACKENDS
USE_VTKM_JOB_POOL
)

@ -97,11 +97,12 @@ void TestNormals(const vtkm::cont::DataSet& dataset, bool structured)
result.GetField("normals").GetData().CopyTo(normals);
VTKM_TEST_ASSERT(normals.GetNumberOfValues() == numVerts,
"Wrong number of values in normals field");
auto normalsPortal = normals.ReadPortal();
for (vtkm::Id i = 0; i < numVerts; ++i)
{
VTKM_TEST_ASSERT(test_equal(normals.ReadPortal().Get(i), expected[i], 0.001),
VTKM_TEST_ASSERT(test_equal(normalsPortal.Get(i), expected[i], 0.001),
"Result (",
normals.ReadPortal().Get(i),
normalsPortal.Get(i),
") does not match expected value (",
expected[i],
") vert ",
@ -124,9 +125,10 @@ void TestNormals(const vtkm::cont::DataSet& dataset, bool structured)
result.GetField("normals").GetData().CopyTo(normals);
VTKM_TEST_ASSERT(normals.GetNumberOfValues() == numVerts,
"Wrong number of values in normals field");
normalsPortal = normals.ReadPortal();
for (vtkm::Id i = 0; i < numVerts; ++i)
{
VTKM_TEST_ASSERT(test_equal(normals.ReadPortal().Get(i), expected[i], 0.001),
VTKM_TEST_ASSERT(test_equal(normalsPortal.Get(i), expected[i], 0.001),
"Result does not match expected values");
}
}

@ -73,9 +73,10 @@ void TestVertexClustering()
auto pointArray = output.GetCoordinateSystem(0).GetData();
VTKM_TEST_ASSERT(pointArray.GetNumberOfValues() == output_points,
"Number of output points mismatch");
auto pointArrayPortal = pointArray.ReadPortal();
for (vtkm::Id i = 0; i < pointArray.GetNumberOfValues(); ++i)
{
const PointType& p1 = pointArray.ReadPortal().Get(i);
const PointType& p1 = pointArrayPortal.Get(i);
PointType p2 = vtkm::make_Vec(output_point[i][0], output_point[i][1], output_point[i][2]);
VTKM_TEST_ASSERT(test_equal(p1, p2), "Point Array mismatch");
}

@ -0,0 +1,254 @@
//============================================================================
// 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/io/BOVDataSetReader.h>
#include <vtkm/cont/DataSetBuilderUniform.h>
#include <vtkm/cont/DataSetFieldAdd.h>
#include <vtkm/io/ErrorIO.h>
#include <fstream>
namespace
{
enum class DataFormat
{
ByteData,
ShortData,
IntegerData,
FloatData,
DoubleData
};
template <typename T>
void ReadBuffer(const std::string& fName, const vtkm::Id& sz, std::vector<T>& buff)
{
FILE* fp = fopen(fName.c_str(), "rb");
size_t readSize = static_cast<size_t>(sz);
if (fp == nullptr)
{
throw vtkm::io::ErrorIO("Unable to open data file: " + fName);
}
buff.resize(readSize);
size_t nread = fread(&buff[0], sizeof(T), readSize, fp);
if (nread != readSize)
{
throw vtkm::io::ErrorIO("Data file read failed: " + fName);
}
fclose(fp);
}
template <typename T>
void ReadScalar(const std::string& fName, const vtkm::Id& nTuples, vtkm::cont::ArrayHandle<T>& var)
{
std::vector<T> buff;
ReadBuffer(fName, nTuples, buff);
var.Allocate(nTuples);
auto writePortal = var.WritePortal();
for (vtkm::Id i = 0; i < nTuples; i++)
{
writePortal.Set(i, buff[static_cast<size_t>(i)]);
}
}
template <typename T>
void ReadVector(const std::string& fName,
const vtkm::Id& nTuples,
vtkm::cont::ArrayHandle<vtkm::Vec<T, 3>>& var)
{
std::vector<T> buff;
ReadBuffer(fName, nTuples * 3, buff);
var.Allocate(nTuples);
vtkm::Vec<T, 3> v;
auto writePortal = var.WritePortal();
for (vtkm::Id i = 0; i < nTuples; i++)
{
v[0] = buff[static_cast<size_t>(i * 3 + 0)];
v[1] = buff[static_cast<size_t>(i * 3 + 1)];
v[2] = buff[static_cast<size_t>(i * 3 + 2)];
writePortal.Set(i, v);
}
}
} // anonymous namespace
namespace vtkm
{
namespace io
{
BOVDataSetReader::BOVDataSetReader(const char* fileName)
: FileName(fileName)
, Loaded(false)
, DataSet()
{
}
BOVDataSetReader::BOVDataSetReader(const std::string& fileName)
: FileName(fileName)
, Loaded(false)
, DataSet()
{
}
const vtkm::cont::DataSet& BOVDataSetReader::ReadDataSet()
{
try
{
this->LoadFile();
}
catch (std::ifstream::failure& e)
{
std::string message("IO Error: ");
throw vtkm::io::ErrorIO(message + e.what());
}
return this->DataSet;
}
void BOVDataSetReader::LoadFile()
{
if (this->Loaded)
return;
std::ifstream stream(this->FileName);
if (stream.fail())
throw vtkm::io::ErrorIO("Failed to open file: " + this->FileName);
DataFormat dataFormat = DataFormat::ByteData;
std::string bovFile, line, token, options, variableName;
vtkm::Id numComponents = 1;
vtkm::Id3 dim;
vtkm::Vec3f origin(0, 0, 0);
vtkm::Vec3f spacing(1, 1, 1);
bool spacingSet = false;
while (stream.good())
{
std::getline(stream, line);
if (line.size() == 0 || line[0] == '#')
continue;
//std::cout<<"::"<<line<<"::"<<std::endl;
std::size_t pos = line.find(":");
if (pos == std::string::npos)
throw vtkm::io::ErrorIO("Unsupported option: " + line);
token = line.substr(0, pos);
options = line.substr(pos + 1, line.size() - 1);
//std::cout<<token<<"::"<<options<<std::endl;
std::stringstream strStream(options);
//Format supports both space and "_" separated tokens...
if (token.find("DATA") != std::string::npos && token.find("FILE") != std::string::npos)
{
strStream >> bovFile >> std::ws;
}
else if (token.find("DATA") != std::string::npos && token.find("SIZE") != std::string::npos)
{
strStream >> dim[0] >> dim[1] >> dim[2] >> std::ws;
}
else if (token.find("BRICK") != std::string::npos && token.find("ORIGIN") != std::string::npos)
{
strStream >> origin[0] >> origin[1] >> origin[2] >> std::ws;
}
//DRP
else if (token.find("BRICK") != std::string::npos && token.find("SIZE") != std::string::npos)
{
strStream >> spacing[0] >> spacing[1] >> spacing[2] >> std::ws;
spacingSet = true;
}
else if (token.find("DATA") != std::string::npos && token.find("FORMAT") != std::string::npos)
{
std::string opt;
strStream >> opt >> std::ws;
if (opt.find("FLOAT") != std::string::npos || opt.find("REAL") != std::string::npos)
dataFormat = DataFormat::FloatData;
else if (opt.find("DOUBLE") != std::string::npos)
dataFormat = DataFormat::DoubleData;
else
throw vtkm::io::ErrorIO("Unsupported data type: " + token);
}
else if (token.find("DATA") != std::string::npos &&
token.find("COMPONENTS") != std::string::npos)
{
strStream >> numComponents >> std::ws;
if (numComponents != 1 && numComponents != 3)
throw vtkm::io::ErrorIO("Unsupported number of components");
}
else if (token.find("VARIABLE") != std::string::npos &&
token.find("PALETTE") == std::string::npos)
{
strStream >> variableName >> std::ws;
if (variableName[0] == '"')
variableName = variableName.substr(1, variableName.size() - 2);
}
}
if (spacingSet)
{
spacing[0] = (spacing[0]) / static_cast<vtkm::FloatDefault>(dim[0] - 1);
spacing[1] = (spacing[1]) / static_cast<vtkm::FloatDefault>(dim[1] - 1);
spacing[2] = (spacing[2]) / static_cast<vtkm::FloatDefault>(dim[2] - 1);
}
std::string fullPathDataFile;
std::size_t pos = FileName.rfind("/");
if (pos != std::string::npos)
{
std::string baseDir;
baseDir = this->FileName.substr(0, pos);
fullPathDataFile = baseDir + "/" + bovFile;
}
else
fullPathDataFile = bovFile;
vtkm::cont::DataSetBuilderUniform dataSetBuilder;
vtkm::cont::DataSetFieldAdd dsf;
this->DataSet = dataSetBuilder.Create(dim, origin, spacing);
vtkm::Id numTuples = dim[0] * dim[1] * dim[2];
if (numComponents == 1)
{
if (dataFormat == DataFormat::FloatData)
{
vtkm::cont::ArrayHandle<vtkm::Float32> var;
ReadScalar(fullPathDataFile, numTuples, var);
dsf.AddPointField(this->DataSet, variableName, var);
}
else if (dataFormat == DataFormat::DoubleData)
{
vtkm::cont::ArrayHandle<vtkm::Float64> var;
ReadScalar(fullPathDataFile, numTuples, var);
dsf.AddPointField(this->DataSet, variableName, var);
}
}
else if (numComponents == 3)
{
if (dataFormat == DataFormat::FloatData)
{
vtkm::cont::ArrayHandle<vtkm::Vec3f_32> var;
ReadVector(fullPathDataFile, numTuples, var);
dsf.AddPointField(this->DataSet, variableName, var);
}
else if (dataFormat == DataFormat::DoubleData)
{
vtkm::cont::ArrayHandle<vtkm::Vec3f_64> var;
ReadVector(fullPathDataFile, numTuples, var);
dsf.AddPointField(this->DataSet, variableName, var);
}
}
this->Loaded = true;
}
}
} // namespace vtkm::io

@ -10,239 +10,31 @@
#ifndef vtk_m_io_BOVDataSetReader_h
#define vtk_m_io_BOVDataSetReader_h
#include <fstream>
#include <vtkm/cont/DataSet.h>
#include <vtkm/cont/DataSetBuilderUniform.h>
#include <vtkm/cont/DataSetFieldAdd.h>
#include <vtkm/io/ErrorIO.h>
#include <vtkm/io/vtkm_io_export.h>
namespace vtkm
{
namespace io
{
class BOVDataSetReader
class VTKM_IO_EXPORT BOVDataSetReader
{
public:
BOVDataSetReader(const char* fileName)
: FileName(fileName)
, Loaded(false)
, DataSet()
{
}
BOVDataSetReader(const std::string& fileName)
: FileName(fileName)
, Loaded(false)
, DataSet()
{
}
VTKM_CONT BOVDataSetReader(const char* fileName);
VTKM_CONT BOVDataSetReader(const std::string& fileName);
const vtkm::cont::DataSet& ReadDataSet()
{
try
{
LoadFile();
}
catch (std::ifstream::failure& e)
{
std::string message("IO Error: ");
throw vtkm::io::ErrorIO(message + e.what());
}
return this->DataSet;
}
VTKM_CONT const vtkm::cont::DataSet& ReadDataSet();
private:
using DataFormat = enum { ByteData, ShortData, IntegerData, FloatData, DoubleData };
void LoadFile()
{
if (this->Loaded)
return;
std::ifstream stream(this->FileName);
if (stream.fail())
throw vtkm::io::ErrorIO("Failed to open file: " + this->FileName);
DataFormat dataFormat = ByteData;
std::string bovFile, line, token, options, variableName;
vtkm::Id numComponents = 1;
vtkm::Id3 dim;
vtkm::Vec3f origin(0, 0, 0);
vtkm::Vec3f spacing(1, 1, 1);
bool spacingSet = false;
while (stream.good())
{
std::getline(stream, line);
if (line.size() == 0 || line[0] == '#')
continue;
//std::cout<<"::"<<line<<"::"<<std::endl;
std::size_t pos = line.find(":");
if (pos == std::string::npos)
throw vtkm::io::ErrorIO("Unsupported option: " + line);
token = line.substr(0, pos);
options = line.substr(pos + 1, line.size() - 1);
//std::cout<<token<<"::"<<options<<std::endl;
std::stringstream strStream(options);
//Format supports both space and "_" separated tokens...
if (token.find("DATA") != std::string::npos && token.find("FILE") != std::string::npos)
{
strStream >> bovFile >> std::ws;
}
else if (token.find("DATA") != std::string::npos && token.find("SIZE") != std::string::npos)
{
strStream >> dim[0] >> dim[1] >> dim[2] >> std::ws;
}
else if (token.find("BRICK") != std::string::npos &&
token.find("ORIGIN") != std::string::npos)
{
strStream >> origin[0] >> origin[1] >> origin[2] >> std::ws;
}
//DRP
else if (token.find("BRICK") != std::string::npos && token.find("SIZE") != std::string::npos)
{
strStream >> spacing[0] >> spacing[1] >> spacing[2] >> std::ws;
spacingSet = true;
}
else if (token.find("DATA") != std::string::npos && token.find("FORMAT") != std::string::npos)
{
std::string opt;
strStream >> opt >> std::ws;
if (opt.find("FLOAT") != std::string::npos || opt.find("REAL") != std::string::npos)
dataFormat = FloatData;
else if (opt.find("DOUBLE") != std::string::npos)
dataFormat = DoubleData;
else
throw vtkm::io::ErrorIO("Unsupported data type: " + token);
}
else if (token.find("DATA") != std::string::npos &&
token.find("COMPONENTS") != std::string::npos)
{
strStream >> numComponents >> std::ws;
if (numComponents != 1 && numComponents != 3)
throw vtkm::io::ErrorIO("Unsupported number of components");
}
else if (token.find("VARIABLE") != std::string::npos &&
token.find("PALETTE") == std::string::npos)
{
strStream >> variableName >> std::ws;
if (variableName[0] == '"')
variableName = variableName.substr(1, variableName.size() - 2);
}
}
if (spacingSet)
{
spacing[0] = (spacing[0]) / static_cast<vtkm::FloatDefault>(dim[0] - 1);
spacing[1] = (spacing[1]) / static_cast<vtkm::FloatDefault>(dim[1] - 1);
spacing[2] = (spacing[2]) / static_cast<vtkm::FloatDefault>(dim[2] - 1);
}
std::string fullPathDataFile;
std::size_t pos = FileName.rfind("/");
if (pos != std::string::npos)
{
std::string baseDir;
baseDir = this->FileName.substr(0, pos);
fullPathDataFile = baseDir + "/" + bovFile;
}
else
fullPathDataFile = bovFile;
vtkm::cont::DataSetBuilderUniform dataSetBuilder;
vtkm::cont::DataSetFieldAdd dsf;
this->DataSet = dataSetBuilder.Create(dim, origin, spacing);
vtkm::Id numTuples = dim[0] * dim[1] * dim[2];
if (numComponents == 1)
{
if (dataFormat == FloatData)
{
vtkm::cont::ArrayHandle<vtkm::Float32> var;
ReadScalar(fullPathDataFile, numTuples, var);
dsf.AddPointField(this->DataSet, variableName, var);
}
else if (dataFormat == DoubleData)
{
vtkm::cont::ArrayHandle<vtkm::Float64> var;
ReadScalar(fullPathDataFile, numTuples, var);
dsf.AddPointField(this->DataSet, variableName, var);
}
}
else if (numComponents == 3)
{
if (dataFormat == FloatData)
{
vtkm::cont::ArrayHandle<vtkm::Vec3f_32> var;
ReadVector(fullPathDataFile, numTuples, var);
dsf.AddPointField(this->DataSet, variableName, var);
}
else if (dataFormat == DoubleData)
{
vtkm::cont::ArrayHandle<vtkm::Vec3f_64> var;
ReadVector(fullPathDataFile, numTuples, var);
dsf.AddPointField(this->DataSet, variableName, var);
}
}
this->Loaded = true;
}
template <typename T>
void ReadBuffer(const std::string& fName, const vtkm::Id& sz, std::vector<T>& buff)
{
FILE* fp = fopen(fName.c_str(), "rb");
size_t readSize = static_cast<size_t>(sz);
if (fp == nullptr)
throw vtkm::io::ErrorIO("Unable to open data file: " + fName);
buff.resize(readSize);
size_t nread = fread(&buff[0], sizeof(T), readSize, fp);
if (nread != readSize)
throw vtkm::io::ErrorIO("Data file read failed: " + fName);
fclose(fp);
}
template <typename T>
void ReadScalar(const std::string& fName,
const vtkm::Id& nTuples,
vtkm::cont::ArrayHandle<T>& var)
{
std::vector<T> buff;
ReadBuffer(fName, nTuples, buff);
var.Allocate(nTuples);
for (vtkm::Id i = 0; i < nTuples; i++)
var.WritePortal().Set(i, buff[(size_t)i]);
}
template <typename T>
void ReadVector(const std::string& fName,
const vtkm::Id& nTuples,
vtkm::cont::ArrayHandle<vtkm::Vec<T, 3>>& var)
{
std::vector<T> buff;
ReadBuffer(fName, nTuples * 3, buff);
var.Allocate(nTuples);
vtkm::Vec<T, 3> v;
for (vtkm::Id i = 0; i < nTuples; i++)
{
v[0] = buff[static_cast<size_t>(i * 3 + 0)];
v[1] = buff[static_cast<size_t>(i * 3 + 1)];
v[2] = buff[static_cast<size_t>(i * 3 + 2)];
var.WritePortal().Set(i, v);
}
}
VTKM_CONT void LoadFile();
std::string FileName;
bool Loaded;
vtkm::cont::DataSet DataSet;
};
}
}
} // vtkm::io
#endif // vtk_m_io_BOVReader_h

@ -13,14 +13,23 @@ set(headers
ErrorIO.h
DecodePNG.h
EncodePNG.h
ImageReader.h
ImageWriter.h
PixelTypes.h
VTKDataSetReader.h
VTKDataSetReaderBase.h
VTKDataSetWriter.h
VTKPolyDataReader.h
VTKRectilinearGridReader.h
VTKStructuredGridReader.h
VTKStructuredPointsReader.h
VTKUnstructuredGridReader.h
VTKDataSetWriter.h
)
set(template_sources
ImageReader.hxx
ImageWriter.hxx
PixelTypes.hxx
)
set(sources
@ -28,12 +37,34 @@ set(sources
EncodePNG.cxx
)
vtkm_declare_headers(${headers})
# TODO: None of these codes actually use a device. Rather, they access ArrayHandle, and we
# currently need to ensure that ArrayHandle is correctly compiled for all devices. This is
# kind of silly, so hopefully sometime in the future you will no longer need to compile for
# devices for ArrayHandle, and this requirement will go away.
set(device_sources
BOVDataSetReader.cxx
VTKDataSetReader.cxx
VTKDataSetReaderBase.cxx
VTKDataSetWriter.cxx
VTKPolyDataReader.cxx
VTKRectilinearGridReader.cxx
VTKStructuredGridReader.cxx
VTKStructuredPointsReader.cxx
VTKUnstructuredGridReader.cxx
)
vtkm_library( NAME vtkm_io
SOURCES ${sources}
HEADERS ${headers}
)
vtkm_declare_headers(
${headers}
${template_sources}
)
vtkm_library(
NAME vtkm_io
SOURCES ${sources}
DEVICE_SOURCES ${device_sources}
HEADERS ${headers}
TEMPLATE_SOURCES ${template_sources}
)
target_link_libraries(vtkm_io PUBLIC vtkm_cont PRIVATE vtkm_lodepng)

@ -13,7 +13,6 @@
#include <vtkm/cont/Logging.h>
#include <vtkm/internal/Configure.h>
VTKM_THIRDPARTY_PRE_INCLUDE
#include <vtkm/thirdparty/lodepng/vtkmlodepng/lodepng.h>
VTKM_THIRDPARTY_POST_INCLUDE

155
vtkm/io/ImageReader.h Normal file

@ -0,0 +1,155 @@
//============================================================================
// 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_io_ImageReader_h
#define vtk_m_io_ImageReader_h
#include <vtkm/Types.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/DataSet.h>
namespace vtkm
{
// Forward Declare
namespace rendering
{
class Canvas;
} // namespace rendering
namespace io
{
/// \brief Manages reading, and loading data from images
///
/// \c BaseImageReader implements methods for loading imaging data from a canvas or
/// ArrayHandle and storing that data in a vtkm::cont::DataSet. Image rgb values
/// are represented as a point field in a 2D uniform dataset.
///
/// \c BaseImageReader can be constructed from a file, canvas, or ArrayHandle. It can
/// also be empy constructed and filled in with a dataset later.
///
/// \c BaseImageReader implements virtual methods for reading files. Ideally,
/// these methods will be overriden in various subclasses to implement specific
/// functionality for reading data to specific image file-types.
///
/// \c The templated type is used when Filling the ImageDataSet.
///
class BaseImageReader
{
public:
/// Constructs an emtpy BaseImageReader.
///
BaseImageReader() = default;
explicit BaseImageReader(const vtkm::Id& maxColorValue)
: MaxColorValue(maxColorValue)
{
}
~BaseImageReader() noexcept = default;
/// Reads image data from a file. Meant to be implemented in overriden
/// image-specific classes
///
virtual vtkm::cont::DataSet ReadFromFile(const std::string& fileName) = 0;
/// Creates an ImageDataSet from a Canvas object
///
vtkm::cont::DataSet CreateImageDataSet(const vtkm::rendering::Canvas& canvas);
/// Creates an ImageDataSet from a RGBA 32bit float color buffer
/// Assumes the color buffer is stored in row-major ordering
///
vtkm::cont::DataSet CreateImageDataSet(const vtkm::cont::ArrayHandle<vtkm::Vec4f_32>& colorBuffer,
const vtkm::Id& width,
const vtkm::Id& height);
const std::string& GetPointFieldName() const { return this->PointFieldName; }
protected:
vtkm::cont::DataSet InitializeImageDataSet(const vtkm::Id& width, const vtkm::Id& height);
std::string PointFieldName = "pixel-data";
vtkm::Id MaxColorValue{ 0 };
};
/// \brief Manages reading images using the PNG format via lodepng
///
/// \c PNGReader extends BaseImageReader and implements reading images in a valid
/// PNG format. It utilizes lodepng's decode file functions to read
/// PNG images that are automatically compressed to optimal sizes relative to
/// the actual bit complexity of the image.
///
/// \c PNGReader will automatically upsample/downsample read image data
/// to a 16 bit RGB no matter how the image is compressed. It is up to the user to
/// decide the pixel format for input PNGs
class PNGReader : public BaseImageReader
{
using Superclass = BaseImageReader;
public:
using Superclass::Superclass;
PNGReader() = default;
~PNGReader() noexcept = default;
/// Reads PNG data from the provided file and stores it
/// as a 16bit RGB value
///
vtkm::cont::DataSet ReadFromFile(const std::string& fileName) override;
/// Reads PNG data from the provided file and stores it
/// according to the method's templated PixelType
///
template <typename PixelType>
vtkm::cont::DataSet ReadFromFile(const std::string& fileName);
};
/// \brief Manages reading images using the PNM format
///
/// \c PNMImage extends BaseImage, and implements reading images from a
/// valid PNM format (for magic number P6). More details on the PNM
/// format can be found here: http://netpbm.sourceforge.net/doc/ppm.html
///
/// When a file is read the parsed MagicNumber and MaxColorSize provided
/// are utilized to correctly parse the bits from the file
class PNMReader : public BaseImageReader
{
using Superclass = BaseImageReader;
public:
using Superclass::Superclass;
PNMReader() = default;
~PNMReader() noexcept = default;
/// Attempts to read the provided file into a DataSet object.
/// Will pull the image's MaxColorValue from the file and then Decode
/// with the appropriate RGB PixelType bit depth.
///
vtkm::cont::DataSet ReadFromFile(const std::string& fileName) override;
protected:
/// Reads image data from the provided inStream with the supplied width/height
/// Stores the data in a vector of PixelType which is converted to an DataSet
///
template <typename PixelType>
vtkm::cont::DataSet DecodeFile(std::ifstream& inStream,
const vtkm::Id& width,
const vtkm::Id& height);
// This is set to only work for P6 pnm image types for now (ie ppm)
std::string MagicNumber{ "P6" };
};
} // namespace io
} // namespace vtkm
#include <vtkm/io/ImageReader.hxx>
#endif

176
vtkm/io/ImageReader.hxx Normal file

@ -0,0 +1,176 @@
//============================================================================
// 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_io_ImageReader_hxx
#define vtk_m_io_ImageReader_hxx
#include <vtkm/cont/CellSetStructured.h>
#include <vtkm/cont/DataSetBuilderUniform.h>
#include <vtkm/cont/DataSetFieldAdd.h>
#include <vtkm/io/ImageReader.h>
#include <vtkm/io/PixelTypes.h>
#include <vtkm/rendering/Canvas.h>
VTKM_THIRDPARTY_PRE_INCLUDE
#include <vtkm/thirdparty/lodepng/vtkmlodepng/lodepng.h>
VTKM_THIRDPARTY_POST_INCLUDE
namespace vtkm
{
namespace io
{
// Start BaseReaderImage Class Template Implementations
VTKM_CONT
vtkm::cont::DataSet BaseImageReader::CreateImageDataSet(const vtkm::rendering::Canvas& canvas)
{
return this->CreateImageDataSet(canvas.GetColorBuffer(), canvas.GetWidth(), canvas.GetHeight());
}
VTKM_CONT
vtkm::cont::DataSet BaseImageReader::CreateImageDataSet(
const vtkm::cont::ArrayHandle<vtkm::Vec4f_32>& colorBuffer,
const vtkm::Id& width,
const vtkm::Id& height)
{
vtkm::cont::ArrayHandle<vtkm::Vec4f_32>::ReadPortalType colorPortal = colorBuffer.ReadPortal();
std::vector<vtkm::Vec4f_32> fieldData;
for (vtkm::Id yIndex = 0; yIndex < height; yIndex++)
{
for (vtkm::Id xIndex = 0; xIndex < width; xIndex++)
{
vtkm::Vec4f_32 tuple = colorPortal.Get(yIndex * width + xIndex);
fieldData.push_back(tuple);
}
}
auto dataSet = this->InitializeImageDataSet(width, height);
vtkm::cont::DataSetFieldAdd dsf;
dsf.AddPointField(dataSet, this->PointFieldName, fieldData);
return dataSet;
}
VTKM_CONT
vtkm::cont::DataSet BaseImageReader::InitializeImageDataSet(const vtkm::Id& width,
const vtkm::Id& height)
{
vtkm::cont::DataSetBuilderUniform dsb;
vtkm::Id2 dimensions(width, height);
return dsb.Create(dimensions);
}
// End BaseReaderImage Class Template Implementations
// Start PNGReader Class Template Implementations
VTKM_CONT
vtkm::cont::DataSet PNGReader::ReadFromFile(const std::string& fileName)
{
return this->ReadFromFile<io::RGBPixel_16>(fileName);
}
VTKM_CONT
template <typename PixelType>
vtkm::cont::DataSet PNGReader::ReadFromFile(const std::string& fileName)
{
unsigned char* imageData;
unsigned uwidth, uheight;
vtkm::Id width, height;
vtkm::png::lodepng_decode_file(&imageData,
&uwidth,
&uheight,
fileName.c_str(),
PixelType::PNG_COLOR_TYPE,
PixelType::BIT_DEPTH);
width = static_cast<vtkm::Id>(uwidth);
height = static_cast<vtkm::Id>(uheight);
// Fill in the data starting from the end (Images are read Top-Left to Bottom-Right,
// but are stored from Bottom-Left to Top-Right)
std::vector<vtkm::Vec4f_32> fieldData;
for (vtkm::Id yIndex = static_cast<vtkm::Id>(height - 1); yIndex >= 0; yIndex--)
{
for (vtkm::Id xIndex = 0; xIndex < static_cast<vtkm::Id>(width); xIndex++)
{
vtkm::Id index = static_cast<vtkm::Id>(yIndex * width + xIndex);
fieldData.push_back(PixelType(imageData, index).ToVec4f());
}
}
auto dataSet = this->InitializeImageDataSet(width, height);
vtkm::cont::DataSetFieldAdd dsf;
dsf.AddPointField(dataSet, this->PointFieldName, fieldData);
free(imageData);
return dataSet;
}
// End PNGReader Class Template Implementations
// Start PNMReader Class Template Implementations
VTKM_CONT
vtkm::cont::DataSet PNMReader::ReadFromFile(const std::string& fileName)
{
std::ifstream inStream(fileName.c_str(), std::ios_base::binary | std::ios_base::in);
vtkm::Id width;
vtkm::Id height;
std::string val;
inStream >> val;
if (this->MagicNumber != val)
{
throw vtkm::cont::ErrorBadValue("MagicNumber: " + this->MagicNumber + " in file: " + fileName +
" did not match: " + val);
}
inStream >> width >> height >> this->MaxColorValue;
inStream.get();
switch (this->MaxColorValue)
{
case 255:
return this->DecodeFile<io::RGBPixel_8>(inStream, width, height);
case 65535:
return this->DecodeFile<io::RGBPixel_16>(inStream, width, height);
default:
throw vtkm::cont::ErrorBadValue("MaxColorValue: " + std::to_string(this->MaxColorValue) +
" from file: " + fileName + " was not one of: {8, 16}");
}
}
VTKM_CONT
template <typename PixelType>
vtkm::cont::DataSet PNMReader::DecodeFile(std::ifstream& inStream,
const vtkm::Id& width,
const vtkm::Id& height)
{
vtkm::UInt32 imageSize = static_cast<vtkm::UInt32>(width * height * PixelType::BYTES_PER_PIXEL);
std::vector<unsigned char> imageData(imageSize);
inStream.read((char*)imageData.data(), imageSize);
// Fill in the data starting from the end (Images are read Top-Left to Bottom-Right,
// but are stored from Bottom-Left to Top-Right)
std::vector<vtkm::Vec4f_32> fieldData;
for (vtkm::Id yIndex = height - 1; yIndex >= 0; yIndex--)
{
for (vtkm::Id xIndex = 0; xIndex < width; xIndex++)
{
vtkm::Id index = yIndex * width + xIndex;
fieldData.push_back(PixelType(imageData.data(), index).ToVec4f());
}
}
auto dataSet = this->InitializeImageDataSet(width, height);
vtkm::cont::DataSetFieldAdd dsf;
dsf.AddPointField(dataSet, this->PointFieldName, fieldData);
return dataSet;
}
// End PNMReader Class Template Implementations
} // namespace io
} // namespace vtkm
#endif

140
vtkm/io/ImageWriter.h Normal file

@ -0,0 +1,140 @@
//============================================================================
// 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_io_ImageWriter_h
#define vtk_m_io_ImageWriter_h
#include <vtkm/Types.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/DataSet.h>
namespace vtkm
{
namespace io
{
/// \brief Manages writing, and loading data from images
///
/// \c BaseImageWriter implements methods for loading imaging data from a canvas or
/// ArrayHandle and storing that data in a vtkm::cont::DataSet. Image rgb values
/// are represented as a point field in a 2D uniform dataset.
///
/// \c BaseImageWriter can be constructed from a file, canvas, or ArrayHandle. It can
/// also be empy constructed and filled in with a dataset later.
///
/// \c BaseImageWriter implements virtual methods for writing files. Ideally,
/// these methods will be overriden in various subclasses to implement specific
/// functionality for writing data to specific image file-types.
///
class BaseImageWriter
{
public:
/// Constructs an emtpy BaseImageWriter.
///
BaseImageWriter() = default;
explicit BaseImageWriter(const vtkm::Id& maxColorValue)
: MaxColorValue(maxColorValue)
{
}
~BaseImageWriter() noexcept = default;
/// Write and store ImageDataSet to a file. Meant to be implemented in
/// overriden image-specific classes
///
virtual void WriteToFile(const std::string& fileName,
const vtkm::cont::DataSet& dataSet) const = 0;
vtkm::Id GetImageWidth(vtkm::cont::DataSet dataSet) const;
vtkm::Id GetImageHeight(vtkm::cont::DataSet dataSet) const;
const std::string& GetPointFieldName() const { return this->PointFieldName; }
void SetMaxColorValue(const vtkm::Id& maxColorValue) { this->MaxColorValue = maxColorValue; }
protected:
std::string PointFieldName = "pixel-data";
vtkm::Id MaxColorValue{ 0 };
};
/// \brief Manages writing images using the PNM format
///
/// \c PNMWriter extends BaseImageWriter, and implements writing images in a
/// valid PNM format (for magic number P6). More details on the PNM
/// format can be found here: http://netpbm.sourceforge.net/doc/ppm.html
///
/// When a file is writen the MaxColorValue found in the file is used to
/// determine the PixelType required to stored PixelType is instead dependent
/// upon the read MaxColorValue obtained from the file
class PNMWriter : public BaseImageWriter
{
using Superclass = BaseImageWriter;
public:
using Superclass::Superclass;
PNMWriter() = default;
~PNMWriter() noexcept = default;
/// Attempts to write the ImageDataSet to a PNM file. The MaxColorValue
/// set in the file with either be selected from the stored MaxColorValue
/// member variable, or from the templated type if MaxColorValue hasn't been
/// set from a read file.
///
void WriteToFile(const std::string& fileName, const vtkm::cont::DataSet& dataSet) const override;
protected:
/// Writes image data stored in ImageDataSet to the provided outStream
/// Casts the data to the provided PixelType
///
template <typename PixelType>
void EncodeFile(std::ofstream& outStream, const vtkm::cont::DataSet& dataSet) const;
// Currently only works with P6 PNM files (PPM)
std::string MagicNumber{ "P6" };
};
/// \brief Manages writing images using the PNG format via lodepng
///
/// \c PNGWriter extends BaseImageWriter and implements writing images in a valid
/// PNG format. It utilizes lodepng's encode file functions to write
/// PNG images that are automatically compressed to optimal sizes relative to
/// the actual bit complexity of the image.
///
/// \c PNGImage will automatically upsample/downsample written image data
/// to the supplied templated PixelType. For example, it is possible to write
/// a 1-bit greyscale image into a 16bit RGB PNG object. It is up to the user to
/// decide the pixel format for output PNGs
class PNGWriter : public BaseImageWriter
{
using Superclass = BaseImageWriter;
public:
using Superclass::Superclass;
PNGWriter() = default;
~PNGWriter() noexcept = default;
/// Writes stored data matched to the class's templated type
/// to a file in PNG format. Relies upon the lodepng encoding
/// method to optimize compression and choose the best storage format.
///
void WriteToFile(const std::string& fileName, const vtkm::cont::DataSet& dataSet) const override;
/// Writes stored data matched to the method's templated type
/// to a file in PNG format. Relies upon the lodepng encoding
/// method to optimize compression and choose the best storage format.
///
template <typename PixelType>
void WriteToFile(const std::string& fileName, const vtkm::cont::DataSet& dataSet) const;
};
} // namespace io
} // namespace vtkm
#include <vtkm/io/ImageWriter.hxx>
#endif

173
vtkm/io/ImageWriter.hxx Normal file

@ -0,0 +1,173 @@
//============================================================================
// 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_io_ImageWriter_hxx
#define vtk_m_io_ImageWriter_hxx
#include <vtkm/cont/CellSetStructured.h>
#include <vtkm/cont/DataSetBuilderUniform.h>
#include <vtkm/cont/DataSetFieldAdd.h>
#include <vtkm/io/ImageWriter.h>
#include <vtkm/io/PixelTypes.h>
VTKM_THIRDPARTY_PRE_INCLUDE
#include <vtkm/thirdparty/lodepng/vtkmlodepng/lodepng.h>
VTKM_THIRDPARTY_POST_INCLUDE
namespace vtkm
{
namespace io
{
VTKM_CONT
vtkm::Id BaseImageWriter::GetImageWidth(vtkm::cont::DataSet dataSet) const
{
if (dataSet.GetNumberOfCoordinateSystems() > 0)
{
// Add 1 since the Bounds are 0 indexed
return static_cast<vtkm::Id>(dataSet.GetCoordinateSystem().GetBounds().X.Max) + 1;
}
return 0;
}
VTKM_CONT
vtkm::Id BaseImageWriter::GetImageHeight(vtkm::cont::DataSet dataSet) const
{
if (dataSet.GetNumberOfCoordinateSystems() > 0)
{
// Add 1 since the Bounds are 0 indexed
return static_cast<vtkm::Id>(dataSet.GetCoordinateSystem().GetBounds().Y.Max) + 1;
}
return 0;
}
VTKM_CONT
void PNMWriter::WriteToFile(const std::string& fileName, const vtkm::cont::DataSet& dataSet) const
{
if (!dataSet.HasField(this->PointFieldName))
{
throw vtkm::cont::ErrorBadValue(
"No pixel data found in DataSet, cannot write without image data!");
}
std::ofstream outStream(fileName.c_str(), std::ios_base::binary | std::ios_base::out);
outStream << this->MagicNumber << std::endl
<< this->GetImageWidth(dataSet) << " " << this->GetImageHeight(dataSet) << std::endl;
switch (this->MaxColorValue)
{
case 0:
this->EncodeFile<RGBPixel_8>(outStream, dataSet);
break;
case 255:
this->EncodeFile<RGBPixel_8>(outStream, dataSet);
break;
case 65535:
this->EncodeFile<RGBPixel_16>(outStream, dataSet);
break;
default:
throw vtkm::cont::ErrorBadValue("MaxColorValue: " + std::to_string(this->MaxColorValue) +
" was not one of: {255, 65535}");
}
}
VTKM_CONT
template <typename PixelType>
void PNMWriter::EncodeFile(std::ofstream& outStream, const vtkm::cont::DataSet& dataSet) const
{
outStream << PixelType::MAX_COLOR_VALUE << std::endl;
auto pixelField = dataSet.GetPointField(this->PointFieldName)
.GetData()
.template Cast<vtkm::cont::ArrayHandle<vtkm::Vec4f_32>>();
auto pixelPortal = pixelField.ReadPortal();
vtkm::UInt32 imageSize =
static_cast<vtkm::UInt32>(pixelField.GetNumberOfValues() * PixelType::BYTES_PER_PIXEL);
std::vector<unsigned char> imageData(imageSize);
// Write out the data starting from the end (Images are stored Bottom-Left to Top-Right,
// but are viewed from Top-Left to Bottom-Right)
vtkm::Id imageIndex = 0;
vtkm::Id imageHeight = this->GetImageHeight(dataSet);
vtkm::Id imageWidth = this->GetImageWidth(dataSet);
for (vtkm::Id yIndex = imageHeight - 1; yIndex >= 0; yIndex--)
{
for (vtkm::Id xIndex = 0; xIndex < imageWidth; xIndex++, imageIndex++)
{
vtkm::Id index = yIndex * imageWidth + xIndex;
PixelType(pixelPortal.Get(index)).FillImageAtIndexWithPixel(imageData.data(), imageIndex);
}
}
outStream.write((char*)imageData.data(), imageSize);
outStream.close();
}
VTKM_CONT
void PNGWriter::WriteToFile(const std::string& fileName, const vtkm::cont::DataSet& dataSet) const
{
switch (this->MaxColorValue)
{
case 0:
WriteToFile<RGBPixel_8>(fileName, dataSet);
break;
case 255:
WriteToFile<RGBPixel_8>(fileName, dataSet);
break;
case 65535:
WriteToFile<RGBPixel_16>(fileName, dataSet);
break;
default:
throw vtkm::cont::ErrorBadValue("MaxColorValue: " + std::to_string(this->MaxColorValue) +
" was not one of: {255, 65535}");
}
}
VTKM_CONT
template <typename PixelType>
void PNGWriter::WriteToFile(const std::string& fileName, const vtkm::cont::DataSet& dataSet) const
{
if (!dataSet.HasField(this->PointFieldName))
{
throw vtkm::cont::ErrorBadValue(
"No pixel data found in DataSet, cannot write without image data!");
}
auto pixelField = dataSet.GetPointField(this->PointFieldName)
.GetData()
.template Cast<vtkm::cont::ArrayHandle<vtkm::Vec4f_32>>();
auto pixelPortal = pixelField.ReadPortal();
std::vector<unsigned char> imageData(static_cast<typename std::vector<unsigned char>::size_type>(
pixelField.GetNumberOfValues() * PixelType::BYTES_PER_PIXEL));
// Write out the data starting from the end (Images are stored Bottom-Left to Top-Right,
// but are viewed from Top-Left to Bottom-Right)
vtkm::Id imageIndex = 0;
vtkm::Id imageHeight = this->GetImageHeight(dataSet);
vtkm::Id imageWidth = this->GetImageWidth(dataSet);
for (vtkm::Id yIndex = imageHeight - 1; yIndex >= 0; yIndex--)
{
for (vtkm::Id xIndex = 0; xIndex < imageWidth; xIndex++, imageIndex++)
{
vtkm::Id index = yIndex * imageWidth + xIndex;
PixelType(pixelPortal.Get(index)).FillImageAtIndexWithPixel(imageData.data(), imageIndex);
}
}
vtkm::png::lodepng_encode_file(fileName.c_str(),
imageData.data(),
static_cast<unsigned>(imageWidth),
static_cast<unsigned>(imageHeight),
PixelType::PNG_COLOR_TYPE,
PixelType::BIT_DEPTH);
}
} // namespace io
} // namespace vtkm
#endif

201
vtkm/io/PixelTypes.h Normal file

@ -0,0 +1,201 @@
//============================================================================
// 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_io_PixelTypes_h
#define vtk_m_io_PixelTypes_h
#include <vtkm/Types.h>
#include <vtkm/VecTraits.h>
VTKM_THIRDPARTY_PRE_INCLUDE
#include <vtkm/thirdparty/lodepng/vtkmlodepng/lodepng.h>
VTKM_THIRDPARTY_POST_INCLUDE
namespace vtkm
{
namespace io
{
// ----------------------------------------------------------------------
// Define custom SFINAE structures to calculate the VTKM types associated
// with provided BitDepths
template <const vtkm::Id size, typename = void>
struct ComponentTypeFromSize
{
};
template <const vtkm::Id size>
struct ComponentTypeFromSize<size, typename std::enable_if<(size == 8)>::type>
{
using type = vtkm::UInt8;
};
template <const vtkm::Id size>
struct ComponentTypeFromSize<size, typename std::enable_if<(size == 16)>::type>
{
using type = vtkm::UInt16;
};
// ----------------------------------------------------------------------
/// \brief Base type for more complex pixels (RGB, Greyscale, etc) that describes various values
/// such as bit-depth, channel width, bytes per pixel, and how various data should be polled
///
/// \c BasePixel takes BitDepth and Channels as template parameters. BitDepth describes the number
/// of bits in the pixel, while Channels describes the multiple of bits that are available.
/// BasePixel extends vtkm::Vec. The ComponentType is pulled from the ComponentTypeFromSize
/// SFINAE struct defined above. This helps with optimizing the pixel size for a given
/// bit-depth. The Size is pulled from the Channels param.
///
/// \c BasePixel requires BitDepths that are > 8 and powers of 2 at the moment. BitDepths of
/// 4, 2, or 1 bit are not correctly handled at the moment.
///
/// \c BasePixel describes how to populate itself from an unsigned char pointer (assuming that
/// the data stored within the pointer matches the bit-depth and channels described by the
/// BasePixel type), and how to fill in data for an unsigned char pointer. This is mostly
/// useful in serialization and deserialization to various image formats.
///
template <const vtkm::Id BitDepth, const vtkm::IdComponent Channels>
class BasePixel : public vtkm::Vec<typename ComponentTypeFromSize<BitDepth>::type, Channels>
{
static_assert(BitDepth >= 8, "BitDepth not >= 8");
static_assert(!(BitDepth & (BitDepth - 1)), "BitDepth not a power of 2");
public:
using Superclass = vtkm::Vec<typename ComponentTypeFromSize<BitDepth>::type, Channels>;
using ComponentType = typename Superclass::ComponentType;
using BaseType = BasePixel<BitDepth, Channels>;
static constexpr vtkm::IdComponent BIT_DEPTH = BitDepth;
static constexpr vtkm::IdComponent NUM_BYTES = BitDepth / 8;
static constexpr vtkm::IdComponent MAX_COLOR_VALUE = (1 << BitDepth) - 1;
static constexpr vtkm::IdComponent NUM_CHANNELS = Superclass::NUM_COMPONENTS;
static constexpr vtkm::IdComponent BYTES_PER_PIXEL = NUM_CHANNELS * NUM_BYTES;
using Superclass::Superclass;
BasePixel() = default;
/// Fills in this->Components by calling ConstructPixelFromImage. Requires
/// the base vec values to be zeroed out initially.
///
BasePixel(const unsigned char* imageData, const vtkm::Id index)
: Superclass(0)
{
ConstructPixelFromImage(imageData, index);
}
virtual ~BasePixel() = default;
/// Calculates this difference between two pixels as a single value.
///
virtual ComponentType Diff(const BaseType& pixel) const = 0;
/// Generates a Vec4f_32 from the current data available in the pixel
///
virtual vtkm::Vec4f_32 ToVec4f() const = 0;
/// Implement the << operator for this class type. Will call the overloaded
/// print method for the subclassed type.
///
friend std::ostream& operator<<(std::ostream& os, const BaseType& basePixel)
{
basePixel.print(os);
return os;
}
/// Takes an output imageData pointer and in index to a location in that dataset
/// and fills in the pixel data at the location. Utilizes BIT_DEPTH and
/// NUM_CHANNELS to fill in multiple bytes worth of data if necessary.
///
void FillImageAtIndexWithPixel(unsigned char* imageData, const vtkm::Id index);
protected:
/// Takes an input imageData pointer and an index to a location in that dataset
/// and fills in this->Components correctly using the provided BIT_DEPTH and
/// NUM_CHANNELS. Does NOT 0 out the current Components.
///
void ConstructPixelFromImage(const unsigned char* imageData, const vtkm::Id index);
virtual void print(std::ostream& os) const = 0;
};
template <const vtkm::Id BitDepth>
class RGBPixel : public BasePixel<BitDepth, 3>
{
public:
// RGB values are stored in a vtkm::Vec<ComponentType, 3>
using Superclass = BasePixel<BitDepth, 3>;
using ComponentType = typename Superclass::ComponentType;
static constexpr vtkm::png::LodePNGColorType PNG_COLOR_TYPE =
vtkm::png::LodePNGColorType::LCT_RGB;
using Superclass::Superclass;
RGBPixel() = default;
RGBPixel(vtkm::Vec4f_32 tuple)
: Superclass(static_cast<ComponentType>(tuple[0] * this->MAX_COLOR_VALUE),
static_cast<ComponentType>(tuple[1] * this->MAX_COLOR_VALUE),
static_cast<ComponentType>(tuple[2] * this->MAX_COLOR_VALUE))
{
}
virtual ~RGBPixel() = default;
ComponentType Diff(const Superclass& pixel) const override;
vtkm::Vec4f_32 ToVec4f() const override;
protected:
void print(std::ostream& os) const override
{
os << "(" << (int)this->Components[0] << "," << (int)this->Components[1] << ","
<< (int)this->Components[2] << ")";
}
};
// Default types for 8 and 16 bit RGB pixels
using RGBPixel_8 = RGBPixel<8>;
using RGBPixel_16 = RGBPixel<16>;
template <const vtkm::Id BitDepth>
class GreyPixel : public BasePixel<BitDepth, 1>
{
public:
// Grey values are stored in a vtkm::Vec<ComponentType, 1>
// Note: A vec of size 1 is used instead of just a `ComponentType`
// in order to simplify the pixel helper functions
using Superclass = BasePixel<BitDepth, 1>;
using ComponentType = typename Superclass::ComponentType;
static constexpr vtkm::png::LodePNGColorType PNG_COLOR_TYPE =
vtkm::png::LodePNGColorType::LCT_GREY;
using Superclass::Superclass;
GreyPixel() = default;
GreyPixel(vtkm::Vec4f_32 tuple)
: Superclass(
static_cast<ComponentType>((tuple[0] + tuple[1] + tuple[2]) * this->MAX_COLOR_VALUE / 3))
{
}
virtual ~GreyPixel() = default;
ComponentType Diff(const Superclass& pixel) const override;
vtkm::Vec4f_32 ToVec4f() const override;
protected:
void print(std::ostream& os) const override { os << "(" << (int)this->Components[0] << ")"; }
};
// Default types for 8 and 16 bit Grey pixels
using GreyPixel_16 = GreyPixel<16>;
using GreyPixel_8 = GreyPixel<8>;
} // namespace io
} // namespace vtkm
#include <vtkm/io/PixelTypes.hxx>
#endif //vtk_m_io_PixelTypes_h

85
vtkm/io/PixelTypes.hxx Normal file

@ -0,0 +1,85 @@
//============================================================================
// 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_io_PixelTypes_hxx
#define vtk_m_io_PixelTypes_hxx
#include <vtkm/Math.h>
#include <vtkm/io/PixelTypes.h>
namespace vtkm
{
namespace io
{
template <const vtkm::Id B, const vtkm::IdComponent C>
void BasePixel<B, C>::FillImageAtIndexWithPixel(unsigned char* imageData, const vtkm::Id index)
{
vtkm::Id initShift = BIT_DEPTH - 8;
for (vtkm::Id channel = 0; channel < NUM_CHANNELS; channel++)
{
for (vtkm::Id shift = initShift, i = 0; shift >= 0; shift -= 8, i++)
{
imageData[index * BYTES_PER_PIXEL + i + (channel * NUM_BYTES)] =
static_cast<unsigned char>((this->Components[channel] & (0xff << shift)) >> shift);
}
}
}
template <const vtkm::Id B, const vtkm::IdComponent C>
void BasePixel<B, C>::ConstructPixelFromImage(const unsigned char* imageData, const vtkm::Id index)
{
vtkm::Id initShift = BIT_DEPTH - 8;
for (vtkm::Id channel = 0; channel < NUM_CHANNELS; channel++)
{
for (vtkm::Id shift = initShift, i = 0; shift >= 0; shift -= 8, i++)
{
this->Components[channel] |= imageData[index * BYTES_PER_PIXEL + i + (channel * NUM_BYTES)]
<< shift;
}
}
}
template <const vtkm::Id B>
typename RGBPixel<B>::ComponentType RGBPixel<B>::Diff(const Superclass& pixel) const
{
return static_cast<RGBPixel<B>::ComponentType>(vtkm::Abs(this->Components[0] - pixel[0]) +
vtkm::Abs(this->Components[1] - pixel[1]) +
vtkm::Abs(this->Components[2] - pixel[2]));
}
template <const vtkm::Id B>
vtkm::Vec4f_32 RGBPixel<B>::ToVec4f() const
{
return vtkm::Vec4f_32(static_cast<vtkm::Float32>(this->Components[0]) / this->MAX_COLOR_VALUE,
static_cast<vtkm::Float32>(this->Components[1]) / this->MAX_COLOR_VALUE,
static_cast<vtkm::Float32>(this->Components[2]) / this->MAX_COLOR_VALUE,
1);
}
template <const vtkm::Id B>
typename GreyPixel<B>::ComponentType GreyPixel<B>::Diff(const Superclass& pixel) const
{
return static_cast<GreyPixel<B>::ComponentType>(vtkm::Abs(this->Components[0] - pixel[0]));
}
template <const vtkm::Id B>
vtkm::Vec4f_32 GreyPixel<B>::ToVec4f() const
{
return vtkm::Vec4f_32(static_cast<vtkm::Float32>(this->Components[0]) / this->MAX_COLOR_VALUE,
static_cast<vtkm::Float32>(this->Components[0]) / this->MAX_COLOR_VALUE,
static_cast<vtkm::Float32>(this->Components[0]) / this->MAX_COLOR_VALUE,
1);
}
} // namespace io
} // namespace vtkm
#endif //vtk_m_io_PixelTypes_h

@ -0,0 +1,92 @@
//============================================================================
// 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/io/VTKDataSetReader.h>
#include <vtkm/io/VTKPolyDataReader.h>
#include <vtkm/io/VTKRectilinearGridReader.h>
#include <vtkm/io/VTKStructuredGridReader.h>
#include <vtkm/io/VTKStructuredPointsReader.h>
#include <vtkm/io/VTKUnstructuredGridReader.h>
#include <memory>
namespace vtkm
{
namespace io
{
VTKDataSetReader::VTKDataSetReader(const char* fileName)
: VTKDataSetReaderBase(fileName)
{
}
VTKDataSetReader::VTKDataSetReader(const std::string& fileName)
: VTKDataSetReaderBase(fileName)
{
}
VTKDataSetReader::~VTKDataSetReader()
{
}
void VTKDataSetReader::PrintSummary(std::ostream& out) const
{
if (this->Reader)
{
this->Reader->PrintSummary(out);
}
else
{
VTKDataSetReaderBase::PrintSummary(out);
}
}
void VTKDataSetReader::CloseFile()
{
if (this->Reader)
{
this->Reader->CloseFile();
}
else
{
VTKDataSetReaderBase::CloseFile();
}
}
void VTKDataSetReader::Read()
{
switch (this->DataFile->Structure)
{
case vtkm::io::internal::DATASET_STRUCTURED_POINTS:
this->Reader.reset(new VTKStructuredPointsReader(""));
break;
case vtkm::io::internal::DATASET_STRUCTURED_GRID:
this->Reader.reset(new VTKStructuredGridReader(""));
break;
case vtkm::io::internal::DATASET_RECTILINEAR_GRID:
this->Reader.reset(new VTKRectilinearGridReader(""));
break;
case vtkm::io::internal::DATASET_POLYDATA:
this->Reader.reset(new VTKPolyDataReader(""));
break;
case vtkm::io::internal::DATASET_UNSTRUCTURED_GRID:
this->Reader.reset(new VTKUnstructuredGridReader(""));
break;
default:
throw vtkm::io::ErrorIO("Unsupported DataSet type.");
}
this->TransferDataFile(*this->Reader.get());
this->Reader->Read();
this->DataSet = this->Reader->GetDataSet();
}
}
} // namespace vtkm::io

@ -11,86 +11,27 @@
#define vtk_m_io_VTKDataSetReader_h
#include <vtkm/io/VTKDataSetReaderBase.h>
#include <vtkm/io/VTKPolyDataReader.h>
#include <vtkm/io/VTKRectilinearGridReader.h>
#include <vtkm/io/VTKStructuredGridReader.h>
#include <vtkm/io/VTKStructuredPointsReader.h>
#include <vtkm/io/VTKUnstructuredGridReader.h>
#include <memory>
namespace vtkm
{
namespace io
{
VTKM_SILENCE_WEAK_VTABLE_WARNING_START
class VTKDataSetReader : public VTKDataSetReaderBase
class VTKM_IO_EXPORT VTKDataSetReader : public VTKDataSetReaderBase
{
public:
explicit VTKDataSetReader(const char* fileName)
: VTKDataSetReaderBase(fileName)
{
}
VTKM_CONT VTKDataSetReader(const char* fileName);
VTKM_CONT VTKDataSetReader(const std::string& fileName);
VTKM_CONT ~VTKDataSetReader() override;
explicit VTKDataSetReader(const std::string& fileName)
: VTKDataSetReaderBase(fileName)
{
}
VTKDataSetReader(const VTKDataSetReader&) = delete;
void operator=(const VTKDataSetReader&) = delete;
virtual void PrintSummary(std::ostream& out) const
{
if (this->Reader)
{
this->Reader->PrintSummary(out);
}
else
{
VTKDataSetReaderBase::PrintSummary(out);
}
}
VTKM_CONT void PrintSummary(std::ostream& out) const override;
private:
virtual void CloseFile()
{
if (this->Reader)
{
this->Reader->CloseFile();
}
else
{
VTKDataSetReaderBase::CloseFile();
}
}
virtual void Read()
{
switch (this->DataFile->Structure)
{
case vtkm::io::internal::DATASET_STRUCTURED_POINTS:
this->Reader.reset(new VTKStructuredPointsReader(""));
break;
case vtkm::io::internal::DATASET_STRUCTURED_GRID:
this->Reader.reset(new VTKStructuredGridReader(""));
break;
case vtkm::io::internal::DATASET_RECTILINEAR_GRID:
this->Reader.reset(new VTKRectilinearGridReader(""));
break;
case vtkm::io::internal::DATASET_POLYDATA:
this->Reader.reset(new VTKPolyDataReader(""));
break;
case vtkm::io::internal::DATASET_UNSTRUCTURED_GRID:
this->Reader.reset(new VTKUnstructuredGridReader(""));
break;
default:
throw vtkm::io::ErrorIO("Unsupported DataSet type.");
}
this->TransferDataFile(*this->Reader.get());
this->Reader->Read();
this->DataSet = this->Reader->GetDataSet();
}
VTKM_CONT void CloseFile() override;
VTKM_CONT void Read() override;
std::unique_ptr<VTKDataSetReaderBase> Reader;
};

@ -0,0 +1,826 @@
//============================================================================
// 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/io/VTKDataSetReaderBase.h>
#include <vtkm/VecTraits.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ArrayPortalToIterators.h>
#include <vtkm/cont/Logging.h>
#include <vtkm/cont/VariantArrayHandle.h>
#include <algorithm>
#include <string>
#include <vector>
namespace
{
inline void PrintVTKDataFileSummary(const vtkm::io::internal::VTKDataSetFile& df, std::ostream& out)
{
out << "\tFile: " << df.FileName << std::endl;
out << "\tVersion: " << df.Version[0] << "." << df.Version[0] << std::endl;
out << "\tTitle: " << df.Title << std::endl;
out << "\tFormat: " << (df.IsBinary ? "BINARY" : "ASCII") << std::endl;
out << "\tDataSet type: " << vtkm::io::internal::DataSetStructureString(df.Structure)
<< std::endl;
}
// Since Fields and DataSets store data in the default VariantArrayHandle, convert
// the data to the closest type supported by default. The following will
// need to be updated if VariantArrayHandle 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::VariantArrayHandle CreateVariantArrayHandle(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::VariantArrayHandle(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::VariantArrayHandle(output);
}
default:
{
VTKM_LOG_S(vtkm::cont::LogLevel::Warn, "Only 1, 2, 3, or 9 components supported. Skipping.");
return vtkm::cont::VariantArrayHandle(vtkm::cont::ArrayHandle<vtkm::Float32>());
}
}
}
} // anonymous namespace
namespace vtkm
{
namespace io
{
VTKDataSetReaderBase::VTKDataSetReaderBase(const char* fileName)
: DataFile(new internal::VTKDataSetFile)
, DataSet()
, Loaded(false)
{
this->DataFile->FileName = fileName;
}
VTKDataSetReaderBase::VTKDataSetReaderBase(const std::string& fileName)
: DataFile(new internal::VTKDataSetFile)
, DataSet()
, Loaded(false)
{
this->DataFile->FileName = fileName;
}
VTKDataSetReaderBase::~VTKDataSetReaderBase()
{
}
const vtkm::cont::DataSet& VTKDataSetReaderBase::ReadDataSet()
{
if (!this->Loaded)
{
try
{
this->OpenFile();
this->ReadHeader();
this->Read();
this->CloseFile();
this->Loaded = true;
}
catch (std::ifstream::failure& e)
{
std::string message("IO Error: ");
throw vtkm::io::ErrorIO(message + e.what());
}
}
return this->DataSet;
}
void VTKDataSetReaderBase::PrintSummary(std::ostream& out) const
{
out << "VTKDataSetReader" << std::endl;
PrintVTKDataFileSummary(*this->DataFile.get(), out);
this->DataSet.PrintSummary(out);
}
void VTKDataSetReaderBase::ReadPoints()
{
std::string dataType;
std::size_t numPoints;
this->DataFile->Stream >> numPoints >> dataType >> std::ws;
vtkm::cont::VariantArrayHandle points =
this->DoReadArrayVariant(vtkm::cont::Field::Association::POINTS, dataType, numPoints, 3);
this->DataSet.AddCoordinateSystem(vtkm::cont::CoordinateSystem("coordinates", points));
}
void VTKDataSetReaderBase::ReadCells(vtkm::cont::ArrayHandle<vtkm::Id>& connectivity,
vtkm::cont::ArrayHandle<vtkm::IdComponent>& numIndices)
{
vtkm::Id numCells, numInts;
this->DataFile->Stream >> numCells >> numInts >> std::ws;
connectivity.Allocate(numInts - numCells);
numIndices.Allocate(numCells);
std::vector<vtkm::Int32> buffer(static_cast<std::size_t>(numInts));
this->ReadArray(buffer);
vtkm::Int32* buffp = &buffer[0];
auto connectivityPortal = connectivity.WritePortal();
auto numIndicesPortal = numIndices.WritePortal();
for (vtkm::Id i = 0, connInd = 0; i < numCells; ++i)
{
vtkm::IdComponent numInds = static_cast<vtkm::IdComponent>(*buffp++);
numIndicesPortal.Set(i, numInds);
for (vtkm::IdComponent j = 0; j < numInds; ++j, ++connInd)
{
connectivityPortal.Set(connInd, static_cast<vtkm::Id>(*buffp++));
}
}
}
void VTKDataSetReaderBase::ReadShapes(vtkm::cont::ArrayHandle<vtkm::UInt8>& shapes)
{
std::string tag;
vtkm::Id numCells;
this->DataFile->Stream >> tag >> numCells >> std::ws;
internal::parseAssert(tag == "CELL_TYPES");
shapes.Allocate(numCells);
std::vector<vtkm::Int32> buffer(static_cast<std::size_t>(numCells));
this->ReadArray(buffer);
vtkm::Int32* buffp = &buffer[0];
auto shapesPortal = shapes.WritePortal();
for (vtkm::Id i = 0; i < numCells; ++i)
{
shapesPortal.Set(i, static_cast<vtkm::UInt8>(*buffp++));
}
}
void VTKDataSetReaderBase::ReadAttributes()
{
if (this->DataFile->Stream.eof())
{
return;
}
vtkm::cont::Field::Association association = vtkm::cont::Field::Association::ANY;
std::size_t size;
std::string tag;
this->DataFile->Stream >> tag;
while (!this->DataFile->Stream.eof())
{
if (tag == "POINT_DATA")
{
association = vtkm::cont::Field::Association::POINTS;
}
else if (tag == "CELL_DATA")
{
association = vtkm::cont::Field::Association::CELL_SET;
}
else
{
internal::parseAssert(false);
}
this->DataFile->Stream >> size;
while (!this->DataFile->Stream.eof())
{
this->DataFile->Stream >> tag;
if (tag == "SCALARS")
{
this->ReadScalars(association, size);
}
else if (tag == "COLOR_SCALARS")
{
this->ReadColorScalars(association, size);
}
else if (tag == "LOOKUP_TABLE")
{
this->ReadLookupTable();
}
else if (tag == "VECTORS" || tag == "NORMALS")
{
this->ReadVectors(association, size);
}
else if (tag == "TEXTURE_COORDINATES")
{
this->ReadTextureCoordinates(association, size);
}
else if (tag == "TENSORS")
{
this->ReadTensors(association, size);
}
else if (tag == "FIELD")
{
this->ReadFields(association, size);
}
else
{
break;
}
}
}
}
void VTKDataSetReaderBase::CloseFile()
{
this->DataFile->Stream.close();
}
void VTKDataSetReaderBase::OpenFile()
{
this->DataFile->Stream.exceptions(std::ifstream::failbit | std::ifstream::badbit);
try
{
this->DataFile->Stream.open(this->DataFile->FileName.c_str(),
std::ios_base::in | std::ios_base::binary);
}
catch (std::ifstream::failure&)
{
std::string message("could not open file \"" + this->DataFile->FileName + "\"");
throw vtkm::io::ErrorIO(message);
}
}
void VTKDataSetReaderBase::ReadHeader()
{
char vstring[] = "# vtk DataFile Version";
const std::size_t vlen = sizeof(vstring);
// Read version line
char vbuf[vlen];
this->DataFile->Stream.read(vbuf, vlen - 1);
vbuf[vlen - 1] = '\0';
if (std::string(vbuf) != std::string(vstring))
{
throw vtkm::io::ErrorIO("Incorrect file format.");
}
char dot;
this->DataFile->Stream >> this->DataFile->Version[0] >> dot >> this->DataFile->Version[1];
// skip rest of the line
std::string skip;
std::getline(this->DataFile->Stream, skip);
if ((this->DataFile->Version[0] > 4) ||
(this->DataFile->Version[0] == 4 && this->DataFile->Version[1] > 2))
{
VTKM_LOG_S(vtkm::cont::LogLevel::Warn,
"Reader may not correctly read >v4.2 files. Reading version "
<< this->DataFile->Version[0]
<< "."
<< this->DataFile->Version[1]
<< ".\n");
}
// Read title line
std::getline(this->DataFile->Stream, this->DataFile->Title);
// Read format line
this->DataFile->IsBinary = false;
std::string format;
this->DataFile->Stream >> format >> std::ws;
if (format == "BINARY")
{
this->DataFile->IsBinary = true;
}
else if (format != "ASCII")
{
throw vtkm::io::ErrorIO("Unsupported Format.");
}
// Read structure line
std::string tag, structStr;
this->DataFile->Stream >> tag >> structStr >> std::ws;
internal::parseAssert(tag == "DATASET");
this->DataFile->Structure = vtkm::io::internal::DataSetStructureId(structStr);
if (this->DataFile->Structure == vtkm::io::internal::DATASET_UNKNOWN)
{
throw vtkm::io::ErrorIO("Unsupported DataSet type.");
}
}
void VTKDataSetReaderBase::AddField(const std::string& name,
vtkm::cont::Field::Association association,
vtkm::cont::VariantArrayHandle& data)
{
if (data.GetNumberOfValues() > 0)
{
switch (association)
{
case vtkm::cont::Field::Association::POINTS:
case vtkm::cont::Field::Association::WHOLE_MESH:
this->DataSet.AddField(vtkm::cont::Field(name, association, data));
break;
case vtkm::cont::Field::Association::CELL_SET:
this->DataSet.AddField(vtkm::cont::Field(name, association, data));
break;
default:
VTKM_LOG_S(vtkm::cont::LogLevel::Warn,
"Not recording field '" << name << "' because it has an unknown association");
break;
}
}
}
void VTKDataSetReaderBase::ReadScalars(vtkm::cont::Field::Association association,
std::size_t numElements)
{
std::string dataName, dataType, lookupTableName;
vtkm::IdComponent numComponents = 1;
this->DataFile->Stream >> dataName >> dataType;
std::string tag;
this->DataFile->Stream >> tag;
if (tag != "LOOKUP_TABLE")
{
try
{
numComponents = std::stoi(tag);
}
catch (std::invalid_argument&)
{
internal::parseAssert(false);
}
this->DataFile->Stream >> tag;
}
internal::parseAssert(tag == "LOOKUP_TABLE");
this->DataFile->Stream >> lookupTableName >> std::ws;
vtkm::cont::VariantArrayHandle data =
this->DoReadArrayVariant(association, dataType, numElements, numComponents);
this->AddField(dataName, association, data);
}
void VTKDataSetReaderBase::ReadColorScalars(vtkm::cont::Field::Association association,
std::size_t numElements)
{
VTKM_LOG_S(vtkm::cont::LogLevel::Warn, "Support for COLOR_SCALARS is not implemented. Skipping.");
std::string dataName;
vtkm::IdComponent numComponents;
this->DataFile->Stream >> dataName >> numComponents >> std::ws;
std::string dataType = this->DataFile->IsBinary ? "unsigned_char" : "float";
vtkm::cont::VariantArrayHandle data =
this->DoReadArrayVariant(association, dataType, numElements, numComponents);
this->AddField(dataName, association, data);
}
void VTKDataSetReaderBase::ReadLookupTable()
{
VTKM_LOG_S(vtkm::cont::LogLevel::Warn, "Support for LOOKUP_TABLE is not implemented. Skipping.");
std::string dataName;
std::size_t numEntries;
this->DataFile->Stream >> dataName >> numEntries >> std::ws;
this->SkipArray(numEntries, vtkm::Vec<vtkm::io::internal::ColorChannel8, 4>());
}
void VTKDataSetReaderBase::ReadTextureCoordinates(vtkm::cont::Field::Association association,
std::size_t numElements)
{
std::string dataName;
vtkm::IdComponent numComponents;
std::string dataType;
this->DataFile->Stream >> dataName >> numComponents >> dataType >> std::ws;
vtkm::cont::VariantArrayHandle data =
this->DoReadArrayVariant(association, dataType, numElements, numComponents);
this->AddField(dataName, association, data);
}
void VTKDataSetReaderBase::ReadVectors(vtkm::cont::Field::Association association,
std::size_t numElements)
{
std::string dataName;
std::string dataType;
this->DataFile->Stream >> dataName >> dataType >> std::ws;
vtkm::cont::VariantArrayHandle data =
this->DoReadArrayVariant(association, dataType, numElements, 3);
this->AddField(dataName, association, data);
}
void VTKDataSetReaderBase::ReadTensors(vtkm::cont::Field::Association association,
std::size_t numElements)
{
std::string dataName;
std::string dataType;
this->DataFile->Stream >> dataName >> dataType >> std::ws;
vtkm::cont::VariantArrayHandle data =
this->DoReadArrayVariant(association, dataType, numElements, 9);
this->AddField(dataName, association, data);
}
void VTKDataSetReaderBase::ReadFields(vtkm::cont::Field::Association association,
std::size_t expectedNumElements)
{
std::string dataName;
vtkm::Id numArrays;
this->DataFile->Stream >> dataName >> numArrays >> std::ws;
for (vtkm::Id i = 0; i < numArrays; ++i)
{
std::size_t numTuples;
vtkm::IdComponent numComponents;
std::string arrayName, dataType;
this->DataFile->Stream >> arrayName >> numComponents >> numTuples >> dataType >> std::ws;
if (numTuples == expectedNumElements)
{
vtkm::cont::VariantArrayHandle data =
this->DoReadArrayVariant(association, dataType, numTuples, numComponents);
this->AddField(arrayName, association, data);
}
else
{
VTKM_LOG_S(vtkm::cont::LogLevel::Warn,
"Field " << arrayName
<< "'s size does not match expected number of elements. Skipping");
}
}
}
void VTKDataSetReaderBase::ReadGlobalFields(std::vector<vtkm::Float32>* visitBounds)
{
std::string dataName;
vtkm::Id numArrays;
this->DataFile->Stream >> dataName >> numArrays >> std::ws;
for (vtkm::Id i = 0; i < numArrays; ++i)
{
std::size_t numTuples;
vtkm::IdComponent numComponents;
std::string arrayName, dataType;
this->DataFile->Stream >> arrayName >> numComponents >> numTuples >> dataType >> std::ws;
if (arrayName == "avtOriginalBounds" && visitBounds)
{
visitBounds->resize(6);
internal::parseAssert(numComponents == 1 && numTuples == 6);
// parse the bounds and fill the bounds vector
this->ReadArray(*visitBounds);
}
else
{
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
"Support for global field " << arrayName << " not implemented. Skipping.");
this->DoSkipArrayVariant(dataType, numTuples, numComponents);
}
}
}
class VTKDataSetReaderBase::SkipArrayVariant
{
public:
SkipArrayVariant(VTKDataSetReaderBase* reader, std::size_t numElements)
: Reader(reader)
, NumElements(numElements)
{
}
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());
}
protected:
VTKDataSetReaderBase* Reader;
std::size_t NumElements;
};
class VTKDataSetReaderBase::ReadArrayVariant : public SkipArrayVariant
{
public:
ReadArrayVariant(VTKDataSetReaderBase* reader,
vtkm::cont::Field::Association association,
std::size_t numElements,
vtkm::cont::VariantArrayHandle& data)
: SkipArrayVariant(reader, numElements)
, Association(association)
, Data(&data)
{
}
template <typename T>
void operator()(T) const
{
std::vector<T> buffer(this->NumElements);
this->Reader->ReadArray(buffer);
if ((this->Association != vtkm::cont::Field::Association::CELL_SET) ||
(this->Reader->GetCellsPermutation().GetNumberOfValues() < 1))
{
*this->Data = CreateVariantArrayHandle(buffer);
}
else
{
// If we are reading data associated with a cell set, we need to (sometimes) permute the
// data due to differences between VTK and VTK-m cell shapes.
auto permutation = this->Reader->GetCellsPermutation().ReadPortal();
vtkm::Id outSize = permutation.GetNumberOfValues();
std::vector<T> permutedBuffer(static_cast<std::size_t>(outSize));
for (vtkm::Id outIndex = 0; outIndex < outSize; outIndex++)
{
std::size_t inIndex = static_cast<std::size_t>(permutation.Get(outIndex));
permutedBuffer[static_cast<std::size_t>(outIndex)] = buffer[inIndex];
}
*this->Data = CreateVariantArrayHandle(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::cont::VariantArrayHandle* Data;
};
void VTKDataSetReaderBase::DoSkipArrayVariant(std::string dataType,
std::size_t numElements,
vtkm::IdComponent numComponents)
{
// string is unsupported for SkipArrayVariant, so it requires some
// special handling
if (dataType == "string")
{
const vtkm::Id stringCount = numComponents * static_cast<vtkm::Id>(numElements);
for (vtkm::Id i = 0; i < stringCount; ++i)
{
std::string trash;
this->DataFile->Stream >> trash;
}
}
else
{
vtkm::io::internal::DataType typeId = vtkm::io::internal::DataTypeId(dataType);
vtkm::io::internal::SelectTypeAndCall(
typeId, numComponents, SkipArrayVariant(this, numElements));
}
}
vtkm::cont::VariantArrayHandle VTKDataSetReaderBase::DoReadArrayVariant(
vtkm::cont::Field::Association association,
std::string dataType,
std::size_t numElements,
vtkm::IdComponent numComponents)
{
// Create empty data to start so that the return can check if data were actually read
vtkm::cont::ArrayHandle<vtkm::Float32> empty;
vtkm::cont::VariantArrayHandle data(empty);
vtkm::io::internal::DataType typeId = vtkm::io::internal::DataTypeId(dataType);
vtkm::io::internal::SelectTypeAndCall(
typeId, numComponents, ReadArrayVariant(this, association, numElements, data));
return data;
}
void VTKDataSetReaderBase::ReadArray(std::vector<vtkm::io::internal::DummyBitType>& buffer)
{
VTKM_LOG_S(vtkm::cont::LogLevel::Warn,
"Support for data type 'bit' is not implemented. Skipping.");
this->SkipArray(buffer.size(), vtkm::io::internal::DummyBitType());
buffer.clear();
}
void VTKDataSetReaderBase::SkipArray(std::size_t numElements,
vtkm::io::internal::DummyBitType,
vtkm::IdComponent numComponents)
{
if (this->DataFile->IsBinary)
{
numElements = (numElements + 7) / 8;
this->DataFile->Stream.seekg(static_cast<std::streamoff>(numElements), std::ios_base::cur);
}
else
{
for (std::size_t i = 0; i < numElements; ++i)
{
vtkm::UInt16 val;
this->DataFile->Stream >> val;
}
}
this->DataFile->Stream >> std::ws;
this->SkipArrayMetaData(numComponents);
}
void VTKDataSetReaderBase::SkipArrayMetaData(vtkm::IdComponent numComponents)
{
if (!this->DataFile->Stream.good())
{
return;
}
auto begining = this->DataFile->Stream.tellg();
std::string tag;
this->DataFile->Stream >> tag;
if (tag != "METADATA")
{
this->DataFile->Stream.seekg(begining);
return;
}
VTKM_LOG_S(vtkm::cont::LogLevel::Warn, "METADATA is not supported. Attempting to Skip.");
this->DataFile->Stream >> tag >> std::ws;
if (tag == "COMPONENT_NAMES")
{
std::string name;
for (vtkm::IdComponent i = 0; i < numComponents; ++i)
{
this->DataFile->Stream >> name >> std::ws;
}
}
else if (tag == "INFORMATION")
{
int numKeys = 0;
this->DataFile->Stream >> numKeys >> std::ws;
// Skipping INFORMATION is tricky. The reader needs to be aware of the types of the
// information, which is not provided in the file.
// Here we will just skip until an empty line is found.
// However, if there are no keys, then there is nothing to read (and the stream tends
// to skip over empty lines.
if (numKeys > 0)
{
std::string line;
do
{
std::getline(this->DataFile->Stream, line);
} while (this->DataFile->Stream.good() && !line.empty());
// Eat any remaining whitespace after the INFORMATION to be ready to read the next token
this->DataFile->Stream >> std::ws;
}
}
else
{
internal::parseAssert(false);
}
}
}
} // namespace vtkm::io

@ -10,25 +10,16 @@
#ifndef vtk_m_io_VTKDataSetReaderBase_h
#define vtk_m_io_VTKDataSetReaderBase_h
#include <vtkm/Types.h>
#include <vtkm/cont/DataSet.h>
#include <vtkm/io/ErrorIO.h>
#include <vtkm/io/vtkm_io_export.h>
#include <vtkm/io/internal/Endian.h>
#include <vtkm/io/internal/VTKDataSetCells.h>
#include <vtkm/io/internal/VTKDataSetStructures.h>
#include <vtkm/io/internal/VTKDataSetTypes.h>
#include <vtkm/Types.h>
#include <vtkm/VecTraits.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ArrayPortalToIterators.h>
#include <vtkm/cont/DataSet.h>
#include <vtkm/cont/Logging.h>
#include <vtkm/cont/VariantArrayHandle.h>
#include <vtkm/internal/ExportMacros.h>
#include <vtkm/io/ErrorIO.h>
#include <algorithm>
#include <fstream>
#include <string>
#include <vector>
namespace vtkm
{
@ -48,16 +39,6 @@ struct VTKDataSetFile
std::ifstream Stream;
};
inline void PrintVTKDataFileSummary(const VTKDataSetFile& df, std::ostream& out)
{
out << "\tFile: " << df.FileName << std::endl;
out << "\tVersion: " << df.Version[0] << "." << df.Version[0] << std::endl;
out << "\tTitle: " << df.Title << std::endl;
out << "\tFormat: " << (df.IsBinary ? "BINARY" : "ASCII") << std::endl;
out << "\tDataSet type: " << vtkm::io::internal::DataSetStructureString(df.Structure)
<< std::endl;
}
inline void parseAssert(bool condition)
{
if (!condition)
@ -82,166 +63,6 @@ struct StreamIOType<vtkm::UInt8>
using Type = vtkm::UInt16;
};
// Since Fields and DataSets store data in the default VariantArrayHandle, convert
// the data to the closest type supported by default. The following will
// need to be updated if VariantArrayHandle 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::VariantArrayHandle CreateVariantArrayHandle(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::VariantArrayHandle(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::VariantArrayHandle(output);
}
default:
{
VTKM_LOG_S(vtkm::cont::LogLevel::Warn, "Only 1, 2, 3, or 9 components supported. Skipping.");
return vtkm::cont::VariantArrayHandle(vtkm::cont::ArrayHandle<vtkm::Float32>());
}
}
}
inline vtkm::cont::DynamicCellSet CreateCellSetStructured(const vtkm::Id3& dim)
{
if (dim[0] > 1 && dim[1] > 1 && dim[2] > 1)
@ -272,564 +93,102 @@ inline vtkm::cont::DynamicCellSet CreateCellSetStructured(const vtkm::Id3& dim)
} // namespace internal
VTKM_SILENCE_WEAK_VTABLE_WARNING_START
class VTKDataSetReaderBase
class VTKM_IO_EXPORT VTKDataSetReaderBase
{
protected:
std::unique_ptr<internal::VTKDataSetFile> DataFile;
vtkm::cont::DataSet DataSet;
private:
bool Loaded;
vtkm::cont::ArrayHandle<vtkm::Id> CellsPermutation;
friend class VTKDataSetReader;
public:
explicit VTKDataSetReaderBase(const char* fileName)
: DataFile(new internal::VTKDataSetFile)
, DataSet()
, Loaded(false)
{
this->DataFile->FileName = fileName;
}
explicit VTKM_CONT VTKDataSetReaderBase(const char* fileName);
explicit VTKDataSetReaderBase(const std::string& fileName)
: DataFile(new internal::VTKDataSetFile)
, DataSet()
, Loaded(false)
{
this->DataFile->FileName = fileName;
}
explicit VTKM_CONT VTKDataSetReaderBase(const std::string& fileName);
virtual ~VTKDataSetReaderBase() {}
virtual VTKM_CONT ~VTKDataSetReaderBase();
const vtkm::cont::DataSet& ReadDataSet()
{
if (!this->Loaded)
{
try
{
this->OpenFile();
this->ReadHeader();
this->Read();
this->CloseFile();
this->Loaded = true;
}
catch (std::ifstream::failure& e)
{
std::string message("IO Error: ");
throw vtkm::io::ErrorIO(message + e.what());
}
}
VTKDataSetReaderBase(const VTKDataSetReaderBase&) = delete;
void operator=(const VTKDataSetReaderBase&) = delete;
return this->DataSet;
}
const VTKM_CONT vtkm::cont::DataSet& ReadDataSet();
const vtkm::cont::DataSet& GetDataSet() const { return this->DataSet; }
virtual void PrintSummary(std::ostream& out) const
{
out << "VTKDataSetReader" << std::endl;
PrintVTKDataFileSummary(*this->DataFile.get(), out);
this->DataSet.PrintSummary(out);
}
virtual VTKM_CONT void PrintSummary(std::ostream& out) const;
protected:
void ReadPoints()
{
std::string dataType;
std::size_t numPoints;
this->DataFile->Stream >> numPoints >> dataType >> std::ws;
VTKM_CONT void ReadPoints();
vtkm::cont::VariantArrayHandle points =
this->DoReadArrayVariant(vtkm::cont::Field::Association::POINTS, dataType, numPoints, 3);
VTKM_CONT void ReadCells(vtkm::cont::ArrayHandle<vtkm::Id>& connectivity,
vtkm::cont::ArrayHandle<vtkm::IdComponent>& numIndices);
this->DataSet.AddCoordinateSystem(vtkm::cont::CoordinateSystem("coordinates", points));
}
VTKM_CONT void ReadShapes(vtkm::cont::ArrayHandle<vtkm::UInt8>& shapes);
void ReadCells(vtkm::cont::ArrayHandle<vtkm::Id>& connectivity,
vtkm::cont::ArrayHandle<vtkm::IdComponent>& numIndices)
{
vtkm::Id numCells, numInts;
this->DataFile->Stream >> numCells >> numInts >> std::ws;
connectivity.Allocate(numInts - numCells);
numIndices.Allocate(numCells);
std::vector<vtkm::Int32> buffer(static_cast<std::size_t>(numInts));
this->ReadArray(buffer);
vtkm::Int32* buffp = &buffer[0];
auto connectivityPortal = connectivity.WritePortal();
auto numIndicesPortal = numIndices.WritePortal();
for (vtkm::Id i = 0, connInd = 0; i < numCells; ++i)
{
vtkm::IdComponent numInds = static_cast<vtkm::IdComponent>(*buffp++);
numIndicesPortal.Set(i, numInds);
for (vtkm::IdComponent j = 0; j < numInds; ++j, ++connInd)
{
connectivityPortal.Set(connInd, static_cast<vtkm::Id>(*buffp++));
}
}
}
void ReadShapes(vtkm::cont::ArrayHandle<vtkm::UInt8>& shapes)
{
std::string tag;
vtkm::Id numCells;
this->DataFile->Stream >> tag >> numCells >> std::ws;
internal::parseAssert(tag == "CELL_TYPES");
shapes.Allocate(numCells);
std::vector<vtkm::Int32> buffer(static_cast<std::size_t>(numCells));
this->ReadArray(buffer);
vtkm::Int32* buffp = &buffer[0];
auto shapesPortal = shapes.WritePortal();
for (vtkm::Id i = 0; i < numCells; ++i)
{
shapesPortal.Set(i, static_cast<vtkm::UInt8>(*buffp++));
}
}
void ReadAttributes()
{
if (this->DataFile->Stream.eof())
{
return;
}
vtkm::cont::Field::Association association = vtkm::cont::Field::Association::ANY;
std::size_t size;
std::string tag;
this->DataFile->Stream >> tag;
while (!this->DataFile->Stream.eof())
{
if (tag == "POINT_DATA")
{
association = vtkm::cont::Field::Association::POINTS;
}
else if (tag == "CELL_DATA")
{
association = vtkm::cont::Field::Association::CELL_SET;
}
else
{
internal::parseAssert(false);
}
this->DataFile->Stream >> size;
while (!this->DataFile->Stream.eof())
{
this->DataFile->Stream >> tag;
if (tag == "SCALARS")
{
this->ReadScalars(association, size);
}
else if (tag == "COLOR_SCALARS")
{
this->ReadColorScalars(association, size);
}
else if (tag == "LOOKUP_TABLE")
{
this->ReadLookupTable();
}
else if (tag == "VECTORS" || tag == "NORMALS")
{
this->ReadVectors(association, size);
}
else if (tag == "TEXTURE_COORDINATES")
{
this->ReadTextureCoordinates(association, size);
}
else if (tag == "TENSORS")
{
this->ReadTensors(association, size);
}
else if (tag == "FIELD")
{
this->ReadFields(association, size);
}
else
{
break;
}
}
}
}
VTKM_CONT void ReadAttributes();
void SetCellsPermutation(const vtkm::cont::ArrayHandle<vtkm::Id>& permutation)
{
this->CellsPermutation = permutation;
}
vtkm::cont::ArrayHandle<vtkm::Id> GetCellsPermutation() const { return this->CellsPermutation; }
VTKM_CONT vtkm::cont::ArrayHandle<vtkm::Id> GetCellsPermutation() const
{
return this->CellsPermutation;
}
void TransferDataFile(VTKDataSetReaderBase& reader)
VTKM_CONT void TransferDataFile(VTKDataSetReaderBase& reader)
{
reader.DataFile.swap(this->DataFile);
this->DataFile.reset(nullptr);
}
virtual void CloseFile() { this->DataFile->Stream.close(); }
VTKM_CONT virtual void CloseFile();
VTKM_CONT virtual void Read() = 0;
private:
void OpenFile()
{
this->DataFile->Stream.exceptions(std::ifstream::failbit | std::ifstream::badbit);
try
{
this->DataFile->Stream.open(this->DataFile->FileName.c_str(),
std::ios_base::in | std::ios_base::binary);
}
catch (std::ifstream::failure&)
{
std::string message("could not open file \"" + this->DataFile->FileName + "\"");
throw vtkm::io::ErrorIO(message);
}
}
void ReadHeader()
{
char vstring[] = "# vtk DataFile Version";
const std::size_t vlen = sizeof(vstring);
// Read version line
char vbuf[vlen];
this->DataFile->Stream.read(vbuf, vlen - 1);
vbuf[vlen - 1] = '\0';
if (std::string(vbuf) != std::string(vstring))
{
throw vtkm::io::ErrorIO("Incorrect file format.");
}
char dot;
this->DataFile->Stream >> this->DataFile->Version[0] >> dot >> this->DataFile->Version[1];
// skip rest of the line
std::string skip;
std::getline(this->DataFile->Stream, skip);
if ((this->DataFile->Version[0] > 4) ||
(this->DataFile->Version[0] == 4 && this->DataFile->Version[1] > 2))
{
VTKM_LOG_S(vtkm::cont::LogLevel::Warn,
"Reader may not correctly read >v4.2 files. Reading version "
<< this->DataFile->Version[0]
<< "."
<< this->DataFile->Version[1]
<< ".\n");
}
// Read title line
std::getline(this->DataFile->Stream, this->DataFile->Title);
// Read format line
this->DataFile->IsBinary = false;
std::string format;
this->DataFile->Stream >> format >> std::ws;
if (format == "BINARY")
{
this->DataFile->IsBinary = true;
}
else if (format != "ASCII")
{
throw vtkm::io::ErrorIO("Unsupported Format.");
}
// Read structure line
std::string tag, structStr;
this->DataFile->Stream >> tag >> structStr >> std::ws;
internal::parseAssert(tag == "DATASET");
this->DataFile->Structure = vtkm::io::internal::DataSetStructureId(structStr);
if (this->DataFile->Structure == vtkm::io::internal::DATASET_UNKNOWN)
{
throw vtkm::io::ErrorIO("Unsupported DataSet type.");
}
}
virtual void Read() = 0;
void AddField(const std::string& name,
vtkm::cont::Field::Association association,
vtkm::cont::VariantArrayHandle& data)
{
if (data.GetNumberOfValues() > 0)
{
switch (association)
{
case vtkm::cont::Field::Association::POINTS:
case vtkm::cont::Field::Association::WHOLE_MESH:
this->DataSet.AddField(vtkm::cont::Field(name, association, data));
break;
case vtkm::cont::Field::Association::CELL_SET:
this->DataSet.AddField(vtkm::cont::Field(name, association, data));
break;
default:
VTKM_LOG_S(vtkm::cont::LogLevel::Warn,
"Not recording field '" << name << "' because it has an unknown association");
break;
}
}
}
void ReadScalars(vtkm::cont::Field::Association association, std::size_t numElements)
{
std::string dataName, dataType, lookupTableName;
vtkm::IdComponent numComponents = 1;
this->DataFile->Stream >> dataName >> dataType;
std::string tag;
this->DataFile->Stream >> tag;
if (tag != "LOOKUP_TABLE")
{
try
{
numComponents = std::stoi(tag);
}
catch (std::invalid_argument&)
{
internal::parseAssert(false);
}
this->DataFile->Stream >> tag;
}
internal::parseAssert(tag == "LOOKUP_TABLE");
this->DataFile->Stream >> lookupTableName >> std::ws;
vtkm::cont::VariantArrayHandle data =
this->DoReadArrayVariant(association, dataType, numElements, numComponents);
this->AddField(dataName, association, data);
}
void ReadColorScalars(vtkm::cont::Field::Association association, std::size_t numElements)
{
VTKM_LOG_S(vtkm::cont::LogLevel::Warn,
"Support for COLOR_SCALARS is not implemented. Skipping.");
std::string dataName;
vtkm::IdComponent numComponents;
this->DataFile->Stream >> dataName >> numComponents >> std::ws;
std::string dataType = this->DataFile->IsBinary ? "unsigned_char" : "float";
vtkm::cont::VariantArrayHandle data =
this->DoReadArrayVariant(association, dataType, numElements, numComponents);
this->AddField(dataName, association, data);
}
void ReadLookupTable()
{
VTKM_LOG_S(vtkm::cont::LogLevel::Warn,
"Support for LOOKUP_TABLE is not implemented. Skipping.");
std::string dataName;
std::size_t numEntries;
this->DataFile->Stream >> dataName >> numEntries >> std::ws;
this->SkipArray(numEntries, vtkm::Vec<vtkm::io::internal::ColorChannel8, 4>());
}
void ReadTextureCoordinates(vtkm::cont::Field::Association association, std::size_t numElements)
{
std::string dataName;
vtkm::IdComponent numComponents;
std::string dataType;
this->DataFile->Stream >> dataName >> numComponents >> dataType >> std::ws;
vtkm::cont::VariantArrayHandle data =
this->DoReadArrayVariant(association, dataType, numElements, numComponents);
this->AddField(dataName, association, data);
}
void ReadVectors(vtkm::cont::Field::Association association, std::size_t numElements)
{
std::string dataName;
std::string dataType;
this->DataFile->Stream >> dataName >> dataType >> std::ws;
vtkm::cont::VariantArrayHandle data =
this->DoReadArrayVariant(association, dataType, numElements, 3);
this->AddField(dataName, association, data);
}
void ReadTensors(vtkm::cont::Field::Association association, std::size_t numElements)
{
std::string dataName;
std::string dataType;
this->DataFile->Stream >> dataName >> dataType >> std::ws;
vtkm::cont::VariantArrayHandle data =
this->DoReadArrayVariant(association, dataType, numElements, 9);
this->AddField(dataName, association, data);
}
void ReadFields(vtkm::cont::Field::Association association, std::size_t expectedNumElements)
{
std::string dataName;
vtkm::Id numArrays;
this->DataFile->Stream >> dataName >> numArrays >> std::ws;
for (vtkm::Id i = 0; i < numArrays; ++i)
{
std::size_t numTuples;
vtkm::IdComponent numComponents;
std::string arrayName, dataType;
this->DataFile->Stream >> arrayName >> numComponents >> numTuples >> dataType >> std::ws;
if (numTuples == expectedNumElements)
{
vtkm::cont::VariantArrayHandle data =
this->DoReadArrayVariant(association, dataType, numTuples, numComponents);
this->AddField(arrayName, association, data);
}
else
{
VTKM_LOG_S(vtkm::cont::LogLevel::Warn,
"Field " << arrayName
<< "'s size does not match expected number of elements. Skipping");
}
}
}
VTKM_CONT void OpenFile();
VTKM_CONT void ReadHeader();
VTKM_CONT void AddField(const std::string& name,
vtkm::cont::Field::Association association,
vtkm::cont::VariantArrayHandle& data);
VTKM_CONT void ReadScalars(vtkm::cont::Field::Association association, std::size_t numElements);
VTKM_CONT void ReadColorScalars(vtkm::cont::Field::Association association,
std::size_t numElements);
VTKM_CONT void ReadLookupTable();
VTKM_CONT void ReadTextureCoordinates(vtkm::cont::Field::Association association,
std::size_t numElements);
VTKM_CONT void ReadVectors(vtkm::cont::Field::Association association, std::size_t numElements);
VTKM_CONT void ReadTensors(vtkm::cont::Field::Association association, std::size_t numElements);
VTKM_CONT void ReadFields(vtkm::cont::Field::Association association,
std::size_t expectedNumElements);
protected:
void ReadGlobalFields(std::vector<vtkm::Float32>* visitBounds = nullptr)
{
std::string dataName;
vtkm::Id numArrays;
this->DataFile->Stream >> dataName >> numArrays >> std::ws;
for (vtkm::Id i = 0; i < numArrays; ++i)
{
std::size_t numTuples;
vtkm::IdComponent numComponents;
std::string arrayName, dataType;
this->DataFile->Stream >> arrayName >> numComponents >> numTuples >> dataType >> std::ws;
if (arrayName == "avtOriginalBounds" && visitBounds)
{
visitBounds->resize(6);
internal::parseAssert(numComponents == 1 && numTuples == 6);
// parse the bounds and fill the bounds vector
this->ReadArray(*visitBounds);
}
else
{
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
"Support for global field " << arrayName << " not implemented. Skipping.");
this->DoSkipArrayVariant(dataType, numTuples, numComponents);
}
}
}
VTKM_CONT void ReadGlobalFields(std::vector<vtkm::Float32>* visitBounds = nullptr);
private:
class SkipArrayVariant
{
public:
SkipArrayVariant(VTKDataSetReaderBase* reader, std::size_t numElements)
: Reader(reader)
, NumElements(numElements)
{
}
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());
}
protected:
VTKDataSetReaderBase* Reader;
std::size_t NumElements;
};
class ReadArrayVariant : public SkipArrayVariant
{
public:
ReadArrayVariant(VTKDataSetReaderBase* reader,
vtkm::cont::Field::Association association,
std::size_t numElements,
vtkm::cont::VariantArrayHandle& data)
: SkipArrayVariant(reader, numElements)
, Association(association)
, Data(&data)
{
}
template <typename T>
void operator()(T) const
{
std::vector<T> buffer(this->NumElements);
this->Reader->ReadArray(buffer);
if ((this->Association != vtkm::cont::Field::Association::CELL_SET) ||
(this->Reader->GetCellsPermutation().GetNumberOfValues() < 1))
{
*this->Data = internal::CreateVariantArrayHandle(buffer);
}
else
{
// If we are reading data associated with a cell set, we need to (sometimes) permute the
// data due to differences between VTK and VTK-m cell shapes.
auto permutation = this->Reader->GetCellsPermutation().ReadPortal();
vtkm::Id outSize = permutation.GetNumberOfValues();
std::vector<T> permutedBuffer(static_cast<std::size_t>(outSize));
for (vtkm::Id outIndex = 0; outIndex < outSize; outIndex++)
{
std::size_t inIndex = static_cast<std::size_t>(permutation.Get(outIndex));
permutedBuffer[static_cast<std::size_t>(outIndex)] = buffer[inIndex];
}
*this->Data = internal::CreateVariantArrayHandle(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::cont::VariantArrayHandle* Data;
};
class SkipArrayVariant;
class ReadArrayVariant;
//Make the Array parsing methods protected so that derived classes
//can call the methods.
protected:
void DoSkipArrayVariant(std::string dataType,
std::size_t numElements,
vtkm::IdComponent numComponents)
{
// string is unsupported for SkipArrayVariant, so it requires some
// special handling
if (dataType == "string")
{
const vtkm::Id stringCount = numComponents * static_cast<vtkm::Id>(numElements);
for (vtkm::Id i = 0; i < stringCount; ++i)
{
std::string trash;
this->DataFile->Stream >> trash;
}
}
else
{
vtkm::io::internal::DataType typeId = vtkm::io::internal::DataTypeId(dataType);
vtkm::io::internal::SelectTypeAndCall(
typeId, numComponents, SkipArrayVariant(this, numElements));
}
}
vtkm::cont::VariantArrayHandle DoReadArrayVariant(vtkm::cont::Field::Association association,
std::string dataType,
std::size_t numElements,
vtkm::IdComponent numComponents)
{
// Create empty data to start so that the return can check if data were actually read
vtkm::cont::ArrayHandle<vtkm::Float32> empty;
vtkm::cont::VariantArrayHandle data(empty);
vtkm::io::internal::DataType typeId = vtkm::io::internal::DataTypeId(dataType);
vtkm::io::internal::SelectTypeAndCall(
typeId, numComponents, ReadArrayVariant(this, association, numElements, data));
return data;
}
VTKM_CONT void DoSkipArrayVariant(std::string dataType,
std::size_t numElements,
vtkm::IdComponent numComponents);
VTKM_CONT vtkm::cont::VariantArrayHandle DoReadArrayVariant(
vtkm::cont::Field::Association association,
std::string dataType,
std::size_t numElements,
vtkm::IdComponent numComponents);
template <typename T>
void ReadArray(std::vector<T>& buffer)
VTKM_CONT void ReadArray(std::vector<T>& buffer)
{
using ComponentType = typename vtkm::VecTraits<T>::ComponentType;
constexpr vtkm::IdComponent numComponents = vtkm::VecTraits<T>::NUM_COMPONENTS;
@ -861,7 +220,8 @@ protected:
}
template <vtkm::IdComponent NumComponents>
void ReadArray(std::vector<vtkm::Vec<vtkm::io::internal::DummyBitType, NumComponents>>& buffer)
VTKM_CONT void ReadArray(
std::vector<vtkm::Vec<vtkm::io::internal::DummyBitType, NumComponents>>& buffer)
{
VTKM_LOG_S(vtkm::cont::LogLevel::Warn,
"Support for data type 'bit' is not implemented. Skipping.");
@ -869,13 +229,7 @@ protected:
buffer.clear();
}
void ReadArray(std::vector<vtkm::io::internal::DummyBitType>& buffer)
{
VTKM_LOG_S(vtkm::cont::LogLevel::Warn,
"Support for data type 'bit' is not implemented. Skipping.");
this->SkipArray(buffer.size(), vtkm::io::internal::DummyBitType());
buffer.clear();
}
VTKM_CONT void ReadArray(std::vector<vtkm::io::internal::DummyBitType>& buffer);
template <typename T>
void SkipArray(std::size_t numElements, T)
@ -912,99 +266,13 @@ protected:
NumComponents);
}
void SkipArray(std::size_t numElements,
vtkm::io::internal::DummyBitType,
vtkm::IdComponent numComponents = 1)
{
if (this->DataFile->IsBinary)
{
numElements = (numElements + 7) / 8;
this->DataFile->Stream.seekg(static_cast<std::streamoff>(numElements), std::ios_base::cur);
}
else
{
for (std::size_t i = 0; i < numElements; ++i)
{
vtkm::UInt16 val;
this->DataFile->Stream >> val;
}
}
this->DataFile->Stream >> std::ws;
this->SkipArrayMetaData(numComponents);
}
VTKM_CONT void SkipArray(std::size_t numElements,
vtkm::io::internal::DummyBitType,
vtkm::IdComponent numComponents = 1);
void SkipArrayMetaData(vtkm::IdComponent numComponents)
{
if (!this->DataFile->Stream.good())
{
return;
}
auto begining = this->DataFile->Stream.tellg();
std::string tag;
this->DataFile->Stream >> tag;
if (tag != "METADATA")
{
this->DataFile->Stream.seekg(begining);
return;
}
VTKM_LOG_S(vtkm::cont::LogLevel::Warn, "METADATA is not supported. Attempting to Skip.");
this->DataFile->Stream >> tag >> std::ws;
if (tag == "COMPONENT_NAMES")
{
std::string name;
for (vtkm::IdComponent i = 0; i < numComponents; ++i)
{
this->DataFile->Stream >> name >> std::ws;
}
}
else if (tag == "INFORMATION")
{
int numKeys = 0;
this->DataFile->Stream >> numKeys >> std::ws;
// Skipping INFORMATION is tricky. The reader needs to be aware of the types of the
// information, which is not provided in the file.
// Here we will just skip until an empty line is found.
// However, if there are no keys, then there is nothing to read (and the stream tends
// to skip over empty lines.
if (numKeys > 0)
{
std::string line;
do
{
std::getline(this->DataFile->Stream, line);
} while (this->DataFile->Stream.good() && !line.empty());
// Eat any remaining whitespace after the INFORMATION to be ready to read the next token
this->DataFile->Stream >> std::ws;
}
}
else
{
internal::parseAssert(false);
}
}
protected:
std::unique_ptr<internal::VTKDataSetFile> DataFile;
vtkm::cont::DataSet DataSet;
private:
bool Loaded;
vtkm::cont::ArrayHandle<vtkm::Id> CellsPermutation;
friend class VTKDataSetReader;
VTKM_CONT void SkipArrayMetaData(vtkm::IdComponent numComponents);
};
VTKM_SILENCE_WEAK_VTABLE_WARNING_END
}
} // vtkm::io
VTKM_BASIC_TYPE_VECTOR(vtkm::io::internal::ColorChannel8)
VTKM_BASIC_TYPE_VECTOR(vtkm::io::internal::DummyBitType)
#endif // vtk_m_io_VTKDataSetReaderBase_h

@ -0,0 +1,407 @@
//============================================================================
// 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/io/VTKDataSetWriter.h>
#include <vtkm/CellShape.h>
#include <vtkm/cont/CellSetExplicit.h>
#include <vtkm/cont/CellSetSingleType.h>
#include <vtkm/cont/CellSetStructured.h>
#include <vtkm/cont/ErrorBadType.h>
#include <vtkm/cont/ErrorBadValue.h>
#include <vtkm/cont/Field.h>
#include <vtkm/io/ErrorIO.h>
#include <vtkm/io/internal/VTKDataSetTypes.h>
#include <algorithm>
#include <cctype>
#include <cstring>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
namespace
{
struct OutputPointsFunctor
{
private:
std::ostream& out;
template <typename PortalType>
VTKM_CONT void Output(const PortalType& portal) const
{
for (vtkm::Id index = 0; index < portal.GetNumberOfValues(); index++)
{
const int VTKDims = 3; // VTK files always require 3 dims for points
using ValueType = typename PortalType::ValueType;
using VecType = typename vtkm::VecTraits<ValueType>;
const ValueType& value = portal.Get(index);
vtkm::IdComponent numComponents = VecType::GetNumberOfComponents(value);
for (vtkm::IdComponent c = 0; c < numComponents && c < VTKDims; c++)
{
out << (c == 0 ? "" : " ") << VecType::GetComponent(value, c);
}
for (vtkm::IdComponent c = numComponents; c < VTKDims; c++)
{
out << " 0";
}
out << '\n';
}
}
public:
VTKM_CONT
OutputPointsFunctor(std::ostream& o)
: out(o)
{
}
template <typename T, typename Storage>
VTKM_CONT void operator()(const vtkm::cont::ArrayHandle<T, Storage>& array) const
{
this->Output(array.ReadPortal());
}
};
struct OutputFieldFunctor
{
private:
std::ostream& out;
template <typename PortalType>
VTKM_CONT void Output(const PortalType& portal) const
{
for (vtkm::Id index = 0; index < portal.GetNumberOfValues(); index++)
{
using ValueType = typename PortalType::ValueType;
using VecType = typename vtkm::VecTraits<ValueType>;
const ValueType& value = portal.Get(index);
vtkm::IdComponent numComponents = VecType::GetNumberOfComponents(value);
for (vtkm::IdComponent c = 0; c < numComponents; c++)
{
out << (c == 0 ? "" : " ") << VecType::GetComponent(value, c);
}
out << '\n';
}
}
public:
VTKM_CONT
OutputFieldFunctor(std::ostream& o)
: out(o)
{
}
template <typename T, typename Storage>
VTKM_CONT void operator()(const vtkm::cont::ArrayHandle<T, Storage>& array) const
{
this->Output(array.ReadPortal());
}
};
class GetDataTypeName
{
public:
GetDataTypeName(std::string& name)
: Name(&name)
{
}
template <typename ArrayHandleType>
void operator()(const ArrayHandleType&) const
{
using DataType = typename vtkm::VecTraits<typename ArrayHandleType::ValueType>::ComponentType;
*this->Name = vtkm::io::internal::DataTypeName<DataType>::Name();
}
private:
std::string* Name;
};
void WritePoints(std::ostream& out, const vtkm::cont::DataSet& dataSet)
{
///\todo: support other coordinate systems
int cindex = 0;
auto cdata = dataSet.GetCoordinateSystem(cindex).GetData();
vtkm::Id npoints = cdata.GetNumberOfValues();
out << "POINTS " << npoints << " " << vtkm::io::internal::DataTypeName<vtkm::FloatDefault>::Name()
<< " " << '\n';
OutputPointsFunctor{ out }(cdata);
}
template <class CellSetType>
void WriteExplicitCells(std::ostream& out, const CellSetType& cellSet)
{
vtkm::Id nCells = cellSet.GetNumberOfCells();
vtkm::Id conn_length = 0;
for (vtkm::Id i = 0; i < nCells; ++i)
{
conn_length += 1 + cellSet.GetNumberOfPointsInCell(i);
}
out << "CELLS " << nCells << " " << conn_length << '\n';
for (vtkm::Id i = 0; i < nCells; ++i)
{
vtkm::cont::ArrayHandle<vtkm::Id> ids;
vtkm::Id nids = cellSet.GetNumberOfPointsInCell(i);
cellSet.GetIndices(i, ids);
out << nids;
auto IdPortal = ids.ReadPortal();
for (int j = 0; j < nids; ++j)
out << " " << IdPortal.Get(j);
out << '\n';
}
out << "CELL_TYPES " << nCells << '\n';
for (vtkm::Id i = 0; i < nCells; ++i)
{
vtkm::Id shape = cellSet.GetCellShape(i);
out << shape << '\n';
}
}
void WriteVertexCells(std::ostream& out, const vtkm::cont::DataSet& dataSet)
{
vtkm::Id nCells = dataSet.GetCoordinateSystem(0).GetNumberOfPoints();
out << "CELLS " << nCells << " " << nCells * 2 << '\n';
for (int i = 0; i < nCells; i++)
{
out << "1 " << i << '\n';
}
out << "CELL_TYPES " << nCells << '\n';
for (int i = 0; i < nCells; i++)
{
out << vtkm::CELL_SHAPE_VERTEX << '\n';
}
}
void WritePointFields(std::ostream& out, const vtkm::cont::DataSet& dataSet)
{
bool wrote_header = false;
for (vtkm::Id f = 0; f < dataSet.GetNumberOfFields(); f++)
{
const vtkm::cont::Field field = dataSet.GetField(f);
if (field.GetAssociation() != vtkm::cont::Field::Association::POINTS)
{
continue;
}
vtkm::Id npoints = field.GetNumberOfValues();
int ncomps = field.GetData().GetNumberOfComponents();
if (ncomps > 4)
{
continue;
}
if (!wrote_header)
{
out << "POINT_DATA " << npoints << '\n';
wrote_header = true;
}
std::string typeName;
vtkm::cont::CastAndCall(field.GetData().ResetTypes(vtkm::TypeListAll{}),
GetDataTypeName(typeName));
std::string name = field.GetName();
for (auto& c : name)
{
if (std::isspace(c))
{
c = '_';
}
}
out << "SCALARS " << name << " " << typeName << " " << ncomps << '\n';
out << "LOOKUP_TABLE default" << '\n';
vtkm::cont::CastAndCall(field.GetData().ResetTypes(vtkm::TypeListAll{}),
OutputFieldFunctor(out));
}
}
void WriteCellFields(std::ostream& out, const vtkm::cont::DataSet& dataSet)
{
bool wrote_header = false;
for (vtkm::Id f = 0; f < dataSet.GetNumberOfFields(); f++)
{
const vtkm::cont::Field field = dataSet.GetField(f);
if (!field.IsFieldCell())
{
continue;
}
vtkm::Id ncells = field.GetNumberOfValues();
int ncomps = field.GetData().GetNumberOfComponents();
if (ncomps > 4)
continue;
if (!wrote_header)
{
out << "CELL_DATA " << ncells << '\n';
wrote_header = true;
}
std::string typeName;
vtkm::cont::CastAndCall(field.GetData().ResetTypes(vtkm::TypeListAll{}),
GetDataTypeName(typeName));
std::string name = field.GetName();
for (auto& c : name)
{
if (std::isspace(c))
{
c = '_';
}
}
out << "SCALARS " << name << " " << typeName << " " << ncomps << '\n';
out << "LOOKUP_TABLE default" << '\n';
vtkm::cont::CastAndCall(field.GetData().ResetTypes(vtkm::TypeListAll{}),
OutputFieldFunctor(out));
}
}
void WriteDataSetAsPoints(std::ostream& out, const vtkm::cont::DataSet& dataSet)
{
out << "DATASET UNSTRUCTURED_GRID" << '\n';
WritePoints(out, dataSet);
WriteVertexCells(out, dataSet);
}
template <class CellSetType>
void WriteDataSetAsUnstructured(std::ostream& out,
const vtkm::cont::DataSet& dataSet,
const CellSetType& cellSet)
{
out << "DATASET UNSTRUCTURED_GRID" << '\n';
WritePoints(out, dataSet);
WriteExplicitCells(out, cellSet);
}
template <vtkm::IdComponent DIM>
void WriteDataSetAsStructured(std::ostream& out,
const vtkm::cont::DataSet& dataSet,
const vtkm::cont::CellSetStructured<DIM>& cellSet)
{
///\todo: support uniform/rectilinear
out << "DATASET STRUCTURED_GRID" << '\n';
auto pointDimensions = cellSet.GetPointDimensions();
using VTraits = vtkm::VecTraits<decltype(pointDimensions)>;
out << "DIMENSIONS ";
out << VTraits::GetComponent(pointDimensions, 0) << " ";
out << (DIM > 1 ? VTraits::GetComponent(pointDimensions, 1) : 1) << " ";
out << (DIM > 2 ? VTraits::GetComponent(pointDimensions, 2) : 1) << " ";
WritePoints(out, dataSet);
}
void Write(std::ostream& out, const vtkm::cont::DataSet& dataSet, bool just_points = false)
{
// The Paraview parser cannot handle scientific notation:
out << std::fixed;
out << "# vtk DataFile Version 3.0" << '\n';
out << "vtk output" << '\n';
out << "ASCII" << '\n';
if (just_points)
{
WriteDataSetAsPoints(out, dataSet);
WritePointFields(out, dataSet);
}
else
{
vtkm::cont::DynamicCellSet cellSet = dataSet.GetCellSet();
if (cellSet.IsType<vtkm::cont::CellSetExplicit<>>())
{
WriteDataSetAsUnstructured(out, dataSet, cellSet.Cast<vtkm::cont::CellSetExplicit<>>());
}
else if (cellSet.IsType<vtkm::cont::CellSetStructured<1>>())
{
WriteDataSetAsStructured(out, dataSet, cellSet.Cast<vtkm::cont::CellSetStructured<1>>());
}
else if (cellSet.IsType<vtkm::cont::CellSetStructured<2>>())
{
WriteDataSetAsStructured(out, dataSet, cellSet.Cast<vtkm::cont::CellSetStructured<2>>());
}
else if (cellSet.IsType<vtkm::cont::CellSetStructured<3>>())
{
WriteDataSetAsStructured(out, dataSet, cellSet.Cast<vtkm::cont::CellSetStructured<3>>());
}
else if (cellSet.IsType<vtkm::cont::CellSetSingleType<>>())
{
// these function just like explicit cell sets
WriteDataSetAsUnstructured(out, dataSet, cellSet.Cast<vtkm::cont::CellSetSingleType<>>());
}
else
{
throw vtkm::cont::ErrorBadType("Could not determine type to write out.");
}
WritePointFields(out, dataSet);
WriteCellFields(out, dataSet);
}
}
} // anonymous namespace
namespace vtkm
{
namespace io
{
VTKDataSetWriter::VTKDataSetWriter(const char* fileName)
: FileName(fileName)
{
}
VTKDataSetWriter::VTKDataSetWriter(const std::string& fileName)
: FileName(fileName)
{
}
void VTKDataSetWriter::WriteDataSet(const vtkm::cont::DataSet& dataSet, bool just_points) const
{
if (dataSet.GetNumberOfCoordinateSystems() < 1)
{
throw vtkm::cont::ErrorBadValue(
"DataSet has no coordinate system, which is not supported by VTK file format.");
}
try
{
std::ofstream fileStream(this->FileName.c_str(), std::fstream::trunc);
Write(fileStream, dataSet, just_points);
fileStream.close();
}
catch (std::ofstream::failure& error)
{
throw vtkm::io::ErrorIO(error.what());
}
}
}
} // namespace vtkm::io

@ -10,400 +10,22 @@
#ifndef vtk_m_io_DataSetWriter_h
#define vtk_m_io_DataSetWriter_h
#include <cctype>
#include <vtkm/CellShape.h>
#include <vtkm/cont/CellSetExplicit.h>
#include <vtkm/cont/CellSetSingleType.h>
#include <vtkm/cont/CellSetStructured.h>
#include <vtkm/cont/DataSet.h>
#include <vtkm/cont/ErrorBadType.h>
#include <vtkm/cont/ErrorBadValue.h>
#include <vtkm/cont/Field.h>
#include <vtkm/io/ErrorIO.h>
#include <vtkm/io/internal/VTKDataSetTypes.h>
#include <algorithm>
#include <cstring>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
#include <vtkm/io/vtkm_io_export.h>
namespace vtkm
{
namespace io
{
namespace detail
{
struct OutputPointsFunctor
{
private:
std::ostream& out;
template <typename PortalType>
VTKM_CONT void Output(const PortalType& portal) const
{
for (vtkm::Id index = 0; index < portal.GetNumberOfValues(); index++)
{
const int VTKDims = 3; // VTK files always require 3 dims for points
using ValueType = typename PortalType::ValueType;
using VecType = typename vtkm::VecTraits<ValueType>;
const ValueType& value = portal.Get(index);
vtkm::IdComponent numComponents = VecType::GetNumberOfComponents(value);
for (vtkm::IdComponent c = 0; c < numComponents && c < VTKDims; c++)
{
out << (c == 0 ? "" : " ") << VecType::GetComponent(value, c);
}
for (vtkm::IdComponent c = numComponents; c < VTKDims; c++)
{
out << " 0";
}
out << '\n';
}
}
public:
VTKM_CONT
OutputPointsFunctor(std::ostream& o)
: out(o)
{
}
template <typename T, typename Storage>
VTKM_CONT void operator()(const vtkm::cont::ArrayHandle<T, Storage>& array) const
{
this->Output(array.ReadPortal());
}
};
struct OutputFieldFunctor
{
private:
std::ostream& out;
template <typename PortalType>
VTKM_CONT void Output(const PortalType& portal) const
{
for (vtkm::Id index = 0; index < portal.GetNumberOfValues(); index++)
{
using ValueType = typename PortalType::ValueType;
using VecType = typename vtkm::VecTraits<ValueType>;
const ValueType& value = portal.Get(index);
vtkm::IdComponent numComponents = VecType::GetNumberOfComponents(value);
for (vtkm::IdComponent c = 0; c < numComponents; c++)
{
out << (c == 0 ? "" : " ") << VecType::GetComponent(value, c);
}
out << '\n';
}
}
public:
VTKM_CONT
OutputFieldFunctor(std::ostream& o)
: out(o)
{
}
template <typename T, typename Storage>
VTKM_CONT void operator()(const vtkm::cont::ArrayHandle<T, Storage>& array) const
{
this->Output(array.ReadPortal());
}
};
class GetDataTypeName
struct VTKM_IO_EXPORT VTKDataSetWriter
{
public:
GetDataTypeName(std::string& name)
: Name(&name)
{
}
VTKM_CONT VTKDataSetWriter(const char* fileName);
VTKM_CONT VTKDataSetWriter(const std::string& fileName);
template <typename ArrayHandleType>
void operator()(const ArrayHandleType&) const
{
using DataType = typename vtkm::VecTraits<typename ArrayHandleType::ValueType>::ComponentType;
*this->Name = vtkm::io::internal::DataTypeName<DataType>::Name();
}
private:
std::string* Name;
};
} // namespace detail
struct VTKDataSetWriter
{
private:
static void WritePoints(std::ostream& out, const vtkm::cont::DataSet& dataSet)
{
///\todo: support other coordinate systems
int cindex = 0;
auto cdata = dataSet.GetCoordinateSystem(cindex).GetData();
vtkm::Id npoints = cdata.GetNumberOfValues();
out << "POINTS " << npoints << " "
<< vtkm::io::internal::DataTypeName<vtkm::FloatDefault>::Name() << " " << '\n';
detail::OutputPointsFunctor{ out }(cdata);
}
template <class CellSetType>
static void WriteExplicitCells(std::ostream& out, const CellSetType& cellSet)
{
vtkm::Id nCells = cellSet.GetNumberOfCells();
vtkm::Id conn_length = 0;
for (vtkm::Id i = 0; i < nCells; ++i)
{
conn_length += 1 + cellSet.GetNumberOfPointsInCell(i);
}
out << "CELLS " << nCells << " " << conn_length << '\n';
for (vtkm::Id i = 0; i < nCells; ++i)
{
vtkm::cont::ArrayHandle<vtkm::Id> ids;
vtkm::Id nids = cellSet.GetNumberOfPointsInCell(i);
cellSet.GetIndices(i, ids);
out << nids;
auto IdPortal = ids.ReadPortal();
for (int j = 0; j < nids; ++j)
out << " " << IdPortal.Get(j);
out << '\n';
}
out << "CELL_TYPES " << nCells << '\n';
for (vtkm::Id i = 0; i < nCells; ++i)
{
vtkm::Id shape = cellSet.GetCellShape(i);
out << shape << '\n';
}
}
static void WriteVertexCells(std::ostream& out, const vtkm::cont::DataSet& dataSet)
{
vtkm::Id nCells = dataSet.GetCoordinateSystem(0).GetNumberOfPoints();
out << "CELLS " << nCells << " " << nCells * 2 << '\n';
for (int i = 0; i < nCells; i++)
{
out << "1 " << i << '\n';
}
out << "CELL_TYPES " << nCells << '\n';
for (int i = 0; i < nCells; i++)
{
out << vtkm::CELL_SHAPE_VERTEX << '\n';
}
}
static void WritePointFields(std::ostream& out, const vtkm::cont::DataSet& dataSet)
{
bool wrote_header = false;
for (vtkm::Id f = 0; f < dataSet.GetNumberOfFields(); f++)
{
const vtkm::cont::Field field = dataSet.GetField(f);
if (field.GetAssociation() != vtkm::cont::Field::Association::POINTS)
{
continue;
}
vtkm::Id npoints = field.GetNumberOfValues();
int ncomps = field.GetData().GetNumberOfComponents();
if (ncomps > 4)
{
continue;
}
if (!wrote_header)
{
out << "POINT_DATA " << npoints << '\n';
wrote_header = true;
}
std::string typeName;
vtkm::cont::CastAndCall(field.GetData().ResetTypes(TypeListAll{}),
detail::GetDataTypeName(typeName));
std::string name = field.GetName();
for (auto& c : name)
{
if (std::isspace(c))
{
c = '_';
}
}
out << "SCALARS " << name << " " << typeName << " " << ncomps << '\n';
out << "LOOKUP_TABLE default" << '\n';
vtkm::cont::CastAndCall(field.GetData().ResetTypes(TypeListAll{}),
detail::OutputFieldFunctor(out));
}
}
static void WriteCellFields(std::ostream& out, const vtkm::cont::DataSet& dataSet)
{
bool wrote_header = false;
for (vtkm::Id f = 0; f < dataSet.GetNumberOfFields(); f++)
{
const vtkm::cont::Field field = dataSet.GetField(f);
if (!field.IsFieldCell())
{
continue;
}
vtkm::Id ncells = field.GetNumberOfValues();
int ncomps = field.GetData().GetNumberOfComponents();
if (ncomps > 4)
continue;
if (!wrote_header)
{
out << "CELL_DATA " << ncells << '\n';
wrote_header = true;
}
std::string typeName;
vtkm::cont::CastAndCall(field.GetData().ResetTypes(TypeListAll{}),
detail::GetDataTypeName(typeName));
std::string name = field.GetName();
for (auto& c : name)
{
if (std::isspace(c))
{
c = '_';
}
}
out << "SCALARS " << name << " " << typeName << " " << ncomps << '\n';
out << "LOOKUP_TABLE default" << '\n';
vtkm::cont::CastAndCall(field.GetData().ResetTypes(TypeListAll{}),
detail::OutputFieldFunctor(out));
}
}
static void WriteDataSetAsPoints(std::ostream& out, const vtkm::cont::DataSet& dataSet)
{
out << "DATASET UNSTRUCTURED_GRID" << '\n';
WritePoints(out, dataSet);
WriteVertexCells(out, dataSet);
}
template <class CellSetType>
static void WriteDataSetAsUnstructured(std::ostream& out,
const vtkm::cont::DataSet& dataSet,
const CellSetType& cellSet)
{
out << "DATASET UNSTRUCTURED_GRID" << '\n';
WritePoints(out, dataSet);
WriteExplicitCells(out, cellSet);
}
template <vtkm::IdComponent DIM>
static void WriteDataSetAsStructured(std::ostream& out,
const vtkm::cont::DataSet& dataSet,
const vtkm::cont::CellSetStructured<DIM>& cellSet)
{
///\todo: support uniform/rectilinear
out << "DATASET STRUCTURED_GRID" << '\n';
auto pointDimensions = cellSet.GetPointDimensions();
using VTraits = vtkm::VecTraits<decltype(pointDimensions)>;
out << "DIMENSIONS ";
out << VTraits::GetComponent(pointDimensions, 0) << " ";
out << (DIM > 1 ? VTraits::GetComponent(pointDimensions, 1) : 1) << " ";
out << (DIM > 2 ? VTraits::GetComponent(pointDimensions, 2) : 1) << " ";
WritePoints(out, dataSet);
}
static void Write(std::ostream& out, const vtkm::cont::DataSet& dataSet, bool just_points = false)
{
// The Paraview parser cannot handle scientific notation:
out << std::fixed;
out << "# vtk DataFile Version 3.0" << '\n';
out << "vtk output" << '\n';
out << "ASCII" << '\n';
if (just_points)
{
WriteDataSetAsPoints(out, dataSet);
WritePointFields(out, dataSet);
}
else
{
vtkm::cont::DynamicCellSet cellSet = dataSet.GetCellSet();
if (cellSet.IsType<vtkm::cont::CellSetExplicit<>>())
{
WriteDataSetAsUnstructured(out, dataSet, cellSet.Cast<vtkm::cont::CellSetExplicit<>>());
}
else if (cellSet.IsType<vtkm::cont::CellSetStructured<1>>())
{
WriteDataSetAsStructured(out, dataSet, cellSet.Cast<vtkm::cont::CellSetStructured<1>>());
}
else if (cellSet.IsType<vtkm::cont::CellSetStructured<2>>())
{
WriteDataSetAsStructured(out, dataSet, cellSet.Cast<vtkm::cont::CellSetStructured<2>>());
}
else if (cellSet.IsType<vtkm::cont::CellSetStructured<3>>())
{
WriteDataSetAsStructured(out, dataSet, cellSet.Cast<vtkm::cont::CellSetStructured<3>>());
}
else if (cellSet.IsType<vtkm::cont::CellSetSingleType<>>())
{
// these function just like explicit cell sets
WriteDataSetAsUnstructured(out, dataSet, cellSet.Cast<vtkm::cont::CellSetSingleType<>>());
}
else
{
throw vtkm::cont::ErrorBadType("Could not determine type to write out.");
}
WritePointFields(out, dataSet);
WriteCellFields(out, dataSet);
}
}
public:
VTKM_CONT
explicit VTKDataSetWriter(const std::string& filename)
: FileName(filename)
{
}
VTKM_CONT
void WriteDataSet(const vtkm::cont::DataSet& dataSet, bool just_points = false) const
{
if (dataSet.GetNumberOfCoordinateSystems() < 1)
{
throw vtkm::cont::ErrorBadValue(
"DataSet has no coordinate system, which is not supported by VTK file format.");
}
try
{
std::ofstream fileStream(this->FileName.c_str(), std::fstream::trunc);
this->Write(fileStream, dataSet, just_points);
fileStream.close();
}
catch (std::ofstream::failure& error)
{
throw vtkm::io::ErrorIO(error.what());
}
}
VTKM_CONT void WriteDataSet(const vtkm::cont::DataSet& dataSet, bool just_points = false) const;
private:
std::string FileName;

@ -0,0 +1,152 @@
//============================================================================
// 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/io/VTKPolyDataReader.h>
namespace
{
template <typename T>
inline vtkm::cont::ArrayHandle<T> ConcatinateArrayHandles(
const std::vector<vtkm::cont::ArrayHandle<T>>& arrays)
{
vtkm::Id size = 0;
for (std::size_t i = 0; i < arrays.size(); ++i)
{
size += arrays[i].GetNumberOfValues();
}
vtkm::cont::ArrayHandle<T> out;
out.Allocate(size);
auto outp = vtkm::cont::ArrayPortalToIteratorBegin(out.WritePortal());
for (std::size_t i = 0; i < arrays.size(); ++i)
{
std::copy(vtkm::cont::ArrayPortalToIteratorBegin(arrays[i].ReadPortal()),
vtkm::cont::ArrayPortalToIteratorEnd(arrays[i].ReadPortal()),
outp);
using DifferenceType = typename std::iterator_traits<decltype(outp)>::difference_type;
std::advance(outp, static_cast<DifferenceType>(arrays[i].GetNumberOfValues()));
}
return out;
}
}
namespace vtkm
{
namespace io
{
VTKPolyDataReader::VTKPolyDataReader(const char* fileName)
: VTKDataSetReaderBase(fileName)
{
}
VTKPolyDataReader::VTKPolyDataReader(const std::string& fileName)
: VTKDataSetReaderBase(fileName)
{
}
void VTKPolyDataReader::Read()
{
if (this->DataFile->Structure != vtkm::io::internal::DATASET_POLYDATA)
{
throw vtkm::io::ErrorIO("Incorrect DataSet type");
}
//We need to be able to handle VisIt files which dump Field data
//at the top of a VTK file
std::string tag;
this->DataFile->Stream >> tag;
if (tag == "FIELD")
{
this->ReadGlobalFields();
this->DataFile->Stream >> tag;
}
// Read the points
internal::parseAssert(tag == "POINTS");
this->ReadPoints();
vtkm::Id numPoints = this->DataSet.GetNumberOfPoints();
// Read the cellset
std::vector<vtkm::cont::ArrayHandle<vtkm::Id>> connectivityArrays;
std::vector<vtkm::cont::ArrayHandle<vtkm::IdComponent>> numIndicesArrays;
std::vector<vtkm::UInt8> shapesBuffer;
while (!this->DataFile->Stream.eof())
{
vtkm::UInt8 shape = vtkm::CELL_SHAPE_EMPTY;
this->DataFile->Stream >> tag;
if (tag == "VERTICES")
{
shape = vtkm::io::internal::CELL_SHAPE_POLY_VERTEX;
}
else if (tag == "LINES")
{
shape = vtkm::io::internal::CELL_SHAPE_POLY_LINE;
}
else if (tag == "POLYGONS")
{
shape = vtkm::CELL_SHAPE_POLYGON;
}
else if (tag == "TRIANGLE_STRIPS")
{
shape = vtkm::io::internal::CELL_SHAPE_TRIANGLE_STRIP;
}
else
{
this->DataFile->Stream.seekg(-static_cast<std::streamoff>(tag.length()), std::ios_base::cur);
break;
}
vtkm::cont::ArrayHandle<vtkm::Id> cellConnectivity;
vtkm::cont::ArrayHandle<vtkm::IdComponent> cellNumIndices;
this->ReadCells(cellConnectivity, cellNumIndices);
connectivityArrays.push_back(cellConnectivity);
numIndicesArrays.push_back(cellNumIndices);
shapesBuffer.insert(
shapesBuffer.end(), static_cast<std::size_t>(cellNumIndices.GetNumberOfValues()), shape);
}
vtkm::cont::ArrayHandle<vtkm::Id> connectivity = ConcatinateArrayHandles(connectivityArrays);
vtkm::cont::ArrayHandle<vtkm::IdComponent> numIndices = ConcatinateArrayHandles(numIndicesArrays);
vtkm::cont::ArrayHandle<vtkm::UInt8> shapes;
shapes.Allocate(static_cast<vtkm::Id>(shapesBuffer.size()));
std::copy(shapesBuffer.begin(),
shapesBuffer.end(),
vtkm::cont::ArrayPortalToIteratorBegin(shapes.WritePortal()));
vtkm::cont::ArrayHandle<vtkm::Id> permutation;
vtkm::io::internal::FixupCellSet(connectivity, numIndices, shapes, permutation);
this->SetCellsPermutation(permutation);
if (vtkm::io::internal::IsSingleShape(shapes))
{
vtkm::cont::CellSetSingleType<> cellSet;
cellSet.Fill(
numPoints, shapes.ReadPortal().Get(0), numIndices.ReadPortal().Get(0), connectivity);
this->DataSet.SetCellSet(cellSet);
}
else
{
auto offsets = vtkm::cont::ConvertNumIndicesToOffsets(numIndices);
vtkm::cont::CellSetExplicit<> cellSet;
cellSet.Fill(numPoints, shapes, connectivity, offsets);
this->DataSet.SetCellSet(cellSet);
}
// Read points and cell attributes
this->ReadAttributes();
}
}
} // namespace vtkm::io

@ -11,6 +11,7 @@
#define vtk_m_io_VTKPolyDataReader_h
#include <vtkm/io/VTKDataSetReaderBase.h>
#include <vtkm/io/internal/VTKDataSetCells.h>
#include <vtkm/cont/ArrayPortalToIterators.h>
@ -21,147 +22,15 @@ namespace vtkm
namespace io
{
namespace internal
{
template <typename T>
inline vtkm::cont::ArrayHandle<T> ConcatinateArrayHandles(
const std::vector<vtkm::cont::ArrayHandle<T>>& arrays)
{
vtkm::Id size = 0;
for (std::size_t i = 0; i < arrays.size(); ++i)
{
size += arrays[i].GetNumberOfValues();
}
vtkm::cont::ArrayHandle<T> out;
out.Allocate(size);
auto outp = vtkm::cont::ArrayPortalToIteratorBegin(out.WritePortal());
for (std::size_t i = 0; i < arrays.size(); ++i)
{
std::copy(vtkm::cont::ArrayPortalToIteratorBegin(arrays[i].ReadPortal()),
vtkm::cont::ArrayPortalToIteratorEnd(arrays[i].ReadPortal()),
outp);
using DifferenceType = typename std::iterator_traits<decltype(outp)>::difference_type;
std::advance(outp, static_cast<DifferenceType>(arrays[i].GetNumberOfValues()));
}
return out;
}
} // namespace internal
VTKM_SILENCE_WEAK_VTABLE_WARNING_START
class VTKPolyDataReader : public VTKDataSetReaderBase
class VTKM_IO_EXPORT VTKPolyDataReader : public VTKDataSetReaderBase
{
public:
explicit VTKPolyDataReader(const char* fileName)
: VTKDataSetReaderBase(fileName)
{
}
explicit VTKM_CONT VTKPolyDataReader(const char* fileName);
explicit VTKM_CONT VTKPolyDataReader(const std::string& fileName);
private:
virtual void Read()
{
if (this->DataFile->Structure != vtkm::io::internal::DATASET_POLYDATA)
{
throw vtkm::io::ErrorIO("Incorrect DataSet type");
}
//We need to be able to handle VisIt files which dump Field data
//at the top of a VTK file
std::string tag;
this->DataFile->Stream >> tag;
if (tag == "FIELD")
{
this->ReadGlobalFields();
this->DataFile->Stream >> tag;
}
// Read the points
internal::parseAssert(tag == "POINTS");
this->ReadPoints();
vtkm::Id numPoints = this->DataSet.GetNumberOfPoints();
// Read the cellset
std::vector<vtkm::cont::ArrayHandle<vtkm::Id>> connectivityArrays;
std::vector<vtkm::cont::ArrayHandle<vtkm::IdComponent>> numIndicesArrays;
std::vector<vtkm::UInt8> shapesBuffer;
while (!this->DataFile->Stream.eof())
{
vtkm::UInt8 shape = vtkm::CELL_SHAPE_EMPTY;
this->DataFile->Stream >> tag;
if (tag == "VERTICES")
{
shape = vtkm::io::internal::CELL_SHAPE_POLY_VERTEX;
}
else if (tag == "LINES")
{
shape = vtkm::io::internal::CELL_SHAPE_POLY_LINE;
}
else if (tag == "POLYGONS")
{
shape = vtkm::CELL_SHAPE_POLYGON;
}
else if (tag == "TRIANGLE_STRIPS")
{
shape = vtkm::io::internal::CELL_SHAPE_TRIANGLE_STRIP;
}
else
{
this->DataFile->Stream.seekg(-static_cast<std::streamoff>(tag.length()),
std::ios_base::cur);
break;
}
vtkm::cont::ArrayHandle<vtkm::Id> cellConnectivity;
vtkm::cont::ArrayHandle<vtkm::IdComponent> cellNumIndices;
this->ReadCells(cellConnectivity, cellNumIndices);
connectivityArrays.push_back(cellConnectivity);
numIndicesArrays.push_back(cellNumIndices);
shapesBuffer.insert(
shapesBuffer.end(), static_cast<std::size_t>(cellNumIndices.GetNumberOfValues()), shape);
}
vtkm::cont::ArrayHandle<vtkm::Id> connectivity =
internal::ConcatinateArrayHandles(connectivityArrays);
vtkm::cont::ArrayHandle<vtkm::IdComponent> numIndices =
internal::ConcatinateArrayHandles(numIndicesArrays);
vtkm::cont::ArrayHandle<vtkm::UInt8> shapes;
shapes.Allocate(static_cast<vtkm::Id>(shapesBuffer.size()));
std::copy(shapesBuffer.begin(),
shapesBuffer.end(),
vtkm::cont::ArrayPortalToIteratorBegin(shapes.WritePortal()));
vtkm::cont::ArrayHandle<vtkm::Id> permutation;
vtkm::io::internal::FixupCellSet(connectivity, numIndices, shapes, permutation);
this->SetCellsPermutation(permutation);
if (vtkm::io::internal::IsSingleShape(shapes))
{
vtkm::cont::CellSetSingleType<> cellSet;
cellSet.Fill(
numPoints, shapes.ReadPortal().Get(0), numIndices.ReadPortal().Get(0), connectivity);
this->DataSet.SetCellSet(cellSet);
}
else
{
auto offsets = vtkm::cont::ConvertNumIndicesToOffsets(numIndices);
vtkm::cont::CellSetExplicit<> cellSet;
cellSet.Fill(numPoints, shapes, connectivity, offsets);
this->DataSet.SetCellSet(cellSet);
}
// Read points and cell attributes
this->ReadAttributes();
}
void Read() override;
};
VTKM_SILENCE_WEAK_VTABLE_WARNING_END
}
} // namespace vtkm::io

@ -0,0 +1,95 @@
//============================================================================
// 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/io/VTKRectilinearGridReader.h>
namespace vtkm
{
namespace io
{
VTKRectilinearGridReader::VTKRectilinearGridReader(const char* fileName)
: VTKDataSetReaderBase(fileName)
{
}
VTKRectilinearGridReader::VTKRectilinearGridReader(const std::string& fileName)
: VTKDataSetReaderBase(fileName)
{
}
void VTKRectilinearGridReader::Read()
{
if (this->DataFile->Structure != vtkm::io::internal::DATASET_RECTILINEAR_GRID)
throw vtkm::io::ErrorIO("Incorrect DataSet type");
//We need to be able to handle VisIt files which dump Field data
//at the top of a VTK file
std::string tag;
this->DataFile->Stream >> tag;
if (tag == "FIELD")
{
this->ReadGlobalFields();
this->DataFile->Stream >> tag;
}
// Read structured grid specific meta-data
internal::parseAssert(tag == "DIMENSIONS");
vtkm::Id3 dim;
this->DataFile->Stream >> dim[0] >> dim[1] >> dim[2] >> std::ws;
//Read the points.
std::string dataType;
std::size_t numPoints[3];
vtkm::cont::VariantArrayHandle X, Y, Z;
// Always read coordinates as vtkm::FloatDefault
std::string readDataType = vtkm::io::internal::DataTypeName<vtkm::FloatDefault>::Name();
this->DataFile->Stream >> tag >> numPoints[0] >> dataType >> std::ws;
if (tag != "X_COORDINATES")
throw vtkm::io::ErrorIO("X_COORDINATES tag not found");
X = this->DoReadArrayVariant(vtkm::cont::Field::Association::ANY, readDataType, numPoints[0], 1);
this->DataFile->Stream >> tag >> numPoints[1] >> dataType >> std::ws;
if (tag != "Y_COORDINATES")
throw vtkm::io::ErrorIO("Y_COORDINATES tag not found");
Y = this->DoReadArrayVariant(vtkm::cont::Field::Association::ANY, readDataType, numPoints[1], 1);
this->DataFile->Stream >> tag >> numPoints[2] >> dataType >> std::ws;
if (tag != "Z_COORDINATES")
throw vtkm::io::ErrorIO("Z_COORDINATES tag not found");
Z = this->DoReadArrayVariant(vtkm::cont::Field::Association::ANY, readDataType, numPoints[2], 1);
if (dim != vtkm::Id3(static_cast<vtkm::Id>(numPoints[0]),
static_cast<vtkm::Id>(numPoints[1]),
static_cast<vtkm::Id>(numPoints[2])))
throw vtkm::io::ErrorIO("DIMENSIONS not equal to number of points");
vtkm::cont::ArrayHandleCartesianProduct<vtkm::cont::ArrayHandle<vtkm::FloatDefault>,
vtkm::cont::ArrayHandle<vtkm::FloatDefault>,
vtkm::cont::ArrayHandle<vtkm::FloatDefault>>
coords;
vtkm::cont::ArrayHandle<vtkm::FloatDefault> Xc, Yc, Zc;
X.CopyTo(Xc);
Y.CopyTo(Yc);
Z.CopyTo(Zc);
coords = vtkm::cont::make_ArrayHandleCartesianProduct(Xc, Yc, Zc);
vtkm::cont::CoordinateSystem coordSys("coordinates", coords);
this->DataSet.AddCoordinateSystem(coordSys);
this->DataSet.SetCellSet(internal::CreateCellSetStructured(dim));
// Read points and cell attributes
this->ReadAttributes();
}
}
} // namespace vtkm::io

@ -17,89 +17,15 @@ namespace vtkm
namespace io
{
VTKM_SILENCE_WEAK_VTABLE_WARNING_START
class VTKRectilinearGridReader : public VTKDataSetReaderBase
class VTKM_IO_EXPORT VTKRectilinearGridReader : public VTKDataSetReaderBase
{
public:
explicit VTKRectilinearGridReader(const char* fileName)
: VTKDataSetReaderBase(fileName)
{
}
explicit VTKM_CONT VTKRectilinearGridReader(const char* fileName);
explicit VTKM_CONT VTKRectilinearGridReader(const std::string& fileName);
private:
virtual void Read()
{
if (this->DataFile->Structure != vtkm::io::internal::DATASET_RECTILINEAR_GRID)
throw vtkm::io::ErrorIO("Incorrect DataSet type");
//We need to be able to handle VisIt files which dump Field data
//at the top of a VTK file
std::string tag;
this->DataFile->Stream >> tag;
if (tag == "FIELD")
{
this->ReadGlobalFields();
this->DataFile->Stream >> tag;
}
// Read structured grid specific meta-data
internal::parseAssert(tag == "DIMENSIONS");
vtkm::Id3 dim;
this->DataFile->Stream >> dim[0] >> dim[1] >> dim[2] >> std::ws;
//Read the points.
std::string dataType;
std::size_t numPoints[3];
vtkm::cont::VariantArrayHandle X, Y, Z;
// Always read coordinates as vtkm::FloatDefault
std::string readDataType = vtkm::io::internal::DataTypeName<vtkm::FloatDefault>::Name();
this->DataFile->Stream >> tag >> numPoints[0] >> dataType >> std::ws;
if (tag != "X_COORDINATES")
throw vtkm::io::ErrorIO("X_COORDINATES tag not found");
X =
this->DoReadArrayVariant(vtkm::cont::Field::Association::ANY, readDataType, numPoints[0], 1);
this->DataFile->Stream >> tag >> numPoints[1] >> dataType >> std::ws;
if (tag != "Y_COORDINATES")
throw vtkm::io::ErrorIO("Y_COORDINATES tag not found");
Y =
this->DoReadArrayVariant(vtkm::cont::Field::Association::ANY, readDataType, numPoints[1], 1);
this->DataFile->Stream >> tag >> numPoints[2] >> dataType >> std::ws;
if (tag != "Z_COORDINATES")
throw vtkm::io::ErrorIO("Z_COORDINATES tag not found");
Z =
this->DoReadArrayVariant(vtkm::cont::Field::Association::ANY, readDataType, numPoints[2], 1);
if (dim != vtkm::Id3(static_cast<vtkm::Id>(numPoints[0]),
static_cast<vtkm::Id>(numPoints[1]),
static_cast<vtkm::Id>(numPoints[2])))
throw vtkm::io::ErrorIO("DIMENSIONS not equal to number of points");
vtkm::cont::ArrayHandleCartesianProduct<vtkm::cont::ArrayHandle<vtkm::FloatDefault>,
vtkm::cont::ArrayHandle<vtkm::FloatDefault>,
vtkm::cont::ArrayHandle<vtkm::FloatDefault>>
coords;
vtkm::cont::ArrayHandle<vtkm::FloatDefault> Xc, Yc, Zc;
X.CopyTo(Xc);
Y.CopyTo(Yc);
Z.CopyTo(Zc);
coords = vtkm::cont::make_ArrayHandleCartesianProduct(Xc, Yc, Zc);
vtkm::cont::CoordinateSystem coordSys("coordinates", coords);
this->DataSet.AddCoordinateSystem(coordSys);
this->DataSet.SetCellSet(internal::CreateCellSetStructured(dim));
// Read points and cell attributes
this->ReadAttributes();
}
VTKM_CONT void Read() override;
};
VTKM_SILENCE_WEAK_VTABLE_WARNING_END
}
} // namespace vtkm::io

@ -0,0 +1,62 @@
//============================================================================
// 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/io/VTKStructuredGridReader.h>
namespace vtkm
{
namespace io
{
VTKStructuredGridReader::VTKStructuredGridReader(const char* fileName)
: VTKDataSetReaderBase(fileName)
{
}
VTKStructuredGridReader::VTKStructuredGridReader(const std::string& fileName)
: VTKDataSetReaderBase(fileName)
{
}
void VTKStructuredGridReader::Read()
{
if (this->DataFile->Structure != vtkm::io::internal::DATASET_STRUCTURED_GRID)
{
throw vtkm::io::ErrorIO("Incorrect DataSet type");
}
std::string tag;
//We need to be able to handle VisIt files which dump Field data
//at the top of a VTK file
this->DataFile->Stream >> tag;
if (tag == "FIELD")
{
this->ReadGlobalFields();
this->DataFile->Stream >> tag;
}
// Read structured grid specific meta-data
internal::parseAssert(tag == "DIMENSIONS");
vtkm::Id3 dim;
this->DataFile->Stream >> dim[0] >> dim[1] >> dim[2] >> std::ws;
this->DataSet.SetCellSet(internal::CreateCellSetStructured(dim));
// Read the points
this->DataFile->Stream >> tag;
internal::parseAssert(tag == "POINTS");
this->ReadPoints();
// Read points and cell attributes
this->ReadAttributes();
}
}
} // namespace vtkm::io

@ -17,53 +17,15 @@ namespace vtkm
namespace io
{
VTKM_SILENCE_WEAK_VTABLE_WARNING_START
class VTKStructuredGridReader : public VTKDataSetReaderBase
class VTKM_IO_EXPORT VTKStructuredGridReader : public VTKDataSetReaderBase
{
public:
explicit VTKStructuredGridReader(const char* fileName)
: VTKDataSetReaderBase(fileName)
{
}
explicit VTKM_CONT VTKStructuredGridReader(const char* fileName);
explicit VTKM_CONT VTKStructuredGridReader(const std::string& fileName);
private:
virtual void Read()
{
if (this->DataFile->Structure != vtkm::io::internal::DATASET_STRUCTURED_GRID)
{
throw vtkm::io::ErrorIO("Incorrect DataSet type");
}
std::string tag;
//We need to be able to handle VisIt files which dump Field data
//at the top of a VTK file
this->DataFile->Stream >> tag;
if (tag == "FIELD")
{
this->ReadGlobalFields();
this->DataFile->Stream >> tag;
}
// Read structured grid specific meta-data
internal::parseAssert(tag == "DIMENSIONS");
vtkm::Id3 dim;
this->DataFile->Stream >> dim[0] >> dim[1] >> dim[2] >> std::ws;
this->DataSet.SetCellSet(internal::CreateCellSetStructured(dim));
// Read the points
this->DataFile->Stream >> tag;
internal::parseAssert(tag == "POINTS");
this->ReadPoints();
// Read points and cell attributes
this->ReadAttributes();
}
VTKM_CONT void Read() override;
};
VTKM_SILENCE_WEAK_VTABLE_WARNING_END
}
} // namespace vtkm::io

@ -0,0 +1,79 @@
//============================================================================
// 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/io/VTKStructuredPointsReader.h>
namespace vtkm
{
namespace io
{
VTKStructuredPointsReader::VTKStructuredPointsReader(const char* fileName)
: VTKDataSetReaderBase(fileName)
{
}
VTKStructuredPointsReader::VTKStructuredPointsReader(const std::string& fileName)
: VTKDataSetReaderBase(fileName)
{
}
void VTKStructuredPointsReader::Read()
{
if (this->DataFile->Structure != vtkm::io::internal::DATASET_STRUCTURED_POINTS)
{
throw vtkm::io::ErrorIO("Incorrect DataSet type");
}
std::string tag;
// Read structured points specific meta-data
vtkm::Id3 dim;
vtkm::Vec3f_32 origin, spacing;
//Two ways the file can describe the dimensions. The proper way is by
//using the DIMENSIONS keyword, but VisIt written VTK files spicify data
//bounds instead, as a FIELD
std::vector<vtkm::Float32> visitBounds;
this->DataFile->Stream >> tag;
if (tag == "FIELD")
{
this->ReadGlobalFields(&visitBounds);
this->DataFile->Stream >> tag;
}
if (visitBounds.empty())
{
internal::parseAssert(tag == "DIMENSIONS");
this->DataFile->Stream >> dim[0] >> dim[1] >> dim[2] >> std::ws;
this->DataFile->Stream >> tag;
}
internal::parseAssert(tag == "SPACING");
this->DataFile->Stream >> spacing[0] >> spacing[1] >> spacing[2] >> std::ws;
if (!visitBounds.empty())
{
//now with spacing and physical bounds we can back compute the dimensions
dim[0] = static_cast<vtkm::Id>((visitBounds[1] - visitBounds[0]) / spacing[0]);
dim[1] = static_cast<vtkm::Id>((visitBounds[3] - visitBounds[2]) / spacing[1]);
dim[2] = static_cast<vtkm::Id>((visitBounds[5] - visitBounds[4]) / spacing[2]);
}
this->DataFile->Stream >> tag >> origin[0] >> origin[1] >> origin[2] >> std::ws;
internal::parseAssert(tag == "ORIGIN");
this->DataSet.SetCellSet(internal::CreateCellSetStructured(dim));
this->DataSet.AddCoordinateSystem(
vtkm::cont::CoordinateSystem("coordinates", dim, origin, spacing));
// Read points and cell attributes
this->ReadAttributes();
}
}
} // namespace vtkm::io

@ -17,70 +17,15 @@ namespace vtkm
namespace io
{
VTKM_SILENCE_WEAK_VTABLE_WARNING_START
class VTKStructuredPointsReader : public VTKDataSetReaderBase
class VTKM_IO_EXPORT VTKStructuredPointsReader : public VTKDataSetReaderBase
{
public:
explicit VTKStructuredPointsReader(const char* fileName)
: VTKDataSetReaderBase(fileName)
{
}
explicit VTKM_CONT VTKStructuredPointsReader(const char* fileName);
explicit VTKM_CONT VTKStructuredPointsReader(const std::string& fileName);
private:
virtual void Read()
{
if (this->DataFile->Structure != vtkm::io::internal::DATASET_STRUCTURED_POINTS)
{
throw vtkm::io::ErrorIO("Incorrect DataSet type");
}
std::string tag;
// Read structured points specific meta-data
vtkm::Id3 dim;
vtkm::Vec3f_32 origin, spacing;
//Two ways the file can describe the dimensions. The proper way is by
//using the DIMENSIONS keyword, but VisIt written VTK files spicify data
//bounds instead, as a FIELD
std::vector<vtkm::Float32> visitBounds;
this->DataFile->Stream >> tag;
if (tag == "FIELD")
{
this->ReadGlobalFields(&visitBounds);
this->DataFile->Stream >> tag;
}
if (visitBounds.empty())
{
internal::parseAssert(tag == "DIMENSIONS");
this->DataFile->Stream >> dim[0] >> dim[1] >> dim[2] >> std::ws;
this->DataFile->Stream >> tag;
}
internal::parseAssert(tag == "SPACING");
this->DataFile->Stream >> spacing[0] >> spacing[1] >> spacing[2] >> std::ws;
if (!visitBounds.empty())
{
//now with spacing and physical bounds we can back compute the dimensions
dim[0] = static_cast<vtkm::Id>((visitBounds[1] - visitBounds[0]) / spacing[0]);
dim[1] = static_cast<vtkm::Id>((visitBounds[3] - visitBounds[2]) / spacing[1]);
dim[2] = static_cast<vtkm::Id>((visitBounds[5] - visitBounds[4]) / spacing[2]);
}
this->DataFile->Stream >> tag >> origin[0] >> origin[1] >> origin[2] >> std::ws;
internal::parseAssert(tag == "ORIGIN");
this->DataSet.SetCellSet(internal::CreateCellSetStructured(dim));
this->DataSet.AddCoordinateSystem(
vtkm::cont::CoordinateSystem("coordinates", dim, origin, spacing));
// Read points and cell attributes
this->ReadAttributes();
}
VTKM_CONT void Read() override;
};
VTKM_SILENCE_WEAK_VTABLE_WARNING_END
}
} // namespace vtkm::io

@ -0,0 +1,88 @@
//============================================================================
// 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/io/VTKUnstructuredGridReader.h>
#include <vtkm/io/internal/VTKDataSetCells.h>
namespace vtkm
{
namespace io
{
VTKUnstructuredGridReader::VTKUnstructuredGridReader(const char* fileName)
: VTKDataSetReaderBase(fileName)
{
}
VTKUnstructuredGridReader::VTKUnstructuredGridReader(const std::string& fileName)
: VTKDataSetReaderBase(fileName)
{
}
void VTKUnstructuredGridReader::Read()
{
if (this->DataFile->Structure != vtkm::io::internal::DATASET_UNSTRUCTURED_GRID)
{
throw vtkm::io::ErrorIO("Incorrect DataSet type");
}
//We need to be able to handle VisIt files which dump Field data
//at the top of a VTK file
std::string tag;
this->DataFile->Stream >> tag;
if (tag == "FIELD")
{
this->ReadGlobalFields();
this->DataFile->Stream >> tag;
}
// Read the points
internal::parseAssert(tag == "POINTS");
this->ReadPoints();
vtkm::Id numPoints = this->DataSet.GetNumberOfPoints();
// Read the cellset
vtkm::cont::ArrayHandle<vtkm::Id> connectivity;
vtkm::cont::ArrayHandle<vtkm::IdComponent> numIndices;
vtkm::cont::ArrayHandle<vtkm::UInt8> shapes;
this->DataFile->Stream >> tag;
internal::parseAssert(tag == "CELLS");
this->ReadCells(connectivity, numIndices);
this->ReadShapes(shapes);
vtkm::cont::ArrayHandle<vtkm::Id> permutation;
vtkm::io::internal::FixupCellSet(connectivity, numIndices, shapes, permutation);
this->SetCellsPermutation(permutation);
//DRP
if (false) //vtkm::io::internal::IsSingleShape(shapes))
{
vtkm::cont::CellSetSingleType<> cellSet;
cellSet.Fill(
numPoints, shapes.ReadPortal().Get(0), numIndices.ReadPortal().Get(0), connectivity);
this->DataSet.SetCellSet(cellSet);
}
else
{
auto offsets = vtkm::cont::ConvertNumIndicesToOffsets(numIndices);
vtkm::cont::CellSetExplicit<> cellSet;
cellSet.Fill(numPoints, shapes, connectivity, offsets);
this->DataSet.SetCellSet(cellSet);
}
// Read points and cell attributes
this->ReadAttributes();
}
}
}

@ -17,77 +17,15 @@ namespace vtkm
namespace io
{
VTKM_SILENCE_WEAK_VTABLE_WARNING_START
class VTKUnstructuredGridReader : public VTKDataSetReaderBase
class VTKM_IO_EXPORT VTKUnstructuredGridReader : public VTKDataSetReaderBase
{
public:
explicit VTKUnstructuredGridReader(const char* fileName)
: VTKDataSetReaderBase(fileName)
{
}
explicit VTKM_CONT VTKUnstructuredGridReader(const char* fileName);
explicit VTKM_CONT VTKUnstructuredGridReader(const std::string& fileName);
private:
virtual void Read()
{
if (this->DataFile->Structure != vtkm::io::internal::DATASET_UNSTRUCTURED_GRID)
{
throw vtkm::io::ErrorIO("Incorrect DataSet type");
}
//We need to be able to handle VisIt files which dump Field data
//at the top of a VTK file
std::string tag;
this->DataFile->Stream >> tag;
if (tag == "FIELD")
{
this->ReadGlobalFields();
this->DataFile->Stream >> tag;
}
// Read the points
internal::parseAssert(tag == "POINTS");
this->ReadPoints();
vtkm::Id numPoints = this->DataSet.GetNumberOfPoints();
// Read the cellset
vtkm::cont::ArrayHandle<vtkm::Id> connectivity;
vtkm::cont::ArrayHandle<vtkm::IdComponent> numIndices;
vtkm::cont::ArrayHandle<vtkm::UInt8> shapes;
this->DataFile->Stream >> tag;
internal::parseAssert(tag == "CELLS");
this->ReadCells(connectivity, numIndices);
this->ReadShapes(shapes);
vtkm::cont::ArrayHandle<vtkm::Id> permutation;
vtkm::io::internal::FixupCellSet(connectivity, numIndices, shapes, permutation);
this->SetCellsPermutation(permutation);
//DRP
if (false) //vtkm::io::internal::IsSingleShape(shapes))
{
vtkm::cont::CellSetSingleType<> cellSet;
cellSet.Fill(
numPoints, shapes.ReadPortal().Get(0), numIndices.ReadPortal().Get(0), connectivity);
this->DataSet.SetCellSet(cellSet);
}
else
{
auto offsets = vtkm::cont::ConvertNumIndicesToOffsets(numIndices);
vtkm::cont::CellSetExplicit<> cellSet;
cellSet.Fill(numPoints, shapes, connectivity, offsets);
this->DataSet.SetCellSet(cellSet);
}
// Read points and cell attributes
this->ReadAttributes();
}
VTKM_CONT void Read() override;
};
VTKM_SILENCE_WEAK_VTABLE_WARNING_END
}
} // namespace vtkm::io

@ -11,6 +11,7 @@
#define vtk_m_io_internal_VTKDataSetTypes_h
#include <vtkm/Types.h>
#include <vtkm/VecTraits.h>
#include <algorithm>
#include <cassert>
@ -238,4 +239,7 @@ inline void SelectTypeAndCall(DataType dtype,
}
} // namespace vtkm::io::internal
VTKM_BASIC_TYPE_VECTOR(vtkm::io::internal::ColorChannel8)
VTKM_BASIC_TYPE_VECTOR(vtkm::io::internal::DummyBitType)
#endif // vtk_m_io_internal_VTKDataSetTypes_h

@ -13,4 +13,6 @@ set(headers
VTKDataSetReader.h
)
vtkm_declare_headers(${headers})
vtkm_declare_headers(
${headers}
)

@ -9,8 +9,20 @@
##============================================================================
set(unit_tests
UnitTestBOVDataSetReader.cxx
UnitTestPixelTypes.cxx
UnitTestVTKDataSetReader.cxx
UnitTestVTKDataSetWriter.cxx
)
)
vtkm_unit_tests(SOURCES ${unit_tests} ALL_BACKENDS)
set(unit_test_libraries vtkm_lodepng vtkm_io)
if(VTKm_ENABLE_RENDERING)
set(unit_tests ${unit_tests}
UnitTestImageWriter.cxx
)
set(unit_test_libraries ${unit_test_libraries} vtkm_rendering)
endif()
vtkm_unit_tests(SOURCES ${unit_tests} ALL_BACKENDS LIBRARIES ${unit_test_libraries})

@ -0,0 +1,70 @@
//============================================================================
// 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 <string>
#include <vtkm/cont/testing/Testing.h>
#include <vtkm/io/BOVDataSetReader.h>
#include <vtkm/io/ErrorIO.h>
namespace
{
inline vtkm::cont::DataSet readBOVDataSet(const char* fname)
{
vtkm::cont::DataSet ds;
vtkm::io::BOVDataSetReader reader(fname);
try
{
ds = reader.ReadDataSet();
}
catch (vtkm::io::ErrorIO& e)
{
std::string message("Error reading ");
message += fname;
message += ", ";
message += e.GetMessage();
VTKM_TEST_FAIL(message.c_str());
}
return ds;
}
} // anonymous namespace
void TestReadingBOVDataSet()
{
std::string bovFile = vtkm::cont::testing::Testing::GetTestDataBasePath() + "/uniform/noise.bov";
auto const& ds = readBOVDataSet(bovFile.data());
VTKM_TEST_ASSERT(ds.GetNumberOfFields() == 1, "Incorrect number of fields");
// See the .bov file: DATA SIZE: 50 50 50
VTKM_TEST_ASSERT(ds.GetNumberOfPoints() == 50 * 50 * 50, "Incorrect number of points");
VTKM_TEST_ASSERT(ds.GetCellSet().GetNumberOfPoints() == 50 * 50 * 50,
"Incorrect number of points (from cell set)");
VTKM_TEST_ASSERT(ds.GetNumberOfCells() == 49 * 49 * 49, "Incorrect number of cells");
// See the .bov file: VARIABLE: "var"
VTKM_TEST_ASSERT(ds.HasField("var"), "Should have field 'var', but does not.");
VTKM_TEST_ASSERT(ds.GetNumberOfFields() == 1, "There is only one field in noise.bov");
VTKM_TEST_ASSERT(ds.GetNumberOfCoordinateSystems() == 1,
"There is only one coordinate system in noise.bov");
auto const& field = ds.GetField("var");
// I'm pretty sure that all .bov files have their fields associated with points . . .
VTKM_TEST_ASSERT(field.GetAssociation() == vtkm::cont::Field::Association::POINTS,
"The field should be associated with points.");
}
int UnitTestBOVDataSetReader(int argc, char* argv[])
{
return vtkm::cont::testing::Testing::Run(TestReadingBOVDataSet, argc, argv);
}

@ -0,0 +1,165 @@
//============================================================================
// 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/testing/Testing.h>
#include <vtkm/io/ImageReader.h>
#include <vtkm/io/ImageWriter.h>
#include <vtkm/io/PixelTypes.h>
#include <vtkm/rendering/Canvas.h>
#include <vtkm/rendering/Color.h>
#include <string>
namespace
{
using namespace vtkm::io;
using namespace vtkm::rendering;
template <typename PixelType>
void TestFilledImage(vtkm::cont::DataSet& dataSet,
const std::string& fieldName,
const vtkm::rendering::Canvas& canvas)
{
VTKM_TEST_ASSERT(dataSet.HasPointField(fieldName), "Point Field Not Found: " + fieldName);
auto pointField = dataSet.GetPointField(fieldName);
VTKM_TEST_ASSERT(pointField.GetNumberOfValues() == canvas.GetWidth() * canvas.GetHeight(),
"wrong image dimensions");
VTKM_TEST_ASSERT(pointField.GetData().template IsType<vtkm::cont::ArrayHandle<vtkm::Vec4f_32>>(),
"wrong ArrayHandle type");
auto pixelPortal =
pointField.GetData().template Cast<vtkm::cont::ArrayHandle<vtkm::Vec4f_32>>().ReadPortal();
auto colorPortal = canvas.GetColorBuffer().ReadPortal();
for (vtkm::Id y = 0; y < canvas.GetHeight(); y++)
{
std::ostringstream row;
row << "[";
for (vtkm::Id x = 0; x < canvas.GetWidth(); x++)
{
auto tuple = colorPortal.Get(y * canvas.GetWidth() + x);
auto pixelVec = PixelType(pixelPortal.Get(y * canvas.GetWidth() + x));
std::ostringstream data;
data << pixelVec << ":" << PixelType(tuple) << std::endl;
VTKM_TEST_ASSERT(pixelVec == PixelType(tuple),
"Stored pixel did not match canvas value" + data.str());
row << pixelVec << ",";
}
row << "]";
}
}
template <typename PixelType>
void TestCreateImageDataSet(BaseImageReader& reader, const vtkm::rendering::Canvas& canvas)
{
auto dataSet = reader.CreateImageDataSet(canvas);
TestFilledImage<PixelType>(dataSet, reader.GetPointFieldName(), canvas);
}
template <typename PixelType>
void TestReadAndWritePNG(const vtkm::rendering::Canvas& canvas, std::string image)
{
auto pngReader = PNGReader();
auto pngWriter = PNGWriter();
vtkm::cont::DataSet dataSet;
bool throws = false;
try
{
pngWriter.WriteToFile(image, dataSet);
}
catch (const vtkm::cont::ErrorBadValue&)
{
throws = true;
}
VTKM_TEST_ASSERT(throws, "Fill Image did not throw with empty data");
dataSet = pngReader.CreateImageDataSet(canvas);
pngWriter.WriteToFile(image, dataSet);
dataSet = pngReader.ReadFromFile(image);
pngWriter.WriteToFile(image, dataSet);
dataSet = pngReader.ReadFromFile(image);
TestFilledImage<PixelType>(dataSet, pngReader.GetPointFieldName(), canvas);
}
template <const vtkm::Id BitDepth>
void TestReadAndWritePNM(const vtkm::rendering::Canvas& canvas)
{
using PixelType = RGBPixel<BitDepth>;
PNMWriter ppmWriter((1 << BitDepth) - 1);
PNMReader ppmReader((1 << BitDepth) - 1);
vtkm::cont::DataSet dataSet;
bool throws = false;
try
{
ppmWriter.WriteToFile("ppmTestFile" + std::to_string(BitDepth) + "bit.ppm", dataSet);
}
catch (const vtkm::cont::ErrorBadValue&)
{
throws = true;
}
VTKM_TEST_ASSERT(throws, "Fill Image did not throw with empty data");
dataSet = ppmReader.CreateImageDataSet(canvas);
ppmWriter.WriteToFile("ppmTestFile.ppm", dataSet);
dataSet = ppmReader.ReadFromFile("ppmTestFile.ppm");
ppmWriter.WriteToFile("ppmTestFile2.ppm", dataSet);
dataSet = ppmReader.ReadFromFile("ppmTestFile2.ppm");
TestFilledImage<PixelType>(dataSet, ppmReader.GetPointFieldName(), canvas);
}
void TestBaseImageMethods(const vtkm::rendering::Canvas& canvas)
{
auto reader = PNGReader();
TestCreateImageDataSet<RGBPixel_8>(reader, canvas);
TestCreateImageDataSet<RGBPixel_16>(reader, canvas);
TestCreateImageDataSet<GreyPixel_8>(reader, canvas);
TestCreateImageDataSet<GreyPixel_16>(reader, canvas);
}
void TestPNMImage(const vtkm::rendering::Canvas& canvas)
{
TestReadAndWritePNM<8>(canvas);
TestReadAndWritePNM<16>(canvas);
}
void TestPNGImage(const vtkm::rendering::Canvas& canvas)
{
TestReadAndWritePNG<RGBPixel_8>(canvas, "pngRGB8Test.png");
TestReadAndWritePNG<RGBPixel_16>(canvas, "pngRGB16Test.png");
TestReadAndWritePNG<GreyPixel_8>(canvas, "pngGrey8Test.png");
TestReadAndWritePNG<GreyPixel_16>(canvas, "pngGrey16Test.png");
}
void TestImage()
{
vtkm::rendering::Canvas canvas(16, 16);
canvas.SetBackgroundColor(vtkm::rendering::Color::red);
canvas.Initialize();
canvas.Activate();
canvas.Clear();
// Line from top left to bottom right, ensures correct transposedness
canvas.AddLine(-0.9, 0.9, 0.9, -0.9, 2.0f, vtkm::rendering::Color::black);
vtkm::Bounds colorBarBounds(-0.8, -0.6, -0.8, 0.8, 0, 0);
canvas.AddColorBar(colorBarBounds, vtkm::cont::ColorTable("inferno"), false);
canvas.BlendBackground();
canvas.SaveAs("baseline.ppm");
TestBaseImageMethods(canvas);
TestPNMImage(canvas);
TestPNGImage(canvas);
}
}
int UnitTestImageWriter(int argc, char* argv[])
{
return vtkm::cont::testing::Testing::Run(TestImage, argc, argv);
}

@ -0,0 +1,176 @@
//============================================================================
// 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/testing/Testing.h>
#include <vtkm/io/PixelTypes.h>
#include <string>
using namespace vtkm::io;
template <typename PixelType>
void TestPixelTypeOperations(const vtkm::UInt16& numPixels = 10)
{
using ValType = typename PixelType::ComponentType;
const ValType numBytes = static_cast<ValType>(PixelType::NUM_BYTES);
const ValType numChannels = static_cast<ValType>(PixelType::NUM_CHANNELS);
// Fill in the imageData through FillPixelData
std::vector<unsigned char> imageData(numPixels * numBytes * numChannels);
std::vector<PixelType> pixelVector(numPixels);
for (ValType i = 0; i < numPixels; i++)
{
ValType pixelVal = 0;
for (ValType j = 0, shift = numBytes - 1; j < numBytes; shift--, j++)
{
pixelVal += (i + j) << (shift * 8);
}
VTKM_LOG_S(vtkm::cont::LogLevel::Info, "pixelVal[" << i << "] = " << pixelVal);
PixelType pixel(pixelVal);
pixelVector[i] = pixel;
pixel.FillImageAtIndexWithPixel(imageData.data(), i);
}
// Test that the imageData values were set correctly
VTKM_TEST_ASSERT(static_cast<vtkm::Id>(imageData.size()) == numPixels * numChannels * numBytes,
"Wrong number of elements");
for (ValType j = 0; j < numBytes; j++)
{
for (ValType i = 0; i < numPixels; i++)
{
for (ValType k = numChannels * i; k < numChannels * i + numChannels; k++)
{
VTKM_TEST_ASSERT(imageData[k * numBytes + j] == i + j,
"Wrong value at index[" + std::to_string(k * numBytes + j) + "]: " +
std::to_string(imageData[k * numBytes + j]) + " != " +
std::to_string(i + j));
}
}
}
// Test that a pixel can be retreived from the filled out data vector
for (vtkm::Id i = 0; i < numPixels; i++)
{
VTKM_TEST_ASSERT(pixelVector[static_cast<typename std::vector<PixelType>::size_type>(i)] ==
PixelType(imageData.data(), i),
"Incorrect pixel value");
}
}
void TestDifferentPixelTypes()
{
VTKM_LOG_S(vtkm::cont::LogLevel::Info, "Testing 8 bit RGB");
TestPixelTypeOperations<RGBPixel_8>();
VTKM_LOG_S(vtkm::cont::LogLevel::Info, "Testing 8 bit Grey");
TestPixelTypeOperations<GreyPixel_8>();
VTKM_LOG_S(vtkm::cont::LogLevel::Info, "Testing 16 bit RGB");
TestPixelTypeOperations<RGBPixel_16>();
VTKM_LOG_S(vtkm::cont::LogLevel::Info, "Testing 16 bit Grey");
TestPixelTypeOperations<GreyPixel_16>();
}
void TestGreyPixelConstructors()
{
std::vector<unsigned char> initData{ 1, 2 };
auto pixel_1 = GreyPixel_8(1);
auto pixel_2 = GreyPixel_8(1);
auto pixel_3 = GreyPixel_8(2);
auto pixel_4 = GreyPixel_8(initData.data(), 0);
auto pixel_5 = GreyPixel_8(initData.data(), 1);
auto pixel_6 = GreyPixel_16(initData.data(), 0);
float color = 10.0f / GreyPixel_16::MAX_COLOR_VALUE;
auto pixel_7 = GreyPixel_16({ color, color, color, 5 });
VTKM_TEST_ASSERT(vtkm::UInt16(1) == pixel_1[0], "Type mis-match");
VTKM_TEST_ASSERT(vtkm::FloatDefault(0) == pixel_1.Diff(pixel_2), "Incorrect Diff");
VTKM_TEST_ASSERT(vtkm::FloatDefault(1) == pixel_1.Diff(pixel_3), "Incorrect Diff");
VTKM_TEST_ASSERT(vtkm::Vec4f_32(1.0f / 255, 1.0f / 255, 1.0f / 255, 1) == pixel_1.ToVec4f(),
"Incorrect Conversion");
VTKM_TEST_ASSERT(vtkm::Vec<vtkm::UInt8, 1>(1) == pixel_4, "Bad 1st value 8 bit construct");
VTKM_TEST_ASSERT(vtkm::Vec<vtkm::UInt8, 1>(2) == pixel_5, "Bad 2nd value 8 bit construct");
VTKM_TEST_ASSERT(vtkm::Vec<vtkm::UInt16, 1>(258) == pixel_6, "Bad 16 bit construct");
VTKM_TEST_ASSERT(vtkm::Vec4f_32(258.0f / 65535, 258.0f / 65535, 258.0f / 65535, 1) ==
pixel_6.ToVec4f(),
"Incorrect Conversion");
VTKM_TEST_ASSERT(vtkm::Vec<vtkm::UInt16, 1>(10) == pixel_7, "Bad Vec4f_32 construction");
VTKM_TEST_ASSERT(GreyPixel<16>::BIT_DEPTH == 16, "Bad BitDepth");
VTKM_TEST_ASSERT(GreyPixel<16>::NUM_BYTES == 2, "Bad NumBytes");
VTKM_TEST_ASSERT(GreyPixel<16>::MAX_COLOR_VALUE == 65535, "Bad NumBytes");
VTKM_TEST_ASSERT(GreyPixel<16>::NUM_CHANNELS == 1, "Bad NumChannels");
VTKM_TEST_ASSERT(GreyPixel<16>::BYTES_PER_PIXEL == 2, "Wrong Pixel Byte distance");
// Shouldn't compile
// auto pixel_4 = RGBPixel_8(1, 1, 1);
// pixel_1.Diff(pixel_4);
}
void TestRGBPixelConstructors()
{
std::vector<unsigned char> initData{ 1, 2, 3, 4, 5, 6 };
auto pixel_1 = RGBPixel_8(1, 1, 1);
auto pixel_2 = RGBPixel_8(1, 1, 1);
auto pixel_3 = RGBPixel_8(1);
auto pixel_4 = RGBPixel_8(2, 2, 2);
auto pixel_5 = RGBPixel_8(initData.data(), 0);
auto pixel_6 = RGBPixel_8(initData.data(), 1);
auto pixel_7 = RGBPixel_16(initData.data(), 0);
float color = 10.0f / RGBPixel_16::MAX_COLOR_VALUE;
auto pixel_8 = RGBPixel_16({ color, color, color, 5 });
VTKM_TEST_ASSERT(vtkm::Vec3ui_8(1, 1, 1) == pixel_1, "Type mis-match");
VTKM_TEST_ASSERT(vtkm::FloatDefault(0) == pixel_1.Diff(pixel_2), "Incorrect Diff");
VTKM_TEST_ASSERT(vtkm::FloatDefault(0) == pixel_1.Diff(pixel_3), "Incorrect Diff");
VTKM_TEST_ASSERT(vtkm::FloatDefault(3) == pixel_1.Diff(pixel_4), "Incorrect Diff");
VTKM_TEST_ASSERT(vtkm::Vec4f_32(1.0f / 255, 1.0f / 255, 1.0f / 255, 1) == pixel_1.ToVec4f(),
"Incorrect Conversion");
VTKM_TEST_ASSERT(vtkm::Vec3ui_8(1, 2, 3) == pixel_5, "Bad 1st value 8 bit construct");
VTKM_TEST_ASSERT(vtkm::Vec3ui_8(4, 5, 6) == pixel_6, "Bad 2nd value 8 bit construct");
VTKM_TEST_ASSERT(vtkm::Vec3ui_16(258, 772, 1286) == pixel_7, "Bad 16 bit construct");
VTKM_TEST_ASSERT(vtkm::Vec4f_32(258.0f / 65535, 772.0f / 65535, 1286.0f / 65535, 1) ==
pixel_7.ToVec4f(),
"Incorrect Conversion");
VTKM_TEST_ASSERT(vtkm::Vec<vtkm::UInt16, 3>(10, 10, 10) == pixel_8, "Bad Vec4f_32 construction");
VTKM_TEST_ASSERT(RGBPixel<16>::BIT_DEPTH == 16, "Bad BitDepth");
VTKM_TEST_ASSERT(RGBPixel<16>::NUM_BYTES == 2, "Bad NumBytes");
VTKM_TEST_ASSERT(RGBPixel<16>::MAX_COLOR_VALUE == 65535, "Bad NumBytes");
VTKM_TEST_ASSERT(RGBPixel<16>::NUM_CHANNELS == 3, "Bad NumChannels");
VTKM_TEST_ASSERT(RGBPixel<16>::BYTES_PER_PIXEL == 6, "Wrong Pixel Byte distance");
// Shouldn't compile
// auto pixel_8 = GreyPixel_8(1);
// pixel_1.Diff(pixel_8);
}
void TestPixelTypes()
{
VTKM_LOG_S(vtkm::cont::LogLevel::Info, "Testing RGBPixel");
TestRGBPixelConstructors();
VTKM_LOG_S(vtkm::cont::LogLevel::Info, "Testing GreyPixel");
TestGreyPixelConstructors();
VTKM_LOG_S(vtkm::cont::LogLevel::Info, "Testing Pixel Types");
TestDifferentPixelTypes();
}
int UnitTestPixelTypes(int argc, char* argv[])
{
return vtkm::cont::testing::Testing::Run(TestPixelTypes, argc, argv);
}

@ -10,6 +10,8 @@
set(headers
VTKDataSetWriter.h
)
)
vtkm_declare_headers(${headers})
vtkm_declare_headers(
${headers}
)

@ -164,15 +164,17 @@ public:
typename VisitArrayType,
typename ThreadToOutArrayType,
typename InputDomainType>
VTKM_EXEC vtkm::exec::arg::ThreadIndicesTopologyMap<InputDomainType> GetThreadIndices(
vtkm::Id threadIndex,
const OutToInArrayType& outToIn,
const VisitArrayType& visit,
const ThreadToOutArrayType& threadToOut,
const InputDomainType& connectivity) const
VTKM_EXEC vtkm::exec::arg::ThreadIndicesTopologyMap<InputDomainType,
vtkm::exec::arg::CustomScatterOrMaskTag>
GetThreadIndices(vtkm::Id threadIndex,
const OutToInArrayType& outToIn,
const VisitArrayType& visit,
const ThreadToOutArrayType& threadToOut,
const InputDomainType& connectivity) const
{
const vtkm::Id outIndex = threadToOut.Get(threadIndex);
return vtkm::exec::arg::ThreadIndicesTopologyMap<InputDomainType>(
return vtkm::exec::arg::ThreadIndicesTopologyMap<InputDomainType,
vtkm::exec::arg::CustomScatterOrMaskTag>(
threadIndex, outToIn.Get(outIndex), visit.Get(outIndex), outIndex, connectivity);
}
@ -199,7 +201,10 @@ public:
typename InputDomainType,
bool S = IsScatterIdentity,
bool M = IsMaskNone>
VTKM_EXEC EnableFnWhen<S && M, vtkm::exec::arg::ThreadIndicesTopologyMap<InputDomainType>>
VTKM_EXEC EnableFnWhen<
S && M,
vtkm::exec::arg::ThreadIndicesTopologyMap<InputDomainType,
vtkm::exec::arg::DefaultScatterAndMaskTag>>
GetThreadIndices(vtkm::Id threadIndex1D,
const vtkm::Id3& threadIndex3D,
const OutToInArrayType& vtkmNotUsed(outToIn),
@ -207,7 +212,8 @@ public:
const ThreadToOutArrayType& vtkmNotUsed(threadToOut),
const InputDomainType& connectivity) const
{
return vtkm::exec::arg::ThreadIndicesTopologyMap<InputDomainType>(
return vtkm::exec::arg::ThreadIndicesTopologyMap<InputDomainType,
vtkm::exec::arg::DefaultScatterAndMaskTag>(
threadIndex3D, threadIndex1D, connectivity);
}
@ -219,21 +225,26 @@ public:
typename InputDomainType,
bool S = IsScatterIdentity,
bool M = IsMaskNone>
VTKM_EXEC EnableFnWhen<!(S && M), vtkm::exec::arg::ThreadIndicesTopologyMap<InputDomainType>>
GetThreadIndices(vtkm::Id threadIndex1D,
const vtkm::Id3& threadIndex3D,
const OutToInArrayType& outToIn,
const VisitArrayType& visit,
const ThreadToOutArrayType& threadToOut,
const InputDomainType& connectivity) const
VTKM_EXEC
EnableFnWhen<!(S && M),
vtkm::exec::arg::ThreadIndicesTopologyMap<InputDomainType,
vtkm::exec::arg::CustomScatterOrMaskTag>>
GetThreadIndices(vtkm::Id threadIndex1D,
const vtkm::Id3& threadIndex3D,
const OutToInArrayType& outToIn,
const VisitArrayType& visit,
const ThreadToOutArrayType& threadToOut,
const InputDomainType& connectivity) const
{
const vtkm::Id outIndex = threadToOut.Get(threadIndex1D);
return vtkm::exec::arg::ThreadIndicesTopologyMap<InputDomainType>(threadIndex3D,
threadIndex1D,
outToIn.Get(outIndex),
visit.Get(outIndex),
outIndex,
connectivity);
return vtkm::exec::arg::ThreadIndicesTopologyMap<InputDomainType,
vtkm::exec::arg::CustomScatterOrMaskTag>(
threadIndex3D,
threadIndex1D,
outToIn.Get(outIndex),
visit.Get(outIndex),
outIndex,
connectivity);
}
};

@ -88,8 +88,6 @@
#include <iomanip>
#include <iostream>
//#define DEBUG_PRINT 1
namespace
{
@ -103,9 +101,10 @@ void DebugPrint(const char* msg, vtkm::cont::ArrayHandle<U>& array)
{
vtkm::Id count = 20;
count = std::min(count, array.GetNumberOfValues());
auto portal = array.ReadPortal();
std::cout << std::setw(15) << msg << ": ";
for (vtkm::Id i = 0; i < count; i++)
std::cout << std::setprecision(3) << std::setw(5) << array.ReadPortal().Get(i) << " ";
std::cout << std::setprecision(3) << std::setw(5) << portal.Get(i) << " ";
std::cout << std::endl;
}
@ -114,9 +113,10 @@ void DebugPrint(const char* msg, vtkm::cont::ArrayHandleReverse<vtkm::cont::Arra
{
vtkm::Id count = 20;
count = std::min(count, array.GetNumberOfValues());
auto portal = array.ReadPortal();
std::cout << std::setw(15) << msg << ": ";
for (vtkm::Id i = 0; i < count; i++)
std::cout << std::setw(5) << array.ReadPortal().Get(i) << " ";
std::cout << std::setw(5) << portal.Get(i) << " ";
std::cout << std::endl;
}
}

@ -50,7 +50,10 @@ struct PointGradient : public vtkm::worklet::WorkletVisitPointsWithCells
const WholeFieldIn& inputField,
GradientOutType& outputGradient) const
{
using CellThreadIndices = vtkm::exec::arg::ThreadIndicesTopologyMap<CellSetInType>;
// Use optimized ThreadIndicesTopologyMap
using CellThreadIndices =
vtkm::exec::arg::ThreadIndicesTopologyMap<CellSetInType,
vtkm::exec::arg::DefaultScatterAndMaskTag>;
using ValueType = typename WholeFieldIn::ValueType;
using CellShapeTag = typename CellSetInType::CellShapeTag;

@ -191,16 +191,18 @@ void TestCellGradientUniform3DWithVectorField2()
{ { 10.025, 10.025, 10.025 }, { 30.075, 30.075, 30.075 }, { 60.175, 60.175, 60.175 } }
};
auto vorticityPortal = extraOutput.Vorticity.ReadPortal();
auto divergencePortal = extraOutput.Divergence.ReadPortal();
for (int i = 0; i < 4; ++i)
{
vtkm::Vec<vtkm::Vec3f_64, 3> eg = expected_gradients[i];
vtkm::Float64 d = extraOutput.Divergence.ReadPortal().Get(i);
vtkm::Float64 d = divergencePortal.Get(i);
VTKM_TEST_ASSERT(test_equal((eg[0][0] + eg[1][1] + eg[2][2]), d),
"Wrong result for Divergence on 3D uniform data");
vtkm::Vec3f_64 ev(eg[1][2] - eg[2][1], eg[2][0] - eg[0][2], eg[0][1] - eg[1][0]);
vtkm::Vec3f_64 v = extraOutput.Vorticity.ReadPortal().Get(i);
vtkm::Vec3f_64 v = vorticityPortal.Get(i);
VTKM_TEST_ASSERT(test_equal(ev, v), "Wrong result for Vorticity on 3D uniform data");
}
}
@ -220,9 +222,10 @@ void TestCellGradientExplicit()
result = gradient.Run(dataSet.GetCellSet(), dataSet.GetCoordinateSystem(), input);
vtkm::Vec3f_32 expected[2] = { { 10.f, 10.1f, 0.0f }, { 10.f, 10.1f, -0.0f } };
auto resultPortal = result.ReadPortal();
for (int i = 0; i < 2; ++i)
{
VTKM_TEST_ASSERT(test_equal(result.ReadPortal().Get(i), expected[i]),
VTKM_TEST_ASSERT(test_equal(resultPortal.Get(i), expected[i]),
"Wrong result for CellGradient worklet on 3D explicit data");
}
}

@ -36,9 +36,11 @@ bool TestArrayHandle(const vtkm::cont::ArrayHandle<T, Storage>& ah,
return false;
}
auto ahPortal = ah.ReadPortal();
auto expectedPortal = expected.ReadPortal();
for (vtkm::Id i = 0; i < size; ++i)
{
if (ah.ReadPortal().Get(i) != expected.ReadPortal().Get(i))
if (ahPortal.Get(i) != expectedPortal.Get(i))
{
return false;
}