Change WorkletPointNeighborhood to specify neighborhood at runtime

Previously, WorkletPointNeighborhood had a template argument to select
the size of the neighborhood. This change removes that template
argument. Instead, the vtkm::exec::arg::BoundaryState methods now take
in a size parameter when determining when it overlaps the boundary.

If in the future we want to add the ability to select the neighborhood
size at compile-time (for performance reasons), I suggest adding this
template argument to the OnBoundary tag for ExecutionSignature.
This commit is contained in:
Kenneth Moreland 2018-11-18 10:41:13 -07:00
parent bc13764228
commit 01a9e85416
11 changed files with 169 additions and 190 deletions

@ -74,7 +74,7 @@ struct GameOfLifePolicy : public vtkm::filter::PolicyBase<GameOfLifePolicy>
using DeviceAdapterList = DevicesToTry;
};
struct UpdateLifeState : public vtkm::worklet::WorkletPointNeighborhood3x3x3
struct UpdateLifeState : public vtkm::worklet::WorkletPointNeighborhood
{
using CountingHandle = vtkm::cont::ArrayHandleCounting<vtkm::Id>;

@ -37,12 +37,11 @@ namespace arg
/// \c FetchTagArrayNeighborhoodIn is a tag used with the \c Fetch class to retrieve
/// values from an neighborhood.
///
template <int NeighborhoodSize>
struct FetchTagArrayNeighborhoodIn
{
};
template <int NeighborhoodSize, typename ExecObjectType>
template <typename ExecObjectType>
struct Neighborhood
{
VTKM_EXEC
@ -57,18 +56,12 @@ struct Neighborhood
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));
}
@ -79,8 +72,8 @@ struct Neighborhood
/// \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 <int NeighborhoodSize>
struct Neighborhood<NeighborhoodSize, vtkm::internal::ArrayPortalUniformPointCoordinates>
template <>
struct Neighborhood<vtkm::internal::ArrayPortalUniformPointCoordinates>
{
VTKM_EXEC
Neighborhood(const vtkm::internal::ArrayPortalUniformPointCoordinates& portal,
@ -108,14 +101,14 @@ struct Neighborhood<NeighborhoodSize, vtkm::internal::ArrayPortalUniformPointCoo
vtkm::internal::ArrayPortalUniformPointCoordinates Portal;
};
template <int NeighborhoodSize, typename ExecObjectType>
struct Fetch<vtkm::exec::arg::FetchTagArrayNeighborhoodIn<NeighborhoodSize>,
template <typename ExecObjectType>
struct Fetch<vtkm::exec::arg::FetchTagArrayNeighborhoodIn,
vtkm::exec::arg::AspectTagDefault,
vtkm::exec::arg::ThreadIndicesPointNeighborhood<NeighborhoodSize>,
vtkm::exec::arg::ThreadIndicesPointNeighborhood,
ExecObjectType>
{
using ThreadIndicesType = vtkm::exec::arg::ThreadIndicesPointNeighborhood<NeighborhoodSize>;
using ValueType = Neighborhood<NeighborhoodSize, ExecObjectType>;
using ThreadIndicesType = vtkm::exec::arg::ThreadIndicesPointNeighborhood;
using ValueType = Neighborhood<ExecObjectType>;
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC

@ -49,13 +49,13 @@ struct OnBoundary : vtkm::exec::arg::ExecutionSignatureTagBase
using AspectTag = vtkm::exec::arg::AspectTagOnBoundary;
};
template <typename FetchTag, int NSize, typename ExecObjectType>
template <typename FetchTag, typename ExecObjectType>
struct Fetch<FetchTag,
vtkm::exec::arg::AspectTagOnBoundary,
vtkm::exec::arg::ThreadIndicesPointNeighborhood<NSize>,
vtkm::exec::arg::ThreadIndicesPointNeighborhood,
ExecObjectType>
{
using ThreadIndicesType = vtkm::exec::arg::ThreadIndicesPointNeighborhood<NSize>;
using ThreadIndicesType = vtkm::exec::arg::ThreadIndicesPointNeighborhood;
using ValueType = vtkm::exec::arg::BoundaryState;

@ -41,91 +41,96 @@ namespace arg
struct BoundaryState
{
VTKM_EXEC
BoundaryState(const vtkm::Id3& ijk, const vtkm::Id3& pdims, int neighborhoodSize)
BoundaryState(const vtkm::Id3& ijk, const vtkm::Id3& pdims)
: 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<vtkm::IdComponent>(-ijk[dim]);
}
if (neighborhoodSize < pdims[dim] - ijk[dim] - 1)
{
this->MaxNeighborhood[dim] = neighborhoodSize;
}
else
{
this->MaxNeighborhood[dim] = static_cast<vtkm::IdComponent>(pdims[dim] - ijk[dim] - 1);
}
}
}
/// Returns the minimum neighbor index in the X direction (between -neighborhood size and 0)
//@{
/// Returns true if a neighborhood of the given number of layers 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.
///
VTKM_EXEC vtkm::IdComponent MinNeighborX() const { return this->MinNeighborhood[0]; }
/// The number of layers defines the size of the neighborhood in terms of how far away it extends
/// from the center. So if there is 1 layer, the neighborhood extends 1 unit away from the center
/// in each direction and is 3x3x3. If there are 2 layers, the neighborhood extends 2 units for a
/// size of 5x5x5.
///
VTKM_EXEC bool InXBoundary(vtkm::IdComponent numLayers) const
{
return (((this->IJK[0] - numLayers) >= 0) &&
((this->IJK[0] + numLayers) < this->PointDimensions[0]));
}
VTKM_EXEC bool InYBoundary(vtkm::IdComponent numLayers) const
{
return (((this->IJK[1] - numLayers) >= 0) &&
((this->IJK[1] + numLayers) < this->PointDimensions[1]));
}
VTKM_EXEC bool InZBoundary(vtkm::IdComponent numLayers) const
{
return (((this->IJK[2] - numLayers) >= 0) &&
((this->IJK[2] + numLayers) < this->PointDimensions[2]));
}
//@}
/// Returns the minimum neighbor index in the Z direction (between -neighborhood size and 0)
/// Returns true if a neighborhood of the given number of layers is contained within the bounds
/// of the cell set. Returns false if the neighborhood extends ouside of the boundary of the
/// data.
///
VTKM_EXEC vtkm::IdComponent MinNeighborY() const { return this->MinNeighborhood[1]; }
/// The number of layers defines the size of the neighborhood in terms of how far away it extends
/// from the center. So if there is 1 layer, the neighborhood extends 1 unit away from the center
/// in each direction and is 3x3x3. If there are 2 layers, the neighborhood extends 2 units for a
/// size of 5x5x5.
///
VTKM_EXEC bool InBoundary(vtkm::IdComponent numLayers) const
{
return this->InXBoundary(numLayers) && this->InYBoundary(numLayers) &&
this->InZBoundary(numLayers);
}
/// Returns the minimum neighbor index in the Z direction (between -neighborhood size and 0)
/// Returns the minimum neighborhood indices that are within the bounds of the data.
///
VTKM_EXEC vtkm::IdComponent MinNeighborZ() const { return this->MinNeighborhood[2]; }
VTKM_EXEC vtkm::Vec<vtkm::IdComponent, 3> MinNeighborIndices(vtkm::IdComponent numLayers) const
{
vtkm::Vec<vtkm::IdComponent, 3> minIndices;
/// Returns the maximum neighbor index in the X direction (between 0 and neighborhood size)
///
VTKM_EXEC vtkm::IdComponent MaxNeighborX() const { return this->MaxNeighborhood[0]; }
for (vtkm::IdComponent component = 0; component < 3; ++component)
{
if (this->IJK[component] >= numLayers)
{
minIndices[component] = -numLayers;
}
else
{
minIndices[component] = static_cast<vtkm::IdComponent>(-this->IJK[component]);
}
}
/// Returns the maximum neighbor index in the Z direction (between 0 and neighborhood size)
///
VTKM_EXEC vtkm::IdComponent MaxNeighborY() const { return this->MaxNeighborhood[1]; }
return minIndices;
}
/// Returns the maximum neighbor index in the Z direction (between 0 and neighborhood size)
/// Returns the minimum neighborhood indices that are within the bounds of the data.
///
VTKM_EXEC vtkm::IdComponent MaxNeighborZ() const { return this->MaxNeighborhood[2]; }
VTKM_EXEC vtkm::Vec<vtkm::IdComponent, 3> MaxNeighborIndices(vtkm::IdComponent numLayers) const
{
vtkm::Vec<vtkm::IdComponent, 3> maxIndices;
/// Returns true if the neighborhood extends past the positive X direction.
///
VTKM_EXEC bool OnXPositive() const { return this->MaxNeighborX() < this->NeighborhoodSize; }
for (vtkm::IdComponent component = 0; component < 3; ++component)
{
if ((this->PointDimensions[component] - this->IJK[component] - 1) >= numLayers)
{
maxIndices[component] = numLayers;
}
else
{
maxIndices[component] = static_cast<vtkm::IdComponent>(this->PointDimensions[component] -
this->IJK[component] - 1);
}
}
/// 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(); }
return maxIndices;
}
//todo: This needs to work with BoundaryConstantValue
//todo: This needs to work with BoundaryPeroidic
@ -140,9 +145,9 @@ struct BoundaryState
VTKM_EXEC vtkm::Id3 NeighborIndexToFullIndexClamp(
const vtkm::Vec<vtkm::IdComponent, 3>& neighbor) const
{
vtkm::Vec<vtkm::IdComponent, 3> clampedNeighbor =
vtkm::Max(this->MinNeighborhood, vtkm::Min(this->MaxNeighborhood, neighbor));
return this->IJK + clampedNeighbor;
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,
@ -181,9 +186,6 @@ struct BoundaryState
vtkm::Id3 IJK;
vtkm::Id3 PointDimensions;
vtkm::Vec<vtkm::IdComponent, 3> MinNeighborhood;
vtkm::Vec<vtkm::IdComponent, 3> MaxNeighborhood;
vtkm::IdComponent NeighborhoodSize;
};
namespace detail
@ -213,7 +215,6 @@ inline VTKM_EXEC vtkm::Id3 To3D(vtkm::Vec<vtkm::Id, 1> index)
/// \brief Container for thread information in a WorkletPointNeighborhood.
///
///
template <int NeighborhoodSize>
class ThreadIndicesPointNeighborhood
{
@ -227,7 +228,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 +253,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<vtkm::IdComponent>(visit.Get(outIndex)))
@ -271,8 +271,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)

