Add Extent classes.

This commit is contained in:
Kenneth Moreland 2014-04-30 17:07:57 -06:00
parent c008213561
commit 5cb4934279
5 changed files with 628 additions and 0 deletions

@ -21,6 +21,7 @@
include_directories(${Boost_INCLUDE_DIRS})
set(headers
Extent.h
Types.h
TypeTraits.h
VectorTraits.h

319
vtkm/Extent.h Normal file

@ -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 <vtkm/Types.h>
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<int Dimensions>
struct Extent
{
vtkm::Tuple<vtkm::Id,Dimensions> Min;
vtkm::Tuple<vtkm::Id,Dimensions> Max;
VTKM_EXEC_CONT_EXPORT
Extent() : Min(0), Max(0) { }
VTKM_EXEC_CONT_EXPORT
Extent(const vtkm::Tuple<vtkm::Id,Dimensions> &min,
const vtkm::Tuple<vtkm::Id,Dimensions> &max)
: Min(min), Max(max) { }
VTKM_EXEC_CONT_EXPORT
Extent(const Extent<Dimensions> &other)
: Min(other.Min), Max(other.Max) { }
VTKM_EXEC_CONT_EXPORT
Extent<Dimensions> &operator=(const Extent<Dimensions> &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<int Dimensions>
VTKM_EXEC_CONT_EXPORT
vtkm::Tuple<vtkm::Id,Dimensions>
ExtentPointDimensions(const vtkm::Extent<Dimensions> &extent)
{
return extent.Max - extent.Min + vtkm::Tuple<vtkm::Id,Dimensions>(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<int Dimensions>
VTKM_EXEC_CONT_EXPORT
vtkm::Tuple<vtkm::Id,Dimensions>
ExtentCellDimensions(const vtkm::Extent<Dimensions> &extent)
{
return extent.Max - extent.Min;
}
/// Given an extent, returns the number of points in the structured mesh.
///
template<int Dimensions>
VTKM_EXEC_CONT_EXPORT
vtkm::Id ExtentNumberOfPoints(const vtkm::Extent<Dimensions> &extent)
{
return internal::product_vector<Dimensions>()(
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<int Dimensions>
VTKM_EXEC_CONT_EXPORT
vtkm::Id ExtentNumberOfCells(const vtkm::Extent<Dimensions> &extent)
{
return internal::product_vector<Dimensions>()(
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<int Dimensions>
VTKM_EXEC_CONT_EXPORT
vtkm::Tuple<vtkm::Id,Dimensions>
ExtentPointFlatIndexToTopologyIndex(vtkm::Id index,
const vtkm::Extent<Dimensions> &extent)
{
const vtkm::Tuple<vtkm::Id,Dimensions> dims =
vtkm::ExtentPointDimensions(extent);
vtkm::Tuple<vtkm::Id,Dimensions> 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<int Dimensions>
VTKM_EXEC_CONT_EXPORT
vtkm::Tuple<vtkm::Id,Dimensions>
ExtentCellFlatIndexToTopologyIndex(vtkm::Id index,
const vtkm::Extent<Dimensions> &extent)
{
const vtkm::Tuple<vtkm::Id,Dimensions> dims =
vtkm::ExtentCellDimensions(extent);
vtkm::Tuple<vtkm::Id,Dimensions> 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<int Dimensions>
VTKM_EXEC_CONT_EXPORT
vtkm::Id
ExtentPointTopologyIndexToFlatIndex(const vtkm::Tuple<vtkm::Id,Dimensions> &ijk,
const vtkm::Extent<Dimensions> &extent)
{
const vtkm::Tuple<vtkm::Id,Dimensions> dims = ExtentPointDimensions(extent);
const vtkm::Tuple<vtkm::Id,Dimensions> 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<int Dimensions>
VTKM_EXEC_CONT_EXPORT
vtkm::Id
ExtentCellTopologyIndexToFlatIndex(const vtkm::Tuple<vtkm::Id,Dimensions> &ijk,
const vtkm::Extent<Dimensions> &extent)
{
const vtkm::Tuple<vtkm::Id,Dimensions> dims = ExtentCellDimensions(extent);
const vtkm::Tuple<vtkm::Id,Dimensions> 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<int Dimensions>
VTKM_EXEC_CONT_EXPORT
vtkm::Id ExtentFirstPointOnCell(vtkm::Id cellIndex,
const Extent<Dimensions> &extent)
{
return ExtentPointTopologyIndexToFlatIndex(
ExtentCellFlatIndexToTopologyIndex(cellIndex,extent),
extent);
}
} // namespace vtkm
#endif //vtk_m_Extent_h

@ -241,6 +241,116 @@ struct copy_vector<3>
}
};
template<int Size>
struct sum_vector
{
template<typename T>
VTKM_EXEC_CONT_EXPORT
typename T::ComponentType operator()(const T &x)
{
return sum_vector<Size-1>()(x) + x[Size-1];
}
};
template<>
struct sum_vector<1>
{
template<typename T>
VTKM_EXEC_CONT_EXPORT
typename T::ComponentType operator()(const T &x)
{
return x[0];
}
};
template<>
struct sum_vector<2>
{
template<typename T>
VTKM_EXEC_CONT_EXPORT
typename T::ComponentType operator()(const T &x)
{
return x[0] + x[1];
}
};
template<>
struct sum_vector<3>
{
template<typename T>
VTKM_EXEC_CONT_EXPORT
typename T::ComponentType operator()(const T &x)
{
return x[0] + x[1] + x[2];
}
};
template<>
struct sum_vector<4>
{
template<typename T>
VTKM_EXEC_CONT_EXPORT
typename T::ComponentType operator()(const T &x)
{
return x[0] + x[1] + x[2] + x[3];
}
};
template<int Size>
struct product_vector
{
template<typename T>
VTKM_EXEC_CONT_EXPORT
typename T::ComponentType operator()(const T &x)
{
return product_vector<Size-1>()(x) * x[Size-1];
}
};
template<>
struct product_vector<1>
{
template<typename T>
VTKM_EXEC_CONT_EXPORT
typename T::ComponentType operator()(const T &x)
{
return x[0];
}
};
template<>
struct product_vector<2>
{
template<typename T>
VTKM_EXEC_CONT_EXPORT
typename T::ComponentType operator()(const T &x)
{
return x[0] * x[1];
}
};
template<>
struct product_vector<3>
{
template<typename T>
VTKM_EXEC_CONT_EXPORT
typename T::ComponentType operator()(const T &x)
{
return x[0] * x[1] * x[2];
}
};
template<>
struct product_vector<4>
{
template<typename T>
VTKM_EXEC_CONT_EXPORT
typename T::ComponentType operator()(const T &x)
{
return x[0] * x[1] * x[2] * x[3];
}
};
} // namespace internal

@ -26,6 +26,7 @@ set(headers
VTKM_declare_headers(${headers})
set(unit_tests
UnitTestExtent.cxx
UnitTestTesting.cxx
UnitTestTypes.cxx
UnitTestTypeTraits.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 <vtkm/Extent.h>
#include <vtkm/testing/Testing.h>
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<int Dimensions>
void TestDimensions(vtkm::Extent<Dimensions>)
{
std::cout << "Testing Dimension sizes for " << Dimensions << " dimensions"
<< std::endl;
vtkm::Extent<Dimensions> extent;
vtkm::Tuple<vtkm::Id,Dimensions> pointDims;
vtkm::Tuple<vtkm::Id,Dimensions> 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<int Dimensions>
void TryIndexConversion(const vtkm::Extent<Dimensions> &extent)
{
typedef vtkm::Tuple<vtkm::Id,Dimensions> 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<int Dimensions>
void TestIndexConversion(vtkm::Extent<Dimensions>)
{
std::cout << "Testing index conversion for " << Dimensions << " dimensions."
<< std::endl;
vtkm::Extent<Dimensions> 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);
}