diff --git a/examples/game_of_life/GameOfLife.cxx b/examples/game_of_life/GameOfLife.cxx index 1b01482a3..01148db3e 100644 --- a/examples/game_of_life/GameOfLife.cxx +++ b/examples/game_of_life/GameOfLife.cxx @@ -74,7 +74,7 @@ struct GameOfLifePolicy : public vtkm::filter::PolicyBase using DeviceAdapterList = DevicesToTry; }; -struct UpdateLifeState : public vtkm::worklet::WorkletPointNeighborhood3x3x3 +struct UpdateLifeState : public vtkm::worklet::WorkletPointNeighborhood { using CountingHandle = vtkm::cont::ArrayHandleCounting; diff --git a/vtkm/exec/BoundaryState.h b/vtkm/exec/BoundaryState.h new file mode 100644 index 000000000..aa7a1a950 --- /dev/null +++ b/vtkm/exec/BoundaryState.h @@ -0,0 +1,188 @@ +//============================================================================ +// 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 2018 National Technology & Engineering Solutions of Sandia, LLC (NTESS). +// Copyright 2018 UT-Battelle, LLC. +// Copyright 2018 Los Alamos National Security. +// +// Under the terms of Contract DE-NA0003525 with NTESS, +// 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_exec_BoundaryState_h +#define vtk_m_exec_BoundaryState_h + +#include + +namespace vtkm +{ +namespace exec +{ + +/// \brief Provides a neighborhood's placement with respect to the mesh's boundary. +/// +/// \c BoundaryState provides functionality for \c WorkletPointNeighborhood algorithms and Fetch's +/// to determine if they are operating on a point near the boundary. It allows you to query about +/// overlaps of the neighborhood and the mesh boundary. It also helps convert local neighborhood +/// ids to the corresponding location in the mesh. +/// +/// This class is typically constructed using the \c Boundary tag in an \c ExecutionSignature. +/// There is little reason to construct this in user code. +/// +struct BoundaryState +{ + VTKM_EXEC + BoundaryState(const vtkm::Id3& ijk, const vtkm::Id3& pdims) + : IJK(ijk) + , PointDimensions(pdims) + { + } + + //@{ + /// Returns true if a neighborhood of the given radius is contained within the bounds of the cell + /// set in the X, Y, or Z direction. Returns false if the neighborhood extends ouside of the + /// boundary of the data in the X, Y, or Z direction. + /// + /// The radius defines the size of the neighborhood in terms of how far away it extends from the + /// center. So if there is a radius of 1, the neighborhood extends 1 unit away from the center in + /// each direction and is 3x3x3. If there is a radius of 2, the neighborhood extends 2 units for + /// a size of 5x5x5. + /// + VTKM_EXEC bool InXBoundary(vtkm::IdComponent radius) const + { + return (((this->IJK[0] - radius) >= 0) && ((this->IJK[0] + radius) < this->PointDimensions[0])); + } + VTKM_EXEC bool InYBoundary(vtkm::IdComponent radius) const + { + return (((this->IJK[1] - radius) >= 0) && ((this->IJK[1] + radius) < this->PointDimensions[1])); + } + VTKM_EXEC bool InZBoundary(vtkm::IdComponent radius) const + { + return (((this->IJK[2] - radius) >= 0) && ((this->IJK[2] + radius) < this->PointDimensions[2])); + } + //@} + + /// Returns true if a neighborhood of the given radius is contained within the bounds + /// of the cell set. Returns false if the neighborhood extends ouside of the boundary of the + /// data. + /// + /// The radius defines the size of the neighborhood in terms of how far away it extends from the + /// center. So if there is a radius of 1, the neighborhood extends 1 unit away from the center in + /// each direction and is 3x3x3. If there is a radius of 2, the neighborhood extends 2 units for + /// a size of 5x5x5. + /// + VTKM_EXEC bool InBoundary(vtkm::IdComponent radius) const + { + return this->InXBoundary(radius) && this->InYBoundary(radius) && this->InZBoundary(radius); + } + + /// Returns the minimum neighborhood indices that are within the bounds of the data. + /// + VTKM_EXEC vtkm::Vec MinNeighborIndices(vtkm::IdComponent radius) const + { + vtkm::Vec minIndices; + + for (vtkm::IdComponent component = 0; component < 3; ++component) + { + if (this->IJK[component] >= radius) + { + minIndices[component] = -radius; + } + else + { + minIndices[component] = static_cast(-this->IJK[component]); + } + } + + return minIndices; + } + + /// Returns the minimum neighborhood indices that are within the bounds of the data. + /// + VTKM_EXEC vtkm::Vec MaxNeighborIndices(vtkm::IdComponent radius) const + { + vtkm::Vec maxIndices; + + for (vtkm::IdComponent component = 0; component < 3; ++component) + { + if ((this->PointDimensions[component] - this->IJK[component] - 1) >= radius) + { + maxIndices[component] = radius; + } + else + { + maxIndices[component] = static_cast(this->PointDimensions[component] - + this->IJK[component] - 1); + } + } + + return maxIndices; + } + + //todo: This needs to work with BoundaryConstantValue + //todo: This needs to work with BoundaryPeroidic + + //@{ + /// Takes a local neighborhood index (in the ranges of -neighborhood size to neighborhood size) + /// and returns the ijk of the equivalent point in the full data set. If the given value is out + /// of range, the value is clamped to the nearest boundary. For example, if given a neighbor + /// index that is past the minimum x range of the data, the index at the minimum x boundary is + /// returned. + /// + VTKM_EXEC vtkm::Id3 NeighborIndexToFullIndexClamp( + const vtkm::Vec& neighbor) const + { + vtkm::Id3 fullIndex = this->IJK + neighbor; + + return vtkm::Max(vtkm::Id3(0), vtkm::Min(this->PointDimensions - vtkm::Id3(1), fullIndex)); + } + + VTKM_EXEC vtkm::Id3 NeighborIndexToFullIndexClamp(vtkm::IdComponent neighborI, + vtkm::IdComponent neighborJ, + vtkm::IdComponent neighborK) const + { + return this->NeighborIndexToFullIndexClamp(vtkm::make_Vec(neighborI, neighborJ, neighborK)); + } + //@} + + //todo: This needs to work with BoundaryConstantValue + //todo: This needs to work with BoundaryPeroidic + + //@{ + /// Takes a local neighborhood index (in the ranges of -neighborhood size to neighborhood size) + /// and returns the flat index of the equivalent point in the full data set. If the given value + /// is out of range, the value is clamped to the nearest boundary. For example, if given a + /// neighbor index that is past the minimum x range of the data, the index at the minimum x + /// boundary is returned. + /// + VTKM_EXEC vtkm::Id NeighborIndexToFlatIndexClamp( + const vtkm::Vec& neighbor) const + { + vtkm::Id3 full = this->NeighborIndexToFullIndexClamp(neighbor); + + return (full[2] * this->PointDimensions[1] + full[1]) * this->PointDimensions[0] + full[0]; + } + + VTKM_EXEC vtkm::Id NeighborIndexToFlatIndexClamp(vtkm::IdComponent neighborI, + vtkm::IdComponent neighborJ, + vtkm::IdComponent neighborK) const + { + return this->NeighborIndexToFlatIndexClamp(vtkm::make_Vec(neighborI, neighborJ, neighborK)); + } + //@} + + vtkm::Id3 IJK; + vtkm::Id3 PointDimensions; +}; +} +} // namespace vtkm::exec + +#endif //vtk_m_exec_BoundaryState_h diff --git a/vtkm/exec/CMakeLists.txt b/vtkm/exec/CMakeLists.txt index bc701d6a7..85a1a1c40 100644 --- a/vtkm/exec/CMakeLists.txt +++ b/vtkm/exec/CMakeLists.txt @@ -20,6 +20,7 @@ set(headers BoundingIntervalHierarchyExec.h + BoundaryState.h AtomicArrayExecutionObject.h CellDerivative.h CellEdge.h @@ -33,6 +34,7 @@ set(headers ConnectivityPermuted.h ConnectivityStructured.h ExecutionWholeArray.h + FieldNeighborhood.h FunctorBase.h Jacobian.h ParametricCoordinates.h diff --git a/vtkm/exec/FieldNeighborhood.h b/vtkm/exec/FieldNeighborhood.h new file mode 100644 index 000000000..5ba09b5ac --- /dev/null +++ b/vtkm/exec/FieldNeighborhood.h @@ -0,0 +1,107 @@ +//============================================================================ +// 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 2018 National Technology & Engineering Solutions of Sandia, LLC (NTESS). +// Copyright 2018 UT-Battelle, LLC. +// Copyright 2018 Los Alamos National Security. +// +// Under the terms of Contract DE-NA0003525 with NTESS, +// 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_exec_FieldNeighborhood_h +#define vtk_m_exec_FieldNeighborhood_h + +#include +#include + +namespace vtkm +{ +namespace exec +{ + +/// \brief Retrieves field values from a neighborhood. +/// +/// \c FieldNeighborhood manages the retrieval of field values within the neighborhood of a +/// \c WorkletPointNeighborhood worklet. The \c Get methods take ijk indices relative to the +/// neighborhood (with 0, 0, 0 being the element visted) and return the field value at that part of +/// the neighborhood. If the requested neighborhood is outside the boundary, a different value will +/// be returned determined by the boundary behavior. A \c BoundaryState object can be used to +/// determine if the neighborhood extends beyond the boundary of the mesh. +/// +/// This class is typically constructued using the \c FieldInNeighborhood tag in an +/// \c ExecutionSignature. There is little reason to construct this in user code. +/// +/// \c FieldNeighborhood is templated on the array portal from which field values are retrieved. +/// +template +struct FieldNeighborhood +{ + VTKM_EXEC + FieldNeighborhood(const FieldPortalType& portal, const vtkm::exec::BoundaryState& boundary) + : Boundary(&boundary) + , Portal(portal) + { + } + + using ValueType = typename FieldPortalType::ValueType; + + VTKM_EXEC + ValueType Get(vtkm::IdComponent i, vtkm::IdComponent j, vtkm::IdComponent k) const + { + return Portal.Get(this->Boundary->NeighborIndexToFlatIndexClamp(i, j, k)); + } + + VTKM_EXEC + ValueType Get(const vtkm::Id3& ijk) const + { + return Portal.Get(this->Boundary->NeighborIndexToFlatIndexClamp(ijk)); + } + + vtkm::exec::BoundaryState const* const Boundary; + FieldPortalType Portal; +}; + +/// \brief Specialization of Neighborhood for ArrayPortalUniformPointCoordinates +/// We can use fast paths inside ArrayPortalUniformPointCoordinates to allow +/// for very fast computation of the coordinates reachable by the neighborhood +template <> +struct FieldNeighborhood +{ + VTKM_EXEC + FieldNeighborhood(const vtkm::internal::ArrayPortalUniformPointCoordinates& portal, + const vtkm::exec::BoundaryState& boundary) + : Boundary(&boundary) + , Portal(portal) + { + } + + using ValueType = vtkm::internal::ArrayPortalUniformPointCoordinates::ValueType; + + VTKM_EXEC + ValueType Get(vtkm::IdComponent i, vtkm::IdComponent j, vtkm::IdComponent k) const + { + return Portal.Get(this->Boundary->NeighborIndexToFullIndexClamp(i, j, k)); + } + + VTKM_EXEC + ValueType Get(const vtkm::Vec& ijk) const + { + return Portal.Get(this->Boundary->NeighborIndexToFullIndexClamp(ijk)); + } + + vtkm::exec::BoundaryState const* const Boundary; + vtkm::internal::ArrayPortalUniformPointCoordinates Portal; +}; +} +} // namespace vtkm::exec + +#endif //vtk_m_exec_FieldNeighborhood_h diff --git a/vtkm/exec/arg/OnBoundary.h b/vtkm/exec/arg/Boundary.h similarity index 80% rename from vtkm/exec/arg/OnBoundary.h rename to vtkm/exec/arg/Boundary.h index 042895a06..4200976ed 100644 --- a/vtkm/exec/arg/OnBoundary.h +++ b/vtkm/exec/arg/Boundary.h @@ -33,31 +33,31 @@ namespace arg /// \brief Aspect tag to use for getting if a point is a boundary point. /// -/// The \c AspectTagOnBoundary aspect tag causes the \c Fetch class to obtain +/// The \c AspectTagBoundary aspect tag causes the \c Fetch class to obtain /// if the point is on a boundary. /// -struct AspectTagOnBoundary +struct AspectTagBoundary { }; /// \brief The \c ExecutionSignature tag to get if executing on a boundary element /// -struct OnBoundary : vtkm::exec::arg::ExecutionSignatureTagBase +struct Boundary : vtkm::exec::arg::ExecutionSignatureTagBase { static constexpr vtkm::IdComponent INDEX = 1; - using AspectTag = vtkm::exec::arg::AspectTagOnBoundary; + using AspectTag = vtkm::exec::arg::AspectTagBoundary; }; -template +template struct Fetch, + vtkm::exec::arg::AspectTagBoundary, + vtkm::exec::arg::ThreadIndicesPointNeighborhood, ExecObjectType> { - using ThreadIndicesType = vtkm::exec::arg::ThreadIndicesPointNeighborhood; + using ThreadIndicesType = vtkm::exec::arg::ThreadIndicesPointNeighborhood; - using ValueType = vtkm::exec::arg::BoundaryState; + using ValueType = vtkm::exec::BoundaryState; VTKM_SUPPRESS_EXEC_WARNINGS VTKM_EXEC diff --git a/vtkm/exec/arg/CMakeLists.txt b/vtkm/exec/arg/CMakeLists.txt index 058f41487..a56690734 100644 --- a/vtkm/exec/arg/CMakeLists.txt +++ b/vtkm/exec/arg/CMakeLists.txt @@ -21,6 +21,7 @@ set(headers AspectTagDefault.h BasicArg.h + Boundary.h CellShape.h ExecutionSignatureTagBase.h Fetch.h @@ -36,7 +37,6 @@ set(headers FromCount.h FromIndices.h InputIndex.h - OnBoundary.h OutputIndex.h ThreadIndices.h ThreadIndicesBasic.h diff --git a/vtkm/exec/arg/FetchTagArrayNeighborhoodIn.h b/vtkm/exec/arg/FetchTagArrayNeighborhoodIn.h index fdb57f4fd..078a7645e 100644 --- a/vtkm/exec/arg/FetchTagArrayNeighborhoodIn.h +++ b/vtkm/exec/arg/FetchTagArrayNeighborhoodIn.h @@ -20,10 +20,10 @@ #ifndef vtk_m_exec_arg_FetchTagArrayNeighborhoodIn_h #define vtk_m_exec_arg_FetchTagArrayNeighborhoodIn_h +#include #include #include #include -#include namespace vtkm { @@ -37,85 +37,18 @@ namespace arg /// \c FetchTagArrayNeighborhoodIn is a tag used with the \c Fetch class to retrieve /// values from an neighborhood. /// -template struct FetchTagArrayNeighborhoodIn { }; -template -struct Neighborhood -{ - VTKM_EXEC - Neighborhood(const ExecObjectType& portal, const vtkm::exec::arg::BoundaryState& boundary) - : Boundary(&boundary) - , Portal(portal) - { - } - - using ValueType = typename ExecObjectType::ValueType; - - VTKM_EXEC - ValueType Get(vtkm::IdComponent i, vtkm::IdComponent j, vtkm::IdComponent k) const - { - VTKM_ASSERT(i <= NeighborhoodSize && i >= -NeighborhoodSize); - VTKM_ASSERT(j <= NeighborhoodSize && j >= -NeighborhoodSize); - VTKM_ASSERT(k <= NeighborhoodSize && k >= -NeighborhoodSize); - return Portal.Get(this->Boundary->NeighborIndexToFlatIndexClamp(i, j, k)); - } - - VTKM_EXEC - ValueType Get(const vtkm::Id3& ijk) const - { - VTKM_ASSERT(ijk[0] <= NeighborhoodSize && ijk[0] >= -NeighborhoodSize); - VTKM_ASSERT(ijk[1] <= NeighborhoodSize && ijk[1] >= -NeighborhoodSize); - VTKM_ASSERT(ijk[2] <= NeighborhoodSize && ijk[2] >= -NeighborhoodSize); - return Portal.Get(this->Boundary->NeighborIndexToFlatIndexClamp(ijk)); - } - - vtkm::exec::arg::BoundaryState const* const Boundary; - ExecObjectType Portal; -}; - -/// \brief Specialization of Neighborhood for ArrayPortalUniformPointCoordinates -/// We can use fast paths inside ArrayPortalUniformPointCoordinates to allow -/// for very fast computation of the coordinates reachable by the neighborhood -template -struct Neighborhood -{ - VTKM_EXEC - Neighborhood(const vtkm::internal::ArrayPortalUniformPointCoordinates& portal, - const vtkm::exec::arg::BoundaryState& boundary) - : Boundary(&boundary) - , Portal(portal) - { - } - - using ValueType = vtkm::internal::ArrayPortalUniformPointCoordinates::ValueType; - - VTKM_EXEC - ValueType Get(vtkm::IdComponent i, vtkm::IdComponent j, vtkm::IdComponent k) const - { - return Portal.Get(this->Boundary->NeighborIndexToFullIndexClamp(i, j, k)); - } - - VTKM_EXEC - ValueType Get(const vtkm::Vec& ijk) const - { - return Portal.Get(this->Boundary->NeighborIndexToFullIndexClamp(ijk)); - } - - vtkm::exec::arg::BoundaryState const* const Boundary; - vtkm::internal::ArrayPortalUniformPointCoordinates Portal; -}; - -template -struct Fetch, +template +struct Fetch, + vtkm::exec::arg::ThreadIndicesPointNeighborhood, ExecObjectType> { - using ThreadIndicesType = vtkm::exec::arg::ThreadIndicesPointNeighborhood; - using ValueType = Neighborhood; + using ThreadIndicesType = vtkm::exec::arg::ThreadIndicesPointNeighborhood; + using ValueType = vtkm::exec::FieldNeighborhood; VTKM_SUPPRESS_EXEC_WARNINGS VTKM_EXEC diff --git a/vtkm/exec/arg/ThreadIndicesPointNeighborhood.h b/vtkm/exec/arg/ThreadIndicesPointNeighborhood.h index ff585051f..a09ea1057 100644 --- a/vtkm/exec/arg/ThreadIndicesPointNeighborhood.h +++ b/vtkm/exec/arg/ThreadIndicesPointNeighborhood.h @@ -20,6 +20,7 @@ #ifndef vtk_m_exec_arg_ThreadIndicesPointNeighborhood_h #define vtk_m_exec_arg_ThreadIndicesPointNeighborhood_h +#include #include #include #include //for Deflate and Inflate @@ -33,159 +34,6 @@ namespace exec namespace arg { -/// \brief Provides information if the current point is a boundary point -/// Provides functionality for WorkletPointNeighborhood algorithms -/// and Fetch's to determine if they are operating on a boundary point - -//Todo we need to have this class handle different BoundaryTypes -struct BoundaryState -{ - VTKM_EXEC - BoundaryState(const vtkm::Id3& ijk, const vtkm::Id3& pdims, int neighborhoodSize) - : IJK(ijk) - , PointDimensions(pdims) - , NeighborhoodSize(neighborhoodSize) - { - for (vtkm::IdComponent dim = 0; dim < 3; ++dim) - { - if (neighborhoodSize < ijk[dim]) - { - this->MinNeighborhood[dim] = -neighborhoodSize; - } - else - { - this->MinNeighborhood[dim] = static_cast(-ijk[dim]); - } - if (neighborhoodSize < pdims[dim] - ijk[dim] - 1) - { - this->MaxNeighborhood[dim] = neighborhoodSize; - } - else - { - this->MaxNeighborhood[dim] = static_cast(pdims[dim] - ijk[dim] - 1); - } - } - } - - /// Returns the minimum neighbor index in the X direction (between -neighborhood size and 0) - /// - VTKM_EXEC vtkm::IdComponent MinNeighborX() const { return this->MinNeighborhood[0]; } - - /// Returns the minimum neighbor index in the Z direction (between -neighborhood size and 0) - /// - VTKM_EXEC vtkm::IdComponent MinNeighborY() const { return this->MinNeighborhood[1]; } - - /// Returns the minimum neighbor index in the Z direction (between -neighborhood size and 0) - /// - VTKM_EXEC vtkm::IdComponent MinNeighborZ() const { return this->MinNeighborhood[2]; } - - /// Returns the maximum neighbor index in the X direction (between 0 and neighborhood size) - /// - VTKM_EXEC vtkm::IdComponent MaxNeighborX() const { return this->MaxNeighborhood[0]; } - - /// Returns the maximum neighbor index in the Z direction (between 0 and neighborhood size) - /// - VTKM_EXEC vtkm::IdComponent MaxNeighborY() const { return this->MaxNeighborhood[1]; } - - /// Returns the maximum neighbor index in the Z direction (between 0 and neighborhood size) - /// - VTKM_EXEC vtkm::IdComponent MaxNeighborZ() const { return this->MaxNeighborhood[2]; } - - /// Returns true if the neighborhood extends past the positive X direction. - /// - VTKM_EXEC bool OnXPositive() const { return this->MaxNeighborX() < this->NeighborhoodSize; } - - /// Returns true if the neighborhood extends past the negative X direction. - /// - VTKM_EXEC bool OnXNegative() const { return -this->MinNeighborX() < this->NeighborhoodSize; } - - /// Returns true if the neighborhood extends past the positive Y direction. - /// - VTKM_EXEC bool OnYPositive() const { return this->MaxNeighborY() < this->NeighborhoodSize; } - - /// Returns true if the neighborhood extends past the negative Y direction. - /// - VTKM_EXEC bool OnYNegative() const { return -this->MinNeighborY() < this->NeighborhoodSize; } - - /// Returns true if the neighborhood extends past the positive Z direction. - /// - VTKM_EXEC bool OnZPositive() const { return this->MaxNeighborZ() < this->NeighborhoodSize; } - - /// Returns true if the neighborhood extends past the negative Z direction. - /// - VTKM_EXEC bool OnZNegative() const { return -this->MinNeighborZ() < this->NeighborhoodSize; } - - /// Returns true if the neighborhood extends past either X boundary. - /// - VTKM_EXEC bool OnX() const { return this->OnXNegative() || this->OnXPositive(); } - - /// Returns true if the neighborhood extends past either Y boundary. - /// - VTKM_EXEC bool OnY() const { return this->OnYNegative() || this->OnYPositive(); } - - /// Returns true if the neighborhood extends past either Z boundary. - /// - VTKM_EXEC bool OnZ() const { return this->OnZNegative() || this->OnZPositive(); } - - //todo: This needs to work with BoundaryConstantValue - //todo: This needs to work with BoundaryPeroidic - - //@{ - /// Takes a local neighborhood index (in the ranges of -neighborhood size to neighborhood size) - /// and returns the ijk of the equivalent point in the full data set. If the given value is out - /// of range, the value is clamped to the nearest boundary. For example, if given a neighbor - /// index that is past the minimum x range of the data, the index at the minimum x boundary is - /// returned. - /// - VTKM_EXEC vtkm::Id3 NeighborIndexToFullIndexClamp( - const vtkm::Vec& neighbor) const - { - vtkm::Vec clampedNeighbor = - vtkm::Max(this->MinNeighborhood, vtkm::Min(this->MaxNeighborhood, neighbor)); - return this->IJK + clampedNeighbor; - } - - VTKM_EXEC vtkm::Id3 NeighborIndexToFullIndexClamp(vtkm::IdComponent neighborI, - vtkm::IdComponent neighborJ, - vtkm::IdComponent neighborK) const - { - return this->NeighborIndexToFullIndexClamp(vtkm::make_Vec(neighborI, neighborJ, neighborK)); - } - //@} - - //todo: This needs to work with BoundaryConstantValue - //todo: This needs to work with BoundaryPeroidic - - //@{ - /// Takes a local neighborhood index (in the ranges of -neighborhood size to neighborhood size) - /// and returns the flat index of the equivalent point in the full data set. If the given value - /// is out of range, the value is clamped to the nearest boundary. For example, if given a - /// neighbor index that is past the minimum x range of the data, the index at the minimum x - /// boundary is returned. - /// - VTKM_EXEC vtkm::Id NeighborIndexToFlatIndexClamp( - const vtkm::Vec& neighbor) const - { - vtkm::Id3 full = this->NeighborIndexToFullIndexClamp(neighbor); - - return (full[2] * this->PointDimensions[1] + full[1]) * this->PointDimensions[0] + full[0]; - } - - VTKM_EXEC vtkm::Id NeighborIndexToFlatIndexClamp(vtkm::IdComponent neighborI, - vtkm::IdComponent neighborJ, - vtkm::IdComponent neighborK) const - { - return this->NeighborIndexToFlatIndexClamp(vtkm::make_Vec(neighborI, neighborJ, neighborK)); - } - //@} - - vtkm::Id3 IJK; - vtkm::Id3 PointDimensions; - vtkm::Vec MinNeighborhood; - vtkm::Vec MaxNeighborhood; - vtkm::IdComponent NeighborhoodSize; -}; - namespace detail { /// Given a \c Vec of (semi) arbitrary size, inflate it to a vtkm::Id3 by padding with zeros. @@ -213,7 +61,6 @@ inline VTKM_EXEC vtkm::Id3 To3D(vtkm::Vec index) /// \brief Container for thread information in a WorkletPointNeighborhood. /// /// -template class ThreadIndicesPointNeighborhood { @@ -227,7 +74,7 @@ public: vtkm::TopologyElementTagPoint, Dimension>& connectivity, vtkm::Id globalThreadIndexOffset = 0) - : State(outIndex, detail::To3D(connectivity.GetPointDimensions()), NeighborhoodSize) + : State(outIndex, detail::To3D(connectivity.GetPointDimensions())) , InputIndex(0) , OutputIndex(0) , VisitIndex(0) @@ -252,8 +99,7 @@ public: Dimension>& connectivity, vtkm::Id globalThreadIndexOffset = 0) : State(detail::To3D(connectivity.FlatToLogicalToIndex(outToIn.Get(outIndex))), - detail::To3D(connectivity.GetPointDimensions()), - NeighborhoodSize) + detail::To3D(connectivity.GetPointDimensions())) , InputIndex(outToIn.Get(outIndex)) , OutputIndex(outIndex) , VisitIndex(static_cast(visit.Get(outIndex))) @@ -271,8 +117,7 @@ public: Dimension>& connectivity, vtkm::Id globalThreadIndexOffset = 0) : State(detail::To3D(connectivity.FlatToLogicalToIndex(inIndex)), - detail::To3D(connectivity.GetPointDimensions()), - NeighborhoodSize) + detail::To3D(connectivity.GetPointDimensions())) , InputIndex(inIndex) , OutputIndex(outIndex) , VisitIndex(visitIndex) @@ -281,7 +126,7 @@ public: } VTKM_EXEC - const BoundaryState& GetBoundaryState() const { return this->State; } + const vtkm::exec::BoundaryState& GetBoundaryState() const { return this->State; } VTKM_EXEC vtkm::Id GetInputIndex() const { return this->InputIndex; } @@ -302,7 +147,7 @@ public: vtkm::Id GetGlobalIndex() const { return (this->GlobalThreadIndexOffset + this->OutputIndex); } private: - BoundaryState State; + vtkm::exec::BoundaryState State; vtkm::Id InputIndex; vtkm::Id OutputIndex; vtkm::IdComponent VisitIndex; diff --git a/vtkm/exec/arg/testing/UnitTestFetchArrayNeighborhoodIn.cxx b/vtkm/exec/arg/testing/UnitTestFetchArrayNeighborhoodIn.cxx index 9248e4ced..f524177f6 100644 --- a/vtkm/exec/arg/testing/UnitTestFetchArrayNeighborhoodIn.cxx +++ b/vtkm/exec/arg/testing/UnitTestFetchArrayNeighborhoodIn.cxx @@ -60,23 +60,33 @@ void verify_neighbors(NeighborhoodType neighbors, vtkm::Id index, vtkm::Id3 inde T expected; auto* boundary = neighbors.Boundary; - //Verify the boundar flags first - VTKM_TEST_ASSERT(test_equal(index3d[0] == (POINT_DIMS[0] - 1), boundary->OnXPositive()), - "Got invalid X+ boundary"); - VTKM_TEST_ASSERT(test_equal(index3d[0] == 0, boundary->OnXNegative()), "Got invalid X- boundary"); - VTKM_TEST_ASSERT(test_equal(index3d[1] == (POINT_DIMS[1] - 1), boundary->OnYPositive()), - "Got invalid Y+ boundary"); - VTKM_TEST_ASSERT(test_equal(index3d[1] == 0, boundary->OnYNegative()), "Got invalid Y- boundary"); - VTKM_TEST_ASSERT(test_equal(index3d[2] == (POINT_DIMS[2] - 1), boundary->OnZPositive()), - "Got invalid Z+ boundary"); - VTKM_TEST_ASSERT(test_equal(index3d[2] == 0, boundary->OnZNegative()), "Got invalid Z- boundary"); + //Verify the boundary flags first + VTKM_TEST_ASSERT(((index3d[0] != 0) && (index3d[0] != (POINT_DIMS[0] - 1))) == + boundary->InXBoundary(1), + "Got invalid X boundary"); + VTKM_TEST_ASSERT(((index3d[1] != 0) && (index3d[1] != (POINT_DIMS[1] - 1))) == + boundary->InYBoundary(1), + "Got invalid Y boundary"); + VTKM_TEST_ASSERT(((index3d[2] != 0) && (index3d[2] != (POINT_DIMS[2] - 1))) == + boundary->InZBoundary(1), + "Got invalid Z boundary"); + + VTKM_TEST_ASSERT(((boundary->MinNeighborIndices(1)[0] == -1) && + (boundary->MaxNeighborIndices(1)[0] == 1)) == boundary->InXBoundary(1), + "Got invalid min/max X indices"); + VTKM_TEST_ASSERT(((boundary->MinNeighborIndices(1)[1] == -1) && + (boundary->MaxNeighborIndices(1)[1] == 1)) == boundary->InYBoundary(1), + "Got invalid min/max Y indices"); + VTKM_TEST_ASSERT(((boundary->MinNeighborIndices(1)[2] == -1) && + (boundary->MaxNeighborIndices(1)[2] == 1)) == boundary->InZBoundary(1), + "Got invalid min/max Z indices"); T forwardX = neighbors.Get(1, 0, 0); - expected = boundary->OnXPositive() ? TestValue(index, T()) : TestValue(index + 1, T()); + expected = (index3d[0] == POINT_DIMS[0] - 1) ? TestValue(index, T()) : TestValue(index + 1, T()); VTKM_TEST_ASSERT(test_equal(forwardX, expected), "Got invalid value from Load."); T backwardsX = neighbors.Get(-1, 0, 0); - expected = boundary->OnXNegative() ? TestValue(index, T()) : TestValue(index - 1, T()); + expected = (index3d[0] == 0) ? TestValue(index, T()) : TestValue(index - 1, T()); VTKM_TEST_ASSERT(test_equal(backwardsX, expected), "Got invalid value from Load."); } @@ -88,9 +98,9 @@ struct FetchArrayNeighborhoodInTests { TestPortal execObject; - using FetchType = vtkm::exec::arg::Fetch, + using FetchType = vtkm::exec::arg::Fetch, + vtkm::exec::arg::ThreadIndicesPointNeighborhood, TestPortal>; FetchType fetch; @@ -117,7 +127,7 @@ struct FetchArrayNeighborhoodInTests for (vtkm::Id i = 0; i < POINT_DIMS[0]; i++, index++) { index3d[0] = i; - vtkm::exec::arg::ThreadIndicesPointNeighborhood<1> indices( + vtkm::exec::arg::ThreadIndicesPointNeighborhood indices( index3d, vtkm::internal::NullType(), vtkm::internal::NullType(), connectivity); auto neighbors = fetch.Load(indices, execObject); @@ -139,7 +149,7 @@ struct FetchArrayNeighborhoodInTests //Verify that 1D scheduling works with neighborhoods for (vtkm::Id index = 0; index < (POINT_DIMS[0] * POINT_DIMS[1] * POINT_DIMS[2]); index++) { - vtkm::exec::arg::ThreadIndicesPointNeighborhood<1> indices( + vtkm::exec::arg::ThreadIndicesPointNeighborhood indices( index, TestIndexPortal(), TestIndexPortal(), connectivity); auto neighbors = fetch.Load(indices, execObject); diff --git a/vtkm/filter/testing/UnitTestMarchingCubesFilter.cxx b/vtkm/filter/testing/UnitTestMarchingCubesFilter.cxx index 9b53e3b9d..8ef970a33 100644 --- a/vtkm/filter/testing/UnitTestMarchingCubesFilter.cxx +++ b/vtkm/filter/testing/UnitTestMarchingCubesFilter.cxx @@ -440,14 +440,14 @@ void TestNormals(const vtkm::cont::DataSet& dataset, bool structured) //Calculated using StructuredPointGradient const vtkm::Vec hq_sg[numVerts] = { - { 0.165519f, 0.687006f, 0.707549f }, { 0.188441f, -0.561729f, 0.805574f }, - { 0.179543f, 0.702158f, 0.689012f }, { 0.271085f, 0.692957f, 0.668074f }, - { 0.00313049f, 0.720109f, 0.693854f }, { 0.549947f, -0.551974f, 0.626804f }, - { -0.447526f, -0.588187f, 0.673614f }, { 0.167553f, -0.779396f, 0.603711f }, - { 0.179543f, 0.702158f, -0.689012f }, { 0.271085f, 0.692957f, -0.668074f }, - { 0.00313049f, 0.720109f, -0.693854f }, { 0.165519f, 0.687006f, -0.707549f }, - { 0.549947f, -0.551974f, -0.626804f }, { -0.447526f, -0.588187f, -0.673614f }, - { 0.167553f, -0.779396f, -0.603711f }, { 0.188441f, -0.561729f, -0.805574f } + { 0.151008f, 0.626778f, 0.764425f }, { 0.133328f, -0.397444f, 0.907889f }, + { 0.162649f, 0.764163f, 0.624180f }, { 0.385327f, 0.664323f, 0.640467f }, + { -0.133720f, 0.713645f, 0.687626f }, { 0.770536f, -0.421248f, 0.478356f }, + { -0.736036f, -0.445244f, 0.509910f }, { 0.123446f, -0.887088f, 0.444788f }, + { 0.162649f, 0.764163f, -0.624180f }, { 0.385327f, 0.664323f, -0.640467f }, + { -0.133720f, 0.713645f, -0.687626f }, { 0.151008f, 0.626778f, -0.764425f }, + { 0.770536f, -0.421248f, -0.478356f }, { -0.736036f, -0.445244f, -0.509910f }, + { 0.123446f, -0.887088f, -0.444788f }, { 0.133328f, -0.397444f, -0.907889f } }; //Calculated using normals of the output triangles @@ -479,7 +479,12 @@ void TestNormals(const vtkm::cont::DataSet& dataset, bool structured) for (vtkm::Id i = 0; i < numVerts; ++i) { VTKM_TEST_ASSERT(test_equal(normals.GetPortalConstControl().Get(i), expected[i], 0.001), - "Result does not match expected values"); + "Result (", + normals.GetPortalConstControl().Get(i), + ") does not match expected value (", + expected[i], + ") vert ", + i); } // Test the other normals generation method diff --git a/vtkm/worklet/MarchingCubes.h b/vtkm/worklet/MarchingCubes.h index 9a95cc303..7d3057b43 100644 --- a/vtkm/worklet/MarchingCubes.h +++ b/vtkm/worklet/MarchingCubes.h @@ -599,13 +599,13 @@ public: //Optimization for structured cellsets so we can call StructuredPointGradient //and have way faster gradients vtkm::exec::ConnectivityStructured pointGeom(geometry); - vtkm::exec::arg::ThreadIndicesPointNeighborhood<3> tpn(pointId, pointId, 0, pointGeom, 0); + vtkm::exec::arg::ThreadIndicesPointNeighborhood tpn(pointId, pointId, 0, pointGeom, 0); const auto& boundary = tpn.GetBoundaryState(); auto pointPortal = pointCoordinates.GetPortal(); auto fieldPortal = inputField.GetPortal(); - vtkm::exec::arg::Neighborhood<1, decltype(pointPortal)> points(pointPortal, boundary); - vtkm::exec::arg::Neighborhood<1, decltype(fieldPortal)> field(fieldPortal, boundary); + vtkm::exec::FieldNeighborhood points(pointPortal, boundary); + vtkm::exec::FieldNeighborhood field(fieldPortal, boundary); vtkm::worklet::gradient::StructuredPointGradient gradient; gradient(boundary, points, field, normal); @@ -683,13 +683,13 @@ public: //Optimization for structured cellsets so we can call StructuredPointGradient //and have way faster gradients vtkm::exec::ConnectivityStructured pointGeom(geometry); - vtkm::exec::arg::ThreadIndicesPointNeighborhood<3> tpn(pointId, pointId, 0, pointGeom, 0); + vtkm::exec::arg::ThreadIndicesPointNeighborhood tpn(pointId, pointId, 0, pointGeom, 0); const auto& boundary = tpn.GetBoundaryState(); auto pointPortal = pointCoordinates.GetPortal(); auto fieldPortal = inputField.GetPortal(); - vtkm::exec::arg::Neighborhood<1, decltype(pointPortal)> points(pointPortal, boundary); - vtkm::exec::arg::Neighborhood<1, decltype(fieldPortal)> field(fieldPortal, boundary); + vtkm::exec::FieldNeighborhood points(pointPortal, boundary); + vtkm::exec::FieldNeighborhood field(fieldPortal, boundary); vtkm::worklet::gradient::StructuredPointGradient gradient; NormalType grad1; diff --git a/vtkm/worklet/WorkletPointNeighborhood.h b/vtkm/worklet/WorkletPointNeighborhood.h index 79723cc81..bcb222403 100644 --- a/vtkm/worklet/WorkletPointNeighborhood.h +++ b/vtkm/worklet/WorkletPointNeighborhood.h @@ -39,12 +39,12 @@ #include #include +#include #include #include #include #include #include -#include #include #include @@ -87,16 +87,16 @@ public: template using Dispatcher = vtkm::worklet::DispatcherPointNeighborhood; - /// \brief The \c ExecutionSignature tag to get if you the current iteration is on a boundary. + /// \brief The \c ExecutionSignature tag to query if the current iteration is inside the boundary. /// - /// A \c WorkletPointNeighborhood operates by iterating over all points using - /// a defined neighborhood. This \c ExecutionSignature tag provides different - /// types when you are on or off a boundary, allowing for separate code paths - /// just for handling boundaries. + /// A \c WorkletPointNeighborhood operates by iterating over all points using a defined + /// neighborhood. This \c ExecutionSignature tag provides a \c BoundaryState object that allows + /// you to query whether the neighborhood of the current iteration is completely inside the + /// bounds of the mesh or if it extends beyond the mesh. This is important as when you are on a + /// boundary the neighboordhood will contain empty values for a certain subset of values, and in + /// this case the values returned will depend on the boundary behavior. /// - /// This is important as when you are on a boundary the neighboordhood will - /// contain empty values for a certain subset of values - struct OnBoundary : vtkm::exec::arg::OnBoundary + struct Boundary : vtkm::exec::arg::Boundary { }; @@ -164,12 +164,9 @@ public: }; }; -template class WorkletPointNeighborhood : public WorkletPointNeighborhoodBase { public: - static constexpr vtkm::IdComponent Neighborhood = Neighborhood_; - /// \brief A control signature tag for neighborhood input values. /// /// A \c WorkletPointNeighborhood operates allowing access to a adjacent point @@ -186,7 +183,7 @@ public: { using TypeCheckTag = vtkm::cont::arg::TypeCheckTagArray; using TransportTag = vtkm::cont::arg::TransportTagArrayIn; - using FetchTag = vtkm::exec::arg::FetchTagArrayNeighborhoodIn; + using FetchTag = vtkm::exec::arg::FetchTagArrayNeighborhoodIn; }; /// Point neighborhood worklets use the related thread indices class. @@ -197,7 +194,7 @@ public: typename OutToInArrayType, typename VisitArrayType, vtkm::IdComponent Dimension> - VTKM_EXEC vtkm::exec::arg::ThreadIndicesPointNeighborhood GetThreadIndices( + VTKM_EXEC vtkm::exec::arg::ThreadIndicesPointNeighborhood GetThreadIndices( const IndexType& threadIndex, const OutToInArrayType& outToIn, const VisitArrayType& visit, @@ -206,14 +203,10 @@ public: Dimension>& inputDomain, //this should be explicitly const T& globalThreadIndexOffset = 0) const { - return vtkm::exec::arg::ThreadIndicesPointNeighborhood( + return vtkm::exec::arg::ThreadIndicesPointNeighborhood( threadIndex, outToIn, visit, inputDomain, globalThreadIndexOffset); } }; - - -using WorkletPointNeighborhood3x3x3 = WorkletPointNeighborhood<1>; -using WorkletPointNeighborhood5x5x5 = WorkletPointNeighborhood<2>; } } diff --git a/vtkm/worklet/connectivities/ImageConnectivity.h b/vtkm/worklet/connectivities/ImageConnectivity.h index 5bb18a6c5..d0f87d01f 100644 --- a/vtkm/worklet/connectivities/ImageConnectivity.h +++ b/vtkm/worklet/connectivities/ImageConnectivity.h @@ -43,7 +43,7 @@ template class ImageGraft; template <> -class ImageGraft<2> : public vtkm::worklet::WorkletPointNeighborhood3x3x3 +class ImageGraft<2> : public vtkm::worklet::WorkletPointNeighborhood { public: using ControlSignature = void(CellSetIn, diff --git a/vtkm/worklet/gradient/StructuredPointGradient.h b/vtkm/worklet/gradient/StructuredPointGradient.h index 3f1426920..026ba30c3 100644 --- a/vtkm/worklet/gradient/StructuredPointGradient.h +++ b/vtkm/worklet/gradient/StructuredPointGradient.h @@ -38,7 +38,7 @@ struct StructuredPointGradientInType : vtkm::ListTagBase }; template -struct StructuredPointGradient : public vtkm::worklet::WorkletPointNeighborhood3x3x3 +struct StructuredPointGradient : public vtkm::worklet::WorkletPointNeighborhood { using ControlSignature = void(CellSetIn, @@ -46,12 +46,12 @@ struct StructuredPointGradient : public vtkm::worklet::WorkletPointNeighborhood3 FieldInNeighborhood>, GradientOutputs outputFields); - using ExecutionSignature = void(OnBoundary, _2, _3, _4); + using ExecutionSignature = void(Boundary, _2, _3, _4); using InputDomain = _1; template - VTKM_EXEC void operator()(const vtkm::exec::arg::BoundaryState& boundary, + VTKM_EXEC void operator()(const vtkm::exec::BoundaryState& boundary, const PointsIn& inputPoints, const FieldIn& inputField, GradientOutType& outputGradient) const @@ -67,9 +67,9 @@ struct StructuredPointGradient : public vtkm::worklet::WorkletPointNeighborhood3 T deta = inputField.Get(0, 1, 0) - inputField.Get(0, -1, 0); T dzeta = inputField.Get(0, 0, 1) - inputField.Get(0, 0, -1); - dxi = (boundary.OnX() ? dxi : dxi * 0.5f); - deta = (boundary.OnY() ? deta : deta * 0.5f); - dzeta = (boundary.OnZ() ? dzeta : dzeta * 0.5f); + dxi = (boundary.InXBoundary(1) ? dxi * 0.5f : dxi); + deta = (boundary.InYBoundary(1) ? deta * 0.5f : deta); + dzeta = (boundary.InZBoundary(1) ? dzeta * 0.5f : dzeta); outputGradient[0] = static_cast(xi[0] * dxi + eta[0] * deta + zeta[0] * dzeta); outputGradient[1] = static_cast(xi[1] * dxi + eta[1] * deta + zeta[1] * dzeta); @@ -77,27 +77,26 @@ struct StructuredPointGradient : public vtkm::worklet::WorkletPointNeighborhood3 } template - VTKM_EXEC void operator()( - const vtkm::exec::arg::BoundaryState& boundary, - const vtkm::exec::arg::Neighborhood<1, vtkm::internal::ArrayPortalUniformPointCoordinates>& - inputPoints, - const FieldIn& inputField, - GradientOutType& outputGradient) const + VTKM_EXEC void operator()(const vtkm::exec::BoundaryState& boundary, + const vtkm::exec::FieldNeighborhood< + vtkm::internal::ArrayPortalUniformPointCoordinates>& inputPoints, + const FieldIn& inputField, + GradientOutType& outputGradient) const { //When the points and cells are both structured we can achieve even better //performance by not doing the Jacobian, but instead do an image gradient //using central differences using PointsIn = - vtkm::exec::arg::Neighborhood<1, vtkm::internal::ArrayPortalUniformPointCoordinates>; + vtkm::exec::FieldNeighborhood; using CoordType = typename PointsIn::ValueType; using OT = typename GradientOutType::ComponentType; CoordType r = inputPoints.Portal.GetSpacing(); - r[0] = (boundary.OnX() ? r[0] : r[0] * 0.5f); - r[1] = (boundary.OnY() ? r[1] : r[1] * 0.5f); - r[2] = (boundary.OnZ() ? r[2] : r[2] * 0.5f); + r[0] = (boundary.InXBoundary(1) ? r[0] * 0.5f : r[0]); + r[1] = (boundary.InYBoundary(1) ? r[1] * 0.5f : r[1]); + r[2] = (boundary.InZBoundary(1) ? r[2] * 0.5f : r[2]); const T dx = inputField.Get(1, 0, 0) - inputField.Get(-1, 0, 0); const T dy = inputField.Get(0, 1, 0) - inputField.Get(0, -1, 0); @@ -113,7 +112,7 @@ struct StructuredPointGradient : public vtkm::worklet::WorkletPointNeighborhood3 //will be float,3 even when T is a 3 component field template VTKM_EXEC void Jacobian(const PointsIn& inputPoints, - const vtkm::exec::arg::BoundaryState& boundary, + const vtkm::exec::BoundaryState& boundary, vtkm::Vec& m_xi, vtkm::Vec& m_eta, vtkm::Vec& m_zeta) const @@ -124,9 +123,9 @@ struct StructuredPointGradient : public vtkm::worklet::WorkletPointNeighborhood3 CoordType eta = inputPoints.Get(0, 1, 0) - inputPoints.Get(0, -1, 0); CoordType zeta = inputPoints.Get(0, 0, 1) - inputPoints.Get(0, 0, -1); - xi = (boundary.OnX() ? xi : xi * 0.5f); - eta = (boundary.OnY() ? eta : eta * 0.5f); - zeta = (boundary.OnZ() ? zeta : zeta * 0.5f); + xi = (boundary.InXBoundary(1) ? xi * 0.5f : xi); + eta = (boundary.InYBoundary(1) ? eta * 0.5f : eta); + zeta = (boundary.InZBoundary(1) ? zeta * 0.5f : zeta); CT aj = xi[0] * eta[1] * zeta[2] + xi[1] * eta[2] * zeta[0] + xi[2] * eta[0] * zeta[1] - xi[2] * eta[1] * zeta[0] - xi[1] * eta[0] * zeta[2] - xi[0] * eta[2] * zeta[1]; diff --git a/vtkm/worklet/testing/UnitTestWorkletMapPointNeighborhood.cxx b/vtkm/worklet/testing/UnitTestWorkletMapPointNeighborhood.cxx index 822365782..24a2369bf 100644 --- a/vtkm/worklet/testing/UnitTestWorkletMapPointNeighborhood.cxx +++ b/vtkm/worklet/testing/UnitTestWorkletMapPointNeighborhood.cxx @@ -36,86 +36,66 @@ namespace test_pointneighborhood { -struct MaxNeighborValue : public vtkm::worklet::WorkletPointNeighborhood3x3x3 +struct MaxNeighborValue : public vtkm::worklet::WorkletPointNeighborhood { using ControlSignature = void(FieldInNeighborhood neighbors, CellSetIn, FieldOut maxV); - using ExecutionSignature = void(OnBoundary, _1, _3); + using ExecutionSignature = void(Boundary, _1, _3); //verify input domain can be something other than first parameter using InputDomain = _2; template - VTKM_EXEC void operator()(const vtkm::exec::arg::BoundaryState& boundary, - const vtkm::exec::arg::Neighborhood<1, FieldIn>& inputField, + VTKM_EXEC void operator()(const vtkm::exec::BoundaryState& boundary, + const vtkm::exec::FieldNeighborhood& inputField, FieldOut& output) const { using ValueType = typename FieldIn::ValueType; auto* nboundary = inputField.Boundary; - if (!(nboundary->OnXPositive() == boundary.OnXPositive())) + if (!(nboundary->InXBoundary(1) == boundary.InXBoundary(1))) { this->RaiseError("Got invalid XPos boundary state"); } - if (!(nboundary->OnXNegative() == boundary.OnXNegative())) - { - this->RaiseError("Got invalid XNeg boundary state"); - } - - if (!(nboundary->OnYPositive() == boundary.OnYPositive())) + if (!(nboundary->InYBoundary(1) == boundary.InYBoundary(1))) { this->RaiseError("Got invalid YPos boundary state"); } - if (!(nboundary->OnYNegative() == boundary.OnYNegative())) - { - this->RaiseError("Got invalid YNeg boundary state"); - } - - if (!(nboundary->OnZPositive() == boundary.OnZPositive())) + if (!(nboundary->InZBoundary(1) == boundary.InZBoundary(1))) { this->RaiseError("Got invalid ZPos boundary state"); } - if (!(nboundary->OnZNegative() == boundary.OnZNegative())) + if (!(nboundary->InBoundary(1) == boundary.InBoundary(1))) { - this->RaiseError("Got invalid ZNeg boundary state"); + this->RaiseError("Got invalid boundary state"); } - if (!(nboundary->OnX() == boundary.OnX())) - { - this->RaiseError("Got invalid X boundary state"); - } - if (!(nboundary->OnY() == boundary.OnY())) - { - this->RaiseError("Got invalid Y boundary state"); - } - if (!(nboundary->OnZ() == boundary.OnZ())) - { - this->RaiseError("Got invalid Z boundary state"); - } - + auto minNeighbors = boundary.MinNeighborIndices(1); + auto maxNeighbors = boundary.MaxNeighborIndices(1); ValueType maxV = inputField.Get(0, 0, 0); //our value - for (vtkm::IdComponent k = 0; k < 3; ++k) + for (vtkm::IdComponent k = minNeighbors[2]; k <= maxNeighbors[2]; ++k) { - for (vtkm::IdComponent j = 0; j < 3; ++j) + for (vtkm::IdComponent j = minNeighbors[1]; j <= maxNeighbors[1]; ++j) { - maxV = vtkm::Max(maxV, inputField.Get(-1, j - 1, k - 1)); - maxV = vtkm::Max(maxV, inputField.Get(0, j - 1, k - 1)); - maxV = vtkm::Max(maxV, inputField.Get(1, j - 1, k - 1)); + for (vtkm::IdComponent i = minNeighbors[0]; i <= maxNeighbors[0]; ++i) + { + maxV = vtkm::Max(maxV, inputField.Get(i, j, k)); + } } } output = static_cast(maxV); } }; -struct ScatterIdentityNeighbor : public vtkm::worklet::WorkletPointNeighborhood5x5x5 +struct ScatterIdentityNeighbor : public vtkm::worklet::WorkletPointNeighborhood { using ControlSignature = void(CellSetIn topology, FieldIn pointCoords); using ExecutionSignature = @@ -130,7 +110,7 @@ struct ScatterIdentityNeighbor : public vtkm::worklet::WorkletPointNeighborhood5 const vtkm::Id& workIndex, const vtkm::Id& inputIndex, const vtkm::Id& outputIndex, - const vtkm::exec::arg::ThreadIndicesPointNeighborhood<2>& vtkmNotUsed(threadIndices), + const vtkm::exec::arg::ThreadIndicesPointNeighborhood& vtkmNotUsed(threadIndices), const vtkm::Id& visitIndex) const { if (workIndex != inputIndex) @@ -151,7 +131,7 @@ struct ScatterIdentityNeighbor : public vtkm::worklet::WorkletPointNeighborhood5 using ScatterType = vtkm::worklet::ScatterIdentity; }; -struct ScatterUniformNeighbor : public vtkm::worklet::WorkletPointNeighborhood5x5x5 +struct ScatterUniformNeighbor : public vtkm::worklet::WorkletPointNeighborhood { using ControlSignature = void(CellSetIn topology, FieldIn pointCoords); using ExecutionSignature = @@ -166,7 +146,7 @@ struct ScatterUniformNeighbor : public vtkm::worklet::WorkletPointNeighborhood5x const vtkm::Id& workIndex, const vtkm::Id& inputIndex, const vtkm::Id& outputIndex, - const vtkm::exec::arg::ThreadIndicesPointNeighborhood<2>& vtkmNotUsed(threadIndices), + const vtkm::exec::arg::ThreadIndicesPointNeighborhood& vtkmNotUsed(threadIndices), const vtkm::Id& visitIndex) const { if ((workIndex / 3) != inputIndex)