Commit 191d6e55 authored by Kenneth Moreland's avatar Kenneth Moreland
Browse files

Add Mask capabilities to worklets

Mask objects allow you to specify which output values should be
generated when a worklet is run. That is, the Mask allows you to skip
the invocation of a worklet for any number of outputs.
parent c27a3366
# Allow masking of worklet invocations
There have recently been use cases where it would be helpful to mask out
some of the invocations of a worklet. The idea is that when invoking a
worklet with a mask array on the input domain, you might implement your
worklet more-or-less like the following.
```cpp
VTKM_EXEC void operator()(bool mask, /* other parameters */)
{
if (mask)
{
// Do interesting stuff
}
}
```
This works, but what if your mask has mostly false values? In that case,
you are spending tons of time loading data to and from memory where fields
are stored for no reason.
You could potentially get around this problem by adding a scatter to the
worklet. However, that will compress the output arrays to only values that
are active in the mask. That is problematic if you want the masked output
in the appropriate place in the original arrays. You will have to do some
complex (and annoying and possibly expensive) permutations of the output
arrays.
Thus, we would like a new feature similar to scatter that instead masks out
invocations so that the worklet is simply not run on those outputs.
## New Interface
The new "Mask" feature that is similar (and orthogonal) to the existing
"Scatter" feature. Worklet objects now define a `MaskType` that provides on
object that manages the selections of which invocations are skipped. The
following Mask objects are defined.
* `MaskNone` - This removes any mask of the output. All outputs are
generated. This is the default if no `MaskType` is explicitly defined.
* `MaskSelect` - The user to provides an array that specifies whether
each output is created with a 1 to mean that the output should be
created an 0 the mean that it should not.
* `MaskIndices` - The user provides an array with a list of indices for
all outputs that should be created.
It will be straightforward to implement other versions of masks. (For
example, you could make a mask class that selectes every Nth entry.) Those
could be made on an as-needed basis.
## Implementation
The implementation follows the same basic idea of how scatters are
implemented.
### Mask Classes
The mask class is required to implement the following items.
* `ThreadToOutputType` - A type for an array that maps a thread index (an
index in the array) to an output index. A reasonable type for this
could be `vtkm::cont::ArrayHandle<vtkm::Id>`.
* `GetThreadToOutputMap` - Given the range for the output (e.g. the
number of items in the output domain), returns an array of type
`ThreadToOutputType` that is the actual map.
* `GetThreadRange` - Given a range for the output (e.g. the number of
items in the output domain), returns the range for the threads (e.g.
the number of times the worklet will be invoked).
### Dispatching
The `vtkm::worklet::internal::DispatcherBase` manages a mask class in
the same way it manages the scatter class. It gets the `MaskType` from
the worklet it is templated on. It requires a `MaskType` object during
its construction.
Previously the dispatcher (and downstream) had to manage the range and
indices of inputs and threads. They now have to also manage a separate
output range/index as now all three may be different.
The `vtkm::Invocation` is changed to hold the ThreadToOutputMap array from
the mask. It likewises has a templated `ChangeThreadToOutputMap` method
added (similar to those already existing for the arrays from a scatter).
This method is used in `DispatcherBase::InvokeTransportParameters` to add
the mask's array to the invocation before calling `InvokeSchedule`.
### Thread Indices
With the addition of masks, the `ThreadIndices` classes are changed to
manage the actual output index. Previously, the output index was always the
same as the thread index. However, now these two can be different. The
`GetThreadIndices` methods of the worklet base classes have an argument
added that is the portal to the ThreadToOutputMap.
The worklet `GetThreadIndices` is called from the `Task` classes. These
classes are changed to pass in this additional argument. Since the `Task`
classes get an `Invocation` object from the dispatcher, which contains the
`ThreadToOutputMap`, this change is trivial.
## Interaction Between Mask and Scatter
Although it seems weird, it should work fine to mix scatters and masks. The
scatter will first be applied to the input to generate a (potential) list
of output elements. The mask will then be applied to these output elements.
......@@ -49,14 +49,25 @@ public:
ThreadIndicesBasic(vtkm::Id threadIndex,
vtkm::Id inIndex,
vtkm::IdComponent visitIndex,
vtkm::Id outIndex,
vtkm::Id globalThreadIndexOffset = 0)
: InputIndex(inIndex)
, OutputIndex(threadIndex)
: ThreadIndex(threadIndex)
, InputIndex(inIndex)
, OutputIndex(outIndex)
, VisitIndex(visitIndex)
, GlobalThreadIndexOffset(globalThreadIndexOffset)
{
}
/// \brief The index of the thread or work invocation.
///
/// This index refers to which instance of the worklet is being invoked. Every invocation of the
/// worklet has a unique thread index. This is also called the work index depending on the
/// context.
///
VTKM_EXEC
vtkm::Id GetThreadIndex() const { return this->ThreadIndex; }
/// \brief The index into the input domain.
///
/// This index refers to the input element (array value, cell, etc.) that
......@@ -98,9 +109,10 @@ public:
///
/// Global index (for streaming)
VTKM_EXEC
vtkm::Id GetGlobalIndex() const { return (this->GlobalThreadIndexOffset + this->OutputIndex); }
vtkm::Id GetGlobalIndex() const { return (this->GlobalThreadIndexOffset + this->ThreadIndex); }
private:
vtkm::Id ThreadIndex;
vtkm::Id InputIndex;
vtkm::Id OutputIndex;
vtkm::IdComponent VisitIndex;
......
......@@ -65,19 +65,14 @@ class ThreadIndicesPointNeighborhood
{
public:
template <typename OutToInArrayType, typename VisitArrayType, vtkm::IdComponent Dimension>
template <vtkm::IdComponent Dimension>
VTKM_EXEC ThreadIndicesPointNeighborhood(
const vtkm::Id3& outIndex,
const OutToInArrayType&,
const VisitArrayType&,
const vtkm::exec::ConnectivityStructured<vtkm::TopologyElementTagCell,
vtkm::TopologyElementTagPoint,
Dimension>& connectivity,
vtkm::Id globalThreadIndexOffset = 0)
: State(outIndex, detail::To3D(connectivity.GetPointDimensions()))
, InputIndex(0)
, OutputIndex(0)
, VisitIndex(0)
, GlobalThreadIndexOffset(globalThreadIndexOffset)
{
using ConnectivityType = vtkm::exec::ConnectivityStructured<vtkm::TopologyElementTagCell,
......@@ -85,41 +80,27 @@ public:
Dimension>;
using ConnRangeType = typename ConnectivityType::SchedulingRangeType;
const ConnRangeType index = detail::Deflate(outIndex, ConnRangeType());
this->InputIndex = connectivity.LogicalToFlatToIndex(index);
this->OutputIndex = this->InputIndex;
}
template <typename OutToInArrayType, typename VisitArrayType, vtkm::IdComponent Dimension>
VTKM_EXEC ThreadIndicesPointNeighborhood(
const vtkm::Id& outIndex,
const OutToInArrayType& outToIn,
const VisitArrayType& visit,
const vtkm::exec::ConnectivityStructured<vtkm::TopologyElementTagCell,
vtkm::TopologyElementTagPoint,
Dimension>& connectivity,
vtkm::Id globalThreadIndexOffset = 0)
: State(detail::To3D(connectivity.FlatToLogicalToIndex(outToIn.Get(outIndex))),
detail::To3D(connectivity.GetPointDimensions()))
, InputIndex(outToIn.Get(outIndex))
, OutputIndex(outIndex)
, VisitIndex(static_cast<vtkm::IdComponent>(visit.Get(outIndex)))
, GlobalThreadIndexOffset(globalThreadIndexOffset)
{
this->ThreadIndex = connectivity.LogicalToFlatToIndex(index);
this->InputIndex = this->ThreadIndex;
this->VisitIndex = 0;
this->OutputIndex = this->ThreadIndex;
}
template <vtkm::IdComponent Dimension>
VTKM_EXEC ThreadIndicesPointNeighborhood(
const vtkm::Id& outIndex,
const vtkm::Id& inIndex,
const vtkm::IdComponent& visitIndex,
vtkm::Id threadIndex,
vtkm::Id inputIndex,
vtkm::IdComponent visitIndex,
vtkm::Id outputIndex,
const vtkm::exec::ConnectivityStructured<vtkm::TopologyElementTagCell,
vtkm::TopologyElementTagPoint,
Dimension>& connectivity,
vtkm::Id globalThreadIndexOffset = 0)
: State(detail::To3D(connectivity.FlatToLogicalToIndex(inIndex)),
: State(detail::To3D(connectivity.FlatToLogicalToIndex(inputIndex)),
detail::To3D(connectivity.GetPointDimensions()))
, InputIndex(inIndex)
, OutputIndex(outIndex)
, ThreadIndex(threadIndex)
, InputIndex(inputIndex)
, OutputIndex(outputIndex)
, VisitIndex(visitIndex)
, GlobalThreadIndexOffset(globalThreadIndexOffset)
{
......@@ -128,6 +109,9 @@ public:
VTKM_EXEC
const vtkm::exec::BoundaryState& GetBoundaryState() const { return this->State; }
VTKM_EXEC
vtkm::Id GetThreadIndex() const { return this->ThreadIndex; }
VTKM_EXEC
vtkm::Id GetInputIndex() const { return this->InputIndex; }
......@@ -148,6 +132,7 @@ public:
private:
vtkm::exec::BoundaryState State;
vtkm::Id ThreadIndex;
vtkm::Id InputIndex;
vtkm::Id OutputIndex;
vtkm::IdComponent VisitIndex;
......
......@@ -48,9 +48,10 @@ public:
vtkm::Id threadIndex,
vtkm::Id inIndex,
vtkm::IdComponent visitIndex,
vtkm::Id outIndex,
const vtkm::exec::internal::ReduceByKeyLookup<P1, P2, P3>& keyLookup,
vtkm::Id globalThreadIndexOffset = 0)
: Superclass(threadIndex, inIndex, visitIndex, globalThreadIndexOffset)
: Superclass(threadIndex, inIndex, visitIndex, outIndex, globalThreadIndexOffset)
, ValueOffset(keyLookup.Offsets.Get(inIndex))
, NumberOfValues(keyLookup.Counts.Get(inIndex))
{
......
......@@ -100,41 +100,20 @@ public:
using CellShapeTag = typename ConnectivityType::CellShapeTag;
VTKM_SUPPRESS_EXEC_WARNINGS
template <typename OutToInArrayType, typename VisitArrayType>
VTKM_EXEC ThreadIndicesTopologyMap(vtkm::Id threadIndex,
const OutToInArrayType& outToIn,
const VisitArrayType& visit,
vtkm::Id inputIndex,
vtkm::IdComponent visitIndex,
vtkm::Id outputIndex,
const ConnectivityType& connectivity,
vtkm::Id globalThreadIndexOffset = 0)
: Superclass(threadIndex,
outToIn.Get(threadIndex),
visit.Get(threadIndex),
globalThreadIndexOffset)
: Superclass(threadIndex, inputIndex, visitIndex, outputIndex, globalThreadIndexOffset)
// The connectivity is stored in the invocation parameter at the given
// input domain index. If this class is being used correctly, the type
// of the domain will match the connectivity type used here. If there is
// a compile error here about a type mismatch, chances are a worklet has
// set its input domain incorrectly.
, IndicesFrom(connectivity.GetIndices(outToIn.Get(threadIndex)))
, CellShape(connectivity.GetCellShape(outToIn.Get(threadIndex)))
{
}
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC
ThreadIndicesTopologyMap(vtkm::Id threadIndex,
vtkm::Id inIndex,
vtkm::IdComponent visitIndex,
const ConnectivityType& connectivity,
vtkm::Id globalThreadIndexOffset = 0)
: Superclass(threadIndex, inIndex, visitIndex, globalThreadIndexOffset)
// The connectivity is stored in the invocation parameter at the given
// input domain index. If this class is being used correctly, the type
// of the domain will match the connectivity type used here. If there is
// a compile error here about a type mismatch, chances are a worklet has
// set its input domain incorrectly.
, IndicesFrom(connectivity.GetIndices(inIndex))
, CellShape(connectivity.GetCellShape(inIndex))
, IndicesFrom(connectivity.GetIndices(inputIndex))
, CellShape(connectivity.GetCellShape(inputIndex))
{
}
......@@ -187,61 +166,51 @@ public:
using CellShapeTag = typename ConnectivityType::CellShapeTag;
using LogicalIndexType = typename ConnectivityType::SchedulingRangeType;
template <typename OutToInArrayType, typename VisitArrayType>
VTKM_EXEC ThreadIndicesTopologyMap(vtkm::Id threadIndex,
const OutToInArrayType& outToIn,
const VisitArrayType& visit,
vtkm::Id inIndex,
vtkm::IdComponent visitIndex,
vtkm::Id outIndex,
const ConnectivityType& connectivity,
vtkm::Id globalThreadIndexOffset = 0)
{
this->InputIndex = outToIn.Get(threadIndex);
this->OutputIndex = threadIndex;
this->VisitIndex = visit.Get(threadIndex);
this->ThreadIndex = threadIndex;
this->InputIndex = inIndex;
this->VisitIndex = visitIndex;
this->OutputIndex = outIndex;
this->LogicalIndex = connectivity.FlatToLogicalToIndex(this->InputIndex);
this->IndicesFrom = connectivity.GetIndices(this->LogicalIndex);
this->CellShape = connectivity.GetCellShape(this->InputIndex);
this->GlobalThreadIndexOffset = globalThreadIndexOffset;
}
template <typename OutToInArrayType, typename VisitArrayType>
VTKM_EXEC ThreadIndicesTopologyMap(const vtkm::Id3& threadIndex,
const OutToInArrayType&,
const VisitArrayType& visit,
const ConnectivityType& connectivity,
const vtkm::Id globalThreadIndexOffset = 0)
{
// We currently only support multidimensional indices on one-to-one input-
// to-output mappings. (We don't have a use case otherwise.)
// that is why the OutToInArrayType is ignored
// That is why we treat teh threadIndex as also the inputIndex and outputIndex
const LogicalIndexType logicalIndex = detail::Deflate(threadIndex, LogicalIndexType());
const vtkm::Id index = connectivity.LogicalToFlatToIndex(logicalIndex);
this->ThreadIndex = index;
this->InputIndex = index;
this->OutputIndex = index;
this->VisitIndex = visit.Get(index);
this->VisitIndex = 0;
this->LogicalIndex = logicalIndex;
this->IndicesFrom = connectivity.GetIndices(logicalIndex);
this->CellShape = connectivity.GetCellShape(index);
this->GlobalThreadIndexOffset = globalThreadIndexOffset;
}
VTKM_SUPPRESS_EXEC_WARNINGS
/// \brief The index of the thread or work invocation.
///
/// This index refers to which instance of the worklet is being invoked. Every invocation of the
/// worklet has a unique thread index. This is also called the work index depending on the
/// context.
///
VTKM_EXEC
ThreadIndicesTopologyMap(vtkm::Id threadIndex,
vtkm::Id vtkmNotUsed(inIndex),
vtkm::IdComponent visitIndex,
const ConnectivityType& connectivity,
vtkm::Id globalThreadIndexOffset = 0)
{
this->InputIndex = threadIndex;
this->OutputIndex = threadIndex;
this->VisitIndex = visitIndex;
this->LogicalIndex = connectivity.FlatToLogicalToIndex(this->InputIndex);
this->IndicesFrom = connectivity.GetIndices(this->LogicalIndex);
this->CellShape = connectivity.GetCellShape(this->InputIndex);
this->GlobalThreadIndexOffset = globalThreadIndexOffset;
}
vtkm::Id GetThreadIndex() const { return this->ThreadIndex; }
/// \brief The logical index into the input domain.
///
......@@ -321,9 +290,10 @@ public:
CellShapeTag GetCellShape() const { return this->CellShape; }
private:
vtkm::Id ThreadIndex;
vtkm::Id InputIndex;
vtkm::Id OutputIndex;
vtkm::IdComponent VisitIndex;
vtkm::Id OutputIndex;
LogicalIndexType LogicalIndex;
IndicesFromType IndicesFrom;
CellShapeTag CellShape;
......@@ -351,16 +321,17 @@ public:
using CellShapeTag = typename ConnectivityType::CellShapeTag;
using LogicalIndexType = typename ConnectivityType::SchedulingRangeType;
template <typename OutToInArrayType, typename VisitArrayType>
VTKM_EXEC ThreadIndicesTopologyMap(vtkm::Id threadIndex,
const OutToInArrayType& outToIn,
const VisitArrayType& visit,
vtkm::Id inputIndex,
vtkm::IdComponent visitIndex,
vtkm::Id outputIndex,
const PermutedConnectivityType& permutation,
vtkm::Id globalThreadIndexOffset = 0)
{
this->InputIndex = outToIn.Get(threadIndex);
this->OutputIndex = threadIndex;
this->VisitIndex = visit.Get(threadIndex);
this->ThreadIndex = threadIndex;
this->InputIndex = inputIndex;
this->VisitIndex = visitIndex;
this->OutputIndex = outputIndex;
const vtkm::Id permutedIndex = permutation.Portal.Get(this->InputIndex);
this->LogicalIndex = permutation.Connectivity.FlatToLogicalToIndex(permutedIndex);
......@@ -369,24 +340,14 @@ public:
this->GlobalThreadIndexOffset = globalThreadIndexOffset;
}
VTKM_SUPPRESS_EXEC_WARNINGS
/// \brief The index of the thread or work invocation.
///
/// This index refers to which instance of the worklet is being invoked. Every invocation of the
/// worklet has a unique thread index. This is also called the work index depending on the
/// context.
///
VTKM_EXEC
ThreadIndicesTopologyMap(vtkm::Id threadIndex,
vtkm::Id vtkmNotUsed(inIndex),
vtkm::IdComponent visitIndex,
const PermutedConnectivityType& permutation,
vtkm::Id globalThreadIndexOffset = 0)
{
this->InputIndex = threadIndex;
this->OutputIndex = threadIndex;
this->VisitIndex = visitIndex;
const vtkm::Id permutedIndex = permutation.Portal.Get(this->InputIndex);
this->LogicalIndex = permutation.Connectivity.FlatToLogicalToIndex(permutedIndex);
this->IndicesFrom = permutation.Connectivity.GetIndices(this->LogicalIndex);
this->CellShape = permutation.Connectivity.GetCellShape(permutedIndex);
this->GlobalThreadIndexOffset = globalThreadIndexOffset;
}
vtkm::Id GetThreadIndex() const { return this->ThreadIndex; }
/// \brief The logical index into the input domain.
///
......@@ -466,9 +427,10 @@ public:
CellShapeTag GetCellShape() const { return this->CellShape; }
private:
vtkm::Id ThreadIndex;
vtkm::Id InputIndex;
vtkm::Id OutputIndex;
vtkm::IdComponent VisitIndex;
vtkm::Id OutputIndex;
LogicalIndexType LogicalIndex;
IndicesFromType IndicesFrom;
CellShapeTag CellShape;
......
......@@ -45,14 +45,6 @@ struct TestPortal
}
};
struct TestIndexPortal
{
using ValueType = vtkm::Id;
VTKM_EXEC_CONT
ValueType Get(vtkm::Id index) const { return index; }
};
template <typename NeighborhoodType, typename T>
void verify_neighbors(NeighborhoodType neighbors, vtkm::Id index, vtkm::Id3 index3d, T)
{
......@@ -127,8 +119,7 @@ struct FetchArrayNeighborhoodInTests
for (vtkm::Id i = 0; i < POINT_DIMS[0]; i++, index++)
{
index3d[0] = i;
vtkm::exec::arg::ThreadIndicesPointNeighborhood indices(
index3d, vtkm::internal::NullType(), vtkm::internal::NullType(), connectivity);
vtkm::exec::arg::ThreadIndicesPointNeighborhood indices(index3d, connectivity);
auto neighbors = fetch.Load(indices, execObject);
......@@ -149,8 +140,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 indices(
index, TestIndexPortal(), TestIndexPortal(), connectivity);
vtkm::exec::arg::ThreadIndicesPointNeighborhood indices(index, index, 0, index, connectivity);
auto neighbors = fetch.Load(indices, execObject);
......
......@@ -82,8 +82,12 @@ struct FetchArrayTopologyMapInTests
FetchType fetch;
const vtkm::Id threadIndex = 0;
const vtkm::Id outputIndex = invocation.ThreadToOutputMap.Get(threadIndex);
const vtkm::Id inputIndex = invocation.OutputToInputMap.Get(outputIndex);
const vtkm::IdComponent visitIndex = invocation.VisitArray.Get(outputIndex);
ThreadIndicesType indices(
0, invocation.OutputToInputMap, invocation.VisitArray, invocation.GetInputDomain());
threadIndex, inputIndex, visitIndex, outputIndex, invocation.GetInputDomain());
typename FetchType::ValueType value =
fetch.Load(indices, invocation.Parameters.template GetParameter<ParamIndex>());
......@@ -125,7 +129,8 @@ struct FetchArrayTopologyMapInTests
BaseFunctionInterface(),
BaseFunctionInterface(),
TestIndexPortal(),
TestZeroPortal()));
TestZeroPortal(),
TestIndexPortal()));
}
};
......@@ -157,20 +162,32 @@ void TryStructuredPointCoordinatesInvocation(const Invocation& invocation)
vtkm::Vec<vtkm::FloatDefault, 3> origin = TestValue(0, vtkm::Vec<vtkm::FloatDefault, 3>());
vtkm::Vec<vtkm::FloatDefault, 3> spacing = TestValue(1, vtkm::Vec<vtkm::FloatDefault, 3>());
vtkm::VecAxisAlignedPointCoordinates<NumDimensions> value = fetch.Load(
ThreadIndicesType(
0, invocation.OutputToInputMap, invocation.VisitArray, invocation.GetInputDomain()),
invocation.Parameters.template GetParameter<ParamIndex>());
VTKM_TEST_ASSERT(test_equal(value.GetOrigin(), origin), "Bad origin.");
VTKM_TEST_ASSERT(test_equal(value.GetSpacing(), spacing), "Bad spacing.");
{
const vtkm::Id threadIndex = 0;
const vtkm::Id outputIndex = invocation.ThreadToOutputMap.Get(threadIndex);
const vtkm::Id inputIndex = invocation.OutputToInputMap.Get(outputIndex);
const vtkm::IdComponent visitIndex = invocation.VisitArray.Get(outputIndex);
vtkm::VecAxisAlignedPointCoordinates<NumDimensions> value =
fetch.Load(ThreadIndicesType(
threadIndex, inputIndex, visitIndex, outputIndex, invocation.GetInputDomain()),
invocation.Parameters.template GetParameter<ParamIndex>());
VTKM_TEST_ASSERT(test_equal(value.GetOrigin(), origin), "Bad origin.");
VTKM_TEST_ASSERT(test_equal(value.GetSpacing(), spacing), "Bad spacing.");
}
origin[0] += spacing[0];
value = fetch.Load(
ThreadIndicesType(
1, invocation.OutputToInputMap, invocation.VisitArray, invocation.GetInputDomain()),
invocation.Parameters.template GetParameter<ParamIndex>());
VTKM_TEST_ASSERT(test_equal(value.GetOrigin(), origin), "Bad origin.");
VTKM_TEST_ASSERT(test_equal(value.GetSpacing(), spacing), "Bad spacing.");
{
const vtkm::Id threadIndex = 1;
const vtkm::Id outputIndex = invocation.ThreadToOutputMap.Get(threadIndex);
const vtkm::Id inputIndex = invocation.OutputToInputMap.Get(outputIndex);
const vtkm::IdComponent visitIndex = invocation.VisitArray.Get(outputIndex);
vtkm::VecAxisAlignedPointCoordinates<NumDimensions> value =
fetch.Load(ThreadIndicesType(
threadIndex, inputIndex, visitIndex, outputIndex, invocation.GetInputDomain()),
invocation.Parameters.template GetParameter<ParamIndex>());
VTKM_TEST_ASSERT(test_equal(value.GetOrigin(), origin), "Bad origin.");
VTKM_TEST_ASSERT(test_equal(value.GetSpacing(), spacing), "Bad spacing.");
}
}
template <vtkm::IdComponent NumDimensions>
......@@ -192,14 +209,16 @@ void TryStructuredPointCoordinates(
BaseFunctionInterface(),
BaseFunctionInterface(),
TestIndexPortal(),
TestZeroPortal()));
TestZeroPortal(),
TestIndexPortal()));
// Try again with topology in argument 3 and point coordinates in argument 1
TryStructuredPointCoordinatesInvocation<NumDimensions, 1>(vtkm::internal::make_Invocation<3>(
BaseFunctionInterface().Replace<3>(connectivity).template Replace<1>(coordinates),
BaseFunctionInterface(),
BaseFunctionInterface(),
TestIndexPortal(),
TestZeroPortal()));
TestZeroPortal(),
TestIndexPortal()));
}
void TryStructuredPointCoordinates()
......
......@@ -87,6 +87,7 @@ public:
this->Worklet.GetThreadIndices(index,
this->Invocation.OutputToInputMap,
this->Invocation.VisitArray,
this->Invocation.ThreadToOutputMap,
this->Invocation.GetInputDomain(),
this->GlobalIndexOffset));
}
......@@ -157,6 +158,7 @@ public:
this->Worklet.GetThreadIndices(index,
this->Invocation.OutputToInputMap,
this->Invocation.VisitArray,
this->Invocation.ThreadToOutputMap,
this->Invocation.GetInputDomain(),
this->GlobalIndexOffset));
}
......
......@@ -74,6 +74,13 @@ struct MyVisitArrayPortal
vtkm::IdComponent Get