// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen // SPDX-License-Identifier: BSD-3-Clause #include "vtkHyperTreeGridPreConfiguredSource.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkNew.h" #include "vtkObjectFactory.h" #include "vtkStreamingDemandDrivenPipeline.h" #include "vtkCellData.h" #include "vtkDoubleArray.h" #include "vtkHyperTree.h" #include "vtkHyperTreeGrid.h" #include "vtkHyperTreeGridNonOrientedCursor.h" #include #include VTK_ABI_NAMESPACE_BEGIN vtkStandardNewMacro(vtkHyperTreeGridPreConfiguredSource); vtkHyperTreeGridPreConfiguredSource::vtkHyperTreeGridPreConfiguredSource() : HTGMode(UNBALANCED_3DEPTH_2BRANCH_2X3) , CustomArchitecture(UNBALANCED) , CustomDim(2) , CustomFactor(2) , CustomDepth(2) { this->SetNumberOfInputPorts(0); this->SetNumberOfOutputPorts(1); this->AppropriateOutput = true; this->CustomExtent[0] = this->CustomExtent[2] = this->CustomExtent[4] = 0.0; this->CustomExtent[1] = this->CustomExtent[3] = this->CustomExtent[5] = 1.0; this->CustomSubdivisions[0] = this->CustomSubdivisions[1] = this->CustomSubdivisions[2] = 2; } int vtkHyperTreeGridPreConfiguredSource::FillOutputPortInformation(int, vtkInformation* info) { info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkHyperTreeGrid"); return 1; } int vtkHyperTreeGridPreConfiguredSource::RequestInformation( vtkInformation* req, vtkInformationVector** inputVector, vtkInformationVector* outputVector) { if (!this->Superclass::RequestInformation(req, inputVector, outputVector)) { return 0; } int wholeExtent[6] = { 0, 1, 0, 1, 0, 1 }; switch (this->HTGMode) { case UNBALANCED_3DEPTH_2BRANCH_2X3: wholeExtent[3] = 2; break; case BALANCED_3DEPTH_2BRANCH_2X3: wholeExtent[3] = 2; break; case UNBALANCED_2DEPTH_3BRANCH_3X3: wholeExtent[1] = wholeExtent[3] = 2; break; case BALANCED_4DEPTH_3BRANCH_2X2: break; case UNBALANCED_3DEPTH_2BRANCH_3X2X3: wholeExtent[1] = wholeExtent[5] = 2; break; case BALANCED_2DEPTH_3BRANCH_3X3X2: wholeExtent[1] = wholeExtent[3] = 2; break; case CUSTOM: wholeExtent[1] = this->CustomSubdivisions[0] - 1; wholeExtent[3] = this->CustomSubdivisions[1] - 1; wholeExtent[5] = this->CustomSubdivisions[2] - 1; break; default: vtkErrorMacro("No suitable HTG mode found."); return 0; } vtkInformation* info = outputVector->GetInformationObject(0); info->Set(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), wholeExtent, 6); info->Set(vtkAlgorithm::CAN_PRODUCE_SUB_EXTENT(), 0); return 1; } int vtkHyperTreeGridPreConfiguredSource::RequestData(vtkInformation* vtkNotUsed(req), vtkInformationVector** vtkNotUsed(inputVector), vtkInformationVector* outputVector) { vtkInformation* outInfo = outputVector->GetInformationObject(0); if (!outInfo) { vtkErrorMacro("Output information not found"); return 0; } vtkHyperTreeGrid* htg = vtkHyperTreeGrid::GetData(outInfo); if (!htg) { vtkErrorMacro("Could not get HyperTreeGrid output"); return 0; } return this->ProcessTrees(nullptr, htg); } int vtkHyperTreeGridPreConfiguredSource::ProcessTrees( vtkHyperTreeGrid* vtkNotUsed(inputObj), vtkDataObject* htgObj) { vtkHyperTreeGrid* htg = vtkHyperTreeGrid::SafeDownCast(htgObj); if (!htg) { vtkErrorMacro("Could not cast vtkDataObject to vtkHyperTreeGrid"); return 0; } switch (this->HTGMode) { case UNBALANCED_3DEPTH_2BRANCH_2X3: this->GenerateUnbalanced3DepthQuadTree2x3(htg); break; case BALANCED_3DEPTH_2BRANCH_2X3: this->GenerateBalanced3DepthQuadTree2x3(htg); break; case UNBALANCED_2DEPTH_3BRANCH_3X3: this->GenerateUnbalanced2Depth3BranchTree3x3(htg); break; case BALANCED_4DEPTH_3BRANCH_2X2: this->GenerateBalanced4Depth3BranchTree2x2(htg); break; case UNBALANCED_3DEPTH_2BRANCH_3X2X3: this->GenerateUnbalanced3DepthOctTree3x2x3(htg); break; case BALANCED_2DEPTH_3BRANCH_3X3X2: this->GenerateBalanced2Depth3BranchTree3x3x2(htg); break; case CUSTOM: if (!this->GenerateCustom(htg)) { vtkErrorMacro("Could not generate custom HyperTreeGrid"); return 0; } break; default: vtkErrorMacro("Unsupported HTG mode"); return 0; } return 1; } void vtkHyperTreeGridPreConfiguredSource::GenerateUnbalanced(vtkHyperTreeGrid* htg, unsigned int dim, unsigned int factor, unsigned int depth, const std::vector& extent, const std::vector& subdivisions) { this->Preprocess(htg, dim, factor, extent, subdivisions); vtkNew levels; levels->SetName("Depth"); levels->SetNumberOfComponents(1); levels->SetNumberOfTuples(0); htg->GetCellData()->AddArray(levels); auto cursor = vtk::TakeSmartPointer(htg->NewNonOrientedCursor(0, true)); cursor->GetTree()->SetGlobalIndexStart(0); levels->InsertValue(0, 0); for (unsigned int l = 0; l < depth; l++) { cursor->SubdivideLeaf(); int numChildren = cursor->GetNumberOfChildren(); for (int iChild = 0; iChild < numChildren; iChild++) { cursor->ToChild(iChild); vtkIdType vertexId = cursor->GetVertexId(); vtkIdType globId = cursor->GetTree()->GetGlobalIndexFromLocal(vertexId); levels->InsertValue(globId, l + 1); cursor->ToParent(); } cursor->ToChild(0); } vtkIdType treeOffset = cursor->GetTree()->GetNumberOfVertices(); vtkIdType nTrees = htg->GetMaxNumberOfTrees(); for (int iT = 1; iT < nTrees; iT++) { cursor = vtk::TakeSmartPointer(htg->NewNonOrientedCursor(iT, true)); vtkHyperTree* tree = cursor->GetTree(); tree->SetGlobalIndexStart(treeOffset); vtkIdType globId = tree->GetGlobalIndexFromLocal(0); levels->InsertValue(globId, 0); treeOffset += tree->GetNumberOfVertices(); } } void vtkHyperTreeGridPreConfiguredSource::GenerateBalanced(vtkHyperTreeGrid* htg, unsigned int dim, unsigned int factor, unsigned int depth, const std::vector& extent, const std::vector& subdivisions) { this->Preprocess(htg, dim, factor, extent, subdivisions); vtkNew levels; levels->SetName("Depth"); levels->SetNumberOfComponents(1); levels->SetNumberOfTuples(0); htg->GetCellData()->AddArray(levels); vtkIdType treeOffset = 0; vtkIdType nTrees = htg->GetMaxNumberOfTrees(); for (int iT = 0; iT < nTrees; iT++) { auto cursor = vtk::TakeSmartPointer(htg->NewNonOrientedCursor(iT, true)); cursor->GetTree()->SetGlobalIndexStart(treeOffset); this->RecurseBalanced(cursor, levels, depth); treeOffset += cursor->GetTree()->GetNumberOfVertices(); } } void vtkHyperTreeGridPreConfiguredSource::RecurseBalanced( vtkHyperTreeGridNonOrientedCursor* cursor, vtkDoubleArray* levels, const int maxDepth) { vtkIdType vertexId = cursor->GetVertexId(); vtkHyperTree* tree = cursor->GetTree(); vtkIdType globId = tree->GetGlobalIndexFromLocal(vertexId); vtkIdType thisLevel = cursor->GetLevel(); levels->InsertValue(globId, thisLevel); if (cursor->IsLeaf()) { if (thisLevel < maxDepth) { cursor->SubdivideLeaf(); this->RecurseBalanced(cursor, levels, maxDepth); } } else { int numChildren = cursor->GetNumberOfChildren(); for (int iChild = 0; iChild < numChildren; iChild++) { cursor->ToChild(iChild); this->RecurseBalanced(cursor, levels, maxDepth); cursor->ToParent(); } } } void vtkHyperTreeGridPreConfiguredSource::Preprocess(vtkHyperTreeGrid* htg, unsigned int dim, unsigned int factor, const std::vector& extent, const std::vector& subdivisions) { if (extent.size() < static_cast(2 * dim)) { vtkErrorMacro("Supplied extent is not long enough"); return; } if (subdivisions.size() < dim) { vtkErrorMacro("Supplied subdivisions is not long enough"); return; } htg->Initialize(); std::array subdivisions3d = { 1, 1, 1 }; std::copy(subdivisions.begin(), subdivisions.end(), subdivisions3d.begin()); htg->SetDimensions(subdivisions3d.data()); htg->SetBranchFactor(factor); auto fillArray = [](vtkDoubleArray* array, vtkIdType numPoints, double minBound, double maxBound) { array->SetNumberOfComponents(1); array->SetNumberOfTuples(numPoints); double step = (maxBound - minBound) / static_cast(numPoints - 1); for (int i = 0; i < numPoints; ++i) { array->SetTypedComponent(i, 0, minBound + step * i); } }; { vtkNew vtkCoords; fillArray(vtkCoords, subdivisions[0], extent[0], extent[1]); htg->SetXCoordinates(vtkCoords); } if (dim > 1) { vtkNew vtkCoords; fillArray(vtkCoords, subdivisions[1], extent[2], extent[3]); htg->SetYCoordinates(vtkCoords); } if (dim > 2) { vtkNew vtkCoords; fillArray(vtkCoords, subdivisions[2], extent[4], extent[5]); htg->SetZCoordinates(vtkCoords); } } void vtkHyperTreeGridPreConfiguredSource::GenerateUnbalanced3DepthQuadTree2x3(vtkHyperTreeGrid* htg) { std::vector extent = { -1.0, 1.0, -1.0, 1.0 }; std::vector subdivisions = { 2, 3 }; this->GenerateUnbalanced(htg, 2, 2, 3, extent, subdivisions); } void vtkHyperTreeGridPreConfiguredSource::GenerateBalanced3DepthQuadTree2x3(vtkHyperTreeGrid* htg) { std::vector extent = { -1.0, 1.0, -1.0, 1.0 }; std::vector subdivisions = { 2, 3 }; this->GenerateBalanced(htg, 2, 2, 3, extent, subdivisions); } void vtkHyperTreeGridPreConfiguredSource::GenerateUnbalanced2Depth3BranchTree3x3( vtkHyperTreeGrid* htg) { std::vector extent = { -1.0, 1.0, -1.0, 1.0 }; std::vector subdivisions = { 3, 3 }; this->GenerateUnbalanced(htg, 2, 3, 2, extent, subdivisions); } void vtkHyperTreeGridPreConfiguredSource::GenerateBalanced4Depth3BranchTree2x2( vtkHyperTreeGrid* htg) { std::vector extent = { -1.0, 1.0, -1.0, 1.0 }; std::vector subdivisions = { 2, 2 }; this->GenerateBalanced(htg, 2, 3, 4, extent, subdivisions); } void vtkHyperTreeGridPreConfiguredSource::GenerateUnbalanced3DepthOctTree3x2x3( vtkHyperTreeGrid* htg) { std::vector extent = { -1.0, 1.0, -1.0, 1.0, -1.0, 1.0 }; std::vector subdivisions = { 3, 2, 3 }; this->GenerateUnbalanced(htg, 3, 2, 3, extent, subdivisions); } void vtkHyperTreeGridPreConfiguredSource::GenerateBalanced2Depth3BranchTree3x3x2( vtkHyperTreeGrid* htg) { std::vector extent = { -1.0, 1.0, -1.0, 1.0, -1.0, 1.0 }; std::vector subdivisions = { 3, 3, 2 }; this->GenerateBalanced(htg, 3, 3, 2, extent, subdivisions); } int vtkHyperTreeGridPreConfiguredSource::GenerateCustom(vtkHyperTreeGrid* htg) { switch (this->CustomArchitecture) { case BALANCED: { this->GenerateBalanced(htg, this->CustomDim, this->CustomFactor, this->CustomDepth, std::vector(this->CustomExtent, this->CustomExtent + this->CustomDim * 2), std::vector( this->CustomSubdivisions, this->CustomSubdivisions + this->CustomDim)); break; } case UNBALANCED: { this->GenerateUnbalanced(htg, this->CustomDim, this->CustomFactor, this->CustomDepth, std::vector(this->CustomExtent, this->CustomExtent + this->CustomDim * 2), std::vector( this->CustomSubdivisions, this->CustomSubdivisions + this->CustomDim)); break; } default: vtkErrorMacro("Using an HTGArchitecture not yet supported by the source"); return 0; } return 1; } VTK_ABI_NAMESPACE_END