//============================================================================= // // 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_worklet_CellSetDualGraph_h #define vtk_m_worklet_CellSetDualGraph_h #include #include #include #include #include struct EdgeCount : public vtkm::worklet::WorkletMapPointToCell { typedef void ControlSignature(CellSetIn, FieldOutCell<> numEdgesInCell); typedef _2 ExecutionSignature(CellShape, PointCount); using InputDomain = _1; template VTKM_EXEC vtkm::IdComponent operator()(CellShapeTag cellShape, vtkm::IdComponent pointCount) const { return vtkm::exec::CellEdgeNumberOfEdges(pointCount, cellShape, *this); } }; struct EdgeExtract : public vtkm::worklet::WorkletMapPointToCell { typedef void ControlSignature(CellSetIn, FieldOutCell<> cellIndices, FieldOutCell<> edgeIndices); typedef void ExecutionSignature(CellShape, InputIndex, PointIndices, VisitIndex, _2, _3); using InputDomain = _1; using ScatterType = vtkm::worklet::ScatterCounting; VTKM_CONT ScatterType GetScatter() const { return this->Scatter; } VTKM_CONT EdgeExtract(const ScatterType& scatter) : Scatter(scatter) { } template VTKM_EXEC void operator()(CellShapeTag cellShape, CellIndexType cellIndex, const PointIndexVecType& pointIndices, vtkm::IdComponent visitIndex, CellIndexType& cellIndexOut, EdgeIndexVecType& edgeIndices) const { cellIndexOut = cellIndex; edgeIndices = vtkm::exec::CellEdgeCanonicalId( pointIndices.GetNumberOfComponents(), visitIndex, cellShape, pointIndices, *this); }; private: ScatterType Scatter; }; struct CellToCellConnectivity : public vtkm::worklet::WorkletMapField { typedef void ControlSignature(FieldIn<> index, WholeArrayIn<> cells, WholeArrayOut<> from, WholeArrayOut<> to); typedef void ExecutionSignature(_1, InputIndex, _2, _3, _4); using InputDomain = _1; template VTKM_EXEC void operator()(vtkm::Id offset, vtkm::Id index, const CellIdPortalType& cells, ConnectivityPortalType& from, ConnectivityPortalType& to) const { from.Set(index * 2, cells.Get(offset)); to.Set(index * 2, cells.Get(offset + 1)); from.Set(index * 2 + 1, cells.Get(offset + 1)); to.Set(index * 2 + 1, cells.Get(offset)); } }; template class CellSetDualGraph { public: using Algorithm = vtkm::cont::DeviceAdapterAlgorithm; struct degree2 { VTKM_EXEC bool operator()(vtkm::Id degree) const { return degree >= 2; } }; template void EdgeToCellConnectivity(const CellSet& cellSet, vtkm::cont::ArrayHandle& cellIds, vtkm::cont::ArrayHandle& cellEdges) const { // Get number of edges for each cell and use it as scatter count. vtkm::cont::ArrayHandle numEdgesPerCell; vtkm::worklet::DispatcherMapTopology edgesPerCellDisp; edgesPerCellDisp.Invoke(cellSet, numEdgesPerCell); // Get uncompress Cell to Edge mapping vtkm::worklet::ScatterCounting scatter{ numEdgesPerCell, DeviceAdapter() }; vtkm::worklet::DispatcherMapTopology edgeExtractDisp{ scatter }; edgeExtractDisp.Invoke(cellSet, cellIds, cellEdges); } template void Run(const CellSetType& cellSet, vtkm::cont::ArrayHandle& numIndicesArray, vtkm::cont::ArrayHandle& indexOffsetArray, vtkm::cont::ArrayHandle& connectivityArray) const { // calculate the uncompressed Edge to Cell connectivity from Point to Cell connectivity // in the CellSet vtkm::cont::ArrayHandle cellIds; vtkm::cont::ArrayHandle cellEdges; EdgeToCellConnectivity(cellSet, cellIds, cellEdges); // sort cell ids by cell edges, this groups cells by cell edges Algorithm::SortByKey(cellEdges, cellIds); // count how many times an edge is shared by cells. vtkm::cont::ArrayHandle uniqueEdges; vtkm::cont::ArrayHandle uniqueEdgeDegree; Algorithm::ReduceByKey( cellEdges, vtkm::cont::ArrayHandleConstant(1, cellEdges.GetNumberOfValues()), uniqueEdges, uniqueEdgeDegree, vtkm::Add()); // Extract edges shared by two cells vtkm::cont::ArrayHandle sharedEdges; Algorithm::CopyIf(uniqueEdges, uniqueEdgeDegree, sharedEdges, degree2()); // find shared edges within all the edges. vtkm::cont::ArrayHandle lb; Algorithm::LowerBounds(cellEdges, sharedEdges, lb); // take each shared edge and the cells to create 2 edges of the dual graph vtkm::cont::ArrayHandle connFrom; vtkm::cont::ArrayHandle connTo; connFrom.Allocate(sharedEdges.GetNumberOfValues() * 2); connTo.Allocate(sharedEdges.GetNumberOfValues() * 2); vtkm::worklet::DispatcherMapField c2cDisp; c2cDisp.Invoke(lb, cellIds, connFrom, connTo); // Turn dual graph into Compressed Sparse Row format Algorithm::SortByKey(connFrom, connTo); Algorithm::Copy(connTo, connectivityArray); vtkm::cont::ArrayHandle dualGraphVertices; Algorithm::ReduceByKey( connFrom, vtkm::cont::ArrayHandleConstant(1, connFrom.GetNumberOfValues()), dualGraphVertices, numIndicesArray, vtkm::Add()); Algorithm::ScanExclusive(numIndicesArray, indexOffsetArray); } }; #endif //vtk_m_worklet_CellSetDualGraph_h