diff --git a/benchmarking/CMakeLists.txt b/benchmarking/CMakeLists.txt index a504d395e..bbfbd8c2a 100644 --- a/benchmarking/CMakeLists.txt +++ b/benchmarking/CMakeLists.txt @@ -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}) diff --git a/docs/changelog/vtk-io-in-library.md b/docs/changelog/vtk-io-in-library.md new file mode 100644 index 000000000..37ed2f4f9 --- /dev/null +++ b/docs/changelog/vtk-io-in-library.md @@ -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. diff --git a/examples/clipping/CMakeLists.txt b/examples/clipping/CMakeLists.txt index 6f26353ce..46bc5bf18 100644 --- a/examples/clipping/CMakeLists.txt +++ b/examples/clipping/CMakeLists.txt @@ -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 diff --git a/examples/hello_worklet/CMakeLists.txt b/examples/hello_worklet/CMakeLists.txt index 806f69b57..eff9dfcae 100644 --- a/examples/hello_worklet/CMakeLists.txt +++ b/examples/hello_worklet/CMakeLists.txt @@ -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 diff --git a/examples/mesh_quality/CMakeLists.txt b/examples/mesh_quality/CMakeLists.txt index 3987f3da2..6308b37b6 100644 --- a/examples/mesh_quality/CMakeLists.txt +++ b/examples/mesh_quality/CMakeLists.txt @@ -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) diff --git a/examples/particle_advection/CMakeLists.txt b/examples/particle_advection/CMakeLists.txt index 5c0b9a006..7866c56c6 100644 --- a/examples/particle_advection/CMakeLists.txt +++ b/examples/particle_advection/CMakeLists.txt @@ -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) diff --git a/examples/redistribute_points/CMakeLists.txt b/examples/redistribute_points/CMakeLists.txt index 8a2ff67e9..59948d79f 100644 --- a/examples/redistribute_points/CMakeLists.txt +++ b/examples/redistribute_points/CMakeLists.txt @@ -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) diff --git a/examples/temporal_advection/CMakeLists.txt b/examples/temporal_advection/CMakeLists.txt index 027a24f7a..eeed9ff44 100644 --- a/examples/temporal_advection/CMakeLists.txt +++ b/examples/temporal_advection/CMakeLists.txt @@ -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) diff --git a/examples/tetrahedra/CMakeLists.txt b/examples/tetrahedra/CMakeLists.txt index c894daee5..7bd8a4e67 100644 --- a/examples/tetrahedra/CMakeLists.txt +++ b/examples/tetrahedra/CMakeLists.txt @@ -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 diff --git a/vtkm/filter/testing/CMakeLists.txt b/vtkm/filter/testing/CMakeLists.txt index 72a572eeb..ab23e36be 100644 --- a/vtkm/filter/testing/CMakeLists.txt +++ b/vtkm/filter/testing/CMakeLists.txt @@ -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 ) diff --git a/vtkm/io/BOVDataSetReader.cxx b/vtkm/io/BOVDataSetReader.cxx new file mode 100644 index 000000000..d66498692 --- /dev/null +++ b/vtkm/io/BOVDataSetReader.cxx @@ -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 + +#include +#include +#include + +#include + +namespace +{ + +enum class DataFormat +{ + ByteData, + ShortData, + IntegerData, + FloatData, + DoubleData +}; + +template +void ReadBuffer(const std::string& fName, const vtkm::Id& sz, std::vector& buff) +{ + FILE* fp = fopen(fName.c_str(), "rb"); + size_t readSize = static_cast(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 +void ReadScalar(const std::string& fName, const vtkm::Id& nTuples, vtkm::cont::ArrayHandle& var) +{ + std::vector 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(i)]); + } +} + +template +void ReadVector(const std::string& fName, + const vtkm::Id& nTuples, + vtkm::cont::ArrayHandle>& var) +{ + std::vector buff; + ReadBuffer(fName, nTuples * 3, buff); + + var.Allocate(nTuples); + vtkm::Vec v; + auto writePortal = var.WritePortal(); + for (vtkm::Id i = 0; i < nTuples; i++) + { + v[0] = buff[static_cast(i * 3 + 0)]; + v[1] = buff[static_cast(i * 3 + 1)]; + v[2] = buff[static_cast(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<<"::"<> 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(dim[0] - 1); + spacing[1] = (spacing[1]) / static_cast(dim[1] - 1); + spacing[2] = (spacing[2]) / static_cast(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 var; + ReadScalar(fullPathDataFile, numTuples, var); + dsf.AddPointField(this->DataSet, variableName, var); + } + else if (dataFormat == DataFormat::DoubleData) + { + vtkm::cont::ArrayHandle var; + ReadScalar(fullPathDataFile, numTuples, var); + dsf.AddPointField(this->DataSet, variableName, var); + } + } + else if (numComponents == 3) + { + if (dataFormat == DataFormat::FloatData) + { + vtkm::cont::ArrayHandle var; + ReadVector(fullPathDataFile, numTuples, var); + dsf.AddPointField(this->DataSet, variableName, var); + } + else if (dataFormat == DataFormat::DoubleData) + { + vtkm::cont::ArrayHandle var; + ReadVector(fullPathDataFile, numTuples, var); + dsf.AddPointField(this->DataSet, variableName, var); + } + } + + this->Loaded = true; +} +} +} // namespace vtkm::io diff --git a/vtkm/io/BOVDataSetReader.h b/vtkm/io/BOVDataSetReader.h index c8981a800..dbd2147c5 100644 --- a/vtkm/io/BOVDataSetReader.h +++ b/vtkm/io/BOVDataSetReader.h @@ -10,234 +10,25 @@ #ifndef vtk_m_io_BOVDataSetReader_h #define vtk_m_io_BOVDataSetReader_h -#include #include -#include -#include -#include + +#include 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<<"::"<> 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(dim[0] - 1); - spacing[1] = (spacing[1]) / static_cast(dim[1] - 1); - spacing[2] = (spacing[2]) / static_cast(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 var; - ReadScalar(fullPathDataFile, numTuples, var); - dsf.AddPointField(this->DataSet, variableName, var); - } - else if (dataFormat == DoubleData) - { - vtkm::cont::ArrayHandle var; - ReadScalar(fullPathDataFile, numTuples, var); - dsf.AddPointField(this->DataSet, variableName, var); - } - } - else if (numComponents == 3) - { - if (dataFormat == FloatData) - { - vtkm::cont::ArrayHandle var; - ReadVector(fullPathDataFile, numTuples, var); - dsf.AddPointField(this->DataSet, variableName, var); - } - else if (dataFormat == DoubleData) - { - vtkm::cont::ArrayHandle var; - ReadVector(fullPathDataFile, numTuples, var); - dsf.AddPointField(this->DataSet, variableName, var); - } - } - - this->Loaded = true; - } - - template - void ReadBuffer(const std::string& fName, const vtkm::Id& sz, std::vector& buff) - { - FILE* fp = fopen(fName.c_str(), "rb"); - size_t readSize = static_cast(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 - void ReadScalar(const std::string& fName, - const vtkm::Id& nTuples, - vtkm::cont::ArrayHandle& var) - { - std::vector buff; - ReadBuffer(fName, nTuples, buff); - var.Allocate(nTuples); - auto writePortal = var.WritePortal(); - for (vtkm::Id i = 0; i < nTuples; i++) - writePortal.Set(i, buff[(size_t)i]); - } - - template - void ReadVector(const std::string& fName, - const vtkm::Id& nTuples, - vtkm::cont::ArrayHandle>& var) - { - std::vector buff; - ReadBuffer(fName, nTuples * 3, buff); - - var.Allocate(nTuples); - vtkm::Vec v; - auto writePortal = var.WritePortal(); - for (vtkm::Id i = 0; i < nTuples; i++) - { - v[0] = buff[static_cast(i * 3 + 0)]; - v[1] = buff[static_cast(i * 3 + 1)]; - v[2] = buff[static_cast(i * 3 + 2)]; - writePortal.Set(i, v); - } - } + VTKM_CONT void LoadFile(); std::string FileName; bool Loaded; diff --git a/vtkm/io/CMakeLists.txt b/vtkm/io/CMakeLists.txt index 7d8bc7660..6c9eaeedb 100644 --- a/vtkm/io/CMakeLists.txt +++ b/vtkm/io/CMakeLists.txt @@ -18,12 +18,12 @@ set(headers PixelTypes.h VTKDataSetReader.h VTKDataSetReaderBase.h + VTKDataSetWriter.h VTKPolyDataReader.h VTKRectilinearGridReader.h VTKStructuredGridReader.h VTKStructuredPointsReader.h VTKUnstructuredGridReader.h - VTKDataSetWriter.h ) set(template_sources @@ -37,6 +37,22 @@ set(sources EncodePNG.cxx ) +# 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_declare_headers( ${headers} ${template_sources} @@ -45,6 +61,7 @@ vtkm_declare_headers( vtkm_library( NAME vtkm_io SOURCES ${sources} + DEVICE_SOURCES ${device_sources} HEADERS ${headers} TEMPLATE_SOURCES ${template_sources} ) diff --git a/vtkm/io/VTKDataSetReader.cxx b/vtkm/io/VTKDataSetReader.cxx new file mode 100644 index 000000000..a1fdbbdb9 --- /dev/null +++ b/vtkm/io/VTKDataSetReader.cxx @@ -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 + +#include +#include +#include +#include +#include + +#include + +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 diff --git a/vtkm/io/VTKDataSetReader.h b/vtkm/io/VTKDataSetReader.h index 166c9466d..49e4b4537 100644 --- a/vtkm/io/VTKDataSetReader.h +++ b/vtkm/io/VTKDataSetReader.h @@ -11,86 +11,27 @@ #define vtk_m_io_VTKDataSetReader_h #include -#include -#include -#include -#include -#include - -#include 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 Reader; }; diff --git a/vtkm/io/VTKDataSetReaderBase.cxx b/vtkm/io/VTKDataSetReaderBase.cxx new file mode 100644 index 000000000..dcbace6e5 --- /dev/null +++ b/vtkm/io/VTKDataSetReaderBase.cxx @@ -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 + +#include +#include +#include +#include +#include + +#include +#include +#include + +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 +struct ClosestCommonType +{ + using Type = T; +}; +template <> +struct ClosestCommonType +{ + using Type = vtkm::Int32; +}; +template <> +struct ClosestCommonType +{ + using Type = vtkm::Int32; +}; +template <> +struct ClosestCommonType +{ + using Type = vtkm::Int32; +}; +template <> +struct ClosestCommonType +{ + using Type = vtkm::Int32; +}; +template <> +struct ClosestCommonType +{ + using Type = vtkm::Int64; +}; +template <> +struct ClosestCommonType +{ + using Type = vtkm::Int64; +}; + +template +struct ClosestFloat +{ + using Type = T; +}; +template <> +struct ClosestFloat +{ + using Type = vtkm::Float32; +}; +template <> +struct ClosestFloat +{ + using Type = vtkm::Float32; +}; +template <> +struct ClosestFloat +{ + using Type = vtkm::Float32; +}; +template <> +struct ClosestFloat +{ + using Type = vtkm::Float32; +}; +template <> +struct ClosestFloat +{ + using Type = vtkm::Float64; +}; +template <> +struct ClosestFloat +{ + using Type = vtkm::Float64; +}; +template <> +struct ClosestFloat +{ + using Type = vtkm::Float64; +}; +template <> +struct ClosestFloat +{ + using Type = vtkm::Float64; +}; + +template +vtkm::cont::VariantArrayHandle CreateVariantArrayHandle(const std::vector& vec) +{ + switch (vtkm::VecTraits::NUM_COMPONENTS) + { + case 1: + { + using CommonType = typename ClosestCommonType::Type; + constexpr bool not_same = !std::is_same::value; + if (not_same) + { + VTKM_LOG_S(vtkm::cont::LogLevel::Info, + "Type " << vtkm::io::internal::DataTypeName::Name() + << " is currently unsupported. Converting to " + << vtkm::io::internal::DataTypeName::Name() + << "."); + } + + vtkm::cont::ArrayHandle output; + output.Allocate(static_cast(vec.size())); + auto portal = output.WritePortal(); + for (vtkm::Id i = 0; i < output.GetNumberOfValues(); ++i) + { + portal.Set(i, static_cast(vec[static_cast(i)])); + } + + return vtkm::cont::VariantArrayHandle(output); + } + case 2: + case 3: + case 9: + { + constexpr auto numComps = vtkm::VecTraits::NUM_COMPONENTS; + + using InComponentType = typename vtkm::VecTraits::ComponentType; + using OutComponentType = typename ClosestFloat::Type; + using CommonType = vtkm::Vec; + constexpr bool not_same = !std::is_same::value; + if (not_same) + { + VTKM_LOG_S(vtkm::cont::LogLevel::Info, + "Type " << vtkm::io::internal::DataTypeName::Name() << "[" + << vtkm::VecTraits::GetNumberOfComponents(T()) + << "] " + << "is currently unsupported. Converting to " + << vtkm::io::internal::DataTypeName::Name() + << "[" + << numComps + << "]."); + } + + vtkm::cont::ArrayHandle output; + output.Allocate(static_cast(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( + vtkm::VecTraits::GetComponent(vec[static_cast(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()); + } + } +} + +} // 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& connectivity, + vtkm::cont::ArrayHandle& numIndices) +{ + vtkm::Id numCells, numInts; + this->DataFile->Stream >> numCells >> numInts >> std::ws; + + connectivity.Allocate(numInts - numCells); + numIndices.Allocate(numCells); + + std::vector buffer(static_cast(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(*buffp++); + numIndicesPortal.Set(i, numInds); + for (vtkm::IdComponent j = 0; j < numInds; ++j, ++connInd) + { + connectivityPortal.Set(connInd, static_cast(*buffp++)); + } + } +} + +void VTKDataSetReaderBase::ReadShapes(vtkm::cont::ArrayHandle& shapes) +{ + std::string tag; + vtkm::Id numCells; + this->DataFile->Stream >> tag >> numCells >> std::ws; + internal::parseAssert(tag == "CELL_TYPES"); + + shapes.Allocate(numCells); + std::vector buffer(static_cast(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(*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()); +} + +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* 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 + void operator()(T) const + { + this->Reader->SkipArray(this->NumElements, T()); + } + + template + void operator()(vtkm::IdComponent numComponents, T) const + { + this->Reader->SkipArray(this->NumElements * static_cast(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 + void operator()(T) const + { + std::vector 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 permutedBuffer(static_cast(outSize)); + for (vtkm::Id outIndex = 0; outIndex < outSize; outIndex++) + { + std::size_t inIndex = static_cast(permutation.Get(outIndex)); + permutedBuffer[static_cast(outIndex)] = buffer[inIndex]; + } + *this->Data = CreateVariantArrayHandle(permutedBuffer); + } + } + + template + 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(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 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& 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(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 diff --git a/vtkm/io/VTKDataSetReaderBase.h b/vtkm/io/VTKDataSetReaderBase.h index 70292392c..245d46eb0 100644 --- a/vtkm/io/VTKDataSetReaderBase.h +++ b/vtkm/io/VTKDataSetReaderBase.h @@ -10,25 +10,16 @@ #ifndef vtk_m_io_VTKDataSetReaderBase_h #define vtk_m_io_VTKDataSetReaderBase_h +#include +#include +#include +#include + #include -#include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include #include -#include -#include 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 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 -struct ClosestCommonType -{ - using Type = T; -}; -template <> -struct ClosestCommonType -{ - using Type = vtkm::Int32; -}; -template <> -struct ClosestCommonType -{ - using Type = vtkm::Int32; -}; -template <> -struct ClosestCommonType -{ - using Type = vtkm::Int32; -}; -template <> -struct ClosestCommonType -{ - using Type = vtkm::Int32; -}; -template <> -struct ClosestCommonType -{ - using Type = vtkm::Int64; -}; -template <> -struct ClosestCommonType -{ - using Type = vtkm::Int64; -}; - -template -struct ClosestFloat -{ - using Type = T; -}; -template <> -struct ClosestFloat -{ - using Type = vtkm::Float32; -}; -template <> -struct ClosestFloat -{ - using Type = vtkm::Float32; -}; -template <> -struct ClosestFloat -{ - using Type = vtkm::Float32; -}; -template <> -struct ClosestFloat -{ - using Type = vtkm::Float32; -}; -template <> -struct ClosestFloat -{ - using Type = vtkm::Float64; -}; -template <> -struct ClosestFloat -{ - using Type = vtkm::Float64; -}; -template <> -struct ClosestFloat -{ - using Type = vtkm::Float64; -}; -template <> -struct ClosestFloat -{ - using Type = vtkm::Float64; -}; - -template -vtkm::cont::VariantArrayHandle CreateVariantArrayHandle(const std::vector& vec) -{ - switch (vtkm::VecTraits::NUM_COMPONENTS) - { - case 1: - { - using CommonType = typename ClosestCommonType::Type; - constexpr bool not_same = !std::is_same::value; - if (not_same) - { - VTKM_LOG_S(vtkm::cont::LogLevel::Info, - "Type " << vtkm::io::internal::DataTypeName::Name() - << " is currently unsupported. Converting to " - << vtkm::io::internal::DataTypeName::Name() - << "."); - } - - vtkm::cont::ArrayHandle output; - output.Allocate(static_cast(vec.size())); - auto portal = output.WritePortal(); - for (vtkm::Id i = 0; i < output.GetNumberOfValues(); ++i) - { - portal.Set(i, static_cast(vec[static_cast(i)])); - } - - return vtkm::cont::VariantArrayHandle(output); - } - case 2: - case 3: - case 9: - { - constexpr auto numComps = vtkm::VecTraits::NUM_COMPONENTS; - - using InComponentType = typename vtkm::VecTraits::ComponentType; - using OutComponentType = typename ClosestFloat::Type; - using CommonType = vtkm::Vec; - constexpr bool not_same = !std::is_same::value; - if (not_same) - { - VTKM_LOG_S(vtkm::cont::LogLevel::Info, - "Type " << vtkm::io::internal::DataTypeName::Name() << "[" - << vtkm::VecTraits::GetNumberOfComponents(T()) - << "] " - << "is currently unsupported. Converting to " - << vtkm::io::internal::DataTypeName::Name() - << "[" - << numComps - << "]."); - } - - vtkm::cont::ArrayHandle output; - output.Allocate(static_cast(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( - vtkm::VecTraits::GetComponent(vec[static_cast(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()); - } - } -} - 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 DataFile; + vtkm::cont::DataSet DataSet; + +private: + bool Loaded; + vtkm::cont::ArrayHandle 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& connectivity, + vtkm::cont::ArrayHandle& numIndices); - this->DataSet.AddCoordinateSystem(vtkm::cont::CoordinateSystem("coordinates", points)); - } + VTKM_CONT void ReadShapes(vtkm::cont::ArrayHandle& shapes); - void ReadCells(vtkm::cont::ArrayHandle& connectivity, - vtkm::cont::ArrayHandle& numIndices) - { - vtkm::Id numCells, numInts; - this->DataFile->Stream >> numCells >> numInts >> std::ws; - - connectivity.Allocate(numInts - numCells); - numIndices.Allocate(numCells); - - std::vector buffer(static_cast(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(*buffp++); - numIndicesPortal.Set(i, numInds); - for (vtkm::IdComponent j = 0; j < numInds; ++j, ++connInd) - { - connectivityPortal.Set(connInd, static_cast(*buffp++)); - } - } - } - - void ReadShapes(vtkm::cont::ArrayHandle& shapes) - { - std::string tag; - vtkm::Id numCells; - this->DataFile->Stream >> tag >> numCells >> std::ws; - internal::parseAssert(tag == "CELL_TYPES"); - - shapes.Allocate(numCells); - std::vector buffer(static_cast(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(*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& permutation) { this->CellsPermutation = permutation; } - vtkm::cont::ArrayHandle GetCellsPermutation() const { return this->CellsPermutation; } + VTKM_CONT vtkm::cont::ArrayHandle 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()); - } - - 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* 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* visitBounds = nullptr); private: - class SkipArrayVariant - { - public: - SkipArrayVariant(VTKDataSetReaderBase* reader, std::size_t numElements) - : Reader(reader) - , NumElements(numElements) - { - } - - template - void operator()(T) const - { - this->Reader->SkipArray(this->NumElements, T()); - } - - template - void operator()(vtkm::IdComponent numComponents, T) const - { - this->Reader->SkipArray(this->NumElements * static_cast(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 - void operator()(T) const - { - std::vector 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 permutedBuffer(static_cast(outSize)); - for (vtkm::Id outIndex = 0; outIndex < outSize; outIndex++) - { - std::size_t inIndex = static_cast(permutation.Get(outIndex)); - permutedBuffer[static_cast(outIndex)] = buffer[inIndex]; - } - *this->Data = internal::CreateVariantArrayHandle(permutedBuffer); - } - } - - template - 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(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 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 - void ReadArray(std::vector& buffer) + VTKM_CONT void ReadArray(std::vector& buffer) { using ComponentType = typename vtkm::VecTraits::ComponentType; constexpr vtkm::IdComponent numComponents = vtkm::VecTraits::NUM_COMPONENTS; @@ -861,7 +220,8 @@ protected: } template - void ReadArray(std::vector>& buffer) + VTKM_CONT void ReadArray( + std::vector>& 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& 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& buffer); template 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(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 DataFile; - vtkm::cont::DataSet DataSet; - -private: - bool Loaded; - vtkm::cont::ArrayHandle 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 diff --git a/vtkm/io/VTKDataSetWriter.cxx b/vtkm/io/VTKDataSetWriter.cxx new file mode 100644 index 000000000..6f3eac1a3 --- /dev/null +++ b/vtkm/io/VTKDataSetWriter.cxx @@ -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 + +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace +{ + +struct OutputPointsFunctor +{ +private: + std::ostream& out; + + template + 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; + + 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 + VTKM_CONT void operator()(const vtkm::cont::ArrayHandle& array) const + { + this->Output(array.ReadPortal()); + } +}; + +struct OutputFieldFunctor +{ +private: + std::ostream& out; + + template + 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; + + 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 + VTKM_CONT void operator()(const vtkm::cont::ArrayHandle& array) const + { + this->Output(array.ReadPortal()); + } +}; + +class GetDataTypeName +{ +public: + GetDataTypeName(std::string& name) + : Name(&name) + { + } + + template + void operator()(const ArrayHandleType&) const + { + using DataType = typename vtkm::VecTraits::ComponentType; + *this->Name = vtkm::io::internal::DataTypeName::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::Name() + << " " << '\n'; + + OutputPointsFunctor{ out }(cdata); +} + +template +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 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 +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 +void WriteDataSetAsStructured(std::ostream& out, + const vtkm::cont::DataSet& dataSet, + const vtkm::cont::CellSetStructured& cellSet) +{ + ///\todo: support uniform/rectilinear + out << "DATASET STRUCTURED_GRID" << '\n'; + + auto pointDimensions = cellSet.GetPointDimensions(); + using VTraits = vtkm::VecTraits; + + 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>()) + { + WriteDataSetAsUnstructured(out, dataSet, cellSet.Cast>()); + } + else if (cellSet.IsType>()) + { + WriteDataSetAsStructured(out, dataSet, cellSet.Cast>()); + } + else if (cellSet.IsType>()) + { + WriteDataSetAsStructured(out, dataSet, cellSet.Cast>()); + } + else if (cellSet.IsType>()) + { + WriteDataSetAsStructured(out, dataSet, cellSet.Cast>()); + } + else if (cellSet.IsType>()) + { + // these function just like explicit cell sets + WriteDataSetAsUnstructured(out, dataSet, cellSet.Cast>()); + } + 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 diff --git a/vtkm/io/VTKDataSetWriter.h b/vtkm/io/VTKDataSetWriter.h index 946ac5c3d..e666f0b7d 100644 --- a/vtkm/io/VTKDataSetWriter.h +++ b/vtkm/io/VTKDataSetWriter.h @@ -10,400 +10,22 @@ #ifndef vtk_m_io_DataSetWriter_h #define vtk_m_io_DataSetWriter_h -#include -#include - -#include -#include -#include #include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include +#include namespace vtkm { namespace io { -namespace detail -{ -struct OutputPointsFunctor -{ -private: - std::ostream& out; - - template - 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; - - 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 - VTKM_CONT void operator()(const vtkm::cont::ArrayHandle& array) const - { - this->Output(array.ReadPortal()); - } -}; - -struct OutputFieldFunctor -{ -private: - std::ostream& out; - - template - 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; - - 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 - VTKM_CONT void operator()(const vtkm::cont::ArrayHandle& 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 - void operator()(const ArrayHandleType&) const - { - using DataType = typename vtkm::VecTraits::ComponentType; - *this->Name = vtkm::io::internal::DataTypeName::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::Name() << " " << '\n'; - - detail::OutputPointsFunctor{ out }(cdata); - } - - template - 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 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 - 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 - static void WriteDataSetAsStructured(std::ostream& out, - const vtkm::cont::DataSet& dataSet, - const vtkm::cont::CellSetStructured& cellSet) - { - ///\todo: support uniform/rectilinear - out << "DATASET STRUCTURED_GRID" << '\n'; - - auto pointDimensions = cellSet.GetPointDimensions(); - using VTraits = vtkm::VecTraits; - - 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>()) - { - WriteDataSetAsUnstructured(out, dataSet, cellSet.Cast>()); - } - else if (cellSet.IsType>()) - { - WriteDataSetAsStructured(out, dataSet, cellSet.Cast>()); - } - else if (cellSet.IsType>()) - { - WriteDataSetAsStructured(out, dataSet, cellSet.Cast>()); - } - else if (cellSet.IsType>()) - { - WriteDataSetAsStructured(out, dataSet, cellSet.Cast>()); - } - else if (cellSet.IsType>()) - { - // these function just like explicit cell sets - WriteDataSetAsUnstructured(out, dataSet, cellSet.Cast>()); - } - 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; diff --git a/vtkm/io/VTKPolyDataReader.cxx b/vtkm/io/VTKPolyDataReader.cxx new file mode 100644 index 000000000..e134d6160 --- /dev/null +++ b/vtkm/io/VTKPolyDataReader.cxx @@ -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 + +namespace +{ + +template +inline vtkm::cont::ArrayHandle ConcatinateArrayHandles( + const std::vector>& arrays) +{ + vtkm::Id size = 0; + for (std::size_t i = 0; i < arrays.size(); ++i) + { + size += arrays[i].GetNumberOfValues(); + } + + vtkm::cont::ArrayHandle 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::difference_type; + std::advance(outp, static_cast(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> connectivityArrays; + std::vector> numIndicesArrays; + std::vector 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(tag.length()), std::ios_base::cur); + break; + } + + vtkm::cont::ArrayHandle cellConnectivity; + vtkm::cont::ArrayHandle cellNumIndices; + this->ReadCells(cellConnectivity, cellNumIndices); + + connectivityArrays.push_back(cellConnectivity); + numIndicesArrays.push_back(cellNumIndices); + shapesBuffer.insert( + shapesBuffer.end(), static_cast(cellNumIndices.GetNumberOfValues()), shape); + } + + vtkm::cont::ArrayHandle connectivity = ConcatinateArrayHandles(connectivityArrays); + vtkm::cont::ArrayHandle numIndices = ConcatinateArrayHandles(numIndicesArrays); + vtkm::cont::ArrayHandle shapes; + shapes.Allocate(static_cast(shapesBuffer.size())); + std::copy(shapesBuffer.begin(), + shapesBuffer.end(), + vtkm::cont::ArrayPortalToIteratorBegin(shapes.WritePortal())); + + vtkm::cont::ArrayHandle 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 diff --git a/vtkm/io/VTKPolyDataReader.h b/vtkm/io/VTKPolyDataReader.h index 3629f62ca..449c1747f 100644 --- a/vtkm/io/VTKPolyDataReader.h +++ b/vtkm/io/VTKPolyDataReader.h @@ -11,6 +11,7 @@ #define vtk_m_io_VTKPolyDataReader_h #include +#include #include @@ -21,147 +22,15 @@ namespace vtkm namespace io { -namespace internal -{ - -template -inline vtkm::cont::ArrayHandle ConcatinateArrayHandles( - const std::vector>& arrays) -{ - vtkm::Id size = 0; - for (std::size_t i = 0; i < arrays.size(); ++i) - { - size += arrays[i].GetNumberOfValues(); - } - - vtkm::cont::ArrayHandle 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::difference_type; - std::advance(outp, static_cast(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> connectivityArrays; - std::vector> numIndicesArrays; - std::vector 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(tag.length()), - std::ios_base::cur); - break; - } - - vtkm::cont::ArrayHandle cellConnectivity; - vtkm::cont::ArrayHandle cellNumIndices; - this->ReadCells(cellConnectivity, cellNumIndices); - - connectivityArrays.push_back(cellConnectivity); - numIndicesArrays.push_back(cellNumIndices); - shapesBuffer.insert( - shapesBuffer.end(), static_cast(cellNumIndices.GetNumberOfValues()), shape); - } - - vtkm::cont::ArrayHandle connectivity = - internal::ConcatinateArrayHandles(connectivityArrays); - vtkm::cont::ArrayHandle numIndices = - internal::ConcatinateArrayHandles(numIndicesArrays); - vtkm::cont::ArrayHandle shapes; - shapes.Allocate(static_cast(shapesBuffer.size())); - std::copy(shapesBuffer.begin(), - shapesBuffer.end(), - vtkm::cont::ArrayPortalToIteratorBegin(shapes.WritePortal())); - - vtkm::cont::ArrayHandle 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 diff --git a/vtkm/io/VTKRectilinearGridReader.cxx b/vtkm/io/VTKRectilinearGridReader.cxx new file mode 100644 index 000000000..9dcf3a5ca --- /dev/null +++ b/vtkm/io/VTKRectilinearGridReader.cxx @@ -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 + +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::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(numPoints[0]), + static_cast(numPoints[1]), + static_cast(numPoints[2]))) + throw vtkm::io::ErrorIO("DIMENSIONS not equal to number of points"); + + vtkm::cont::ArrayHandleCartesianProduct, + vtkm::cont::ArrayHandle, + vtkm::cont::ArrayHandle> + coords; + + vtkm::cont::ArrayHandle 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 diff --git a/vtkm/io/VTKRectilinearGridReader.h b/vtkm/io/VTKRectilinearGridReader.h index 92a5c6e05..37c681c28 100644 --- a/vtkm/io/VTKRectilinearGridReader.h +++ b/vtkm/io/VTKRectilinearGridReader.h @@ -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::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(numPoints[0]), - static_cast(numPoints[1]), - static_cast(numPoints[2]))) - throw vtkm::io::ErrorIO("DIMENSIONS not equal to number of points"); - - vtkm::cont::ArrayHandleCartesianProduct, - vtkm::cont::ArrayHandle, - vtkm::cont::ArrayHandle> - coords; - - vtkm::cont::ArrayHandle 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 diff --git a/vtkm/io/VTKStructuredGridReader.cxx b/vtkm/io/VTKStructuredGridReader.cxx new file mode 100644 index 000000000..76b7d2101 --- /dev/null +++ b/vtkm/io/VTKStructuredGridReader.cxx @@ -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 + +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 diff --git a/vtkm/io/VTKStructuredGridReader.h b/vtkm/io/VTKStructuredGridReader.h index b37e98301..745cef2b7 100644 --- a/vtkm/io/VTKStructuredGridReader.h +++ b/vtkm/io/VTKStructuredGridReader.h @@ -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 diff --git a/vtkm/io/VTKStructuredPointsReader.cxx b/vtkm/io/VTKStructuredPointsReader.cxx new file mode 100644 index 000000000..1293da374 --- /dev/null +++ b/vtkm/io/VTKStructuredPointsReader.cxx @@ -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 + +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 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((visitBounds[1] - visitBounds[0]) / spacing[0]); + dim[1] = static_cast((visitBounds[3] - visitBounds[2]) / spacing[1]); + dim[2] = static_cast((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 diff --git a/vtkm/io/VTKStructuredPointsReader.h b/vtkm/io/VTKStructuredPointsReader.h index 17d786380..2e998f96f 100644 --- a/vtkm/io/VTKStructuredPointsReader.h +++ b/vtkm/io/VTKStructuredPointsReader.h @@ -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 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((visitBounds[1] - visitBounds[0]) / spacing[0]); - dim[1] = static_cast((visitBounds[3] - visitBounds[2]) / spacing[1]); - dim[2] = static_cast((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 diff --git a/vtkm/io/VTKUnstructuredGridReader.cxx b/vtkm/io/VTKUnstructuredGridReader.cxx new file mode 100644 index 000000000..0fb69cacb --- /dev/null +++ b/vtkm/io/VTKUnstructuredGridReader.cxx @@ -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 + +#include + +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 connectivity; + vtkm::cont::ArrayHandle numIndices; + vtkm::cont::ArrayHandle shapes; + + this->DataFile->Stream >> tag; + internal::parseAssert(tag == "CELLS"); + + this->ReadCells(connectivity, numIndices); + this->ReadShapes(shapes); + + vtkm::cont::ArrayHandle 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(); +} +} +} diff --git a/vtkm/io/VTKUnstructuredGridReader.h b/vtkm/io/VTKUnstructuredGridReader.h index bee4e06f8..4d60e1d39 100644 --- a/vtkm/io/VTKUnstructuredGridReader.h +++ b/vtkm/io/VTKUnstructuredGridReader.h @@ -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 connectivity; - vtkm::cont::ArrayHandle numIndices; - vtkm::cont::ArrayHandle shapes; - - this->DataFile->Stream >> tag; - internal::parseAssert(tag == "CELLS"); - - this->ReadCells(connectivity, numIndices); - this->ReadShapes(shapes); - - vtkm::cont::ArrayHandle 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 diff --git a/vtkm/io/internal/VTKDataSetTypes.h b/vtkm/io/internal/VTKDataSetTypes.h index 8210ff197..30e9ece20 100644 --- a/vtkm/io/internal/VTKDataSetTypes.h +++ b/vtkm/io/internal/VTKDataSetTypes.h @@ -11,6 +11,7 @@ #define vtk_m_io_internal_VTKDataSetTypes_h #include +#include #include #include @@ -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 diff --git a/vtkm/io/testing/CMakeLists.txt b/vtkm/io/testing/CMakeLists.txt index f17628c77..33ee8762e 100644 --- a/vtkm/io/testing/CMakeLists.txt +++ b/vtkm/io/testing/CMakeLists.txt @@ -15,14 +15,14 @@ set(unit_tests UnitTestVTKDataSetWriter.cxx ) -vtkm_unit_tests(SOURCES ${unit_tests} ALL_BACKENDS LIBRARIES vtkm_lodepng) +set(unit_test_libraries vtkm_lodepng vtkm_io) -if(NOT VTKm_ENABLE_RENDERING) - return() +if(VTKm_ENABLE_RENDERING) + set(unit_tests ${unit_tests} + UnitTestImageWriter.cxx + ) + + set(unit_test_libraries ${unit_test_libraries} vtkm_rendering) endif() -set(image_unit_tests - UnitTestImageWriter.cxx -) - -vtkm_unit_tests(NAME UnitTests_vtkm_io_image_testing SOURCES ${image_unit_tests} ALL_BACKENDS LIBRARIES vtkm_rendering vtkm_lodepng) +vtkm_unit_tests(SOURCES ${unit_tests} ALL_BACKENDS LIBRARIES ${unit_test_libraries}) diff --git a/vtkm/io/testing/UnitTestBOVDataSetReader.cxx b/vtkm/io/testing/UnitTestBOVDataSetReader.cxx index 833d23d85..f1af8c023 100644 --- a/vtkm/io/testing/UnitTestBOVDataSetReader.cxx +++ b/vtkm/io/testing/UnitTestBOVDataSetReader.cxx @@ -11,6 +11,7 @@ #include #include #include +#include namespace {