From 5cb493427978ec6f37fc2b52d98018b4a43ec6d1 Mon Sep 17 00:00:00 2001 From: Kenneth Moreland Date: Wed, 30 Apr 2014 17:07:57 -0600 Subject: [PATCH] Add Extent classes. --- vtkm/CMakeLists.txt | 1 + vtkm/Extent.h | 319 ++++++++++++++++++++++++++++++++ vtkm/Types.h | 110 +++++++++++ vtkm/testing/CMakeLists.txt | 1 + vtkm/testing/UnitTestExtent.cxx | 197 ++++++++++++++++++++ 5 files changed, 628 insertions(+) create mode 100644 vtkm/Extent.h create mode 100644 vtkm/testing/UnitTestExtent.cxx diff --git a/vtkm/CMakeLists.txt b/vtkm/CMakeLists.txt index a53bb3b42..48afad60e 100644 --- a/vtkm/CMakeLists.txt +++ b/vtkm/CMakeLists.txt @@ -21,6 +21,7 @@ include_directories(${Boost_INCLUDE_DIRS}) set(headers + Extent.h Types.h TypeTraits.h VectorTraits.h diff --git a/vtkm/Extent.h b/vtkm/Extent.h new file mode 100644 index 000000000..77abf2951 --- /dev/null +++ b/vtkm/Extent.h @@ -0,0 +1,319 @@ +//============================================================================ +// 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. +// +// Copyright 2014 Sandia Corporation. +// Copyright 2014 UT-Battelle, LLC. +// Copyright 2014. Los Alamos National Security +// +// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// the U.S. Government retains certain rights in this software. +// +// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National +// Laboratory (LANL), the U.S. Government retains certain rights in +// this software. +//============================================================================ +#ifndef vtk_m_Extent_h +#define vtk_m_Extent_h + +#include + +namespace vtkm { + +/// Extent stores the values for the index ranges for a structured grid array. +/// It does this through the minimum indices and the maximum indices. +/// +template +struct Extent +{ + vtkm::Tuple Min; + vtkm::Tuple Max; + + VTKM_EXEC_CONT_EXPORT + Extent() : Min(0), Max(0) { } + + VTKM_EXEC_CONT_EXPORT + Extent(const vtkm::Tuple &min, + const vtkm::Tuple &max) + : Min(min), Max(max) { } + + VTKM_EXEC_CONT_EXPORT + Extent(const Extent &other) + : Min(other.Min), Max(other.Max) { } + + VTKM_EXEC_CONT_EXPORT + Extent &operator=(const Extent &rhs) + { + this->Min = rhs.Min; + this->Max = rhs.Max; + return *this; + } +} __attribute__ ((aligned(VTKM_SIZE_ID))); + +/// This is the Extent to use for structured grids with 3 topological +/// dimensions. +/// +typedef vtkm::Extent<3> Extent3 __attribute__ ((aligned(VTKM_SIZE_ID))); + +/// This is the Extent to use for structured grids with 2 topological +/// dimensions. +/// +typedef vtkm::Extent<2> Extent2 __attribute__ ((aligned(VTKM_SIZE_ID))); + +/// Given an extent, returns the array dimensions for the points. +/// +template +VTKM_EXEC_CONT_EXPORT +vtkm::Tuple +ExtentPointDimensions(const vtkm::Extent &extent) +{ + return extent.Max - extent.Min + vtkm::Tuple(1); +} + +VTKM_EXEC_CONT_EXPORT +vtkm::Id3 ExtentPointDimensions(const vtkm::Extent3 &extent) +{ + // Efficient implementation that uses no temporary Id3 to create dimensions. + return vtkm::Id3(extent.Max[0] - extent.Min[0] + 1, + extent.Max[1] - extent.Min[1] + 1, + extent.Max[2] - extent.Min[2] + 1); +} + +VTKM_EXEC_CONT_EXPORT +vtkm::Id2 ExtentPointDimensions(const vtkm::Extent2 &extent) +{ + // Efficient implementation that uses no temporary Id2 to create dimensions. + return vtkm::Id2(extent.Max[0] - extent.Min[0] + 1, + extent.Max[1] - extent.Min[1] + 1); +} + +/// Given an extent, returns the array dimensions for the cells. +/// +template +VTKM_EXEC_CONT_EXPORT +vtkm::Tuple +ExtentCellDimensions(const vtkm::Extent &extent) +{ + return extent.Max - extent.Min; +} + +/// Given an extent, returns the number of points in the structured mesh. +/// +template +VTKM_EXEC_CONT_EXPORT +vtkm::Id ExtentNumberOfPoints(const vtkm::Extent &extent) +{ + return internal::product_vector()( + vtkm::ExtentPointDimensions(extent)); +} + +template<> +VTKM_EXEC_CONT_EXPORT +vtkm::Id ExtentNumberOfPoints(const vtkm::Extent3 &extent) +{ + // Efficient implementation that uses no temporary Id3. + return ( + (extent.Max[0] - extent.Min[0] + 1) + * (extent.Max[1] - extent.Min[1] + 1) + * (extent.Max[2] - extent.Min[2] + 1)); +} + +template<> +VTKM_EXEC_CONT_EXPORT +vtkm::Id ExtentNumberOfPoints(const vtkm::Extent2 &extent) +{ + // Efficient implementation that uses no temporary Id2. + return ( + (extent.Max[0] - extent.Min[0] + 1) + * (extent.Max[1] - extent.Min[1] + 1)); +} + +/// Given an extent, returns the number of cells in the structured mesh. +/// +template +VTKM_EXEC_CONT_EXPORT +vtkm::Id ExtentNumberOfCells(const vtkm::Extent &extent) +{ + return internal::product_vector()( + vtkm::ExtentCellDimensions(extent)); +} + +template<> +VTKM_EXEC_CONT_EXPORT +vtkm::Id ExtentNumberOfCells(const vtkm::Extent3 &extent) +{ + // Efficient implementation that uses no temporary Id3. + return ( + (extent.Max[0] - extent.Min[0]) + * (extent.Max[1] - extent.Min[1]) + * (extent.Max[2] - extent.Min[2])); +} + +template<> +VTKM_EXEC_CONT_EXPORT +vtkm::Id ExtentNumberOfCells(const vtkm::Extent2 &extent) +{ + // Efficient implementation that uses no temporary Id2. + return ( + (extent.Max[0] - extent.Min[0]) + * (extent.Max[1] - extent.Min[1])); +} + +/// Elements in structured grids have a single index with 0 being the entry at +/// the minimum extent in every direction and then increasing first in the r +/// then the s direction and so on. This method converts a flat index to the +/// topological coordinates (e.g. r,s,t for 3d topologies). +/// +template +VTKM_EXEC_CONT_EXPORT +vtkm::Tuple +ExtentPointFlatIndexToTopologyIndex(vtkm::Id index, + const vtkm::Extent &extent) +{ + const vtkm::Tuple dims = + vtkm::ExtentPointDimensions(extent); + vtkm::Tuple ijkIndex; + vtkm::Id indexOnDim = index; + for (int dimIndex = 0; dimIndex < Dimensions-1; dimIndex++) + { + ijkIndex[dimIndex] = indexOnDim % dims[dimIndex] + extent.Min[dimIndex]; + indexOnDim /= dims[dimIndex]; + } + // Special case for last dimension to remove some unneeded operations + ijkIndex[Dimensions-1] = indexOnDim + extent.Min[Dimensions-1]; + return ijkIndex; +} + +VTKM_EXEC_CONT_EXPORT +vtkm::Id3 ExtentPointFlatIndexToTopologyIndex(vtkm::Id index, + const vtkm::Extent3 &extent) +{ + // Efficient implementation that tries to reduce the number of temporary + // variables. + const vtkm::Id3 dims = vtkm::ExtentPointDimensions(extent); + return vtkm::Id3((index % dims[0]) + extent.Min[0], + ((index / dims[0]) % dims[1]) + extent.Min[1], + ((index / (dims[0]*dims[1]))) + extent.Min[2]); +} + +VTKM_EXEC_CONT_EXPORT +vtkm::Id2 ExtentPointFlatIndexToTopologyIndex(vtkm::Id index, + const vtkm::Extent2 &extent) +{ + // Efficient implementation that tries to reduce the number of temporary + // variables. + const vtkm::Id2 dims = vtkm::ExtentPointDimensions(extent); + return vtkm::Id2((index % dims[0]) + extent.Min[0], + (index / dims[0]) + extent.Min[1]); +} + +/// Elements in structured grids have a single index with 0 being the entry at +/// the minimum extent in every direction and then increasing first in the r +/// then the s direction and so on. This method converts a flat index to the +/// topological coordinates (e.g. r,s,t for 3d topologies). +/// +template +VTKM_EXEC_CONT_EXPORT +vtkm::Tuple +ExtentCellFlatIndexToTopologyIndex(vtkm::Id index, + const vtkm::Extent &extent) +{ + const vtkm::Tuple dims = + vtkm::ExtentCellDimensions(extent); + vtkm::Tuple ijkIndex; + vtkm::Id indexOnDim = index; + for (int dimIndex = 0; dimIndex < Dimensions-1; dimIndex++) + { + ijkIndex[dimIndex] = indexOnDim % dims[dimIndex] + extent.Min[dimIndex]; + indexOnDim /= dims[dimIndex]; + } + // Special case for last dimension to remove some unneeded operations + ijkIndex[Dimensions-1] = indexOnDim + extent.Min[Dimensions-1]; + return ijkIndex; +} + +VTKM_EXEC_CONT_EXPORT +vtkm::Id3 ExtentCellFlatIndexToTopologyIndex(vtkm::Id index, + const vtkm::Extent3 &extent) +{ + // Efficient implementation that tries to reduce the number of temporary + // variables. + const vtkm::Id3 dims = vtkm::ExtentCellDimensions(extent); + return vtkm::Id3((index % dims[0]) + extent.Min[0], + ((index / dims[0]) % dims[1]) + extent.Min[1], + ((index / (dims[0]*dims[1]))) + extent.Min[2]); +} + +VTKM_EXEC_CONT_EXPORT +vtkm::Id2 ExtentCellFlatIndexToTopologyIndex(vtkm::Id index, + const vtkm::Extent2 &extent) +{ + // Efficient implementation that tries to reduce the number of temporary + // variables. + const vtkm::Id2 dims = vtkm::ExtentCellDimensions(extent); + return vtkm::Id2((index % dims[0]) + extent.Min[0], + (index / dims[0]) + extent.Min[1]); +} + +/// Elements in structured grids have a single index with 0 being the entry at +/// the minimum extent in every direction and then increasing first in the r +/// then the s direction and so on. This method converts topological +/// coordinates to a flat index. +/// +template +VTKM_EXEC_CONT_EXPORT +vtkm::Id +ExtentPointTopologyIndexToFlatIndex(const vtkm::Tuple &ijk, + const vtkm::Extent &extent) +{ + const vtkm::Tuple dims = ExtentPointDimensions(extent); + const vtkm::Tuple deltas = ijk - extent.Min; + vtkm::Id flatIndex = deltas[Dimensions-1]; + for (int dimIndex = Dimensions-2; dimIndex >= 0; dimIndex--) + { + flatIndex = flatIndex*dims[dimIndex] + deltas[dimIndex]; + } + return flatIndex; +} + +/// Elements in structured grids have a single index with 0 being the entry at +/// the minimum extent in every direction and then increasing first in the r +/// then the s direction and so on. This method converts topological +/// coordinates to a flat index. +/// +template +VTKM_EXEC_CONT_EXPORT +vtkm::Id +ExtentCellTopologyIndexToFlatIndex(const vtkm::Tuple &ijk, + const vtkm::Extent &extent) +{ + const vtkm::Tuple dims = ExtentCellDimensions(extent); + const vtkm::Tuple deltas = ijk - extent.Min; + vtkm::Id flatIndex = deltas[Dimensions-1]; + for (int dimIndex = Dimensions-2; dimIndex >= 0; dimIndex--) + { + flatIndex = flatIndex*dims[dimIndex] + deltas[dimIndex]; + } + return flatIndex; +} + +/// Given a cell index, returns the index to the first point incident on that +/// cell. +/// +template +VTKM_EXEC_CONT_EXPORT +vtkm::Id ExtentFirstPointOnCell(vtkm::Id cellIndex, + const Extent &extent) +{ + return ExtentPointTopologyIndexToFlatIndex( + ExtentCellFlatIndexToTopologyIndex(cellIndex,extent), + extent); +} + +} // namespace vtkm + +#endif //vtk_m_Extent_h diff --git a/vtkm/Types.h b/vtkm/Types.h index d13a9b186..5b995fdc5 100644 --- a/vtkm/Types.h +++ b/vtkm/Types.h @@ -241,6 +241,116 @@ struct copy_vector<3> } }; +template +struct sum_vector +{ + template + VTKM_EXEC_CONT_EXPORT + typename T::ComponentType operator()(const T &x) + { + return sum_vector()(x) + x[Size-1]; + } +}; + +template<> +struct sum_vector<1> +{ + template + VTKM_EXEC_CONT_EXPORT + typename T::ComponentType operator()(const T &x) + { + return x[0]; + } +}; + +template<> +struct sum_vector<2> +{ + template + VTKM_EXEC_CONT_EXPORT + typename T::ComponentType operator()(const T &x) + { + return x[0] + x[1]; + } +}; + +template<> +struct sum_vector<3> +{ + template + VTKM_EXEC_CONT_EXPORT + typename T::ComponentType operator()(const T &x) + { + return x[0] + x[1] + x[2]; + } +}; + +template<> +struct sum_vector<4> +{ + template + VTKM_EXEC_CONT_EXPORT + typename T::ComponentType operator()(const T &x) + { + return x[0] + x[1] + x[2] + x[3]; + } +}; + +template +struct product_vector +{ + template + VTKM_EXEC_CONT_EXPORT + typename T::ComponentType operator()(const T &x) + { + return product_vector()(x) * x[Size-1]; + } +}; + +template<> +struct product_vector<1> +{ + template + VTKM_EXEC_CONT_EXPORT + typename T::ComponentType operator()(const T &x) + { + return x[0]; + } +}; + +template<> +struct product_vector<2> +{ + template + VTKM_EXEC_CONT_EXPORT + typename T::ComponentType operator()(const T &x) + { + return x[0] * x[1]; + } +}; + +template<> +struct product_vector<3> +{ + template + VTKM_EXEC_CONT_EXPORT + typename T::ComponentType operator()(const T &x) + { + return x[0] * x[1] * x[2]; + } +}; + +template<> +struct product_vector<4> +{ + template + VTKM_EXEC_CONT_EXPORT + typename T::ComponentType operator()(const T &x) + { + return x[0] * x[1] * x[2] * x[3]; + } +}; + } // namespace internal diff --git a/vtkm/testing/CMakeLists.txt b/vtkm/testing/CMakeLists.txt index 5e69e0130..0a2aace33 100644 --- a/vtkm/testing/CMakeLists.txt +++ b/vtkm/testing/CMakeLists.txt @@ -26,6 +26,7 @@ set(headers VTKM_declare_headers(${headers}) set(unit_tests + UnitTestExtent.cxx UnitTestTesting.cxx UnitTestTypes.cxx UnitTestTypeTraits.cxx diff --git a/vtkm/testing/UnitTestExtent.cxx b/vtkm/testing/UnitTestExtent.cxx new file mode 100644 index 000000000..a1f834a25 --- /dev/null +++ b/vtkm/testing/UnitTestExtent.cxx @@ -0,0 +1,197 @@ +//============================================================================ +// 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. +// +// Copyright 2014 Sandia Corporation. +// Copyright 2014 UT-Battelle, LLC. +// Copyright 2014. Los Alamos National Security +// +// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// the U.S. Government retains certain rights in this software. +// +// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National +// Laboratory (LANL), the U.S. Government retains certain rights in +// this software. +//============================================================================ + +#include + +#include + +namespace { + +const int MIN_VALUES[] = { -5, 8, 40, -8, -3 }; +const int MAX_VALUES[] = { 10, 25, 44, -2, 1 }; +const int POINT_DIMS[] = { 16, 18, 5, 7, 5 }; +const int CELL_DIMS[] = { 15, 17, 4, 6, 4 }; +const int NUM_POINTS[] = { 0, 16, 288, 1440, 10080, 50400 }; +const int NUM_CELLS[] = { 0, 15, 255, 1020, 6120, 24480 }; + +template +void TestDimensions(vtkm::Extent) +{ + std::cout << "Testing Dimension sizes for " << Dimensions << " dimensions" + << std::endl; + + vtkm::Extent extent; + vtkm::Tuple pointDims; + vtkm::Tuple cellDims; + vtkm::Id numPoints; + vtkm::Id numCells; + + for (int dimIndex = 0; dimIndex < Dimensions; dimIndex++) + { + extent.Min[dimIndex] = 0; extent.Max[dimIndex] = 10; + } + pointDims = vtkm::ExtentPointDimensions(extent); + cellDims = vtkm::ExtentCellDimensions(extent); + for (int dimIndex = 0; dimIndex < Dimensions; dimIndex++) + { + VTKM_TEST_ASSERT(pointDims[dimIndex] == 11, + "Got incorrect point dimensions for extent."); + VTKM_TEST_ASSERT(cellDims[dimIndex] == 10, + "Got incorrect point dimensions for extent."); + } + + for (int dimIndex = 0; dimIndex < Dimensions; dimIndex++) + { + extent.Min[dimIndex] = MIN_VALUES[dimIndex]; + extent.Max[dimIndex] = MAX_VALUES[dimIndex]; + } + pointDims = vtkm::ExtentPointDimensions(extent); + cellDims = vtkm::ExtentCellDimensions(extent); + for (int dimIndex = 0; dimIndex < Dimensions; dimIndex++) + { + VTKM_TEST_ASSERT(pointDims[dimIndex] == POINT_DIMS[dimIndex], + "Got incorrect point dimensions for extent."); + VTKM_TEST_ASSERT(cellDims[dimIndex] == CELL_DIMS[dimIndex], + "Got incorrect point dimensions for extent."); + } + numPoints = vtkm::ExtentNumberOfPoints(extent); + numCells = vtkm::ExtentNumberOfCells(extent); + VTKM_TEST_ASSERT(numPoints == NUM_POINTS[Dimensions], + "Got wrong number of points."); + VTKM_TEST_ASSERT(numCells == NUM_CELLS[Dimensions], + "Got wrong number of cells."); +} + +template +void TryIndexConversion(const vtkm::Extent &extent) +{ + typedef vtkm::Tuple IdX; + vtkm::Id lastFlatIndex; + IdX correctTopologyIndex; + + std::cout << " Testing point index conversion" << std::endl; + correctTopologyIndex = IdX(100000); + lastFlatIndex = vtkm::ExtentNumberOfPoints(extent); + for (vtkm::Id correctFlatIndex = 0; + correctFlatIndex < lastFlatIndex; + correctFlatIndex++) + { + // Increment topology index + for (int dimIndex = 0; dimIndex < Dimensions; dimIndex++) + { + correctTopologyIndex[dimIndex]++; + if (correctTopologyIndex[dimIndex] <= extent.Max[dimIndex]) { break; } + correctTopologyIndex[dimIndex] = extent.Min[dimIndex]; + // Iterate to increment the next index. + } + + vtkm::Id computedFlatIndex = + vtkm::ExtentPointTopologyIndexToFlatIndex(correctTopologyIndex, extent); + VTKM_TEST_ASSERT(computedFlatIndex == correctFlatIndex, + "Got incorrect flat index."); + + IdX computedTopologyIndex = + vtkm::ExtentPointFlatIndexToTopologyIndex(correctFlatIndex, extent); + VTKM_TEST_ASSERT(computedTopologyIndex == correctTopologyIndex, + "Got incorrect topology index."); + } + // Sanity check to make sure we got to the last topology index. + VTKM_TEST_ASSERT(correctTopologyIndex == extent.Max, + "Test code error. Indexing problem."); + + std::cout << " Testing cell index conversion" << std::endl; + correctTopologyIndex = IdX(100000); + lastFlatIndex = vtkm::ExtentNumberOfCells(extent); + for (vtkm::Id correctFlatIndex = 0; + correctFlatIndex < lastFlatIndex; + correctFlatIndex++) + { + // Increment topology index + for (int dimIndex = 0; dimIndex < Dimensions; dimIndex++) + { + correctTopologyIndex[dimIndex]++; + if (correctTopologyIndex[dimIndex] < extent.Max[dimIndex]) { break; } + correctTopologyIndex[dimIndex] = extent.Min[dimIndex]; + // Iterate to increment the next index. + } + + vtkm::Id computedFlatIndex = + vtkm::ExtentCellTopologyIndexToFlatIndex(correctTopologyIndex, extent); + VTKM_TEST_ASSERT(computedFlatIndex == correctFlatIndex, + "Got incorrect flat index."); + + IdX computedTopologyIndex = + vtkm::ExtentCellFlatIndexToTopologyIndex(correctFlatIndex, extent); + VTKM_TEST_ASSERT(computedTopologyIndex == correctTopologyIndex, + "Got incorrect topology index."); + + vtkm::Id expectedFirstPointIndex = + vtkm::ExtentPointTopologyIndexToFlatIndex(correctTopologyIndex, extent); + vtkm::Id computedFirstPointIndex = + vtkm::ExtentFirstPointOnCell(correctFlatIndex, extent); + VTKM_TEST_ASSERT(computedFirstPointIndex == expectedFirstPointIndex, + "Got wrong first point index."); + } + // Sanity check to make sure we got to the last topology index. + VTKM_TEST_ASSERT(correctTopologyIndex == extent.Max - IdX(1), + "Test code error. Indexing problem."); +} + +template +void TestIndexConversion(vtkm::Extent) +{ + std::cout << "Testing index conversion for " << Dimensions << " dimensions." + << std::endl; + + vtkm::Extent extent; + + for (int dimIndex = 0; dimIndex < Dimensions; dimIndex++) + { + extent.Min[dimIndex] = 0; extent.Max[dimIndex] = 10; + } + TryIndexConversion(extent); + + for (int dimIndex = 0; dimIndex < Dimensions; dimIndex++) + { + extent.Min[dimIndex] = MIN_VALUES[dimIndex]; + extent.Max[dimIndex] = MAX_VALUES[dimIndex]; + } + TryIndexConversion(extent); +} + +void ExtentTests() +{ + TestDimensions(vtkm::Extent<1>()); + TestDimensions(vtkm::Extent2()); + TestDimensions(vtkm::Extent3()); + TestDimensions(vtkm::Extent<5>()); + + TestIndexConversion(vtkm::Extent<1>()); + TestIndexConversion(vtkm::Extent2()); + TestIndexConversion(vtkm::Extent3()); + TestIndexConversion(vtkm::Extent<5>()); +} + +} // anonymous namespace + +int UnitTestExtent(int, char *[]) +{ + return vtkm::testing::Testing::Run(ExtentTests); +}