@ -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<T> execObject;
using FetchType = vtkm::exec::arg::Fetch<vtkm::exec::arg::FetchTagArrayNeighborhoodIn<1>,
using FetchType = vtkm::exec::arg::Fetch<vtkm::exec::arg::FetchTagArrayNeighborhoodIn,
vtkm::exec::arg::AspectTagDefault,
vtkm::exec::arg::ThreadIndicesPointNeighborhood<1>,
vtkm::exec::arg::ThreadIndicesPointNeighborhood,
TestPortal<T>>;
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);

@ -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

@ -599,13 +599,13 @@ public:
//Optimization for structured cellsets so we can call StructuredPointGradient
//and have way faster gradients
vtkm::exec::ConnectivityStructured<Cell, Point, 3> 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::arg::Neighborhood<decltype(pointPortal)> points(pointPortal, boundary);
vtkm::exec::arg::Neighborhood<decltype(fieldPortal)> field(fieldPortal, boundary);
vtkm::worklet::gradient::StructuredPointGradient<T> 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<Cell, Point, 3> 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::arg::Neighborhood<decltype(pointPortal)> points(pointPortal, boundary);
vtkm::exec::arg::Neighborhood<decltype(fieldPortal)> field(fieldPortal, boundary);
vtkm::worklet::gradient::StructuredPointGradient<T> gradient;
NormalType grad1;

