Skip to content
Snippets Groups Projects
Commit b49d62da authored by Louis Gombert's avatar Louis Gombert :speech_balloon:
Browse files

HTG Leaves Volume: generalize volume to other dimensions

parent 561477a7
No related branches found
No related tags found
No related merge requests found
## 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.
## 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.
......@@ -14,7 +14,7 @@ set(classes
vtkHyperTreeGridThreshold
vtkHyperTreeGridToDualGrid
vtkHyperTreeGridToUnstructuredGrid
vtkHyperTreeGridVisibleLeavesVolume
vtkHyperTreeGridVisibleLeavesSize
vtkImageDataToHyperTreeGrid
)
......
......@@ -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})
......
......@@ -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();
......
// 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();
......
// 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
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment