vtk-m/vtkm/cont/testing/UnitTestDataSetBuilderRectilinear.cxx

298 lines
10 KiB
C++
Raw Normal View History

2019-04-15 23:24:21 +00:00
//============================================================================
// 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.
2019-04-15 23:24:21 +00:00
//============================================================================
#include <vtkm/cont/CellSetStructured.h>
#include <vtkm/cont/DataSetBuilderRectilinear.h>
#include <vtkm/cont/testing/MakeTestDataSet.h>
#include <vtkm/cont/testing/Testing.h>
#include <ctime>
#include <random>
#include <vector>
2017-05-18 14:29:41 +00:00
namespace DataSetBuilderRectilinearNamespace
{
std::mt19937 g_RandomGenerator;
void ValidateDataSet(const vtkm::cont::DataSet& ds,
int dim,
vtkm::Id numPoints,
vtkm::Id numCells,
2017-05-18 14:29:41 +00:00
const vtkm::Bounds& bounds)
{
//Verify basics..
VTKM_TEST_ASSERT(ds.GetNumberOfFields() == 3, "Wrong number of fields.");
2017-05-18 14:29:41 +00:00
VTKM_TEST_ASSERT(ds.GetNumberOfCoordinateSystems() == 1, "Wrong number of coordinate systems.");
VTKM_TEST_ASSERT(ds.GetNumberOfPoints() == numPoints, "Wrong number of coordinates.");
VTKM_TEST_ASSERT(ds.GetNumberOfCells() == numCells, "Wrong number of cells.");
// test various field-getting methods and associations
try
{
ds.GetCellField("cellvar");
}
catch (...)
{
VTKM_TEST_FAIL("Failed to get field 'cellvar' with Association::Cells.");
}
try
{
ds.GetPointField("pointvar");
}
catch (...)
{
VTKM_TEST_FAIL("Failed to get field 'pointvar' with ASSOC_POINT_SET.");
}
//Make sure the bounds are correct.
vtkm::Bounds res = ds.GetCoordinateSystem().GetBounds();
2017-05-18 14:29:41 +00:00
VTKM_TEST_ASSERT(test_equal(bounds, res), "Bounds of coordinates do not match");
if (dim == 1)
{
vtkm::cont::CellSetStructured<1> cellSet;
ds.GetCellSet().AsCellSet(cellSet);
vtkm::IdComponent shape = cellSet.GetCellShape();
VTKM_TEST_ASSERT(shape == vtkm::CELL_SHAPE_LINE, "Wrong element type");
}
else if (dim == 2)
{
vtkm::cont::CellSetStructured<2> cellSet;
ds.GetCellSet().AsCellSet(cellSet);
vtkm::IdComponent shape = cellSet.GetCellShape();
VTKM_TEST_ASSERT(shape == vtkm::CELL_SHAPE_QUAD, "Wrong element type");
}
else if (dim == 3)
{
vtkm::cont::CellSetStructured<3> cellSet;
ds.GetCellSet().AsCellSet(cellSet);
vtkm::IdComponent shape = cellSet.GetCellShape();
VTKM_TEST_ASSERT(shape == vtkm::CELL_SHAPE_HEXAHEDRON, "Wrong element type");
}
}
template <typename T>
2017-05-18 14:29:41 +00:00
void FillArray(std::vector<T>& arr, vtkm::Id size, vtkm::IdComponent fillMethod)
{
arr.resize(static_cast<std::size_t>(size));
arr[0] = T(0);
for (size_t i = 1; i < static_cast<std::size_t>(size); i++)
{
T xi = static_cast<T>(i);
switch (fillMethod)
{
2017-05-18 14:29:41 +00:00
case 0:
break;
case 1:
xi /= static_cast<vtkm::Float32>(size - 1);
break;
case 2:
xi *= 2;
break;
case 3:
xi *= 0.1f;
break;
case 4:
xi *= xi;
break;
default:
VTKM_TEST_FAIL("Bad internal test state: invalid fill method.");
}
arr[i] = xi;
}
}
template <typename T>
2017-05-18 14:29:41 +00:00
void RectilinearTests()
{
const vtkm::Id NUM_TRIALS = 10;
const vtkm::Id MAX_DIM_SIZE = 20;
const vtkm::Id NUM_FILL_METHODS = 5;
vtkm::cont::DataSetBuilderRectilinear dataSetBuilder;
2016-01-14 21:01:28 +00:00
std::uniform_int_distribution<vtkm::Id> randomDim(1, MAX_DIM_SIZE);
2017-05-18 14:29:41 +00:00
std::uniform_int_distribution<vtkm::IdComponent> randomFill(0, NUM_FILL_METHODS - 1);
2016-01-14 21:01:28 +00:00
for (vtkm::Id trial = 0; trial < NUM_TRIALS; trial++)
2016-01-14 21:01:28 +00:00
{
std::cout << "Trial " << trial << std::endl;
Improvements to moving data into ArrayHandle We have made several improvements to adding data into an `ArrayHandle`. ## Moving data from an `std::vector` For numerous reasons, it is convenient to define data in a `std::vector` and then wrap that into an `ArrayHandle`. It is often the case that an `std::vector` is filled and then becomes unused once it is converted to an `ArrayHandle`. In this case, what we really want is to pass the data off to the `ArrayHandle` so that the `ArrayHandle` is now managing the data and not the `std::vector`. C++11 has a mechanism to do this: move semantics. You can now pass variables to functions as an "rvalue" (right-hand value). When something is passed as an rvalue, it can pull state out of that variable and move it somewhere else. `std::vector` implements this movement so that an rvalue can be moved to another `std::vector` without actually copying the data. `make_ArrayHandle` now also takes advantage of this feature to move rvalue `std::vector`s. There is a special form of `make_ArrayHandle` named `make_ArrayHandleMove` that takes an rvalue. There is also a special overload of `make_ArrayHandle` itself that handles an rvalue `vector`. (However, using the explicit move version is better if you want to make sure the data is actually moved.) ## Make `ArrayHandle` from initalizer list A common use case for using `std::vector` (particularly in our unit tests) is to quickly add an initalizer list into an `ArrayHandle`. Now you can by simply passing an initializer list to `make_ArrayHandle`. ## Deprecated `make_ArrayHandle` with default shallow copy For historical reasons, passing an `std::vector` or a pointer to `make_ArrayHandle` does a shallow copy (i.e. `CopyFlag` defaults to `Off`). Although more efficient, this mode is inherintly unsafe, and making it the default is asking for trouble. To combat this, calling `make_ArrayHandle` without a copy flag is deprecated. In this way, if you wish to do the faster but more unsafe creation of an `ArrayHandle` you should explicitly express that. This requried quite a few changes through the VTK-m source (particularly in the tests). ## Similar changes to `Field` `vtkm::cont::Field` has a `make_Field` helper function that is similar to `make_ArrayHandle`. It also features the ability to create fields from `std::vector`s and C arrays. It also likewise had the same unsafe behavior by default of not copying from the source of the arrays. That behavior has similarly been depreciated. You now have to specify a copy flag. The ability to construct a `Field` from an initializer list of values has also been added.
2020-07-16 16:32:32 +00:00
vtkm::cont::DataSet dataSet;
vtkm::Id3 dimensions(
randomDim(g_RandomGenerator), randomDim(g_RandomGenerator), randomDim(g_RandomGenerator));
std::cout << "Dimensions: " << dimensions << std::endl;
vtkm::IdComponent fillMethodX = randomFill(g_RandomGenerator);
vtkm::IdComponent fillMethodY = randomFill(g_RandomGenerator);
vtkm::IdComponent fillMethodZ = randomFill(g_RandomGenerator);
2017-05-18 14:29:41 +00:00
std::cout << "Fill methods: [" << fillMethodX << "," << fillMethodY << "," << fillMethodZ << "]"
<< std::endl;
std::vector<T> xCoordinates;
std::vector<T> yCoordinates;
std::vector<T> zCoordinates;
FillArray(xCoordinates, dimensions[0], fillMethodX);
FillArray(yCoordinates, dimensions[1], fillMethodY);
FillArray(zCoordinates, dimensions[2], fillMethodZ);
vtkm::Id numPoints = 1, numCells = 1;
2017-05-18 14:29:41 +00:00
vtkm::Bounds bounds(0, 0, 0, 0, 0, 0);
int ndims = 0;
std::cout << "1D parameters" << std::endl;
bounds.X = vtkm::Range(xCoordinates.front(), xCoordinates.back());
numPoints *= dimensions[0];
if (dimensions[0] > 1)
{
numCells = dimensions[0] - 1;
ndims += 1;
}
if (ndims)
{
std::vector<T> varP1D(static_cast<unsigned long>(numPoints));
for (unsigned long i = 0; i < static_cast<unsigned long>(numPoints); i++)
{
float fi = static_cast<float>(i);
varP1D[i] = static_cast<T>(fi * 1.1f);
}
std::vector<T> varC1D(static_cast<unsigned long>(numCells));
for (unsigned long i = 0; i < static_cast<unsigned long>(numCells); i++)
{
float fi = static_cast<float>(i);
varC1D[i] = static_cast<T>(fi * 1.1f);
}
std::cout << " Create with std::vector" << std::endl;
dataSet = dataSetBuilder.Create(xCoordinates);
2020-05-27 19:27:47 +00:00
dataSet.AddPointField("pointvar", varP1D);
dataSet.AddCellField("cellvar", varC1D);
ValidateDataSet(dataSet, ndims, numPoints, numCells, bounds);
}
std::cout << "2D parameters" << std::endl;
bounds.Y = vtkm::Range(yCoordinates.front(), yCoordinates.back());
numPoints *= dimensions[1];
if (dimensions[1] > 1)
{
numCells *= dimensions[1] - 1;
ndims += 1;
}
if (ndims)
{
std::vector<T> varP2D(static_cast<unsigned long>(numPoints));
for (unsigned long i = 0; i < static_cast<unsigned long>(numPoints); i++)
{
float fi = static_cast<float>(i);
varP2D[i] = static_cast<T>(fi * 1.1f);
}
std::vector<T> varC2D(static_cast<unsigned long>(numCells));
for (unsigned long i = 0; i < static_cast<unsigned long>(numCells); i++)
{
float fi = static_cast<float>(i);
varC2D[i] = static_cast<T>(fi * 1.1f);
}
std::cout << " Create with std::vector" << std::endl;
dataSet = dataSetBuilder.Create(xCoordinates, yCoordinates);
2020-05-27 19:27:47 +00:00
dataSet.AddPointField("pointvar", varP2D);
dataSet.AddCellField("cellvar", varC2D);
ValidateDataSet(dataSet, ndims, numPoints, numCells, bounds);
std::cout << " Create with C array" << std::endl;
dataSet = dataSetBuilder.Create(
dimensions[0], dimensions[1], xCoordinates.data(), yCoordinates.data());
dataSet.AddPointField("pointvar", varP2D.data(), numPoints);
dataSet.AddCellField("cellvar", varC2D.data(), numCells);
ValidateDataSet(dataSet, ndims, numPoints, numCells, bounds);
std::cout << " Create with ArrayHandle" << std::endl;
Improvements to moving data into ArrayHandle We have made several improvements to adding data into an `ArrayHandle`. ## Moving data from an `std::vector` For numerous reasons, it is convenient to define data in a `std::vector` and then wrap that into an `ArrayHandle`. It is often the case that an `std::vector` is filled and then becomes unused once it is converted to an `ArrayHandle`. In this case, what we really want is to pass the data off to the `ArrayHandle` so that the `ArrayHandle` is now managing the data and not the `std::vector`. C++11 has a mechanism to do this: move semantics. You can now pass variables to functions as an "rvalue" (right-hand value). When something is passed as an rvalue, it can pull state out of that variable and move it somewhere else. `std::vector` implements this movement so that an rvalue can be moved to another `std::vector` without actually copying the data. `make_ArrayHandle` now also takes advantage of this feature to move rvalue `std::vector`s. There is a special form of `make_ArrayHandle` named `make_ArrayHandleMove` that takes an rvalue. There is also a special overload of `make_ArrayHandle` itself that handles an rvalue `vector`. (However, using the explicit move version is better if you want to make sure the data is actually moved.) ## Make `ArrayHandle` from initalizer list A common use case for using `std::vector` (particularly in our unit tests) is to quickly add an initalizer list into an `ArrayHandle`. Now you can by simply passing an initializer list to `make_ArrayHandle`. ## Deprecated `make_ArrayHandle` with default shallow copy For historical reasons, passing an `std::vector` or a pointer to `make_ArrayHandle` does a shallow copy (i.e. `CopyFlag` defaults to `Off`). Although more efficient, this mode is inherintly unsafe, and making it the default is asking for trouble. To combat this, calling `make_ArrayHandle` without a copy flag is deprecated. In this way, if you wish to do the faster but more unsafe creation of an `ArrayHandle` you should explicitly express that. This requried quite a few changes through the VTK-m source (particularly in the tests). ## Similar changes to `Field` `vtkm::cont::Field` has a `make_Field` helper function that is similar to `make_ArrayHandle`. It also features the ability to create fields from `std::vector`s and C arrays. It also likewise had the same unsafe behavior by default of not copying from the source of the arrays. That behavior has similarly been depreciated. You now have to specify a copy flag. The ability to construct a `Field` from an initializer list of values has also been added.
2020-07-16 16:32:32 +00:00
dataSet =
dataSetBuilder.Create(vtkm::cont::make_ArrayHandle(xCoordinates, vtkm::CopyFlag::Off),
vtkm::cont::make_ArrayHandle(yCoordinates, vtkm::CopyFlag::Off));
dataSet.AddPointField("pointvar", vtkm::cont::make_ArrayHandle(varP2D, vtkm::CopyFlag::Off));
dataSet.AddCellField("cellvar", vtkm::cont::make_ArrayHandle(varC2D, vtkm::CopyFlag::Off));
ValidateDataSet(dataSet, ndims, numPoints, numCells, bounds);
}
std::cout << "3D parameters" << std::endl;
bounds.Z = vtkm::Range(zCoordinates.front(), zCoordinates.back());
numPoints *= dimensions[2];
if (dimensions[2] > 1)
{
numCells *= dimensions[2] - 1;
ndims += 1;
}
if (ndims)
{
std::vector<T> varP3D(static_cast<unsigned long>(numPoints));
for (unsigned long i = 0; i < static_cast<unsigned long>(numPoints); i++)
{
float fi = static_cast<float>(i);
varP3D[i] = static_cast<T>(fi * 1.1f);
}
std::vector<T> varC3D(static_cast<unsigned long>(numCells));
for (unsigned long i = 0; i < static_cast<unsigned long>(numCells); i++)
{
float fi = static_cast<float>(i);
varC3D[i] = static_cast<T>(fi * 1.1f);
}
std::cout << " Create with std::vector" << std::endl;
dataSet = dataSetBuilder.Create(xCoordinates, yCoordinates, zCoordinates);
2020-05-27 19:27:47 +00:00
dataSet.AddPointField("pointvar", varP3D);
dataSet.AddCellField("cellvar", varC3D);
ValidateDataSet(dataSet, ndims, numPoints, numCells, bounds);
std::cout << " Create with C array" << std::endl;
dataSet = dataSetBuilder.Create(dimensions[0],
dimensions[1],
dimensions[2],
xCoordinates.data(),
yCoordinates.data(),
zCoordinates.data());
Improvements to moving data into ArrayHandle We have made several improvements to adding data into an `ArrayHandle`. ## Moving data from an `std::vector` For numerous reasons, it is convenient to define data in a `std::vector` and then wrap that into an `ArrayHandle`. It is often the case that an `std::vector` is filled and then becomes unused once it is converted to an `ArrayHandle`. In this case, what we really want is to pass the data off to the `ArrayHandle` so that the `ArrayHandle` is now managing the data and not the `std::vector`. C++11 has a mechanism to do this: move semantics. You can now pass variables to functions as an "rvalue" (right-hand value). When something is passed as an rvalue, it can pull state out of that variable and move it somewhere else. `std::vector` implements this movement so that an rvalue can be moved to another `std::vector` without actually copying the data. `make_ArrayHandle` now also takes advantage of this feature to move rvalue `std::vector`s. There is a special form of `make_ArrayHandle` named `make_ArrayHandleMove` that takes an rvalue. There is also a special overload of `make_ArrayHandle` itself that handles an rvalue `vector`. (However, using the explicit move version is better if you want to make sure the data is actually moved.) ## Make `ArrayHandle` from initalizer list A common use case for using `std::vector` (particularly in our unit tests) is to quickly add an initalizer list into an `ArrayHandle`. Now you can by simply passing an initializer list to `make_ArrayHandle`. ## Deprecated `make_ArrayHandle` with default shallow copy For historical reasons, passing an `std::vector` or a pointer to `make_ArrayHandle` does a shallow copy (i.e. `CopyFlag` defaults to `Off`). Although more efficient, this mode is inherintly unsafe, and making it the default is asking for trouble. To combat this, calling `make_ArrayHandle` without a copy flag is deprecated. In this way, if you wish to do the faster but more unsafe creation of an `ArrayHandle` you should explicitly express that. This requried quite a few changes through the VTK-m source (particularly in the tests). ## Similar changes to `Field` `vtkm::cont::Field` has a `make_Field` helper function that is similar to `make_ArrayHandle`. It also features the ability to create fields from `std::vector`s and C arrays. It also likewise had the same unsafe behavior by default of not copying from the source of the arrays. That behavior has similarly been depreciated. You now have to specify a copy flag. The ability to construct a `Field` from an initializer list of values has also been added.
2020-07-16 16:32:32 +00:00
dataSet.AddPointField("pointvar", vtkm::cont::make_ArrayHandle(varP3D, vtkm::CopyFlag::Off));
dataSet.AddCellField("cellvar", vtkm::cont::make_ArrayHandle(varC3D, vtkm::CopyFlag::Off));
ValidateDataSet(dataSet, ndims, numPoints, numCells, bounds);
std::cout << " Create with ArrayHandle" << std::endl;
Improvements to moving data into ArrayHandle We have made several improvements to adding data into an `ArrayHandle`. ## Moving data from an `std::vector` For numerous reasons, it is convenient to define data in a `std::vector` and then wrap that into an `ArrayHandle`. It is often the case that an `std::vector` is filled and then becomes unused once it is converted to an `ArrayHandle`. In this case, what we really want is to pass the data off to the `ArrayHandle` so that the `ArrayHandle` is now managing the data and not the `std::vector`. C++11 has a mechanism to do this: move semantics. You can now pass variables to functions as an "rvalue" (right-hand value). When something is passed as an rvalue, it can pull state out of that variable and move it somewhere else. `std::vector` implements this movement so that an rvalue can be moved to another `std::vector` without actually copying the data. `make_ArrayHandle` now also takes advantage of this feature to move rvalue `std::vector`s. There is a special form of `make_ArrayHandle` named `make_ArrayHandleMove` that takes an rvalue. There is also a special overload of `make_ArrayHandle` itself that handles an rvalue `vector`. (However, using the explicit move version is better if you want to make sure the data is actually moved.) ## Make `ArrayHandle` from initalizer list A common use case for using `std::vector` (particularly in our unit tests) is to quickly add an initalizer list into an `ArrayHandle`. Now you can by simply passing an initializer list to `make_ArrayHandle`. ## Deprecated `make_ArrayHandle` with default shallow copy For historical reasons, passing an `std::vector` or a pointer to `make_ArrayHandle` does a shallow copy (i.e. `CopyFlag` defaults to `Off`). Although more efficient, this mode is inherintly unsafe, and making it the default is asking for trouble. To combat this, calling `make_ArrayHandle` without a copy flag is deprecated. In this way, if you wish to do the faster but more unsafe creation of an `ArrayHandle` you should explicitly express that. This requried quite a few changes through the VTK-m source (particularly in the tests). ## Similar changes to `Field` `vtkm::cont::Field` has a `make_Field` helper function that is similar to `make_ArrayHandle`. It also features the ability to create fields from `std::vector`s and C arrays. It also likewise had the same unsafe behavior by default of not copying from the source of the arrays. That behavior has similarly been depreciated. You now have to specify a copy flag. The ability to construct a `Field` from an initializer list of values has also been added.
2020-07-16 16:32:32 +00:00
dataSet =
dataSetBuilder.Create(vtkm::cont::make_ArrayHandle(xCoordinates, vtkm::CopyFlag::Off),
vtkm::cont::make_ArrayHandle(yCoordinates, vtkm::CopyFlag::Off),
vtkm::cont::make_ArrayHandle(zCoordinates, vtkm::CopyFlag::Off));
dataSet.AddPointField("pointvar", vtkm::cont::make_ArrayHandle(varP3D, vtkm::CopyFlag::Off));
dataSet.AddCellField("cellvar", vtkm::cont::make_ArrayHandle(varC3D, vtkm::CopyFlag::Off));
ValidateDataSet(dataSet, ndims, numPoints, numCells, bounds);
}
2016-01-14 21:01:28 +00:00
}
}
2017-05-18 14:29:41 +00:00
void TestDataSetBuilderRectilinear()
{
vtkm::UInt32 seed = static_cast<vtkm::UInt32>(std::time(nullptr));
std::cout << "Seed: " << seed << std::endl;
g_RandomGenerator.seed(seed);
std::cout << "======== Float32 ==========================" << std::endl;
RectilinearTests<vtkm::Float32>();
std::cout << "======== Float64 ==========================" << std::endl;
RectilinearTests<vtkm::Float64>();
}
} // namespace DataSetBuilderRectilinearNamespace
int UnitTestDataSetBuilderRectilinear(int argc, char* argv[])
{
2017-05-18 14:29:41 +00:00
using namespace DataSetBuilderRectilinearNamespace;
return vtkm::cont::testing::Testing::Run(TestDataSetBuilderRectilinear, argc, argv);
}