From 5cb493427978ec6f37fc2b52d98018b4a43ec6d1 Mon Sep 17 00:00:00 2001 From: Kenneth Moreland Date: Wed, 30 Apr 2014 17:07:57 -0600 Subject: [PATCH 1/5] 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); +} From 406e655910f34c2c2a106ceed4b5acb7a600aebb Mon Sep 17 00:00:00 2001 From: Kenneth Moreland Date: Thu, 1 May 2014 19:19:54 -0400 Subject: [PATCH 2/5] Add implicit array for uniform grid point coordinates. --- vtkm/cont/ArrayHandleCounting.h | 2 + .../cont/ArrayHandleUniformPointCoordinates.h | 158 ++++++++++++++++++ vtkm/cont/CMakeLists.txt | 2 + vtkm/cont/testing/CMakeLists.txt | 1 + ...TestArrayHandleUniformPointCoordinates.cxx | 87 ++++++++++ 5 files changed, 250 insertions(+) create mode 100644 vtkm/cont/ArrayHandleUniformPointCoordinates.h create mode 100644 vtkm/cont/testing/UnitTestArrayHandleUniformPointCoordinates.cxx diff --git a/vtkm/cont/ArrayHandleCounting.h b/vtkm/cont/ArrayHandleCounting.h index 5efb04cd5..2520ad90d 100644 --- a/vtkm/cont/ArrayHandleCounting.h +++ b/vtkm/cont/ArrayHandleCounting.h @@ -118,11 +118,13 @@ class ArrayHandleCounting > Superclass; public: + VTKM_CONT_EXPORT ArrayHandleCounting(CountingValueType startingValue, vtkm::Id length) :Superclass(typename Superclass::PortalConstControl(startingValue, length)) { } + VTKM_CONT_EXPORT ArrayHandleCounting():Superclass() {} }; diff --git a/vtkm/cont/ArrayHandleUniformPointCoordinates.h b/vtkm/cont/ArrayHandleUniformPointCoordinates.h new file mode 100644 index 000000000..7134cd8fb --- /dev/null +++ b/vtkm/cont/ArrayHandleUniformPointCoordinates.h @@ -0,0 +1,158 @@ +//============================================================================ +// 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_cont_ArrayHandleUniformPointCoordinates_h +#define vtk_m_cont_ArrayHandleUniformPointCoordinates_h + +#include + +#include +#include + +#include + +namespace vtkm { +namespace cont { + +namespace internal { + +/// \brief An implicit array port that computes point coordinates for a uniform +/// grid. +/// +class ArrayPortalUniformPointCoordinates +{ +public: + typedef vtkm::Vector3 ValueType; + + VTKM_EXEC_CONT_EXPORT + ArrayPortalUniformPointCoordinates() : NumberOfValues(0) { } + + VTKM_EXEC_CONT_EXPORT + ArrayPortalUniformPointCoordinates(vtkm::Extent3 extent, + vtkm::Vector3 origin, + vtkm::Vector3 spacing) + : Extent(extent), + Dimensions(vtkm::ExtentPointDimensions(extent)), + NumberOfValues(vtkm::ExtentNumberOfPoints(extent)), + Origin(origin), + Spacing(spacing) + { } + + VTKM_EXEC_CONT_EXPORT + ArrayPortalUniformPointCoordinates( + const ArrayPortalUniformPointCoordinates &src) + : Extent(src.Extent), + Dimensions(src.Dimensions), + NumberOfValues(src.NumberOfValues), + Origin(src.Origin), + Spacing(src.Spacing) + { } + + VTKM_EXEC_CONT_EXPORT + ArrayPortalUniformPointCoordinates & + operator=(const ArrayPortalUniformPointCoordinates &src) + { + this->Extent = src.Extent; + this->Dimensions = src.Dimensions; + this->NumberOfValues = src.NumberOfValues; + this->Origin = src.Origin; + this->Spacing = src.Spacing; + return *this; + } + + VTKM_EXEC_CONT_EXPORT + vtkm::Id GetNumberOfValues() const { return this->NumberOfValues; } + + VTKM_EXEC_CONT_EXPORT + vtkm::Vector3 Get(vtkm::Id index) const { + return this->GetCoordinatesForTopologyIndex( + vtkm::ExtentPointFlatIndexToTopologyIndex(index, this->Extent)); + } + + VTKM_EXEC_CONT_EXPORT + vtkm::Id3 GetRange3() const { return this->Dimensions; } + + VTKM_EXEC_CONT_EXPORT + vtkm::Vector3 Get(vtkm::Id3 index) const { + return this->GetCoordinatesForTopologyIndex(index + this->Extent.Min); + } + + typedef vtkm::cont::internal::IteratorFromArrayPortal< + ArrayPortalUniformPointCoordinates> IteratorType; + + VTKM_CONT_EXPORT + IteratorType GetIteratorBegin() const { + return IteratorType(*this); + } + + VTKM_CONT_EXPORT + IteratorType GetIteratorEnd() const { + return IteratorType(*this, this->NumberOfValues); + } + +private: + vtkm::Extent3 Extent; + vtkm::Id3 Dimensions; + vtkm::Id NumberOfValues; + vtkm::Vector3 Origin; + vtkm::Vector3 Spacing; + + VTKM_EXEC_CONT_EXPORT + vtkm::Vector3 GetCoordinatesForTopologyIndex(vtkm::Id3 ijk) const { + return vtkm::Vector3(this->Origin[0] + this->Spacing[0]*ijk[0], + this->Origin[1] + this->Spacing[1]*ijk[1], + this->Origin[2] + this->Spacing[2]*ijk[2]); + } +}; + +} // namespace internal + +/// ArrayHandleUniformPointCoordinates is a specialization of ArrayHandle. It +/// contains the information necessary to compute the point coordinates in a +/// uniform orthogonal grid (extent, origin, and spacing) and implicitly +/// computes these coordinates in its array portal. +/// +class ArrayHandleUniformPointCoordinates + : public vtkm::cont::ArrayHandle< + vtkm::Vector3, + vtkm::cont::ArrayContainerControlTagImplicit< + internal::ArrayPortalUniformPointCoordinates> > +{ + typedef vtkm::cont::ArrayHandle< + vtkm::Vector3, + vtkm::cont::ArrayContainerControlTagImplicit< + internal::ArrayPortalUniformPointCoordinates> > Superclass; + +public: + VTKM_CONT_EXPORT + ArrayHandleUniformPointCoordinates() : Superclass() { } + + VTKM_CONT_EXPORT + ArrayHandleUniformPointCoordinates(vtkm::Extent3 extent, + vtkm::Vector3 origin, + vtkm::Vector3 spacing) + : Superclass( + internal::ArrayPortalUniformPointCoordinates(extent, origin, spacing)) + { } +}; + +} +} // namespace vtkm::cont + +#endif //vtk_+m_cont_ArrayHandleUniformPointCoordinates_h diff --git a/vtkm/cont/CMakeLists.txt b/vtkm/cont/CMakeLists.txt index f56518d16..69722e9f8 100644 --- a/vtkm/cont/CMakeLists.txt +++ b/vtkm/cont/CMakeLists.txt @@ -25,6 +25,8 @@ set(headers ArrayContainerControlBasic.h ArrayContainerControlImplicit.h ArrayHandle.h + ArrayHandleCounting.h + ArrayHandleUniformPointCoordinates.h ArrayPortal.h Assert.h DeviceAdapter.h diff --git a/vtkm/cont/testing/CMakeLists.txt b/vtkm/cont/testing/CMakeLists.txt index 782a32928..8b4064ca8 100644 --- a/vtkm/cont/testing/CMakeLists.txt +++ b/vtkm/cont/testing/CMakeLists.txt @@ -30,6 +30,7 @@ set(unit_tests UnitTestArrayContainerControlImplicit.cxx UnitTestArrayHandle.cxx UnitTestArrayHandleCounting.cxx + UnitTestArrayHandleUniformPointCoordinates.cxx UnitTestContTesting.cxx UnitTestDeviceAdapterAlgorithmDependency.cxx UnitTestDeviceAdapterAlgorithmGeneral.cxx diff --git a/vtkm/cont/testing/UnitTestArrayHandleUniformPointCoordinates.cxx b/vtkm/cont/testing/UnitTestArrayHandleUniformPointCoordinates.cxx new file mode 100644 index 000000000..7300407f5 --- /dev/null +++ b/vtkm/cont/testing/UnitTestArrayHandleUniformPointCoordinates.cxx @@ -0,0 +1,87 @@ +//============================================================================ +// 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 vtkm::Id3 MIN_VALUES(-5, 8, 40); +const vtkm::Id3 MAX_VALUES(10, 25, 44); +const vtkm::Id3 POINT_DIMS(16, 18, 5); +const vtkm::Id NUM_POINTS = 1440; + +const vtkm::Vector3 ORIGIN(30, -3, -14); +const vtkm::Vector3 SPACING(10, 1, 0.1); +const vtkm::Vector3 LOWER_LEFT(-20, 5, -10); // MIN_VALUES*SPACING + ORIGIN + +void TestArrayHandleUniformPointCoordinates() +{ + std::cout << "Creating ArrayHandleUniformPointCoordinates" << std::endl; + + vtkm::cont::ArrayHandleUniformPointCoordinates arrayHandle( + vtkm::Extent3(MIN_VALUES, MAX_VALUES), ORIGIN, SPACING); + VTKM_TEST_ASSERT(arrayHandle.GetNumberOfValues() == NUM_POINTS, + "Array computed wrong number of points."); + + std::cout << "Getting array portal." << std::endl; + vtkm::cont::internal::ArrayPortalUniformPointCoordinates portal = + arrayHandle.GetPortalConstControl(); + VTKM_TEST_ASSERT(portal.GetNumberOfValues() == NUM_POINTS, + "Portal has wrong number of points."); + VTKM_TEST_ASSERT(portal.GetRange3() == POINT_DIMS, + "Portal range is wrong."); + + std::cout << "Checking computed values of portal." << std::endl; + vtkm::Vector3 expectedValue; + vtkm::Id flatIndex = 0; + vtkm::Id3 blockIndex; + expectedValue[2] = LOWER_LEFT[2]; + for (blockIndex[2] = 0; blockIndex[2] < POINT_DIMS[2]; blockIndex[2]++) + { + expectedValue[1] = LOWER_LEFT[1]; + for (blockIndex[1] = 0; blockIndex[1] < POINT_DIMS[1]; blockIndex[1]++) + { + expectedValue[0] = LOWER_LEFT[0]; + for (blockIndex[0] = 0; blockIndex[0] < POINT_DIMS[0]; blockIndex[0]++) + { + VTKM_TEST_ASSERT(test_equal(expectedValue, portal.Get(flatIndex)), + "Got wrong value for flat index."); + + VTKM_TEST_ASSERT(test_equal(expectedValue, portal.Get(blockIndex)), + "Got wrong value for block index."); + + flatIndex++; + expectedValue[0] += SPACING[0]; + } + expectedValue[1] += SPACING[1]; + } + expectedValue[2] += SPACING[2]; + } +} + +} // anonymous namespace + +int UnitTestArrayHandleUniformPointCoordinates(int, char *[]) +{ + return vtkm::cont::testing::Testing::Run( + TestArrayHandleUniformPointCoordinates); +} From 438fe0ff8de303088183240c901cf63a00e03e18 Mon Sep 17 00:00:00 2001 From: Kenneth Moreland Date: Tue, 6 May 2014 13:28:08 -0600 Subject: [PATCH 3/5] Implement FunctionInterface::StaticTransform This will allow a faster conversion than the dynamic transform and will allow you to define compile-time types for transformation unlike dynamic transform or invoke with transform. --- vtkm/internal/FunctionInterface.h | 178 +++++++++++++++++- .../testing/UnitTestFunctionInterface.cxx | 44 ++++- 2 files changed, 220 insertions(+), 2 deletions(-) diff --git a/vtkm/internal/FunctionInterface.h b/vtkm/internal/FunctionInterface.h index 665f0cf98..714e671d8 100644 --- a/vtkm/internal/FunctionInterface.h +++ b/vtkm/internal/FunctionInterface.h @@ -247,7 +247,7 @@ struct IdentityFunctor { f(BOOST_PP_ENUM_SHIFTED(NumParamsPlusOne, VTK_M_DO_INVOKE_TPARAM, )); \ } #define VTK_M_DO_INVOKE_REPEAT(z, NumParams, data) \ - VTK_M_DO_INVOKE(BOOST_PP_INC(NumParams)); + VTK_M_DO_INVOKE(BOOST_PP_INC(NumParams)) #define VTK_M_DO_INVOKE_NAME DoInvokeCont #define VTK_M_DO_INVOKE_EXPORT VTKM_CONT_EXPORT @@ -318,6 +318,69 @@ struct FunctionInterfaceCopyParameters<0, ParameterIndex> { } }; +template +struct FunctionInterfaceStaticTransformType; + +// The following code uses the Boost preprocessor utilities to create +// definitions of DoStaticTransform functions for all supported number of +// arguments. The created functions are conceptually defined as follows: +// +// template +// VTKM_CONT_EXPORT +// void DoStaticTransformCont( +// const Transform &transform, +// const ParameterContainer &originalParameters, +// ParameterContainer &transformedParameters) +// { +// transformedParameters.Parameter1 = transform(originalParameters.Parameter1); +// transformedParameters.Parameter2 = transform(originalParameters.Parameter2); +// ... +// } +// +// We define multiple DoStaticTransformCont and DoStaticTransformExec that do +// identical things with different exports. It is important to have these +// separate definitions instead of a single version with VTKM_EXEC_CONT_EXPORT +// because the transform to be invoked may only be viable in one or the other. + +#define VTK_M_DO_STATIC_TRANSFORM_ASSIGN(z, count, data) \ + BOOST_PP_IF(count, \ + BOOST_PP_CAT(transformedParameters.Parameter, count) = \ + transform(BOOST_PP_CAT(originalParameters.Parameter, count));,) + +#define VTK_M_DO_STATIC_TRANSFORM(NumParamsPlusOne) \ + template \ + VTK_M_DO_STATIC_TRANSFORM_EXPORT \ + void VTK_M_DO_STATIC_TRANSFORM_NAME( \ + const Transform &transform, \ + ParameterContainer &originalParameters, \ + ParameterContainer &transformedParameters) \ + { \ + (void)transform; \ + (void)originalParameters; \ + (void)transformedParameters; \ + BOOST_PP_REPEAT(NumParamsPlusOne, VTK_M_DO_STATIC_TRANSFORM_ASSIGN,) \ + } +#define VTK_M_DO_STATIC_TRANSFORM_REPEAT(z, NumParams, data) \ + VTK_M_DO_STATIC_TRANSFORM(BOOST_PP_INC(NumParams)) + +#define VTK_M_DO_STATIC_TRANSFORM_NAME DoStaticTransformCont +#define VTK_M_DO_STATIC_TRANSFORM_EXPORT VTKM_CONT_EXPORT +BOOST_PP_REPEAT(BOOST_PP_INC(VTKM_MAX_FUNCTION_PARAMETERS), + VTK_M_DO_STATIC_TRANSFORM_REPEAT,) +#undef VTK_M_DO_STATIC_TRANSFORM_EXPORT +#undef VTK_M_DO_STATIC_TRANSFORM_NAME + +#define VTK_M_DO_STATIC_TRANSFORM_NAME DoStaticTransformExec +#define VTK_M_DO_STATIC_TRANSFORM_EXPORT VTKM_EXEC_EXPORT +BOOST_PP_REPEAT(BOOST_PP_INC(VTKM_MAX_FUNCTION_PARAMETERS), + VTK_M_DO_STATIC_TRANSFORM_REPEAT,) +#undef VTK_M_DO_STATIC_TRANSFORM_EXPORT +#undef VTK_M_DO_STATIC_TRANSFORM_NAME + template + struct StaticTransformType { + typedef FunctionInterface< + typename detail::FunctionInterfaceStaticTransformType< + FunctionSignature,Transform>::type> type; + }; + + /// \brief Transforms the \c FunctionInterface based on compile-time + /// information. + /// + /// The \c StaticTransform method transforms all the parameters of this \c + /// FunctionInterface to different types and values based on compile-time + /// information. It operates by accepting a functor that defines a unary + /// function whose argument is the parameter to transform and the return + /// value is the transformed value. The functor must also contain a templated + /// struct name ReturnType with an internal type named \c type that defines + /// the return type of the transform for a given input type. + /// + /// The transformation is only applied to the parameters of the function. The + /// return argument is uneffected. + /// + /// The return type can be determined with the \c StaticTransformType + /// template. + /// + /// Here is an example of a transformation that converts a \c + /// FunctionInterface to another \c FunctionInterface containing pointers to + /// all of the parameters. + /// + /// \code + /// struct MyTransformFunctor { + /// template + /// struct ReturnType { + /// typedef const T *type; + /// }; + /// + /// template + /// DAX_CONT_EXPORT + /// const T *operator()(const T &x) const { + /// return &x; + /// } + /// }; + /// + /// template + /// typename vtkm::internal::FunctionInterface::template StaticTransformType::type + /// ImportantStuff(const vtkm::internal::FunctionInterface &funcInterface) + /// { + /// return funcInterface.StaticTransformCont(MyTransformFunctor()); + /// } + /// \endcode + /// + template + VTKM_CONT_EXPORT + typename StaticTransformType::type + StaticTransformCont(const Transform &transform) + { + typename StaticTransformType::type newFuncInterface; + detail::DoStaticTransformCont(transform, + this->Parameters, + newFuncInterface.Parameters); + return newFuncInterface; + } + template + VTKM_EXEC_EXPORT + typename StaticTransformType::type + StaticTransformExec(const Transform &transform) + { + typename StaticTransformType::type newFuncInterface; + detail::DoStaticTransformExec(transform, + this->Parameters, + newFuncInterface.Parameters); + return newFuncInterface; + } + /// \brief Transforms the \c FunctionInterface based on run-time information. /// /// The \c DynamicTransform method transforms all the parameters of this \c @@ -655,6 +791,46 @@ private: namespace detail { +// The following code uses the Boost preprocessor utilities to create +// definitions of FunctionInterfaceStaticTransformType for all supported number +// of arguments. The created classes are conceptually defined as follows: +// +// template +// struct FunctionInterfaceStaticTransformType { +// typedef P0(type)(typename Transform::template ReturnType::type, +// typename Transform::template ReturnType::type, ...); +// }; + +#define VTK_M_STATIC_TRANSFORM_TPARAM(z, ParamIndex, data) \ + BOOST_PP_IF( \ + ParamIndex, \ + typename Transform::template ReturnType::type,) + +#define VTK_M_STATIC_TRANSFORM_TYPE(NumParamsPlusOne) \ + template \ + struct FunctionInterfaceStaticTransformType< \ + P0(BOOST_PP_ENUM_SHIFTED_PARAMS(NumParamsPlusOne, P)), \ + Transform> \ + { \ + typedef P0(type)( \ + BOOST_PP_ENUM_SHIFTED(NumParamsPlusOne, VTK_M_STATIC_TRANSFORM_TPARAM,) \ + ); \ + }; +#define VTK_M_STATIC_TRANSFORM_TYPE_REPEAT(z, NumParams, data) \ + VTK_M_STATIC_TRANSFORM_TYPE(BOOST_PP_INC(NumParams)) + +BOOST_PP_REPEAT(BOOST_PP_INC(VTKM_MAX_FUNCTION_PARAMETERS), + VTK_M_STATIC_TRANSFORM_TYPE_REPEAT,) + +#undef VTK_M_STATIC_TRANSFORM_TYPE_REPEAT +#undef VTK_M_STATIC_TRANSFORM_TYPE +#undef VTK_M_STATIC_TRANSFORM_TPARAM + + template + struct ReturnType { + typedef const T *type; + }; + + template + const T *operator()(const T &x) const { + return &x; + } +}; + struct ThreePointerArgFunctor { void operator()(const Type1 *a1, const Type2 *a2, const Type3 *a3) const { - std::cout << "In 3 arg functor." << std::endl; + std::cout << "In 3 point arg functor." << std::endl; VTKM_TEST_ASSERT(*a1 == Arg1, "Arg 1 incorrect."); VTKM_TEST_ASSERT(*a2 == Arg2, "Arg 2 incorrect."); @@ -409,6 +421,35 @@ void TestTransformInvoke() "Got bad result from invoke."); } +void TestStaticTransform() +{ + std::cout << "Trying static transform." << std::endl; + typedef vtkm::internal::FunctionInterface + OriginalType; + OriginalType funcInterface = + vtkm::internal::make_FunctionInterface(Arg1, Arg2, Arg3); + + std::cout << "Transform with reported type." << std::endl; + typedef OriginalType::StaticTransformType::type + ReportedType; + ReportedType funcInterfaceTransform1 = + funcInterface.StaticTransformCont(PointerTransform()); + funcInterfaceTransform1.InvokeCont(ThreePointerArgFunctor()); + funcInterfaceTransform1 = + funcInterface.StaticTransformExec(PointerTransform()); + funcInterfaceTransform1.InvokeExec(ThreePointerArgFunctor()); + + std::cout << "Transform with expected type." << std::endl; + typedef vtkm::internal::FunctionInterface + ExpectedType; + ReportedType funcInterfaceTransform2 = + funcInterface.StaticTransformCont(PointerTransform()); + funcInterfaceTransform2.InvokeCont(ThreePointerArgFunctor()); + funcInterfaceTransform2 = + funcInterface.StaticTransformExec(PointerTransform()); + funcInterfaceTransform2.InvokeExec(ThreePointerArgFunctor()); +} + void TestDynamicTransform() { std::cout << "Trying dynamic transform." << std::endl; @@ -487,6 +528,7 @@ void TestFunctionInterface() TestInvokeResult(); TestAppend(); TestTransformInvoke(); + TestStaticTransform(); TestDynamicTransform(); TestInvokeTime(); } From d3134b70509181f6f32f757004174a1dc0692867 Mon Sep 17 00:00:00 2001 From: Kenneth Moreland Date: Tue, 13 May 2014 13:18:21 -0600 Subject: [PATCH 4/5] Add ForEach methods to FunctionInterface. Provides a convienient mechanism to do an in-place type-preserving transform or a check of each parameter. --- vtkm/internal/FunctionInterface.h | 136 ++++++++++++++++-- .../testing/UnitTestFunctionInterface.cxx | 36 +++++ 2 files changed, 161 insertions(+), 11 deletions(-) diff --git a/vtkm/internal/FunctionInterface.h b/vtkm/internal/FunctionInterface.h index 714e671d8..02a5a8bb8 100644 --- a/vtkm/internal/FunctionInterface.h +++ b/vtkm/internal/FunctionInterface.h @@ -192,11 +192,15 @@ struct IdentityFunctor { // definitions of DoInvoke functions for all supported number of arguments. // The created functions are conceptually defined as follows: // -// template +// template // VTKM_CONT_EXPORT // void DoInvokeCont(const Function &f, -// ParameterContainer ¶meters, -// FunctionInterfaceReturnContainer &result, +// ParameterContainer ¶meters, +// FunctionInterfaceReturnContainer &result, // const TransformFunctor &transform) // { // result.Value = transform(f(transform(parameters.Parameter1),...)); @@ -356,7 +360,7 @@ struct FunctionInterfaceStaticTransformType; VTK_M_DO_STATIC_TRANSFORM_EXPORT \ void VTK_M_DO_STATIC_TRANSFORM_NAME( \ const Transform &transform, \ - ParameterContainer &originalParameters, \ + const ParameterContainer &originalParameters, \ ParameterContainer &transformedParameters) \ { \ (void)transform; \ @@ -381,12 +385,96 @@ BOOST_PP_REPEAT(BOOST_PP_INC(VTKM_MAX_FUNCTION_PARAMETERS), #undef VTK_M_DO_STATIC_TRANSFORM_EXPORT #undef VTK_M_DO_STATIC_TRANSFORM_NAME +#undef VTK_M_DO_STATIC_TRANSFORM_REPEAT +#undef VTK_M_DO_STATIC_TRANSFORM +#undef VTK_M_DO_STATIC_TRANSFORM_ASSIGN + template class FunctionInterfaceDynamicTransformContContinue; +// The following code uses the Boost preprocessor utilities to create +// definitions of DoForEach functions for all supported number of arguments. +// The created functions are conceptually defined as follows: +// +// template +// VTKM_CONT_EXPORT +// void DoForEachCont(const Functor &f, +// ParameterContainer ¶meters) +// +// { +// f(parameters.Parameter1); +// f(parameters.Parameter2); +// ... +// } +// +// We define multiple DoForEachCont and DoForEachExec that do identical things +// with different exports. It is important to have these separate definitions +// instead of a single version with VTKM_EXEC_CONT_EXPORT because the functor +// to be invoked on each parameter may only be viable in one or the other. +// There are also separate versions that support a const FunctionInterface and +// a non-const FunctionInterface. + +#define VTK_M_DO_FOR_EACH_CALL_PARAM(z, count, data) \ + BOOST_PP_IF(count, f(BOOST_PP_CAT(parameters.Parameter, count));,) + +#define VTK_M_DO_FOR_EACH(NumParamsPlusOne) \ + template \ + VTK_M_DO_FOR_EACH_EXPORT \ + void VTK_M_DO_FOR_EACH_NAME( \ + const Functor &f, \ + VTK_M_DO_FOR_EACH_FI_CONST ParameterContainer ¶meters) \ + { \ + (void)f; \ + (void)parameters; \ + BOOST_PP_REPEAT(NumParamsPlusOne, VTK_M_DO_FOR_EACH_CALL_PARAM,) \ + } +#define VTK_M_DO_FOR_EACH_REPEAT(z, NumParams, data) \ + VTK_M_DO_FOR_EACH(BOOST_PP_INC(NumParams)) + +#define VTK_M_DO_FOR_EACH_EXPORT VTKM_CONT_EXPORT +#define VTK_M_DO_FOR_EACH_NAME DoForEachCont +#define VTK_M_DO_FOR_EACH_FI_CONST const +BOOST_PP_REPEAT(BOOST_PP_INC(VTKM_MAX_FUNCTION_PARAMETERS), + VTK_M_DO_FOR_EACH_REPEAT,) +#undef VTK_M_DO_FOR_EACH_FI_CONST +#undef VTK_M_DO_FOR_EACH_NAME +#undef VTK_M_DO_FOR_EACH_EXPORT + +#define VTK_M_DO_FOR_EACH_EXPORT VTKM_CONT_EXPORT +#define VTK_M_DO_FOR_EACH_NAME DoForEachCont +#define VTK_M_DO_FOR_EACH_FI_CONST +BOOST_PP_REPEAT(BOOST_PP_INC(VTKM_MAX_FUNCTION_PARAMETERS), + VTK_M_DO_FOR_EACH_REPEAT,) +#undef VTK_M_DO_FOR_EACH_FI_CONST +#undef VTK_M_DO_FOR_EACH_NAME +#undef VTK_M_DO_FOR_EACH_EXPORT + +#define VTK_M_DO_FOR_EACH_EXPORT VTKM_EXEC_EXPORT +#define VTK_M_DO_FOR_EACH_NAME DoForEachExec +#define VTK_M_DO_FOR_EACH_FI_CONST const +BOOST_PP_REPEAT(BOOST_PP_INC(VTKM_MAX_FUNCTION_PARAMETERS), + VTK_M_DO_FOR_EACH_REPEAT,) +#undef VTK_M_DO_FOR_EACH_FI_CONST +#undef VTK_M_DO_FOR_EACH_NAME +#undef VTK_M_DO_FOR_EACH_EXPORT + +#define VTK_M_DO_FOR_EACH_EXPORT VTKM_EXEC_EXPORT +#define VTK_M_DO_FOR_EACH_NAME DoForEachExec +#define VTK_M_DO_FOR_EACH_FI_CONST +BOOST_PP_REPEAT(BOOST_PP_INC(VTKM_MAX_FUNCTION_PARAMETERS), + VTK_M_DO_FOR_EACH_REPEAT,) +#undef VTK_M_DO_FOR_EACH_FI_CONST +#undef VTK_M_DO_FOR_EACH_NAME +#undef VTK_M_DO_FOR_EACH_EXPORT + +#undef VTK_M_DO_FOR_EACH_REPEAT +#undef VTK_M_DO_FOR_EACH +#undef VTK_M_DO_FOR_EACH_CALL_PARAM + } // namespace detail template @@ -461,7 +549,7 @@ public: template VTKM_EXEC_CONT_EXPORT typename ParameterType::type - GetParameter() { + GetParameter() const { return detail::GetParameter(this->Parameters); } @@ -632,7 +720,7 @@ public: /// \brief Transforms the \c FunctionInterface based on compile-time /// information. /// - /// The \c StaticTransform method transforms all the parameters of this \c + /// The \c StaticTransform methods transform all the parameters of this \c /// FunctionInterface to different types and values based on compile-time /// information. It operates by accepting a functor that defines a unary /// function whose argument is the parameter to transform and the return @@ -675,7 +763,7 @@ public: template VTKM_CONT_EXPORT typename StaticTransformType::type - StaticTransformCont(const Transform &transform) + StaticTransformCont(const Transform &transform) const { typename StaticTransformType::type newFuncInterface; detail::DoStaticTransformCont(transform, @@ -686,7 +774,7 @@ public: template VTKM_EXEC_EXPORT typename StaticTransformType::type - StaticTransformExec(const Transform &transform) + StaticTransformExec(const Transform &transform) const { typename StaticTransformType::type newFuncInterface; detail::DoStaticTransformExec(transform, @@ -767,9 +855,8 @@ public: /// template VTKM_CONT_EXPORT - void - DynamicTransformCont(const TransformFunctor &transform, - const FinishFunctor &finish) { + void DynamicTransformCont(const TransformFunctor &transform, + const FinishFunctor &finish) { typedef detail::FunctionInterfaceDynamicTransformContContinue< FunctionSignature, ResultType(), @@ -784,6 +871,33 @@ public: this->Result = emptyInterface.GetReturnValueSafe(); } + /// \brief Applies a function to all the parameters. + /// + /// The \c ForEach methods take a function and apply that function to each + /// of the parameters in the \c FunctionInterface. (Return values are not + /// effected.) + /// + template + VTKM_CONT_EXPORT + void ForEachCont(const Functor &f) const { + detail::DoForEachCont(f, this->Parameters); + } + template + VTKM_CONT_EXPORT + void ForEachCont(const Functor &f) { + detail::DoForEachCont(f, this->Parameters); + } + template + VTKM_EXEC_EXPORT + void ForEachExec(const Functor &f) const { + detail::DoForEachExec(f, this->Parameters); + } + template + VTKM_EXEC_EXPORT + void ForEachExec(const Functor &f) { + detail::DoForEachExec(f, this->Parameters); + } + private: vtkm::internal::FunctionInterfaceReturnContainer Result; detail::ParameterContainer Parameters; diff --git a/vtkm/internal/testing/UnitTestFunctionInterface.cxx b/vtkm/internal/testing/UnitTestFunctionInterface.cxx index 5a961a7cc..e41f124a0 100644 --- a/vtkm/internal/testing/UnitTestFunctionInterface.cxx +++ b/vtkm/internal/testing/UnitTestFunctionInterface.cxx @@ -298,6 +298,14 @@ struct DynamicTransformFinish } }; +struct ForEachFunctor +{ + template + void operator()(T &x) const { x = 2*x; } + + void operator()(std::string &x) const { x.append("*2"); } +}; + void TryFunctionInterface5( vtkm::internal::FunctionInterface funcInterface) { @@ -470,6 +478,33 @@ void TestDynamicTransform() "DynamicTransform did not call finish the right number of times."); } +void TestForEach() +{ + std::cout << "Checking running a function on each parameter." << std::endl; + vtkm::internal::FunctionInterface + funcInterface = vtkm::internal::make_FunctionInterface( + Arg1, Arg2, Arg3, Arg4, Arg5); + VTKM_TEST_ASSERT(funcInterface.GetParameter<1>() == Arg1, "Arg 1 incorrect."); + VTKM_TEST_ASSERT(funcInterface.GetParameter<2>() == Arg2, "Arg 2 incorrect."); + VTKM_TEST_ASSERT(funcInterface.GetParameter<3>() == Arg3, "Arg 3 incorrect."); + VTKM_TEST_ASSERT(funcInterface.GetParameter<4>() == Arg4, "Arg 4 incorrect."); + VTKM_TEST_ASSERT(funcInterface.GetParameter<5>() == Arg5, "Arg 5 incorrect."); + + funcInterface.ForEachCont(ForEachFunctor()); + VTKM_TEST_ASSERT(funcInterface.GetParameter<1>() == 2*Arg1, "Arg 1 incorrect."); + VTKM_TEST_ASSERT(funcInterface.GetParameter<2>() == 2*Arg2, "Arg 2 incorrect."); + VTKM_TEST_ASSERT(funcInterface.GetParameter<3>() == Arg3+"*2", "Arg 3 incorrect."); + VTKM_TEST_ASSERT(funcInterface.GetParameter<4>() == 2*Arg4, "Arg 4 incorrect."); + VTKM_TEST_ASSERT(funcInterface.GetParameter<5>() == 2*Arg5, "Arg 5 incorrect."); + + funcInterface.ForEachExec(ForEachFunctor()); + VTKM_TEST_ASSERT(funcInterface.GetParameter<1>() == 4*Arg1, "Arg 1 incorrect."); + VTKM_TEST_ASSERT(funcInterface.GetParameter<2>() == 4*Arg2, "Arg 2 incorrect."); + VTKM_TEST_ASSERT(funcInterface.GetParameter<3>() == Arg3+"*2*2", "Arg 3 incorrect."); + VTKM_TEST_ASSERT(funcInterface.GetParameter<4>() == 4*Arg4, "Arg 4 incorrect."); + VTKM_TEST_ASSERT(funcInterface.GetParameter<5>() == 4*Arg5, "Arg 5 incorrect."); +} + void TestInvokeTime() { std::cout << "Checking time to call lots of args lots of times." << std::endl; @@ -530,6 +565,7 @@ void TestFunctionInterface() TestTransformInvoke(); TestStaticTransform(); TestDynamicTransform(); + TestForEach(); TestInvokeTime(); } From 261157ed2201708a42713580ca0c9ed7218d5045 Mon Sep 17 00:00:00 2001 From: Kenneth Moreland Date: Mon, 5 May 2014 09:24:03 -0600 Subject: [PATCH 5/5] Created ArrayHandleCompositeVector. This derived array handle creates an array of vectors whose components come from other arrays of vectors. In either case ArrayHandleCompositeVector handles scalars as vectors of size 1. --- vtkm/cont/ArrayHandleCompositeVector.h | 716 ++++++++++++++++++ vtkm/cont/CMakeLists.txt | 1 + vtkm/cont/testing/CMakeLists.txt | 1 + .../UnitTestArrayHandleCompositeVector.cxx | 313 ++++++++ 4 files changed, 1031 insertions(+) create mode 100644 vtkm/cont/ArrayHandleCompositeVector.h create mode 100644 vtkm/cont/testing/UnitTestArrayHandleCompositeVector.cxx diff --git a/vtkm/cont/ArrayHandleCompositeVector.h b/vtkm/cont/ArrayHandleCompositeVector.h new file mode 100644 index 000000000..b205d819d --- /dev/null +++ b/vtkm/cont/ArrayHandleCompositeVector.h @@ -0,0 +1,716 @@ +//============================================================================ +// 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_ArrayHandleCompositeVector_h +#define vtk_m_ArrayHandleCompositeVector_h + +#include +#include +#include + +#include + +#include + +#include + +namespace vtkm { +namespace cont { + +namespace internal { + +namespace detail { + +template +struct CompositeVectorSwizzleFunctor +{ + static const int NUM_COMPONENTS = + vtkm::VectorTraits::NUM_COMPONENTS; + typedef vtkm::Tuple ComponentMapType; + + // Caution! This is a reference. + const ComponentMapType &SourceComponents; + + VTKM_EXEC_CONT_EXPORT + CompositeVectorSwizzleFunctor(const ComponentMapType &sourceComponents) + : SourceComponents(sourceComponents) { } + + // Currently only supporting 1-4 components. + template + VTKM_EXEC_CONT_EXPORT + ValueType operator()(const T1 &p1) const { + return ValueType( + vtkm::VectorTraits::GetComponent(p1, this->SourceComponents[0])); + } + + template + VTKM_EXEC_CONT_EXPORT + ValueType operator()(const T1 &p1, const T2 &p2) const { + return ValueType( + vtkm::VectorTraits::GetComponent(p1, this->SourceComponents[0]), + vtkm::VectorTraits::GetComponent(p2, this->SourceComponents[1])); + } + + template + VTKM_EXEC_CONT_EXPORT + ValueType operator()(const T1 &p1, const T2 &p2, const T3 &p3) const { + return ValueType( + vtkm::VectorTraits::GetComponent(p1, this->SourceComponents[0]), + vtkm::VectorTraits::GetComponent(p2, this->SourceComponents[1]), + vtkm::VectorTraits::GetComponent(p3, this->SourceComponents[2])); + } + + template + VTKM_EXEC_CONT_EXPORT + ValueType operator()(const T1 &p1, + const T2 &p2, + const T3 &p3, + const T4 &p4) const { + return ValueType( + vtkm::VectorTraits::GetComponent(p1, this->SourceComponents[0]), + vtkm::VectorTraits::GetComponent(p2, this->SourceComponents[1]), + vtkm::VectorTraits::GetComponent(p3, this->SourceComponents[2]), + vtkm::VectorTraits::GetComponent(p4, this->SourceComponents[3])); + } +}; + +template +struct CompositeVectorPullValueFunctor +{ + vtkm::Id Index; + + VTKM_EXEC_EXPORT + CompositeVectorPullValueFunctor(vtkm::Id index) : Index(index) { } + + // This form is to pull values out of array arguments. + template + VTKM_EXEC_EXPORT + typename PortalType::ValueType operator()(const PortalType &portal) const { + return portal.Get(this->Index); + } + + // This form is an identity to pass the return value back. + VTKM_EXEC_EXPORT + const ReturnValueType &operator()(const ReturnValueType &value) const { + return value; + } +}; + +struct CompositeVectorArrayToPortalCont { + template + struct ReturnType { + typedef typename ArrayHandleType::PortalConstControl type; + }; + + template + VTKM_CONT_EXPORT + typename ReturnType::type + operator()(const ArrayHandleType &array) const { + return array.GetPortalConstControl(); + } +}; + +template +struct CompositeVectorArrayToPortalExec { + template + struct ReturnType { + typedef typename ArrayHandleType::template ExecutionTypes< + DeviceAdapterTag>::PortalConst type; + }; + + template + VTKM_CONT_EXPORT + typename ReturnType::type + operator()(const ArrayHandleType &array) const { + return array.PrepareForInput(DeviceAdapterTag()); + } +}; + +struct CheckArraySizeFunctor { + vtkm::Id ExpectedSize; + CheckArraySizeFunctor(vtkm::Id expectedSize) : ExpectedSize(expectedSize) { } + + template + void operator()(const T &a) const { + if (a.GetNumberOfValues() != this->ExpectedSize) + { + throw vtkm::cont::ErrorControlBadValue( + "All input arrays to ArrayHandleCompositeVector must be the same size."); + } + } +}; + +} // namespace detail + +/// \brief A portal that gets values from components of other portals. +/// +/// This is the portal used within ArrayHandleCompositeVector. +/// +template +class ArrayPortalCompositeVector +{ + typedef vtkm::internal::FunctionInterface PortalTypes; + typedef vtkm::Tuple ComponentMapType; + +public: + typedef typename PortalTypes::ResultType ValueType; + static const int NUM_COMPONENTS = + vtkm::VectorTraits::NUM_COMPONENTS; + + BOOST_STATIC_ASSERT(NUM_COMPONENTS == PortalTypes::ARITY); + + VTKM_EXEC_CONT_EXPORT + ArrayPortalCompositeVector() { } + + VTKM_CONT_EXPORT + ArrayPortalCompositeVector( + const PortalTypes portals, + vtkm::Tuple sourceComponents) + : Portals(portals), SourceComponents(sourceComponents) { } + + VTKM_EXEC_EXPORT + vtkm::Id GetNumberOfValues() const { + return this->Portals.template GetParameter<1>().GetNumberOfValues(); + } + + VTKM_EXEC_EXPORT + ValueType Get(vtkm::Id index) const { + // This might be inefficient because we are copying all the portals only + // because they are coupled with the return value. + PortalTypes localPortals = this->Portals; + localPortals.InvokeExec( + detail::CompositeVectorSwizzleFunctor(this->SourceComponents), + detail::CompositeVectorPullValueFunctor(index)); + return localPortals.GetReturnValue(); + } + +private: + PortalTypes Portals; + ComponentMapType SourceComponents; +}; + +/// \brief A "portal" that holds arrays to get components from. +/// +/// This class takes place as the control-side portal within an +/// ArrayHandleCompositeVector. This is an incomplete implementation, so you +/// really can't use it to get values. However, between this and the +/// specialization ArrayTransfer, it's enough to get values to the execution +/// environment. +/// +template +class ArrayPortalCompositeVectorCont +{ + typedef vtkm::internal::FunctionInterface + FunctionInterfaceArrays; + +public: + typedef typename FunctionInterfaceArrays::ResultType ValueType; + static const int NUM_COMPONENTS = + vtkm::VectorTraits::NUM_COMPONENTS; + typedef vtkm::Tuple ComponentMapType; + + // If you get a compile error here, it means you probably tried to create + // an ArrayHandleCompositeVector with a return type of a vector with a + // different number of components than the number of arrays given. + BOOST_STATIC_ASSERT(NUM_COMPONENTS == FunctionInterfaceArrays::ARITY); + + VTKM_CONT_EXPORT + ArrayPortalCompositeVectorCont() : NumberOfValues(0) { } + + VTKM_CONT_EXPORT + ArrayPortalCompositeVectorCont( + const FunctionInterfaceArrays &arrays, + const ComponentMapType &vtkmNotUsed(sourceComponents)) + : NumberOfValues(arrays.template GetParameter<1>().GetNumberOfValues()) { } + + VTKM_CONT_EXPORT + vtkm::Id GetNumberOfValues() const { + return this->NumberOfValues; + } + + VTKM_CONT_EXPORT + ValueType Get(vtkm::Id vtkmNotUsed(index)) const { + throw vtkm::cont::ErrorControlInternal("Not implemented."); + } + + VTKM_CONT_EXPORT + void Set(vtkm::Id vtkmNotUsed(index), ValueType vtkmNotUsed(value)) { + throw vtkm::cont::ErrorControlInternal("Not implemented."); + } + + // Not a viable type, but there is no implementation. + typedef ValueType *IteratorType; + + VTKM_CONT_EXPORT + IteratorType GetIteratorBegin() const { + throw vtkm::cont::ErrorControlInternal("Not implemented."); + } + + VTKM_CONT_EXPORT + IteratorType GetIteratorEnd() const { + throw vtkm::cont::ErrorControlInternal("Not implemented."); + } + +private: + vtkm::Id NumberOfValues; +}; + +template +struct ArrayContainerControlTagCompositeVector { }; + +/// A convenience class that provides a typedef to the appropriate tag for +/// a counting array container. +template +struct ArrayHandleCompositeVectorTraits +{ + typedef vtkm::cont::internal::ArrayContainerControlTagCompositeVector< + SignatureWithArrays> Tag; + typedef typename vtkm::internal::FunctionInterface::ResultType + ValueType; + typedef vtkm::cont::internal::ArrayContainerControl< + ValueType, Tag> ContainerType; +}; + +// It may seem weird that this specialization throws an exception for +// everything, but that is because all the functionality is handled in the +// ArrayTransfer class. +template +class ArrayContainerControl< + typename ArrayHandleCompositeVectorTraits::ValueType, + vtkm::cont::internal::ArrayContainerControlTagCompositeVector > +{ + typedef vtkm::internal::FunctionInterface + FunctionInterfaceWithArrays; + static const int NUM_COMPONENTS = FunctionInterfaceWithArrays::ARITY; + typedef vtkm::Tuple ComponentMapType; + +public: + typedef ArrayPortalCompositeVectorCont PortalType; + typedef PortalType PortalConstType; + typedef typename PortalType::ValueType ValueType; + + VTKM_CONT_EXPORT + ArrayContainerControl() : Valid(false) { } + + VTKM_CONT_EXPORT + ArrayContainerControl(const FunctionInterfaceWithArrays &arrays, + const ComponentMapType &sourceComponents) + : Arrays(arrays), SourceComponents(sourceComponents), Valid(true) + { + arrays.ForEachCont( + detail::CheckArraySizeFunctor(this->GetNumberOfValues())); + } + + VTKM_CONT_EXPORT + PortalType GetPortal() { + throw vtkm::cont::ErrorControlBadValue( + "Composite vector arrays are read only."); + } + + VTKM_CONT_EXPORT + PortalConstType GetPortalConst() const { + if (!this->Valid) + { + throw vtkm::cont::ErrorControlBadValue( + "Tried to use an ArrayHandleCompositeHandle without dependent arrays."); + } + return PortalConstType(this->Arrays, this->SourceComponents); + } + + VTKM_CONT_EXPORT + vtkm::Id GetNumberOfValues() const { + if (!this->Valid) + { + throw vtkm::cont::ErrorControlBadValue( + "Tried to use an ArrayHandleCompositeHandle without dependent arrays."); + } + return this->Arrays.template GetParameter<1>().GetNumberOfValues(); + } + + VTKM_CONT_EXPORT + void Allocate(vtkm::Id vtkmNotUsed(numberOfValues)) { + throw vtkm::cont::ErrorControlInternal( + + "The allocate method for the composite vector control array " + "container should never have been called. The allocate is generally " + "only called by the execution array manager, and the array transfer " + "for the transform container should prevent the execution array " + "manager from being directly used."); + } + + VTKM_CONT_EXPORT + void Shrink(vtkm::Id vtkmNotUsed(numberOfValues)) { + throw vtkm::cont::ErrorControlBadValue( + "Composite vector arrays are read-only."); + } + + VTKM_CONT_EXPORT + void ReleaseResources() { + if (this->Valid) + { + // TODO: Implement this. + } + } + + VTKM_CONT_EXPORT + const FunctionInterfaceWithArrays &GetArrays() const { + VTKM_ASSERT_CONT(this->Valid); + return this->Arrays; + } + + VTKM_CONT_EXPORT + const ComponentMapType &GetSourceComponents() const { + VTKM_ASSERT_CONT(this->Valid); + return this->SourceComponents; + } + +private: + FunctionInterfaceWithArrays Arrays; + ComponentMapType SourceComponents; + bool Valid; +}; + +template +class ArrayTransfer< + typename ArrayHandleCompositeVectorTraits::ValueType, + vtkm::cont::internal::ArrayContainerControlTagCompositeVector, + DeviceAdapterTag> +{ + VTKM_IS_DEVICE_ADAPTER_TAG(DeviceAdapterTag); + + typedef typename ArrayHandleCompositeVectorTraits::ContainerType + ContainerType; + + typedef vtkm::internal::FunctionInterface + FunctionWithArrays; + typedef typename FunctionWithArrays::template StaticTransformType< + detail::CompositeVectorArrayToPortalExec >::type + FunctionWithPortals; + typedef typename FunctionWithPortals::Signature SignatureWithPortals; + +public: + typedef typename ArrayHandleCompositeVectorTraits::ValueType + ValueType; + + // These are not currently fully implemented. + typedef typename ContainerType::PortalType PortalControl; + typedef typename ContainerType::PortalConstType PortalConstControl; + + typedef ArrayPortalCompositeVector PortalExecution; + typedef ArrayPortalCompositeVector PortalConstExecution; + + VTKM_CONT_EXPORT + ArrayTransfer() : ContainerValid(false) { } + + VTKM_CONT_EXPORT + vtkm::Id GetNumberOfValues() const { + VTKM_ASSERT_CONT(this->ContainerValid); + return this->Container.GetNumberOfValues(); + } + + VTKM_CONT_EXPORT + void LoadDataForInput(PortalConstControl vtkmNotUsed(contPortal)) + { + throw vtkm::cont::ErrorControlInternal( + "ArrayHandleCompositeVector in a bad state. " + "There must be a UserArray set, but how did that happen?"); + } + + VTKM_CONT_EXPORT + void LoadDataForInput(const ContainerType &controlArray) + { + this->Container = controlArray; + this->ContainerValid = true; + } + + VTKM_CONT_EXPORT + void LoadDataForInPlace(ContainerType &vtkmNotUsed(controlArray)) + { + throw vtkm::cont::ErrorControlBadValue( + "Composite vector arrays cannot be used for output or in place."); + } + + VTKM_CONT_EXPORT + void AllocateArrayForOutput(ContainerType &vtkmNotUsed(controlArray), + vtkm::Id vtkmNotUsed(numberOfValues)) + { + throw vtkm::cont::ErrorControlBadValue( + "Composite vector arrays cannot be used for output."); + } + + VTKM_CONT_EXPORT + void RetrieveOutputData(ContainerType &vtkmNotUsed(controlArray)) const + { + throw vtkm::cont::ErrorControlBadValue( + "Composite vector arrays cannot be used for output."); + } + + template + VTKM_CONT_EXPORT + void CopyInto(IteratorTypeControl vtkmNotUsed(dest)) const + { + throw vtkm::cont::ErrorControlInternal( + "CopyInto not implemented for composite vector arrays."); + } + + VTKM_CONT_EXPORT + void Shrink(vtkm::Id vtkmNotUsed(numberOfValues)) + { + throw vtkm::cont::ErrorControlBadValue( + "Composite vector arrays cannot be resized."); + } + + VTKM_CONT_EXPORT + PortalExecution GetPortalExecution() + { + throw vtkm::cont::ErrorControlBadValue( + "Composite vector arrays are read-only. (Get the const portal.)"); + } + + VTKM_CONT_EXPORT + PortalConstExecution GetPortalConstExecution() const + { + VTKM_ASSERT_CONT(this->ContainerValid); + return + PortalConstExecution( + this->Container.GetArrays().StaticTransformCont( + detail::CompositeVectorArrayToPortalExec()), + this->Container.GetSourceComponents()); + } + + VTKM_CONT_EXPORT + void ReleaseResources() { + this->Container.ReleaseResources(); + } + +private: + bool ContainerValid; + ContainerType Container; +}; + +} // namespace internal + +/// \brief An \c ArrayHandle that combines components from other arrays. +/// +/// \c ArrayHandleCompositeVector is a specialization of \c ArrayHandle that +/// derives its content from other arrays. It takes up to 4 other \c +/// ArrayHandle objects and mimics an array that contains vectors with +/// components that come from these delegate arrays. +/// +/// The easiest way to create and type an \c ArrayHandleCompositeVector is +/// to use the \c make_ArrayHandleCompositeVector functions. +/// +template +class ArrayHandleCompositeVector + : public vtkm::cont::ArrayHandle< + typename internal::ArrayHandleCompositeVectorTraits::ValueType, + typename internal::ArrayHandleCompositeVectorTraits::Tag> +{ + typedef typename internal::ArrayHandleCompositeVectorTraits::ContainerType + ArrayContainerControlType; + typedef typename internal::ArrayPortalCompositeVectorCont::ComponentMapType + ComponentMapType; + +public: + typedef vtkm::cont::ArrayHandle< + typename internal::ArrayHandleCompositeVectorTraits::ValueType, + typename internal::ArrayHandleCompositeVectorTraits::Tag> + Superclass; + typedef typename Superclass::ValueType ValueType; + + VTKM_CONT_EXPORT + ArrayHandleCompositeVector() : Superclass() { } + + VTKM_CONT_EXPORT + ArrayHandleCompositeVector( + const vtkm::internal::FunctionInterface &arrays, + const ComponentMapType &sourceComponents) + : Superclass(ArrayContainerControlType(arrays, sourceComponents)) + { } + + /// Template constructors for passing in types. You'll get weird compile + /// errors if the argument types do not actually match the types in the + /// signature. + /// + template + VTKM_CONT_EXPORT + ArrayHandleCompositeVector(const ArrayHandleType1 &array1, + int sourceComponent1) + : Superclass(ArrayContainerControlType( + vtkm::internal::make_FunctionInterface(array1), + ComponentMapType(sourceComponent1))) + { } + template + VTKM_CONT_EXPORT + ArrayHandleCompositeVector(const ArrayHandleType1 &array1, + int sourceComponent1, + const ArrayHandleType2 &array2, + int sourceComponent2) + : Superclass(ArrayContainerControlType( + vtkm::internal::make_FunctionInterface( + array1, array2), + ComponentMapType(sourceComponent1, + sourceComponent2))) + { } + template + VTKM_CONT_EXPORT + ArrayHandleCompositeVector(const ArrayHandleType1 &array1, + int sourceComponent1, + const ArrayHandleType2 &array2, + int sourceComponent2, + const ArrayHandleType3 &array3, + int sourceComponent3) + : Superclass(ArrayContainerControlType( + vtkm::internal::make_FunctionInterface( + array1, array2, array3), + ComponentMapType(sourceComponent1, + sourceComponent2, + sourceComponent3))) + { } + template + VTKM_CONT_EXPORT + ArrayHandleCompositeVector(const ArrayHandleType1 &array1, + int sourceComponent1, + const ArrayHandleType2 &array2, + int sourceComponent2, + const ArrayHandleType3 &array3, + int sourceComponent3, + const ArrayHandleType4 &array4, + int sourceComponent4) + : Superclass(ArrayContainerControlType( + vtkm::internal::make_FunctionInterface( + array1, array2, array3, array4), + ComponentMapType(sourceComponent1, + sourceComponent2, + sourceComponent3, + sourceComponent4))) + { } +}; + +/// Create a composite vector array from other arrays. +/// +template +VTKM_CONT_EXPORT +ArrayHandleCompositeVector< + typename vtkm::VectorTraits::ComponentType( + vtkm::cont::ArrayHandle)> +make_ArrayHandleCompositeVector( + const vtkm::cont::ArrayHandle &array1, + int sourceComponent1) +{ + return ArrayHandleCompositeVector< + typename vtkm::VectorTraits::ComponentType( + vtkm::cont::ArrayHandle)>(array1, + sourceComponent1); +} +template +VTKM_CONT_EXPORT +ArrayHandleCompositeVector< + vtkm::Tuple::ComponentType,2>( + vtkm::cont::ArrayHandle, + vtkm::cont::ArrayHandle)> +make_ArrayHandleCompositeVector( + const vtkm::cont::ArrayHandle &array1, + int sourceComponent1, + const vtkm::cont::ArrayHandle &array2, + int sourceComponent2) +{ + return ArrayHandleCompositeVector< + vtkm::Tuple::ComponentType,2>( + vtkm::cont::ArrayHandle, + vtkm::cont::ArrayHandle)>(array1, + sourceComponent1, + array2, + sourceComponent2); +} +template +VTKM_CONT_EXPORT +ArrayHandleCompositeVector< + vtkm::Tuple::ComponentType,3>( + vtkm::cont::ArrayHandle, + vtkm::cont::ArrayHandle, + vtkm::cont::ArrayHandle)> +make_ArrayHandleCompositeVector( + const vtkm::cont::ArrayHandle &array1, + int sourceComponent1, + const vtkm::cont::ArrayHandle &array2, + int sourceComponent2, + const vtkm::cont::ArrayHandle &array3, + int sourceComponent3) +{ + return ArrayHandleCompositeVector< + vtkm::Tuple::ComponentType,3>( + vtkm::cont::ArrayHandle, + vtkm::cont::ArrayHandle, + vtkm::cont::ArrayHandle)>(array1, + sourceComponent1, + array2, + sourceComponent2, + array3, + sourceComponent3); +} +template +VTKM_CONT_EXPORT +ArrayHandleCompositeVector< + vtkm::Tuple::ComponentType,4>( + vtkm::cont::ArrayHandle, + vtkm::cont::ArrayHandle, + vtkm::cont::ArrayHandle, + vtkm::cont::ArrayHandle)> +make_ArrayHandleCompositeVector( + const vtkm::cont::ArrayHandle &array1, + int sourceComponent1, + const vtkm::cont::ArrayHandle &array2, + int sourceComponent2, + const vtkm::cont::ArrayHandle &array3, + int sourceComponent3, + const vtkm::cont::ArrayHandle &array4, + int sourceComponent4) +{ + return ArrayHandleCompositeVector< + vtkm::Tuple::ComponentType,4>( + vtkm::cont::ArrayHandle, + vtkm::cont::ArrayHandle, + vtkm::cont::ArrayHandle, + vtkm::cont::ArrayHandle)>(array1, + sourceComponent1, + array2, + sourceComponent2, + array3, + sourceComponent3, + array4, + sourceComponent4); +} + +} +} // namespace vtkm::cont + +#endif //vtk_m_ArrayHandleCompositeVector_h diff --git a/vtkm/cont/CMakeLists.txt b/vtkm/cont/CMakeLists.txt index 69722e9f8..42b62f338 100644 --- a/vtkm/cont/CMakeLists.txt +++ b/vtkm/cont/CMakeLists.txt @@ -25,6 +25,7 @@ set(headers ArrayContainerControlBasic.h ArrayContainerControlImplicit.h ArrayHandle.h + ArrayHandleCompositeVector.h ArrayHandleCounting.h ArrayHandleUniformPointCoordinates.h ArrayPortal.h diff --git a/vtkm/cont/testing/CMakeLists.txt b/vtkm/cont/testing/CMakeLists.txt index 8b4064ca8..a953a8253 100644 --- a/vtkm/cont/testing/CMakeLists.txt +++ b/vtkm/cont/testing/CMakeLists.txt @@ -29,6 +29,7 @@ set(unit_tests UnitTestArrayContainerControlBasic.cxx UnitTestArrayContainerControlImplicit.cxx UnitTestArrayHandle.cxx + UnitTestArrayHandleCompositeVector.cxx UnitTestArrayHandleCounting.cxx UnitTestArrayHandleUniformPointCoordinates.cxx UnitTestContTesting.cxx diff --git a/vtkm/cont/testing/UnitTestArrayHandleCompositeVector.cxx b/vtkm/cont/testing/UnitTestArrayHandleCompositeVector.cxx new file mode 100644 index 000000000..6d1512d4a --- /dev/null +++ b/vtkm/cont/testing/UnitTestArrayHandleCompositeVector.cxx @@ -0,0 +1,313 @@ +//============================================================================ +// 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. +//============================================================================ + +// Make sure ArrayHandleCompositeVector does not rely on default container or +// device adapter. +#define VTKM_ARRAY_CONTAINER_CONTROL VTKM_ARRAY_CONTAINER_CONTROL_ERROR +#define VTKM_DEVICE_ADAPTER VTKM_DEVICE_ADAPTER_ERROR + +#include + +#include + +#include +#include + +#include + +#include + +namespace { + +const vtkm::Id ARRAY_SIZE = 10; + +typedef vtkm::cont::ArrayContainerControlTagBasic Container; + +vtkm::Scalar TestValue(vtkm::Id index, int inComponentIndex, int inArrayId) +{ + return index + vtkm::Scalar(0.1)*inComponentIndex + vtkm::Scalar(0.01)*inArrayId; +} + +template +vtkm::cont::ArrayHandle +MakeInputArray(int arrayId) +{ + typedef vtkm::VectorTraits VTraits; + + // Create a buffer with valid test values. + ValueType buffer[ARRAY_SIZE]; + for (vtkm::Id index = 0; index < ARRAY_SIZE; index++) + { + for (int componentIndex = 0; + componentIndex < VTraits::NUM_COMPONENTS; + componentIndex++) + { + VTraits::SetComponent(buffer[index], + componentIndex, + TestValue(index, componentIndex, arrayId)); + } + } + + // Make an array handle that points to this buffer. + typedef vtkm::cont::ArrayHandle ArrayHandleType; + ArrayHandleType bufferHandle = + vtkm::cont::make_ArrayHandle(buffer, ARRAY_SIZE, Container()); + + // When this function returns, the array is going to go out of scope, which + // will invalidate the array handle we just created. So copy to a new buffer + // that will stick around after we return. + ArrayHandleType copyHandle; + vtkm::cont::DeviceAdapterAlgorithm::Copy( + bufferHandle, copyHandle); + + return copyHandle; +} + +template +void CheckArray(const vtkm::cont::ArrayHandle &outArray, + const int *inComponents, + const int *inArrayIds) +{ + // ArrayHandleCompositeVector currently does not implement the ability to + // get to values on the control side, so copy to an array that is accessible. + typedef vtkm::cont::ArrayHandle ArrayHandleType; + ArrayHandleType arrayCopy; + vtkm::cont::DeviceAdapterAlgorithm::Copy( + outArray, arrayCopy); + + typename ArrayHandleType::PortalConstControl portal = + arrayCopy.GetPortalConstControl(); + typedef vtkm::VectorTraits VTraits; + for (vtkm::Id index = 0; index < ARRAY_SIZE; index++) + { + ValueType retreivedValue = portal.Get(index); + for (int componentIndex = 0; + componentIndex < VTraits::NUM_COMPONENTS; + componentIndex++) + { + vtkm::Scalar retrievedComponent = + VTraits::GetComponent(retreivedValue, componentIndex); + vtkm::Scalar expectedComponent = TestValue(index, + inComponents[componentIndex], + inArrayIds[componentIndex]); + VTKM_TEST_ASSERT(retrievedComponent == expectedComponent, + "Got bad value."); + } + } +} + +template +void TryScalarArray() +{ + std::cout << "Creating a scalar array from one of " + << inComponents << " components." << std::endl; + + typedef vtkm::Tuple InValueType; + typedef vtkm::cont::ArrayHandle InArrayType; + int inArrayId = 0; + InArrayType inArray = MakeInputArray(inArrayId); + + typedef vtkm::cont::ArrayHandleCompositeVector + OutArrayType; + for (int inComponentIndex = 0; + inComponentIndex < inComponents; + inComponentIndex++) + { + OutArrayType outArray = + vtkm::cont::make_ArrayHandleCompositeVector(inArray, inComponentIndex); + CheckArray(outArray, &inComponentIndex, &inArrayId); + } +} + +template +void TryVector4(vtkm::cont::ArrayHandle array1, + vtkm::cont::ArrayHandle array2, + vtkm::cont::ArrayHandle array3, + vtkm::cont::ArrayHandle array4) +{ + int arrayIds[4] = {0, 1, 2, 3}; + int inComponents[4]; + + for (inComponents[0] = 0; + inComponents[0] < vtkm::VectorTraits::NUM_COMPONENTS; + inComponents[0]++) + { + for (inComponents[1] = 0; + inComponents[1] < vtkm::VectorTraits::NUM_COMPONENTS; + inComponents[1]++) + { + for (inComponents[2] = 0; + inComponents[2] < vtkm::VectorTraits::NUM_COMPONENTS; + inComponents[2]++) + { + for (inComponents[3] = 0; + inComponents[3] < vtkm::VectorTraits::NUM_COMPONENTS; + inComponents[3]++) + { + CheckArray( + vtkm::cont::make_ArrayHandleCompositeVector( + array1, inComponents[0], + array2, inComponents[1], + array3, inComponents[2], + array4, inComponents[3]), + inComponents, + arrayIds); + } + } + } + } +} + +template +void TryVector3(vtkm::cont::ArrayHandle array1, + vtkm::cont::ArrayHandle array2, + vtkm::cont::ArrayHandle array3) +{ + int arrayIds[3] = {0, 1, 2}; + int inComponents[3]; + + for (inComponents[0] = 0; + inComponents[0] < vtkm::VectorTraits::NUM_COMPONENTS; + inComponents[0]++) + { + for (inComponents[1] = 0; + inComponents[1] < vtkm::VectorTraits::NUM_COMPONENTS; + inComponents[1]++) + { + for (inComponents[2] = 0; + inComponents[2] < vtkm::VectorTraits::NUM_COMPONENTS; + inComponents[2]++) + { + CheckArray( + vtkm::cont::make_ArrayHandleCompositeVector( + array1, inComponents[0], + array2, inComponents[1], + array3, inComponents[2]), + inComponents, + arrayIds); + } + } + } + + std::cout << " Fourth component from Scalar." << std::endl; + TryVector4(array1, array2, array3, MakeInputArray(3)); + std::cout << " Fourth component from Vector4." << std::endl; + TryVector4(array1, array2, array3, MakeInputArray(3)); +} + +template +void TryVector2(vtkm::cont::ArrayHandle array1, + vtkm::cont::ArrayHandle array2) +{ + int arrayIds[2] = {0, 1}; + int inComponents[2]; + + for (inComponents[0] = 0; + inComponents[0] < vtkm::VectorTraits::NUM_COMPONENTS; + inComponents[0]++) + { + for (inComponents[1] = 0; + inComponents[1] < vtkm::VectorTraits::NUM_COMPONENTS; + inComponents[1]++) + { + CheckArray( + vtkm::cont::make_ArrayHandleCompositeVector( + array1, inComponents[0], + array2, inComponents[1]), + inComponents, + arrayIds); + } + } + + std::cout << " Third component from Scalar." << std::endl; + TryVector3(array1, array2, MakeInputArray(2)); + std::cout << " Third component from Vector2." << std::endl; + TryVector3(array1, array2, MakeInputArray(2)); +} + +template +void TryVector1(vtkm::cont::ArrayHandle array1) +{ + int arrayIds[1] = {0}; + int inComponents[1]; + + for (inComponents[0] = 0; + inComponents[0] < vtkm::VectorTraits::NUM_COMPONENTS; + inComponents[0]++) + { + CheckArray( + vtkm::cont::make_ArrayHandleCompositeVector(array1, inComponents[0]), + inComponents, + arrayIds); + } + + std::cout << " Second component from Scalar." << std::endl; + TryVector2(array1, MakeInputArray(1)); + std::cout << " Second component from Vector4." << std::endl; + TryVector2(array1, MakeInputArray(1)); +} + +void TryVector() +{ + std::cout << "Trying many permutations of composite vectors." << std::endl; + + std::cout << " First component from Scalar." << std::endl; + TryVector1(MakeInputArray(0)); + std::cout << " First component from Vector3." << std::endl; + TryVector1(MakeInputArray(0)); +} + +void TestBadArrayLengths() { + std::cout << "Checking behavior when size of input arrays do not agree." + << std::endl; + + typedef vtkm::cont::ArrayHandle InArrayType; + InArrayType longInArray = MakeInputArray(0); + InArrayType shortInArray = MakeInputArray(1); + shortInArray.Shrink(ARRAY_SIZE/2); + + try + { + vtkm::cont::make_ArrayHandleCompositeVector(longInArray,0, shortInArray,0); + VTKM_TEST_FAIL("Did not get exception like expected."); + } + catch (vtkm::cont::ErrorControlBadValue error) + { + std::cout << "Got expected error: " << std::endl + << error.GetMessage() << std::endl; + } +} + +void TestCompositeVector() { + TryScalarArray<2>(); + TryScalarArray<3>(); + TryScalarArray<4>(); + + TryVector(); + + TestBadArrayLengths(); +} + +} // anonymous namespace + +int UnitTestArrayHandleCompositeVector(int, char *[]) +{ + return vtkm::cont::testing::Testing::Run(TestCompositeVector); +}