From b49d62daf9c17337c39f254eff63cf07a4c8b41a Mon Sep 17 00:00:00 2001 From: Louis Gombert <louis.gombert@kitware.com> Date: Fri, 15 Mar 2024 10:39:55 +0000 Subject: [PATCH] HTG Leaves Volume: generalize volume to other dimensions --- .../release/dev/htg-visible-leaves-size.md | 8 ++ .../release/dev/htg-visible-leaves-volume.md | 8 -- Filters/HyperTree/CMakeLists.txt | 2 +- Filters/HyperTree/Testing/Cxx/CMakeLists.txt | 2 +- ...=> TestHyperTreeGridVisibleLeavesSize.cxx} | 10 +- ... => vtkHyperTreeGridVisibleLeavesSize.cxx} | 111 +++++++++--------- ....h => vtkHyperTreeGridVisibleLeavesSize.h} | 48 ++++---- 7 files changed, 98 insertions(+), 91 deletions(-) create mode 100644 Documentation/release/dev/htg-visible-leaves-size.md delete mode 100644 Documentation/release/dev/htg-visible-leaves-volume.md rename Filters/HyperTree/Testing/Cxx/{TestHyperTreeGridVisibleLeavesVolume.cxx => TestHyperTreeGridVisibleLeavesSize.cxx} (93%) rename Filters/HyperTree/{vtkHyperTreeGridVisibleLeavesVolume.cxx => vtkHyperTreeGridVisibleLeavesSize.cxx} (69%) rename Filters/HyperTree/{vtkHyperTreeGridVisibleLeavesVolume.h => vtkHyperTreeGridVisibleLeavesSize.h} (59%) diff --git a/Documentation/release/dev/htg-visible-leaves-size.md b/Documentation/release/dev/htg-visible-leaves-size.md new file mode 100644 index 00000000000..db7e8560ad1 --- /dev/null +++ b/Documentation/release/dev/htg-visible-leaves-size.md @@ -0,0 +1,8 @@ +## Hyper Tree Grid Compute Visible Leaves Size filter + +A new HTG utility filter for HTG has been added : `vtkHyperTreeGridVisibleLeavesSize`. +This filter creates 2 new cell fields using implicit arrays under the hood: +- `ValidCell` has a (double) value of 1.0 for visible (non ghost, non masked) leaf cells, and 0.0 for the others. +- `CellSize`'s value corresponds to the volume of the cell in 3D, or area in 2D. + +`ValidCell` can allow, with `CellSize`, to compute volume aggregations over the HTG. diff --git a/Documentation/release/dev/htg-visible-leaves-volume.md b/Documentation/release/dev/htg-visible-leaves-volume.md deleted file mode 100644 index 7e8291f5802..00000000000 --- a/Documentation/release/dev/htg-visible-leaves-volume.md +++ /dev/null @@ -1,8 +0,0 @@ -## Hyper Tree Grid Compute Visible Leaves Volume filter - -A new HTG utility filter for HTG has been added : `vtkHyperTreeGridVisibleLeavesVolume`. -This filter creates 2 new cell fields using implicit arrays under the hood: -- `vtkValidCell` has a (double) value of 1.0 for visible (non ghost, non masked) leaf cells, and 0.0 for the others. -- `vtkVolume`'s value corresponds to the volume of the cell. - -`vtkValidCell` can allow, with `vtkVolume`, to compute volume aggregations over the HTG. diff --git a/Filters/HyperTree/CMakeLists.txt b/Filters/HyperTree/CMakeLists.txt index d80f2c3851e..115cd8ee7df 100644 --- a/Filters/HyperTree/CMakeLists.txt +++ b/Filters/HyperTree/CMakeLists.txt @@ -14,7 +14,7 @@ set(classes vtkHyperTreeGridThreshold vtkHyperTreeGridToDualGrid vtkHyperTreeGridToUnstructuredGrid - vtkHyperTreeGridVisibleLeavesVolume + vtkHyperTreeGridVisibleLeavesSize vtkImageDataToHyperTreeGrid ) diff --git a/Filters/HyperTree/Testing/Cxx/CMakeLists.txt b/Filters/HyperTree/Testing/Cxx/CMakeLists.txt index 6cd791b24d4..df039795049 100644 --- a/Filters/HyperTree/Testing/Cxx/CMakeLists.txt +++ b/Filters/HyperTree/Testing/Cxx/CMakeLists.txt @@ -96,7 +96,7 @@ set(test_sources TestHyperTreeGridTernarySphereMaterial.cxx TestHyperTreeGridTernarySphereMaterialReflections.cxx TestHyperTreeGridToDualGrid.cxx - TestHyperTreeGridVisibleLeavesVolume.cxx,NO_VALID,NO_OUPUT + TestHyperTreeGridVisibleLeavesSize.cxx,NO_VALID,NO_OUPUT ) vtk_add_test_cxx(vtkFiltersHyperTreeCxxTests tests ${test_sources}) diff --git a/Filters/HyperTree/Testing/Cxx/TestHyperTreeGridVisibleLeavesVolume.cxx b/Filters/HyperTree/Testing/Cxx/TestHyperTreeGridVisibleLeavesSize.cxx similarity index 93% rename from Filters/HyperTree/Testing/Cxx/TestHyperTreeGridVisibleLeavesVolume.cxx rename to Filters/HyperTree/Testing/Cxx/TestHyperTreeGridVisibleLeavesSize.cxx index 0b79c1ad6bc..c066985da23 100644 --- a/Filters/HyperTree/Testing/Cxx/TestHyperTreeGridVisibleLeavesVolume.cxx +++ b/Filters/HyperTree/Testing/Cxx/TestHyperTreeGridVisibleLeavesSize.cxx @@ -4,7 +4,7 @@ #include "vtkCellData.h" #include "vtkHyperTreeGrid.h" #include "vtkHyperTreeGridNonOrientedGeometryCursor.h" -#include "vtkHyperTreeGridVisibleLeavesVolume.h" +#include "vtkHyperTreeGridVisibleLeavesSize.h" #include "vtkNew.h" #include "vtkTestUtilities.h" #include "vtkUnsignedCharArray.h" @@ -90,7 +90,7 @@ bool CheckTree(vtkHyperTreeGridNonOrientedGeometryCursor* cursor, vtkHyperTreeGr } } -int TestHyperTreeGridVisibleLeavesVolume(int argc, char* argv[]) +int TestHyperTreeGridVisibleLeavesSize(int argc, char* argv[]) { // Read HTG file containing ghost cells vtkNew<vtkXMLHyperTreeGridReader> reader; @@ -107,10 +107,10 @@ int TestHyperTreeGridVisibleLeavesVolume(int argc, char* argv[]) inputHTG->SetMask(maskArray); // Compute visible leaves volume - vtkNew<vtkHyperTreeGridVisibleLeavesVolume> leavesFilter; - leavesFilter->SetCellVolumeArrayName("Vol"); + vtkNew<vtkHyperTreeGridVisibleLeavesSize> leavesFilter; + leavesFilter->SetCellSizeArrayName("Vol"); leavesFilter->SetValidCellArrayName("Valid"); - leavesFilter->SetInputConnection(reader->GetOutputPort()); + leavesFilter->SetInputData(inputHTG); leavesFilter->Update(); vtkHyperTreeGrid* leavesVolumeHTG = leavesFilter->GetHyperTreeGridOutput(); diff --git a/Filters/HyperTree/vtkHyperTreeGridVisibleLeavesVolume.cxx b/Filters/HyperTree/vtkHyperTreeGridVisibleLeavesSize.cxx similarity index 69% rename from Filters/HyperTree/vtkHyperTreeGridVisibleLeavesVolume.cxx rename to Filters/HyperTree/vtkHyperTreeGridVisibleLeavesSize.cxx index db7ce7025ff..232c0af2181 100644 --- a/Filters/HyperTree/vtkHyperTreeGridVisibleLeavesVolume.cxx +++ b/Filters/HyperTree/vtkHyperTreeGridVisibleLeavesSize.cxx @@ -1,6 +1,6 @@ // SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen // SPDX-License-Identifier: BSD-3-Clause -#include "vtkHyperTreeGridVisibleLeavesVolume.h" +#include "vtkHyperTreeGridVisibleLeavesSize.h" #include "vtkBitArray.h" #include "vtkCellData.h" @@ -26,7 +26,7 @@ #include <vector> VTK_ABI_NAMESPACE_BEGIN -vtkStandardNewMacro(vtkHyperTreeGridVisibleLeavesVolume) +vtkStandardNewMacro(vtkHyperTreeGridVisibleLeavesSize) namespace { @@ -61,10 +61,12 @@ vtkStandardNewMacro(vtkHyperTreeGridVisibleLeavesVolume) template <typename T> using vtkScalarBooleanArray = vtkImplicitArray<vtkScalarBooleanImplicitBackend<T>>; + + using LevelType = unsigned char; } //------------------------------------------------------------------------------ -class vtkHyperTreeGridVisibleLeavesVolume::vtkInternal +class vtkHyperTreeGridVisibleLeavesSize::vtkInternal { public: vtkInternal() = default; @@ -75,24 +77,24 @@ public: */ bool Initialize(vtkHyperTreeGrid* inputHTG) { - this->VolumeDiscreteValues->SetNumberOfComponents(1); - this->VolumeDiscreteValues->SetNumberOfTuples(inputHTG->GetNumberOfLevels()); - if (this->VolumeDiscreteValues->GetNumberOfTuples() > 256) + this->SizeDiscreteValues->SetNumberOfComponents(1); + this->SizeDiscreteValues->SetNumberOfTuples(inputHTG->GetNumberOfLevels()); + if (this->SizeDiscreteValues->GetNumberOfTuples() > 256) { - vtkErrorWithObjectMacro(nullptr, << "Cannot compute volume for more than 256 levels, got" - << this->VolumeDiscreteValues->GetNumberOfTuples()); + vtkErrorWithObjectMacro(nullptr, << "Cannot compute size for more than 256 levels, got" + << this->SizeDiscreteValues->GetNumberOfTuples()); return false; } - this->ComputeLevelVolumes(inputHTG); + this->ComputeLevelSizes(inputHTG); this->PackedValidCellArray.clear(); this->PackedValidCellArray.resize(inputHTG->GetNumberOfCells(), false); - this->OutputVolumeArray->SetNumberOfComponents(1); - this->OutputVolumeArray->SetNumberOfTuples(inputHTG->GetNumberOfCells()); + this->OutputSizeArray->SetNumberOfComponents(1); + this->OutputSizeArray->SetNumberOfTuples(inputHTG->GetNumberOfCells()); - this->VolumeIndirectionTable->SetNumberOfComponents(1); - this->VolumeIndirectionTable->SetNumberOfTuples(inputHTG->GetNumberOfCells()); + this->SizeIndirectionTable->SetNumberOfComponents(1); + this->SizeIndirectionTable->SetNumberOfTuples(inputHTG->GetNumberOfCells()); this->InputMask = inputHTG->HasMask() ? inputHTG->GetMask() : nullptr; this->InputGhost = inputHTG->GetGhostCells(); @@ -121,20 +123,20 @@ public: } /** - * Build the output volume array from internally stored values + * Build the output size array from internally stored values */ - vtkDataArray* GetAndFinalizeVolumeArray(const std::string& volumeArrayName) + vtkDataArray* GetAndFinalizeSizeArray(const std::string& sizeArrayName) { - // The volume values take a discrete number of different values : one value for each level - // Thus, we can use an indexed (implicit) array as an indirection table to store the volume as a + // The size values take a discrete number of different values : one value for each level + // Thus, we can use an indexed (implicit) array as an indirection table to store the size as a // uchar (256 possible values/levels) instead of a double for each cell to save memory (1 byte // stored instead of 8) - this->OutputVolumeArray->SetName(volumeArrayName.c_str()); - this->OutputVolumeArray->SetNumberOfComponents(1); - this->OutputVolumeArray->SetNumberOfTuples(this->VolumeIndirectionTable->GetNumberOfValues()); - this->OutputVolumeArray->SetBackend(std::make_shared<vtkIndexedImplicitBackend<double>>( - VolumeIndirectionTable, VolumeDiscreteValues)); - return this->OutputVolumeArray; + this->OutputSizeArray->SetName(sizeArrayName.c_str()); + this->OutputSizeArray->SetNumberOfComponents(1); + this->OutputSizeArray->SetNumberOfTuples(this->SizeIndirectionTable->GetNumberOfValues()); + this->OutputSizeArray->SetBackend(std::make_shared<vtkIndexedImplicitBackend<double>>( + SizeIndirectionTable, SizeDiscreteValues)); + return this->OutputSizeArray; } /** @@ -143,8 +145,8 @@ public: void RecordDepth(vtkHyperTreeGridNonOrientedGeometryCursor* cursor) { assert("pre: level is less than 256" && cursor->GetLevel() <= 256); - this->VolumeIndirectionTable->SetTuple1( - cursor->GetGlobalNodeIndex(), static_cast<unsigned char>(cursor->GetLevel())); + this->SizeIndirectionTable->SetTuple1( + cursor->GetGlobalNodeIndex(), static_cast<::LevelType>(cursor->GetLevel())); } /** @@ -174,63 +176,66 @@ private: std::vector<bool> PackedValidCellArray; // Operations on bool vector are not atomic. This structure needs to // change if this filter is parallelized. - vtkNew<vtkUnsignedCharArray> VolumeIndirectionTable; - vtkNew<vtkDoubleArray> VolumeDiscreteValues; + vtkNew<vtkUnsignedCharArray> SizeIndirectionTable; + vtkNew<vtkDoubleArray> SizeDiscreteValues; // Output data arrays vtkNew<::vtkScalarBooleanArray<double>> ValidCellsImplicitArray; - vtkNew<vtkIndexedArray<double>> OutputVolumeArray; + vtkNew<vtkIndexedArray<double>> OutputSizeArray; /** - * Fill the VolumeDiscreteValues array with volume values for each level, + * Fill the SizeDiscreteValues array with size values for each level, * based on the HTG's first tree scales. * We make the assumption that the HTG is uniform and invidual tree scales have not been changed. */ - void ComputeLevelVolumes(vtkHyperTreeGrid* inputHTG) + void ComputeLevelSizes(vtkHyperTreeGrid* inputHTG) { vtkHyperTree* tree = inputHTG->GetTree(0); std::shared_ptr<vtkHyperTreeGridScales> scale = tree->GetScales(); - for (unsigned char level = 0; - level < static_cast<unsigned char>(this->VolumeDiscreteValues->GetNumberOfTuples()); - level++) + for (LevelType level = 0; + level < static_cast<LevelType>(this->SizeDiscreteValues->GetNumberOfTuples()); level++) { - double cellVolume{ 1 }; - if (inputHTG->GetDimension() != 3) - { - // 1D and 2D cells have a null volume - cellVolume = 0; - } - else + bool nullSize = true; + double cellSize{ 1.0 }; + double size[3]; + scale->GetScale(level, size); + std::vector<double> dimensions(size, size + 3); + for (auto& edgeSize : dimensions) { - double size[3]; - scale->GetScale(level, size); - std::vector<double> dimensions(size, size + 3); - for (auto& edgeSize : dimensions) + if (edgeSize != 0.0) { - cellVolume *= edgeSize; + nullSize = false; + cellSize *= edgeSize; } } - this->VolumeDiscreteValues->SetTuple1(level, cellVolume); + if (nullSize) + { + // Every size coordinate is null, so the cell size is also null + cellSize = 0.0; + } + this->SizeDiscreteValues->SetTuple1(level, cellSize); } } }; //------------------------------------------------------------------------------ -vtkHyperTreeGridVisibleLeavesVolume::vtkHyperTreeGridVisibleLeavesVolume() +vtkHyperTreeGridVisibleLeavesSize::vtkHyperTreeGridVisibleLeavesSize() { this->Internal = std::unique_ptr<vtkInternal>(new vtkInternal()); this->AppropriateOutput = true; }; //------------------------------------------------------------------------------ -void vtkHyperTreeGridVisibleLeavesVolume::PrintSelf(ostream& ost, vtkIndent indent) +void vtkHyperTreeGridVisibleLeavesSize::PrintSelf(ostream& os, vtkIndent indent) { - this->Superclass::PrintSelf(ost, indent); + this->Superclass::PrintSelf(os, indent); + os << indent << "Cell Size array name: " << this->GetCellSizeArrayName() << "\n"; + os << indent << "Cell Validity array name: " << this->GetValidCellArrayName() << "\n"; } //------------------------------------------------------------------------------ -int vtkHyperTreeGridVisibleLeavesVolume::ProcessTrees( +int vtkHyperTreeGridVisibleLeavesSize::ProcessTrees( vtkHyperTreeGrid* input, vtkDataObject* outputDO) { vtkHyperTreeGrid* outputHTG = vtkHyperTreeGrid::SafeDownCast(outputDO); @@ -263,18 +268,18 @@ int vtkHyperTreeGridVisibleLeavesVolume::ProcessTrees( this->ProcessNode(outCursor); } - // Append both volume and cell validity array to the output + // Append both size and cell validity array to the output outputHTG->GetCellData()->AddArray( this->Internal->GetAndFinalizeValidityArray(this->GetValidCellArrayName())); outputHTG->GetCellData()->AddArray( - this->Internal->GetAndFinalizeVolumeArray(this->GetCellVolumeArrayName())); + this->Internal->GetAndFinalizeSizeArray(this->GetCellSizeArrayName())); this->UpdateProgress(1.); return 1; } //------------------------------------------------------------------------------ -void vtkHyperTreeGridVisibleLeavesVolume::ProcessNode( +void vtkHyperTreeGridVisibleLeavesSize::ProcessNode( vtkHyperTreeGridNonOrientedGeometryCursor* outCursor) { vtkIdType currentId = outCursor->GetGlobalNodeIndex(); diff --git a/Filters/HyperTree/vtkHyperTreeGridVisibleLeavesVolume.h b/Filters/HyperTree/vtkHyperTreeGridVisibleLeavesSize.h similarity index 59% rename from Filters/HyperTree/vtkHyperTreeGridVisibleLeavesVolume.h rename to Filters/HyperTree/vtkHyperTreeGridVisibleLeavesSize.h index 2af5f2362e2..2dd131cbf45 100644 --- a/Filters/HyperTree/vtkHyperTreeGridVisibleLeavesVolume.h +++ b/Filters/HyperTree/vtkHyperTreeGridVisibleLeavesSize.h @@ -1,23 +1,25 @@ // SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen // SPDX-License-Identifier: BSD-3-Clause /** - * @class vtkHyperTreeGridVisibleLeavesVolume + * @class vtkHyperTreeGridVisibleLeavesSize * @brief Generate a cell field equal to 1 if the cell is a valid leaf and 0 otherwise, as well as - * a volume field. + * a size field. * - * vtkHyperTreeGridVisibleLeavesVolume creates 2 distinct (double) cell fields. + * vtkHyperTreeGridVisibleLeavesSize creates 2 distinct (double) cell fields. * The first one, named 'ValidCell' by default, has a value of 1.0 for leaf (non-refined) cells * that are neither masked nor ghost, and 0.0 otherwise. * - * The second one, named 'CellVolume' by default, is set to the volume of the cell, depending on its - * depth level. This field has a value for every cell traversed through the cursor, valid or not. + * The second one, named 'CellSize' by default, is set to the size (volume) of the cell for 3D HTGs, + * depending on its depth level. This field has a value for every cell traversed through the cursor, + * valid or not. By extension, CellSize is set to the cell area for 2D HTG and cell length for 1D. + * In practice, we ignore null size coordinates when computing the value. * * These 2 fields can be used for data aggregation or computations over the whole grid, ie computing - * the total volume of a given HTG. These fields are implemented as + * the total size of a given HTG. These fields are implemented as * implicit arrays, in order to lower the memory footprint of the filter. * * Note that the filter needs to be run again if cells are refined after its execution. - * The volume computation can support at most 256 levels. + * The size computation can support at most 256 levels. * * @sa * vtkHyperTreeGrid vtkHyperTreeGridAlgorithm @@ -28,8 +30,8 @@ * CEA, DAM, DIF, F-91297 Arpajon, France. */ -#ifndef vtkHyperTreeGridVisibleLeavesVolume_h -#define vtkHyperTreeGridVisibleLeavesVolume_h +#ifndef vtkHyperTreeGridVisibleLeavesSize_h +#define vtkHyperTreeGridVisibleLeavesSize_h #include "vtkFiltersHyperTreeModule.h" // For export macro #include "vtkHyperTreeGridAlgorithm.h" @@ -44,21 +46,21 @@ class vtkInformation; class vtkHyperTreeGrid; class vtkHyperTreeGridNonOrientedGeometryCursor; -class VTKFILTERSHYPERTREE_EXPORT vtkHyperTreeGridVisibleLeavesVolume +class VTKFILTERSHYPERTREE_EXPORT vtkHyperTreeGridVisibleLeavesSize : public vtkHyperTreeGridAlgorithm { public: - static vtkHyperTreeGridVisibleLeavesVolume* New(); - vtkTypeMacro(vtkHyperTreeGridVisibleLeavesVolume, vtkHyperTreeGridAlgorithm) + static vtkHyperTreeGridVisibleLeavesSize* New(); + vtkTypeMacro(vtkHyperTreeGridVisibleLeavesSize, vtkHyperTreeGridAlgorithm) void PrintSelf(ostream& ost, vtkIndent indent) override; ///@{ /** - * Get/Set the name used for the cell volume array. - * Defaults to 'CellVolume' + * Get/Set the name used for the cell size array. + * Defaults to 'CellSize' */ - vtkGetMacro(CellVolumeArrayName, std::string); - vtkSetMacro(CellVolumeArrayName, std::string); + vtkGetMacro(CellSizeArrayName, std::string); + vtkSetMacro(CellSizeArrayName, std::string); ///@} ///@{ @@ -71,8 +73,8 @@ public: ///@} protected: - vtkHyperTreeGridVisibleLeavesVolume(); - ~vtkHyperTreeGridVisibleLeavesVolume() override = default; + vtkHyperTreeGridVisibleLeavesSize(); + ~vtkHyperTreeGridVisibleLeavesSize() override = default; /** * Main filter routine : iterate over the trees and fill output array structures. @@ -80,19 +82,19 @@ protected: int ProcessTrees(vtkHyperTreeGrid*, vtkDataObject*) override; private: - vtkHyperTreeGridVisibleLeavesVolume(const vtkHyperTreeGridVisibleLeavesVolume&) = delete; - void operator=(const vtkHyperTreeGridVisibleLeavesVolume&) = delete; + vtkHyperTreeGridVisibleLeavesSize(const vtkHyperTreeGridVisibleLeavesSize&) = delete; + void operator=(const vtkHyperTreeGridVisibleLeavesSize&) = delete; /** * Process a single tree, recursively descending into the tree, down to leaves */ void ProcessNode(vtkHyperTreeGridNonOrientedGeometryCursor*); + std::string CellSizeArrayName = "CellSize"; + std::string ValidCellArrayName = "ValidCell"; + class vtkInternal; std::unique_ptr<vtkInternal> Internal; - - std::string CellVolumeArrayName = "CellVolume"; - std::string ValidCellArrayName = "ValidCell"; }; VTK_ABI_NAMESPACE_END -- GitLab