@ -164,12 +164,9 @@ public:
};
};
template <int Neighborhood_>
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<TypeList>;
using TransportTag = vtkm::cont::arg::TransportTagArrayIn;
using FetchTag = vtkm::exec::arg::FetchTagArrayNeighborhoodIn<Neighborhood>;
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<Neighborhood> 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<Neighborhood>(
return vtkm::exec::arg::ThreadIndicesPointNeighborhood(
threadIndex, outToIn, visit, inputDomain, globalThreadIndexOffset);
}
};
using WorkletPointNeighborhood3x3x3 = WorkletPointNeighborhood<1>;
using WorkletPointNeighborhood5x5x5 = WorkletPointNeighborhood<2>;
}
}

@ -43,7 +43,7 @@ template <int Dimension>
class ImageGraft;
template <>
class ImageGraft<2> : public vtkm::worklet::WorkletPointNeighborhood3x3x3
class ImageGraft<2> : public vtkm::worklet::WorkletPointNeighborhood
{
public:
using ControlSignature = void(CellSetIn,

@ -38,7 +38,7 @@ struct StructuredPointGradientInType : vtkm::ListTagBase<T>
};
template <typename T>
struct StructuredPointGradient : public vtkm::worklet::WorkletPointNeighborhood3x3x3
struct StructuredPointGradient : public vtkm::worklet::WorkletPointNeighborhood
{
using ControlSignature = void(CellSetIn,
@ -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<OT>(xi[0] * dxi + eta[0] * deta + zeta[0] * dzeta);
outputGradient[1] = static_cast<OT>(xi[1] * dxi + eta[1] * deta + zeta[1] * dzeta);
@ -77,27 +77,26 @@ struct StructuredPointGradient : public vtkm::worklet::WorkletPointNeighborhood3
}
template <typename FieldIn, typename GradientOutType>
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::arg::BoundaryState& boundary,
const vtkm::exec::arg::Neighborhood<
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::arg::Neighborhood<vtkm::internal::ArrayPortalUniformPointCoordinates>;
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);
@ -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];

@ -36,7 +36,7 @@
namespace test_pointneighborhood
{
struct MaxNeighborValue : public vtkm::worklet::WorkletPointNeighborhood3x3x3
struct MaxNeighborValue : public vtkm::worklet::WorkletPointNeighborhood
{
using ControlSignature = void(FieldInNeighborhood<Scalar> neighbors,
@ -49,73 +49,53 @@ struct MaxNeighborValue : public vtkm::worklet::WorkletPointNeighborhood3x3x3
template <typename FieldIn, typename FieldOut>
VTKM_EXEC void operator()(const vtkm::exec::arg::BoundaryState& boundary,
const vtkm::exec::arg::Neighborhood<1, FieldIn>& inputField,
const vtkm::exec::arg::Neighborhood<FieldIn>& 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<FieldOut>(maxV);
}
};
struct ScatterIdentityNeighbor : public vtkm::worklet::WorkletPointNeighborhood5x5x5
struct ScatterIdentityNeighbor : public vtkm::worklet::WorkletPointNeighborhood
{
using ControlSignature = void(CellSetIn topology, FieldIn<Vec3> 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<Vec3> 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)