//============================================================================ // 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_CellSetExplicit_hxx #define vtk_m_cont_CellSetExplicit_hxx #include #include #include #include // This file uses a lot of very verbose identifiers and the clang formatted // code quickly becomes unreadable. Stick with manual formatting for now. // // clang-format off namespace vtkm { namespace cont { template VTKM_CONT CellSetExplicit::CellSetExplicit() : CellSet() , Data(std::make_shared()) { } template VTKM_CONT CellSetExplicit::CellSetExplicit(const Thisclass& src) : CellSet(src) , Data(src.Data) { } template VTKM_CONT CellSetExplicit::CellSetExplicit(Thisclass &&src) noexcept : CellSet(std::forward(src)) , Data(std::move(src.Data)) { } template VTKM_CONT auto CellSetExplicit::operator=(const Thisclass& src) -> Thisclass& { this->CellSet::operator=(src); this->Data = src.Data; return *this; } template VTKM_CONT auto CellSetExplicit::operator=(Thisclass&& src) noexcept -> Thisclass& { this->CellSet::operator=(std::forward(src)); this->Data = std::move(src.Data); return *this; } template VTKM_CONT CellSetExplicit::~CellSetExplicit() { // explicitly define instead of '=default' to workaround an intel compiler bug // (see #179) } template VTKM_CONT void CellSetExplicit::PrintSummary(std::ostream& out) const { out << " ExplicitCellSet:" << std::endl; out << " CellPointIds:" << std::endl; this->Data->CellPointIds.PrintSummary(out); out << " PointCellIds:" << std::endl; this->Data->PointCellIds.PrintSummary(out); } template VTKM_CONT void CellSetExplicit::ReleaseResourcesExecution() { this->Data->CellPointIds.ReleaseResourcesExecution(); this->Data->PointCellIds.ReleaseResourcesExecution(); } template VTKM_CONT vtkm::Id CellSetExplicit::GetNumberOfCells() const { return this->Data->CellPointIds.GetNumberOfElements(); } template VTKM_CONT vtkm::Id CellSetExplicit::GetNumberOfPoints() const { return this->Data->NumberOfPoints; } template VTKM_CONT vtkm::Id CellSetExplicit::GetNumberOfFaces() const { return -1; } template VTKM_CONT vtkm::Id CellSetExplicit::GetNumberOfEdges() const { return -1; } //---------------------------------------------------------------------------- template VTKM_CONT void CellSetExplicit::GetCellPointIds(vtkm::Id cellId, vtkm::Id* ptids) const { const auto offPortal = this->Data->CellPointIds.Offsets.ReadPortal(); const vtkm::Id start = offPortal.Get(cellId); const vtkm::Id end = offPortal.Get(cellId + 1); const vtkm::IdComponent numIndices = static_cast(end - start); auto connPortal = this->Data->CellPointIds.Connectivity.ReadPortal(); for (vtkm::IdComponent i = 0; i < numIndices; i++) { ptids[i] = connPortal.Get(start + i); } } //---------------------------------------------------------------------------- template VTKM_CONT vtkm::Id CellSetExplicit ::GetSchedulingRange(vtkm::TopologyElementTagCell) const { return this->GetNumberOfCells(); } template VTKM_CONT vtkm::Id CellSetExplicit ::GetSchedulingRange(vtkm::TopologyElementTagPoint) const { return this->GetNumberOfPoints(); } template VTKM_CONT vtkm::IdComponent CellSetExplicit ::GetNumberOfPointsInCell(vtkm::Id cellid) const { const auto portal = this->Data->CellPointIds.Offsets.ReadPortal(); return static_cast(portal.Get(cellid + 1) - portal.Get(cellid)); } template VTKM_CONT typename vtkm::cont::ArrayHandle::ReadPortalType CellSetExplicit::ShapesReadPortal() const { return this->Data->CellPointIds.Shapes.ReadPortal(); } template VTKM_CONT VTKM_DEPRECATED(1.6, "Calling GetCellShape(cellid) is a performance bug. Call ShapesReadPortal() and loop over the Get.") vtkm::UInt8 CellSetExplicit ::GetCellShape(vtkm::Id cellid) const { return this->ShapesReadPortal().Get(cellid); } template template VTKM_CONT void CellSetExplicit ::GetIndices(vtkm::Id cellId, vtkm::Vec& ids) const { const auto offPortal = this->Data->CellPointIds.Offsets.ReadPortal(); const vtkm::Id start = offPortal.Get(cellId); const vtkm::Id end = offPortal.Get(cellId + 1); const auto numCellIndices = static_cast(end - start); const auto connPortal = this->Data->CellPointIds.Connectivity.ReadPortal(); VTKM_LOG_IF_S(vtkm::cont::LogLevel::Warn, numCellIndices != NumVecIndices, "GetIndices given a " << NumVecIndices << "-vec to fetch a cell with " << numCellIndices << "points. " "Truncating result."); const vtkm::IdComponent numIndices = vtkm::Min(NumVecIndices, numCellIndices); for (vtkm::IdComponent i = 0; i < numIndices; i++) { ids[i] = connPortal.Get(start + i); } } template VTKM_CONT void CellSetExplicit ::GetIndices(vtkm::Id cellId, vtkm::cont::ArrayHandle& ids) const { const auto offPortal = this->Data->CellPointIds.Offsets.ReadPortal(); const vtkm::Id start = offPortal.Get(cellId); const vtkm::Id end = offPortal.Get(cellId + 1); const vtkm::IdComponent numIndices = static_cast(end - start); ids.Allocate(numIndices); auto connPortal = this->Data->CellPointIds.Connectivity.ReadPortal(); auto outIdPortal = ids.WritePortal(); for (vtkm::IdComponent i = 0; i < numIndices; i++) { outIdPortal.Set(i, connPortal.Get(start + i)); } } //---------------------------------------------------------------------------- namespace internal { // Sets the first value of the array to zero if the handle is writable, // otherwise do nothing: template typename std::enable_if::value>::type SetFirstToZeroIfWritable(ArrayType&& array) { using ValueType = typename std::decay::type::ValueType; using Traits = vtkm::TypeTraits; array.WritePortal().Set(0, Traits::ZeroInitialization()); } template typename std::enable_if::value>::type SetFirstToZeroIfWritable(ArrayType&&) { /* no-op */ } } // end namespace internal template VTKM_CONT void CellSetExplicit ::PrepareToAddCells(vtkm::Id numCells, vtkm::Id connectivityMaxLen) { this->Data->CellPointIds.Shapes.Allocate(numCells); this->Data->CellPointIds.Connectivity.Allocate(connectivityMaxLen); this->Data->CellPointIds.Offsets.Allocate(numCells + 1); internal::SetFirstToZeroIfWritable(this->Data->CellPointIds.Offsets); this->Data->NumberOfCellsAdded = 0; this->Data->ConnectivityAdded = 0; } template template VTKM_CONT void CellSetExplicit::AddCell(vtkm::UInt8 cellType, vtkm::IdComponent numVertices, const IdVecType& ids) { using Traits = vtkm::VecTraits; VTKM_STATIC_ASSERT_MSG((std::is_same::value), "CellSetSingleType::AddCell requires vtkm::Id for indices."); if (Traits::GetNumberOfComponents(ids) < numVertices) { throw vtkm::cont::ErrorBadValue("Not enough indices given to CellSetExplicit::AddCell."); } if (this->Data->NumberOfCellsAdded >= this->Data->CellPointIds.Shapes.GetNumberOfValues()) { throw vtkm::cont::ErrorBadValue("Added more cells then expected."); } if (this->Data->ConnectivityAdded + numVertices > this->Data->CellPointIds.Connectivity.GetNumberOfValues()) { throw vtkm::cont::ErrorBadValue( "Connectivity increased past estimated maximum connectivity."); } auto shapes = this->Data->CellPointIds.Shapes.WritePortal(); auto conn = this->Data->CellPointIds.Connectivity.WritePortal(); auto offsets = this->Data->CellPointIds.Offsets.WritePortal(); shapes.Set(this->Data->NumberOfCellsAdded, cellType); for (vtkm::IdComponent iVec = 0; iVec < numVertices; ++iVec) { conn.Set(this->Data->ConnectivityAdded + iVec, Traits::GetComponent(ids, iVec)); } this->Data->NumberOfCellsAdded++; this->Data->ConnectivityAdded += numVertices; // Set the end offset for the added cell: offsets.Set(this->Data->NumberOfCellsAdded, this->Data->ConnectivityAdded); } template VTKM_CONT void CellSetExplicit::CompleteAddingCells(vtkm::Id numPoints) { this->Data->NumberOfPoints = numPoints; this->Data->CellPointIds.Connectivity.Allocate(this->Data->ConnectivityAdded, vtkm::CopyFlag::On); this->Data->CellPointIds.ElementsValid = true; if (this->Data->NumberOfCellsAdded != this->GetNumberOfCells()) { throw vtkm::cont::ErrorBadValue("Did not add as many cells as expected."); } this->Data->NumberOfCellsAdded = -1; this->Data->ConnectivityAdded = -1; } //---------------------------------------------------------------------------- template VTKM_CONT void CellSetExplicit ::Fill(vtkm::Id numPoints, const vtkm::cont::ArrayHandle& shapes, const vtkm::cont::ArrayHandle& connectivity, const vtkm::cont::ArrayHandle& offsets) { // Validate inputs: // Even for an empty cellset, offsets must contain a single 0: VTKM_ASSERT(offsets.GetNumberOfValues() > 0); // Must be [numCells + 1] offsets and [numCells] shapes VTKM_ASSERT(offsets.GetNumberOfValues() == shapes.GetNumberOfValues() + 1); // The last offset must be the size of the connectivity array. VTKM_ASSERT(vtkm::cont::ArrayGetValue(offsets.GetNumberOfValues() - 1, offsets) == connectivity.GetNumberOfValues()); this->Data->NumberOfPoints = numPoints; this->Data->CellPointIds.Shapes = shapes; this->Data->CellPointIds.Connectivity = connectivity; this->Data->CellPointIds.Offsets = offsets; this->Data->CellPointIds.ElementsValid = true; this->ResetConnectivity(TopologyElementTagPoint{}, TopologyElementTagCell{}); } //---------------------------------------------------------------------------- template template VTKM_CONT auto CellSetExplicit ::PrepareForInput(vtkm::cont::DeviceAdapterId device, VisitTopology, IncidentTopology, vtkm::cont::Token& token) const -> ExecConnectivityType { this->BuildConnectivity(device, VisitTopology{}, IncidentTopology{}); const auto& connectivity = this->GetConnectivity(VisitTopology{}, IncidentTopology{}); VTKM_ASSERT(connectivity.ElementsValid); using ExecObjType = ExecConnectivityType; return ExecObjType(connectivity.Shapes.PrepareForInput(device, token), connectivity.Connectivity.PrepareForInput(device, token), connectivity.Offsets.PrepareForInput(device, token)); } //---------------------------------------------------------------------------- template template VTKM_CONT auto CellSetExplicit ::GetShapesArray(VisitTopology, IncidentTopology) const -> const typename ConnectivityChooser::ShapesArrayType& { this->BuildConnectivity(vtkm::cont::DeviceAdapterTagAny{}, VisitTopology{}, IncidentTopology{}); return this->GetConnectivity(VisitTopology{}, IncidentTopology{}).Shapes; } template template VTKM_CONT auto CellSetExplicit ::GetConnectivityArray(VisitTopology, IncidentTopology) const -> const typename ConnectivityChooser::ConnectivityArrayType& { this->BuildConnectivity(vtkm::cont::DeviceAdapterTagAny{}, VisitTopology{}, IncidentTopology{}); return this->GetConnectivity(VisitTopology{}, IncidentTopology{}).Connectivity; } template template VTKM_CONT auto CellSetExplicit ::GetOffsetsArray(VisitTopology, IncidentTopology) const -> const typename ConnectivityChooser::OffsetsArrayType& { this->BuildConnectivity(vtkm::cont::DeviceAdapterTagAny{}, VisitTopology{}, IncidentTopology{}); return this->GetConnectivity(VisitTopology{}, IncidentTopology{}).Offsets; } template template VTKM_CONT auto CellSetExplicit ::GetNumIndicesArray(VisitTopology visited, IncidentTopology incident) const -> typename ConnectivityChooser::NumIndicesArrayType { // Converts to NumIndicesArrayType (which is an ArrayHandleOffsetsToNumComponents) return this->GetOffsetsArray(visited, incident); } //---------------------------------------------------------------------------- template VTKM_CONT std::shared_ptr CellSetExplicit::NewInstance() const { return std::make_shared(); } template VTKM_CONT void CellSetExplicit::DeepCopy(const CellSet* src) { const auto* other = dynamic_cast(src); if (!other) { throw vtkm::cont::ErrorBadType("CellSetExplicit::DeepCopy types don't match"); } ShapesArrayType shapes; ConnectivityArrayType conn; OffsetsArrayType offsets; const auto ct = vtkm::TopologyElementTagCell{}; const auto pt = vtkm::TopologyElementTagPoint{}; shapes.DeepCopyFrom(other->GetShapesArray(ct, pt)); conn.DeepCopyFrom(other->GetConnectivityArray(ct, pt)); offsets.DeepCopyFrom(other->GetOffsetsArray(ct, pt)); this->Fill(other->GetNumberOfPoints(), shapes, conn, offsets); } } } // vtkm::cont // clang-format on #endif