diff --git a/docs/changelog/scatter-extrude-cells.md b/docs/changelog/scatter-extrude-cells.md new file mode 100644 index 000000000..4fb364416 --- /dev/null +++ b/docs/changelog/scatter-extrude-cells.md @@ -0,0 +1,6 @@ +# Support scatter/mask for CellSetExtrude + +Scheduling topology map workets for `CellSetExtrude` always worked, but the +there were indexing problems when a `Scatter` or a `Mask` was used. This +has been corrected, and now `Scatter`s and `Mask`s are supported on +topology maps on `CellSetExtrude`. diff --git a/vtkm/cont/testing/UnitTestCellSetExtrude.cxx b/vtkm/cont/testing/UnitTestCellSetExtrude.cxx index 09b5a7ebe..df188ee27 100644 --- a/vtkm/cont/testing/UnitTestCellSetExtrude.cxx +++ b/vtkm/cont/testing/UnitTestCellSetExtrude.cxx @@ -7,11 +7,14 @@ // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notice for more information. //============================================================================ -#include + +#include #include +#include #include #include +#include #include #include @@ -21,8 +24,8 @@ namespace { std::vector points_rz = { 1.72485139f, 0.020562f, 1.73493571f, 0.02052826f, 1.73478011f, 0.02299051f }; //really a vec -std::vector topology = { 0, 2, 1 }; -std::vector nextNode = { 0, 1, 2 }; +std::vector topology = { 0, 2, 1 }; +std::vector nextNode = { 0, 1, 2 }; struct CopyTopo : public vtkm::worklet::WorkletVisitCellsWithPoints @@ -37,76 +40,124 @@ struct CopyTopo : public vtkm::worklet::WorkletVisitCellsWithPoints } }; -struct CopyReverseCellCount : public vtkm::worklet::WorkletVisitPointsWithCells +struct CopyTopoScatter : public vtkm::worklet::WorkletVisitCellsWithPoints { - typedef void ControlSignature(CellSetIn, FieldOutPoint); - typedef _2 ExecutionSignature(CellShape, CellCount, CellIndices); + typedef void ControlSignature(CellSetIn, FieldOutCell); + typedef _2 ExecutionSignature(CellShape, PointIndices); + + using ScatterType = vtkm::worklet::ScatterPermutation; template + VTKM_EXEC T&& operator()(vtkm::CellShapeTagWedge, T&& t) const + { + return std::forward(t); + } +}; + +struct CopyReverseCellCount : public vtkm::worklet::WorkletVisitPointsWithCells +{ + typedef void ControlSignature(CellSetIn, FieldOutPoint, FieldOutPoint); + typedef _2 ExecutionSignature(CellShape, CellCount, CellIndices, _3); + + template VTKM_EXEC vtkm::Int32 operator()(vtkm::CellShapeTagVertex shape, vtkm::IdComponent count, - T&& t) const + CellIndicesType&& cellIndices, + OutVec& outIndices) const { + cellIndices.CopyInto(outIndices); if (shape.Id == vtkm::CELL_SHAPE_VERTEX) { bool valid = true; for (vtkm::IdComponent i = 0; i < count; ++i) { - valid = valid && t[i] > 0; + valid = valid && cellIndices[i] >= 0; } - return (valid && count == t.GetNumberOfComponents()) ? count : -1; + return (valid && count == cellIndices.GetNumberOfComponents()) ? count : -1; + } + return -1; + } +}; + +struct CopyReverseCellCountScatter : public vtkm::worklet::WorkletVisitPointsWithCells +{ + typedef void ControlSignature(CellSetIn, FieldOutPoint, FieldOutPoint); + typedef _2 ExecutionSignature(CellShape, CellCount, CellIndices, _3); + + using ScatterType = vtkm::worklet::ScatterPermutation; + + template + VTKM_EXEC vtkm::Int32 operator()(vtkm::CellShapeTagVertex shape, + vtkm::IdComponent count, + CellIndicesType&& cellIndices, + OutVec& outIndices) const + { + cellIndices.CopyInto(outIndices); + if (shape.Id == vtkm::CELL_SHAPE_VERTEX) + { + bool valid = true; + for (vtkm::IdComponent i = 0; i < count; ++i) + { + valid = valid && cellIndices[i] >= 0; + } + return (valid && count == cellIndices.GetNumberOfComponents()) ? count : -1; } return -1; } }; template -void verify_topo(vtkm::cont::ArrayHandle, S> const& handle, vtkm::Id expectedLen) +void verify_topo(vtkm::cont::ArrayHandle, S> const& handle, + vtkm::Id expectedLen, + vtkm::Id skip) { auto portal = handle.ReadPortal(); - VTKM_TEST_ASSERT(portal.GetNumberOfValues() == expectedLen, "topology portal size is incorrect"); + VTKM_TEST_ASSERT((portal.GetNumberOfValues() * skip) == expectedLen, + "topology portal size is incorrect"); - for (vtkm::Id i = 0; i < expectedLen - 1; ++i) + for (vtkm::Id i = 0; i < expectedLen; i += skip) { - auto v = portal.Get(i); + auto v = portal.Get(i / skip); vtkm::Vec e; - e[0] = (static_cast(topology[0]) + (i * static_cast(topology.size()))); - e[1] = (static_cast(topology[1]) + (i * static_cast(topology.size()))); - e[2] = (static_cast(topology[2]) + (i * static_cast(topology.size()))); - e[3] = - (static_cast(topology[0]) + ((i + 1) * static_cast(topology.size()))); - e[4] = - (static_cast(topology[1]) + ((i + 1) * static_cast(topology.size()))); - e[5] = - (static_cast(topology[2]) + ((i + 1) * static_cast(topology.size()))); + vtkm::Id offset1 = i * static_cast(topology.size()); + vtkm::Id offset2 = + (i < expectedLen - 1) ? (offset1 + static_cast(topology.size())) : 0; + e[0] = (static_cast(topology[0]) + offset1); + e[1] = (static_cast(topology[1]) + offset1); + e[2] = (static_cast(topology[2]) + offset1); + e[3] = (static_cast(topology[0]) + offset2); + e[4] = (static_cast(topology[1]) + offset2); + e[5] = (static_cast(topology[2]) + offset2); std::cout << "v, e: " << v << ", " << e << "\n"; VTKM_TEST_ASSERT(test_equal(v, e), "incorrect conversion of topology to Cartesian space"); } - - auto v = portal.Get(expectedLen - 1); - vtkm::Vec e; - e[0] = (static_cast(topology[0]) + - ((expectedLen - 1) * static_cast(topology.size()))); - e[1] = (static_cast(topology[1]) + - ((expectedLen - 1) * static_cast(topology.size()))); - e[2] = (static_cast(topology[2]) + - ((expectedLen - 1) * static_cast(topology.size()))); - e[3] = (static_cast(topology[0])); - e[4] = (static_cast(topology[1])); - e[5] = (static_cast(topology[2])); - VTKM_TEST_ASSERT(test_equal(v, e), "incorrect conversion of topology to Cartesian space"); } -template -void verify_reverse_topo(vtkm::cont::ArrayHandle const& handle, vtkm::Id expectedLen) +void verify_reverse_topo(const vtkm::cont::ArrayHandle& counts, + const vtkm::cont::ArrayHandle& indices, + vtkm::Id expectedLen, + vtkm::Id skip) { - auto portal = handle.ReadPortal(); - VTKM_TEST_ASSERT(portal.GetNumberOfValues() == expectedLen, "topology portal size is incorrect"); - for (vtkm::Id i = 0; i < expectedLen - 1; ++i) + auto countsPortal = counts.ReadPortal(); + VTKM_TEST_ASSERT((countsPortal.GetNumberOfValues() * skip) == expectedLen, + "topology portal size is incorrect"); + auto indicesPortal = indices.ReadPortal(); + VTKM_TEST_ASSERT((indicesPortal.GetNumberOfValues() * skip) == expectedLen); + for (vtkm::Id i = 0; i < expectedLen - 1; i += skip) { - auto v = portal.Get(i); - VTKM_TEST_ASSERT((v <= 2), "incorrect conversion to reverse topology"); + auto vCount = countsPortal.Get(i / skip); + auto vIndices = indicesPortal.Get(i / skip); + std::cout << vCount << ":" << vIndices << " "; + vtkm::Int32 eCount = 2; + vtkm::Id2 eIndices((i / 3) - 1, i / 3); + if (eIndices[0] < 0) + { + eIndices[0] = (expectedLen / 3) - 1; + } + VTKM_TEST_ASSERT(vCount == eCount); + VTKM_TEST_ASSERT(vIndices == eIndices); } + std::cout << "\n"; } int TestCellSetExtrude() { @@ -117,22 +168,48 @@ int TestCellSetExtrude() VTKM_TEST_ASSERT(cells.GetNumberOfPoints() == coords.GetNumberOfValues(), "number of points don't match between cells and coordinates"); - // Verify the topology by copying it into another array + vtkm::cont::Invoker invoke; + + std::cout << "Verify the topology by copying it into another array\n"; { vtkm::cont::ArrayHandle> output; - vtkm::worklet::DispatcherMapTopology dispatcher; - dispatcher.Invoke(cells, output); - verify_topo(output, 8); + invoke(CopyTopo{}, cells, output); + verify_topo(output, numPlanes, 1); } - - // Verify the reverse topology by copying the number of cells each point is - // used by it into another array + std::cout << "Verify the topology works with a scatter\n"; { - vtkm::cont::ArrayHandle output; - vtkm::worklet::DispatcherMapTopology dispatcher; - dispatcher.Invoke(cells, output); - verify_reverse_topo(output, 24); + constexpr vtkm::Id skip = 2; + vtkm::cont::ArrayHandle> output; + invoke(CopyTopoScatter{}, + CopyTopoScatter::ScatterType( + vtkm::cont::make_ArrayHandleCounting(0, skip, numPlanes / skip)), + cells, + output); + verify_topo(output, numPlanes, skip); + } + + std::cout << "Verify the reverse topology by copying the number of cells each point is " + << "used by it into another array.\n"; + { + vtkm::cont::ArrayHandle incidentCount; + vtkm::cont::ArrayHandle incidentIndices; + invoke(CopyReverseCellCount{}, cells, incidentCount, incidentIndices); + verify_reverse_topo(incidentCount, incidentIndices, 3 * numPlanes, 1); + } + + std::cout << "Verify reverse topology map with scatter\n"; + { + constexpr vtkm::Id skip = 2; + vtkm::cont::ArrayHandle incidentCount; + vtkm::cont::ArrayHandle incidentIndices; + invoke(CopyReverseCellCountScatter{}, + CopyTopoScatter::ScatterType( + vtkm::cont::make_ArrayHandleCounting(0, skip, (3 * numPlanes) / skip)), + cells, + incidentCount, + incidentIndices); + verify_reverse_topo(incidentCount, incidentIndices, 3 * numPlanes, skip); } return 0; diff --git a/vtkm/exec/arg/ThreadIndicesExtrude.h b/vtkm/exec/arg/ThreadIndicesExtrude.h index fd143c789..7692b5955 100644 --- a/vtkm/exec/arg/ThreadIndicesExtrude.h +++ b/vtkm/exec/arg/ThreadIndicesExtrude.h @@ -35,18 +35,17 @@ public: VTKM_SUPPRESS_EXEC_WARNINGS VTKM_EXEC ThreadIndicesTopologyMap(vtkm::Id threadIndex, - vtkm::Id vtkmNotUsed(inputIndex), - vtkm::IdComponent vtkmNotUsed(visitIndex), - vtkm::Id vtkmNotUsed(outputIndex), + vtkm::Id inputIndex, + vtkm::IdComponent visitIndex, + vtkm::Id outputIndex, const ConnectivityType& connectivity) { - const LogicalIndexType logicalIndex = detail::Deflate(threadIndex, LogicalIndexType()); - const vtkm::Id index = connectivity.LogicalToFlatToIndex(logicalIndex); + const LogicalIndexType logicalIndex = connectivity.FlatToLogicalToIndex(inputIndex); - this->ThreadIndex = index; - this->InputIndex = index; - this->OutputIndex = index; - this->VisitIndex = 0; + this->ThreadIndex = threadIndex; + this->InputIndex = inputIndex; + this->OutputIndex = outputIndex; + this->VisitIndex = visitIndex; this->LogicalIndex = logicalIndex; this->IndicesIncident = connectivity.GetIndices(logicalIndex); //this->CellShape = connectivity.GetCellShape(index); @@ -198,18 +197,17 @@ public: VTKM_SUPPRESS_EXEC_WARNINGS VTKM_EXEC ThreadIndicesTopologyMap(vtkm::Id& threadIndex, - vtkm::Id vtkmNotUsed(inputIndex), - vtkm::IdComponent vtkmNotUsed(visitIndex), - vtkm::Id vtkmNotUsed(outputIndex), + vtkm::Id inputIndex, + vtkm::IdComponent visitIndex, + vtkm::Id outputIndex, const ConnectivityType& connectivity) { - const LogicalIndexType logicalIndex = detail::Deflate(threadIndex, LogicalIndexType()); - const vtkm::Id index = connectivity.LogicalToFlatToIndex(logicalIndex); + const LogicalIndexType logicalIndex = connectivity.FlatToLogicalToIndex(inputIndex); - this->ThreadIndex = index; - this->InputIndex = index; - this->OutputIndex = index; - this->VisitIndex = 0; + this->ThreadIndex = threadIndex; + this->InputIndex = inputIndex; + this->OutputIndex = outputIndex; + this->VisitIndex = visitIndex; this->LogicalIndex = logicalIndex; this->IndicesIncident = connectivity.GetIndices(logicalIndex); }