vtk-m2/vtkm/io/testing/UnitTestVTKDataSetWriter.cxx
Kenneth Moreland 2d30e6d45a Coordinate systems are stored as Fields
Previously, `DataSet` managed `CoordinateSystem`s separately from `Field`s.
However, a `CoordinateSystem` is really just a `Field` with some special
attributes. Thus, coordiante systems are now just listed along with the
rest of the fields, and the coordinate systems are simply strings that
point back to the appropriate field. (This was actually the original
concept for `DataSet`, but the coordinate systems were separated from
fields for some now obsolete reasons.)
2022-11-11 06:17:58 -07:00

278 lines
10 KiB
C++

//============================================================================
// 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 <cmath>
#include <complex>
#include <cstdio>
#include <vector>
#include <vtkm/cont/ArrayHandleSOA.h>
#include <vtkm/io/VTKDataSetReader.h>
#include <vtkm/io/VTKDataSetWriter.h>
#include <vtkm/cont/DataSetBuilderUniform.h>
#include <vtkm/cont/testing/MakeTestDataSet.h>
#include <vtkm/cont/testing/Testing.h>
namespace
{
#define WRITE_FILE(MakeTestDataMethod) \
TestVTKWriteTestData(#MakeTestDataMethod, tds.MakeTestDataMethod())
struct CheckSameField
{
template <typename T, typename S>
void operator()(const vtkm::cont::ArrayHandle<T, S>& originalArray,
const vtkm::cont::Field& fileField) const
{
vtkm::cont::ArrayHandle<T> fileArray;
fileField.GetData().AsArrayHandle(fileArray);
VTKM_TEST_ASSERT(test_equal_portals(originalArray.ReadPortal(), fileArray.ReadPortal()));
}
};
struct CheckSameCoordinateSystem
{
template <typename T>
void operator()(const vtkm::cont::ArrayHandle<T>& originalArray,
const vtkm::cont::CoordinateSystem& fileCoords) const
{
CheckSameField{}(originalArray, fileCoords);
}
template <typename T>
void operator()(const vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagSOA>& originalArray,
const vtkm::cont::CoordinateSystem& fileCoords) const
{
CheckSameField{}(originalArray, fileCoords);
}
void operator()(const vtkm::cont::ArrayHandleUniformPointCoordinates& originalArray,
const vtkm::cont::CoordinateSystem& fileCoords) const
{
VTKM_TEST_ASSERT(fileCoords.GetData().IsType<vtkm::cont::ArrayHandleUniformPointCoordinates>());
vtkm::cont::ArrayHandleUniformPointCoordinates fileArray =
fileCoords.GetData().AsArrayHandle<vtkm::cont::ArrayHandleUniformPointCoordinates>();
auto originalPortal = originalArray.ReadPortal();
auto filePortal = fileArray.ReadPortal();
VTKM_TEST_ASSERT(test_equal(originalPortal.GetOrigin(), filePortal.GetOrigin()));
VTKM_TEST_ASSERT(test_equal(originalPortal.GetSpacing(), filePortal.GetSpacing()));
VTKM_TEST_ASSERT(test_equal(originalPortal.GetRange3(), filePortal.GetRange3()));
}
template <typename T>
using ArrayHandleRectilinearCoords = vtkm::cont::ArrayHandle<
T,
typename vtkm::cont::ArrayHandleCartesianProduct<vtkm::cont::ArrayHandle<T>,
vtkm::cont::ArrayHandle<T>,
vtkm::cont::ArrayHandle<T>>::StorageTag>;
template <typename T>
void operator()(const ArrayHandleRectilinearCoords<T>& originalArray,
const vtkm::cont::CoordinateSystem& fileCoords) const
{
VTKM_TEST_ASSERT(fileCoords.GetData().IsType<ArrayHandleRectilinearCoords<T>>());
ArrayHandleRectilinearCoords<T> fileArray =
fileCoords.GetData().AsArrayHandle<ArrayHandleRectilinearCoords<T>>();
auto originalPortal = originalArray.ReadPortal();
auto filePortal = fileArray.ReadPortal();
VTKM_TEST_ASSERT(
test_equal_portals(originalPortal.GetFirstPortal(), filePortal.GetFirstPortal()));
VTKM_TEST_ASSERT(
test_equal_portals(originalPortal.GetSecondPortal(), filePortal.GetSecondPortal()));
VTKM_TEST_ASSERT(
test_equal_portals(originalPortal.GetThirdPortal(), filePortal.GetThirdPortal()));
}
#ifdef VTKM_ADD_XGC_DEFAULT_TYPES
// Just added to fix compilation errors when building with XGC types added to default types
// An XGC data set wouldn't be directly written out to a VTK file, it should be converted
// to an explicit grid first and then written out.
template <typename T>
void operator()(const vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagXGCCoordinates>&,
const vtkm::cont::CoordinateSystem&) const
{
throw vtkm::cont::ErrorBadType("UnitTestVTKDataSetWriter::CheckSameCoordinateSystem() shouldn't"
" be called on ArrayHandleXGCCoordinates");
}
#endif
};
void CheckWrittenReadData(const vtkm::cont::DataSet& originalData,
const vtkm::cont::DataSet& fileData)
{
VTKM_TEST_ASSERT(originalData.GetNumberOfPoints() == fileData.GetNumberOfPoints());
VTKM_TEST_ASSERT(originalData.GetNumberOfCells() == fileData.GetNumberOfCells());
for (vtkm::IdComponent fieldId = 0; fieldId < originalData.GetNumberOfFields(); ++fieldId)
{
vtkm::cont::Field originalField = originalData.GetField(fieldId);
if (originalField.IsPointField() &&
(originalField.GetName() == originalData.GetCoordinateSystemName()))
{
// Do not check the field that is the first coordinate system. It is likely to have
// changed name because VTK does not name coordinate systems.
continue;
}
VTKM_TEST_ASSERT(fileData.HasField(originalField.GetName(), originalField.GetAssociation()));
vtkm::cont::Field fileField =
fileData.GetField(originalField.GetName(), originalField.GetAssociation());
vtkm::cont::CastAndCall(originalField, CheckSameField{}, fileField);
}
VTKM_TEST_ASSERT(fileData.GetNumberOfCoordinateSystems() > 0);
vtkm::cont::CastAndCall(originalData.GetCoordinateSystem().GetData(),
CheckSameCoordinateSystem{},
fileData.GetCoordinateSystem());
}
void TestVTKWriteTestData(const std::string& methodName, const vtkm::cont::DataSet& data)
{
std::cout << "Writing " << methodName << std::endl;
vtkm::io::VTKDataSetWriter writer(methodName + ".vtk");
writer.WriteDataSet(data);
// Read back and check.
vtkm::io::VTKDataSetReader reader(methodName + ".vtk");
CheckWrittenReadData(data, reader.ReadDataSet());
std::cout << "Writing " << methodName << " ascii" << std::endl;
vtkm::io::VTKDataSetWriter writerAscii(methodName + "-ascii.vtk");
writerAscii.SetFileTypeToAscii();
writerAscii.WriteDataSet(data);
// Read back and check.
vtkm::io::VTKDataSetReader readerAscii(methodName + "-ascii.vtk");
CheckWrittenReadData(data, readerAscii.ReadDataSet());
std::cout << "Writing " << methodName << " binary" << std::endl;
vtkm::io::VTKDataSetWriter writerBinary(methodName + "-binary.vtk");
writerBinary.SetFileTypeToBinary();
writerBinary.WriteDataSet(data);
// Read back and check.
vtkm::io::VTKDataSetReader readerBinary(methodName + "-binary.vtk");
CheckWrittenReadData(data, readerBinary.ReadDataSet());
}
void TestVTKExplicitWrite()
{
vtkm::cont::testing::MakeTestDataSet tds;
WRITE_FILE(Make1DExplicitDataSet0);
WRITE_FILE(Make2DExplicitDataSet0);
WRITE_FILE(Make3DExplicitDataSet0);
WRITE_FILE(Make3DExplicitDataSet1);
WRITE_FILE(Make3DExplicitDataSet2);
WRITE_FILE(Make3DExplicitDataSet3);
WRITE_FILE(Make3DExplicitDataSet4);
WRITE_FILE(Make3DExplicitDataSet5);
WRITE_FILE(Make3DExplicitDataSet6);
WRITE_FILE(Make3DExplicitDataSet7);
WRITE_FILE(Make3DExplicitDataSet8);
WRITE_FILE(Make3DExplicitDataSetZoo);
WRITE_FILE(Make3DExplicitDataSetPolygonal);
WRITE_FILE(Make3DExplicitDataSetCowNose);
std::cout << "Set writer to output an explicit grid" << std::endl;
vtkm::io::VTKDataSetWriter writer("Make3DExplicitDataSet0.vtk");
writer.WriteDataSet(tds.Make3DExplicitDataSet0());
}
void TestVTKUniformWrite()
{
vtkm::cont::testing::MakeTestDataSet tds;
WRITE_FILE(Make1DUniformDataSet0);
WRITE_FILE(Make1DUniformDataSet1);
WRITE_FILE(Make1DUniformDataSet2);
WRITE_FILE(Make2DUniformDataSet0);
WRITE_FILE(Make2DUniformDataSet1);
WRITE_FILE(Make2DUniformDataSet2);
WRITE_FILE(Make3DUniformDataSet0);
WRITE_FILE(Make3DUniformDataSet1);
// WRITE_FILE(Make3DUniformDataSet2); Skip this one. It's really big.
WRITE_FILE(Make3DUniformDataSet3);
WRITE_FILE(Make3DRegularDataSet0);
WRITE_FILE(Make3DRegularDataSet1);
std::cout << "Set writer to output an uniform grid" << std::endl;
vtkm::io::VTKDataSetWriter writer("Make3DUniformDataSet0.vtk");
writer.WriteDataSet(tds.Make3DUniformDataSet0());
}
void TestVTKRectilinearWrite()
{
vtkm::cont::testing::MakeTestDataSet tds;
WRITE_FILE(Make2DRectilinearDataSet0);
WRITE_FILE(Make3DRectilinearDataSet0);
std::cout << "Set writer to output a rectilinear grid" << std::endl;
vtkm::io::VTKDataSetWriter writer("Make3DRectilinearDataSet0.vtk");
writer.WriteDataSet(tds.Make3DRectilinearDataSet0());
}
void TestVTKCompoundWrite()
{
double s_min = 0.00001;
double s_max = 1.0;
double t_min = -2.0;
double t_max = 2.0;
int s_samples = 16;
vtkm::cont::DataSetBuilderUniform dsb;
vtkm::Id2 dims(s_samples, s_samples);
vtkm::Vec2f_64 origin(t_min, s_min);
vtkm::Float64 ds = (s_max - s_min) / vtkm::Float64(dims[0] - 1);
vtkm::Float64 dt = (t_max - t_min) / vtkm::Float64(dims[1] - 1);
vtkm::Vec2f_64 spacing(dt, ds);
vtkm::cont::DataSet dataSet = dsb.Create(dims, origin, spacing);
size_t nVerts = static_cast<size_t>(s_samples * s_samples);
std::vector<vtkm::Vec2f_64> points(nVerts);
size_t idx = 0;
for (vtkm::Id y = 0; y < dims[0]; ++y)
{
for (vtkm::Id x = 0; x < dims[1]; ++x)
{
double s = s_min + static_cast<vtkm::Float64>(y) * ds;
double t = t_min + static_cast<vtkm::Float64>(x) * dt;
// This function is not meaningful:
auto z = std::exp(std::complex<double>(s, t));
points[idx] = { std::sqrt(std::norm(z)), std::arg(z) };
idx++;
}
}
dataSet.AddPointField("z", points.data(), static_cast<vtkm::Id>(points.size()));
vtkm::io::VTKDataSetWriter writer("chirp.vtk");
writer.WriteDataSet(dataSet);
std::remove("chirp.vtk");
}
void TestVTKWrite()
{
TestVTKExplicitWrite();
TestVTKUniformWrite();
TestVTKRectilinearWrite();
TestVTKCompoundWrite();
}
} //Anonymous namespace
int UnitTestVTKDataSetWriter(int argc, char* argv[])
{
return vtkm::cont::testing::Testing::Run(TestVTKWrite, argc, argv);
}