//============================================================================ // 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. //============================================================================ #ifndef vtk_m_cont_CellSetPermutation_h #define vtk_m_cont_CellSetPermutation_h #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef VTKM_DEFAULT_CELLSET_PERMUTATION_STORAGE_TAG #define VTKM_DEFAULT_CELLSET_PERMUTATION_STORAGE_TAG VTKM_DEFAULT_STORAGE_TAG #endif namespace vtkm { namespace cont { namespace internal { // To generate the reverse connectivity table with the // ReverseConnectivityBuilder, we need a compact connectivity array that // contains only the cell definitions from the permuted dataset, and an offsets // array. These helpers are used to generate these arrays so that they can be // converted in the reverse conn table. class RConnTableHelpers { public: struct WriteNumIndices : public vtkm::worklet::WorkletVisitCellsWithPoints { using ControlSignature = void(CellSetIn cellset, FieldOutCell numIndices); using ExecutionSignature = void(PointCount, _2); using InputDomain = _1; VTKM_EXEC void operator()(vtkm::IdComponent pointCount, vtkm::IdComponent& numIndices) const { numIndices = pointCount; } }; struct WriteConnectivity : public vtkm::worklet::WorkletVisitCellsWithPoints { using ControlSignature = void(CellSetIn cellset, FieldOutCell connectivity); using ExecutionSignature = void(PointCount, PointIndices, _2); using InputDomain = _1; template VTKM_EXEC void operator()(vtkm::IdComponent pointCount, const PointIndicesType& pointIndices, OutConnectivityType& connectivity) const { for (vtkm::IdComponent i = 0; i < pointCount; ++i) { connectivity[i] = pointIndices[i]; } } }; public: template static VTKM_CONT vtkm::cont::ArrayHandle GetNumIndicesArray( const CellSetPermutationType& cs, vtkm::cont::DeviceAdapterId device) { vtkm::cont::ArrayHandle numIndices; vtkm::cont::Invoker{ device }(WriteNumIndices{}, cs, numIndices); return numIndices; } template static VTKM_CONT vtkm::cont::ArrayHandle GetOffsetsArray( const vtkm::cont::ArrayHandle& numIndices, vtkm::Id& connectivityLength /* outparam */, vtkm::cont::DeviceAdapterId) { return vtkm::cont::internal::ConvertNumComponentsToOffsetsTemplate(numIndices, connectivityLength); } template static vtkm::cont::ArrayHandle GetConnectivityArray( const CellSetPermutationType& cs, const vtkm::cont::ArrayHandle& offsets, vtkm::Id connectivityLength, vtkm::cont::DeviceAdapterId device) { vtkm::cont::ArrayHandle connectivity; connectivity.Allocate(connectivityLength); auto connWrap = vtkm::cont::make_ArrayHandleGroupVecVariable(connectivity, offsets); vtkm::cont::Invoker{ device }(WriteConnectivity{}, cs, connWrap); return connectivity; } }; // This holds the temporary input arrays for the ReverseConnectivityBuilder // algorithm. template struct RConnBuilderInputData { using ConnectivityArrayType = vtkm::cont::ArrayHandle; using OffsetsArrayType = vtkm::cont::ArrayHandle; using NumIndicesArrayType = vtkm::cont::ArrayHandle; ConnectivityArrayType Connectivity; OffsetsArrayType Offsets; // Includes the past-the-end offset. NumIndicesArrayType NumIndices; }; // default for CellSetPermutations of any cell type template class RConnBuilderInput { public: using ConnectivityArrays = vtkm::cont::internal::RConnBuilderInputData<>; static ConnectivityArrays Get(const CellSetPermutationType& cellset, vtkm::cont::DeviceAdapterId device) { using Helper = RConnTableHelpers; ConnectivityArrays conn; vtkm::Id connectivityLength = 0; conn.NumIndices = Helper::GetNumIndicesArray(cellset, device); conn.Offsets = Helper::GetOffsetsArray(conn.NumIndices, connectivityLength, device); conn.Connectivity = Helper::GetConnectivityArray(cellset, conn.Offsets, connectivityLength, device); return conn; } }; // Specialization for CellSetExplicit/CellSetSingleType template class RConnBuilderInput, PermutationArrayHandleType>> { private: using BaseCellSetType = CellSetExplicit; using CellSetPermutationType = CellSetPermutation; using InShapesArrayType = typename BaseCellSetType::ShapesArrayType; using InNumIndicesArrayType = typename BaseCellSetType::NumIndicesArrayType; using ConnectivityStorageTag = vtkm::cont::ArrayHandle::StorageTag; using OffsetsStorageTag = vtkm::cont::ArrayHandle::StorageTag; using NumIndicesStorageTag = typename vtkm::cont::ArrayHandlePermutation::StorageTag; public: using ConnectivityArrays = vtkm::cont::internal:: RConnBuilderInputData; static ConnectivityArrays Get(const CellSetPermutationType& cellset, vtkm::cont::DeviceAdapterId device) { using Helper = RConnTableHelpers; static constexpr vtkm::TopologyElementTagCell cell{}; static constexpr vtkm::TopologyElementTagPoint point{}; auto fullCellSet = cellset.GetFullCellSet(); vtkm::Id connectivityLength = 0; ConnectivityArrays conn; fullCellSet.GetOffsetsArray(cell, point); // We can use the implicitly generated NumIndices array to save a bit of // memory: conn.NumIndices = vtkm::cont::make_ArrayHandlePermutation( cellset.GetValidCellIds(), fullCellSet.GetNumIndicesArray(cell, point)); // Need to generate the offsets from scratch so that they're ordered for the // lower-bounds binary searches in ReverseConnectivityBuilder. conn.Offsets = Helper::GetOffsetsArray(conn.NumIndices, connectivityLength, device); // Need to create a copy of this containing *only* the permuted cell defs, // in order, since the ReverseConnectivityBuilder will process every entry // in the connectivity array and we don't want the removed cells to be // included. conn.Connectivity = Helper::GetConnectivityArray(cellset, conn.Offsets, connectivityLength, device); return conn; } }; // Specialization for CellSetStructured template class RConnBuilderInput< CellSetPermutation, PermutationArrayHandleType>> { private: using CellSetPermutationType = CellSetPermutation, PermutationArrayHandleType>; public: using ConnectivityArrays = vtkm::cont::internal::RConnBuilderInputData< VTKM_DEFAULT_STORAGE_TAG, typename vtkm::cont::ArrayHandleCounting::StorageTag, typename vtkm::cont::ArrayHandleConstant::StorageTag>; static ConnectivityArrays Get(const CellSetPermutationType& cellset, vtkm::cont::DeviceAdapterId device) { vtkm::Id numberOfCells = cellset.GetNumberOfCells(); vtkm::IdComponent numPointsInCell = vtkm::internal::ConnectivityStructuredInternals::NUM_POINTS_IN_CELL; vtkm::Id connectivityLength = numberOfCells * numPointsInCell; ConnectivityArrays conn; conn.NumIndices = make_ArrayHandleConstant(numPointsInCell, numberOfCells); conn.Offsets = ArrayHandleCounting(0, numPointsInCell, numberOfCells + 1); conn.Connectivity = RConnTableHelpers::GetConnectivityArray(cellset, conn.Offsets, connectivityLength, device); return conn; } }; template struct CellSetPermutationTraits; template struct CellSetPermutationTraits> { using OriginalCellSet = OriginalCellSet_; using PermutationArrayHandleType = PermutationArrayHandleType_; }; template struct CellSetPermutationTraits< CellSetPermutation, PermutationArrayHandleType_>> { using PreviousCellSet = CellSetPermutation; using PermutationArrayHandleType = vtkm::cont::ArrayHandlePermutation< PermutationArrayHandleType_, typename CellSetPermutationTraits::PermutationArrayHandleType>; using OriginalCellSet = typename CellSetPermutationTraits::OriginalCellSet; using Superclass = CellSetPermutation; }; template struct CellSetPermutationConnectivityChooser; template struct CellSetPermutationConnectivityChooser { using ExecPortalType = typename PermutationArrayHandleType::ReadPortalType; using OrigExecObjectType = typename OriginalCellSetType::template ExecConnectivityType; using ExecConnectivityType = vtkm::exec::ConnectivityPermutedVisitCellsWithPoints; }; template struct CellSetPermutationConnectivityChooser { using ConnectivityPortalType = typename vtkm::cont::ArrayHandle::ReadPortalType; using NumIndicesPortalType = typename vtkm::cont::ArrayHandle::ReadPortalType; using OffsetPortalType = typename vtkm::cont::ArrayHandle::ReadPortalType; using ExecConnectivityType = vtkm::exec::ConnectivityPermutedVisitPointsWithCells; }; } // internal template > class CellSetPermutation : public CellSet { VTKM_IS_CELL_SET(OriginalCellSetType_); VTKM_IS_ARRAY_HANDLE(PermutationArrayHandleType_); VTKM_STATIC_ASSERT_MSG( (std::is_same::value), "Must use ArrayHandle with value type of Id for permutation array."); public: using OriginalCellSetType = OriginalCellSetType_; using PermutationArrayHandleType = PermutationArrayHandleType_; VTKM_CONT CellSetPermutation(const PermutationArrayHandleType& validCellIds, const OriginalCellSetType& cellset) : CellSet() , ValidCellIds(validCellIds) , FullCellSet(cellset) { } VTKM_CONT CellSetPermutation() : CellSet() , ValidCellIds() , FullCellSet() { } ~CellSetPermutation() override {} CellSetPermutation(const CellSetPermutation& src) : CellSet() , ValidCellIds(src.ValidCellIds) , FullCellSet(src.FullCellSet) { } CellSetPermutation& operator=(const CellSetPermutation& src) { this->ValidCellIds = src.ValidCellIds; this->FullCellSet = src.FullCellSet; return *this; } VTKM_CONT const OriginalCellSetType& GetFullCellSet() const { return this->FullCellSet; } VTKM_CONT const PermutationArrayHandleType& GetValidCellIds() const { return this->ValidCellIds; } VTKM_CONT vtkm::Id GetNumberOfCells() const override { return this->ValidCellIds.GetNumberOfValues(); } VTKM_CONT vtkm::Id GetNumberOfPoints() const override { return this->FullCellSet.GetNumberOfPoints(); } VTKM_CONT vtkm::Id GetNumberOfFaces() const override { return -1; } VTKM_CONT vtkm::Id GetNumberOfEdges() const override { return -1; } VTKM_CONT void ReleaseResourcesExecution() override { this->ValidCellIds.ReleaseResourcesExecution(); this->FullCellSet.ReleaseResourcesExecution(); this->VisitPointsWithCells.ReleaseResourcesExecution(); } VTKM_CONT vtkm::IdComponent GetNumberOfPointsInCell(vtkm::Id cellIndex) const override { // Looping over GetNumberOfPointsInCell is a performance bug. return this->FullCellSet.GetNumberOfPointsInCell( this->ValidCellIds.ReadPortal().Get(cellIndex)); } VTKM_DEPRECATED(1.6, "Calling GetCellShape(cellid) is a performance bug. Call ShapesReadPortal() " "and loop over the Get.") vtkm::UInt8 GetCellShape(vtkm::Id id) const override { // Looping over GetCellShape is a performance bug. VTKM_DEPRECATED_SUPPRESS_BEGIN return this->FullCellSet.GetCellShape(this->ValidCellIds.ReadPortal().Get(id)); VTKM_DEPRECATED_SUPPRESS_END } void GetCellPointIds(vtkm::Id id, vtkm::Id* ptids) const override { // Looping over GetCellPointsIdx is a performance bug. return this->FullCellSet.GetCellPointIds(this->ValidCellIds.ReadPortal().Get(id), ptids); } std::shared_ptr NewInstance() const override { return std::make_shared(); } void DeepCopy(const CellSet* src) override { const auto* other = dynamic_cast(src); if (!other) { throw vtkm::cont::ErrorBadType("CellSetPermutation::DeepCopy types don't match"); } this->FullCellSet.DeepCopy(&(other->GetFullCellSet())); vtkm::cont::ArrayCopy(other->GetValidCellIds(), this->ValidCellIds); } //This is the way you can fill the memory from another system without copying VTKM_CONT void Fill(const PermutationArrayHandleType& validCellIds, const OriginalCellSetType& cellset) { this->ValidCellIds = validCellIds; this->FullCellSet = cellset; } VTKM_CONT vtkm::Id GetSchedulingRange(vtkm::TopologyElementTagCell) const { return this->ValidCellIds.GetNumberOfValues(); } VTKM_CONT vtkm::Id GetSchedulingRange(vtkm::TopologyElementTagPoint) const { return this->FullCellSet.GetNumberOfPoints(); } public: template using ExecConnectivityType = typename internal::CellSetPermutationConnectivityChooser< VisitTopology, IncidentTopology, OriginalCellSetType, PermutationArrayHandleType>::ExecConnectivityType; VTKM_CONT ExecConnectivityType PrepareForInput(vtkm::cont::DeviceAdapterId device, vtkm::TopologyElementTagCell visitTopology, vtkm::TopologyElementTagPoint incidentTopology, vtkm::cont::Token& token) const { using ConnectivityType = ExecConnectivityType; return ConnectivityType( this->ValidCellIds.PrepareForInput(device, token), this->FullCellSet.PrepareForInput(device, visitTopology, incidentTopology, token)); } VTKM_CONT ExecConnectivityType PrepareForInput(vtkm::cont::DeviceAdapterId device, vtkm::TopologyElementTagPoint, vtkm::TopologyElementTagCell, vtkm::cont::Token& token) const { if (!this->VisitPointsWithCells.ElementsValid) { auto connTable = internal::RConnBuilderInput::Get(*this, device); internal::ComputeRConnTable( this->VisitPointsWithCells, connTable, this->GetNumberOfPoints(), device); } using ConnectivityType = ExecConnectivityType; return ConnectivityType(this->VisitPointsWithCells.Connectivity.PrepareForInput(device, token), this->VisitPointsWithCells.Offsets.PrepareForInput(device, token)); } VTKM_CONT void PrintSummary(std::ostream& out) const override { out << "CellSetPermutation of: " << std::endl; this->FullCellSet.PrintSummary(out); out << "Permutation Array: " << std::endl; vtkm::cont::printSummary_ArrayHandle(this->ValidCellIds, out); } private: using VisitPointsWithCellsConnectivity = vtkm::cont::internal::ConnectivityExplicitInternals< typename ArrayHandleConstant::StorageTag>; PermutationArrayHandleType ValidCellIds; OriginalCellSetType FullCellSet; mutable VisitPointsWithCellsConnectivity VisitPointsWithCells; }; template class CellSetPermutation, PermutationArrayHandleType2> : public internal::CellSetPermutationTraits< CellSetPermutation, PermutationArrayHandleType2>>::Superclass { private: using Superclass = typename internal::CellSetPermutationTraits::Superclass; public: VTKM_CONT CellSetPermutation(const PermutationArrayHandleType2& validCellIds, const CellSetPermutation& cellset) : Superclass(vtkm::cont::make_ArrayHandlePermutation(validCellIds, cellset.GetValidCellIds()), cellset.GetFullCellSet()) { } VTKM_CONT CellSetPermutation() : Superclass() { } ~CellSetPermutation() override {} VTKM_CONT void Fill(const PermutationArrayHandleType2& validCellIds, const CellSetPermutation& cellset) { this->ValidCellIds = make_ArrayHandlePermutation(validCellIds, cellset.GetValidCellIds()); this->FullCellSet = cellset.GetFullCellSet(); } std::shared_ptr NewInstance() const override { return std::make_shared(); } }; template vtkm::cont::CellSetPermutation make_CellSetPermutation( const PermutationArrayHandleType& cellIndexMap, const OriginalCellSet& cellSet) { VTKM_IS_CELL_SET(OriginalCellSet); VTKM_IS_ARRAY_HANDLE(PermutationArrayHandleType); return vtkm::cont::CellSetPermutation(cellIndexMap, cellSet); } } } // namespace vtkm::cont //============================================================================= // Specializations of serialization related classes /// @cond SERIALIZATION namespace vtkm { namespace cont { template struct SerializableTypeString> { static VTKM_CONT const std::string& Get() { static std::string name = "CS_Permutation<" + SerializableTypeString::Get() + "," + SerializableTypeString::Get() + ">"; return name; } }; } } // vtkm::cont namespace mangled_diy_namespace { template struct Serialization> { private: using Type = vtkm::cont::CellSetPermutation; public: static VTKM_CONT void save(BinaryBuffer& bb, const Type& cs) { vtkmdiy::save(bb, cs.GetFullCellSet()); vtkmdiy::save(bb, cs.GetValidCellIds()); } static VTKM_CONT void load(BinaryBuffer& bb, Type& cs) { CSType fullCS; vtkmdiy::load(bb, fullCS); AHValidCellIds validCellIds; vtkmdiy::load(bb, validCellIds); cs = make_CellSetPermutation(validCellIds, fullCS); } }; } // diy /// @endcond SERIALIZATION #endif //vtk_m_cont_CellSetPermutation_h