Fem: Add upstream vtkCleanUnstructuredGrid class source files
This commit is contained in:
@@ -87,6 +87,14 @@ if(BUILD_FEM_VTK)
|
||||
VTKExtensions/vtkFemFrameSourceAlgorithm.h
|
||||
VTKExtensions/vtkFemFrameSourceAlgorithm.cpp
|
||||
)
|
||||
SET(VTK_SRCS_0903
|
||||
VTKExtensions/vtkCleanUnstructuredGrid.h
|
||||
VTKExtensions/vtkCleanUnstructuredGrid.cxx
|
||||
VTKExtensions/vtkSMPTools.h
|
||||
)
|
||||
if (${VTK_MAJOR_VERSION} EQUAL 9 AND ${VTK_MINOR_VERSION} LESS 3)
|
||||
list(APPEND FemVTK_SRCS ${VTK_SRCS_0903})
|
||||
endif()
|
||||
SOURCE_GROUP("VTKExtensions" FILES ${FemVTK_SRCS})
|
||||
endif(BUILD_FEM_VTK)
|
||||
|
||||
|
||||
@@ -148,10 +148,14 @@
|
||||
#include <gp_Vec.hxx>
|
||||
|
||||
// VTK
|
||||
#include <vtkVersionMacros.h>
|
||||
#include <vtkAlgorithmOutput.h>
|
||||
#include <vtkAppendFilter.h>
|
||||
#include <vtkArrayCalculator.h>
|
||||
#include <vtkCellArray.h>
|
||||
#if VTK_VERSION_NUMBER >= VTK_VERSION_CHECK(9, 3, 0)
|
||||
#include <vtkCleanUnstructuredGrid.h>
|
||||
#endif
|
||||
#include <vtkCompositeDataSet.h>
|
||||
#include <vtkDataArray.h>
|
||||
#include <vtkDataSetReader.h>
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
SET(FemVTK_SRCS
|
||||
vtkFemFrameSourceAlgorithm.h
|
||||
vtkFemFrameSourceAlgorithm.cpp
|
||||
)
|
||||
|
||||
target_sources(Fem PRIVATE ${FemVTK_SRCS})
|
||||
680
src/Mod/Fem/App/VTKExtensions/vtkCleanUnstructuredGrid.cxx
Normal file
680
src/Mod/Fem/App/VTKExtensions/vtkCleanUnstructuredGrid.cxx
Normal file
@@ -0,0 +1,680 @@
|
||||
// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
|
||||
// SPDX-FileCopyrightText: Copyright (c) Kitware, Inc.
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#ifndef _PreComp_
|
||||
#include <vtkArrayDispatch.h>
|
||||
#include <vtkArrayDispatchArrayList.h>
|
||||
#include <vtkBitArray.h>
|
||||
#include <vtkCell.h>
|
||||
#include <vtkCellData.h>
|
||||
#include <vtkCellSizeFilter.h>
|
||||
#include <vtkCellTypes.h>
|
||||
#include <vtkCollection.h>
|
||||
#include <vtkDataArrayRange.h>
|
||||
#include <vtkDataSet.h>
|
||||
#include <vtkDoubleArray.h>
|
||||
#include <vtkIncrementalPointLocator.h>
|
||||
#include <vtkInformation.h>
|
||||
#include <vtkInformationVector.h>
|
||||
#include <vtkIntArray.h>
|
||||
#include <vtkMergePoints.h>
|
||||
#include <vtkObjectFactory.h>
|
||||
#include <vtkPointData.h>
|
||||
#include <vtkPointSet.h>
|
||||
#include <vtkPoints.h>
|
||||
#include <vtkRectilinearGrid.h>
|
||||
#include <vtkSMPThreadLocalObject.h>
|
||||
#include <vtkStringArray.h>
|
||||
#include <vtkUnstructuredGrid.h>
|
||||
|
||||
#include <unordered_set>
|
||||
#endif
|
||||
|
||||
#include "vtkCleanUnstructuredGrid.h"
|
||||
#include "vtkSMPTools.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
int GetDimension(unsigned char type)
|
||||
{
|
||||
// For the most common cell types, this is a fast call. If the cell type is
|
||||
// more exotic, then the cell must be grabbed and queried directly, which is
|
||||
// slow.
|
||||
switch (type) {
|
||||
case VTK_EMPTY_CELL:
|
||||
case VTK_VERTEX:
|
||||
case VTK_POLY_VERTEX:
|
||||
return 0;
|
||||
case VTK_LINE:
|
||||
case VTK_POLY_LINE:
|
||||
case VTK_QUADRATIC_EDGE:
|
||||
case VTK_CUBIC_LINE:
|
||||
case VTK_LAGRANGE_CURVE:
|
||||
case VTK_BEZIER_CURVE:
|
||||
return 1;
|
||||
case VTK_TRIANGLE:
|
||||
case VTK_QUAD:
|
||||
case VTK_PIXEL:
|
||||
case VTK_POLYGON:
|
||||
case VTK_TRIANGLE_STRIP:
|
||||
case VTK_QUADRATIC_TRIANGLE:
|
||||
case VTK_QUADRATIC_QUAD:
|
||||
case VTK_QUADRATIC_POLYGON:
|
||||
case VTK_BIQUADRATIC_QUAD:
|
||||
case VTK_BIQUADRATIC_TRIANGLE:
|
||||
case VTK_LAGRANGE_TRIANGLE:
|
||||
case VTK_LAGRANGE_QUADRILATERAL:
|
||||
case VTK_BEZIER_TRIANGLE:
|
||||
case VTK_BEZIER_QUADRILATERAL:
|
||||
return 2;
|
||||
case VTK_TETRA:
|
||||
case VTK_VOXEL:
|
||||
case VTK_HEXAHEDRON:
|
||||
case VTK_WEDGE:
|
||||
case VTK_PYRAMID:
|
||||
case VTK_PENTAGONAL_PRISM:
|
||||
case VTK_HEXAGONAL_PRISM:
|
||||
case VTK_QUADRATIC_TETRA:
|
||||
case VTK_QUADRATIC_HEXAHEDRON:
|
||||
case VTK_QUADRATIC_WEDGE:
|
||||
case VTK_QUADRATIC_PYRAMID:
|
||||
case VTK_BIQUADRATIC_QUADRATIC_HEXAHEDRON:
|
||||
case VTK_BIQUADRATIC_QUADRATIC_WEDGE:
|
||||
case VTK_TRIQUADRATIC_HEXAHEDRON:
|
||||
case VTK_TRIQUADRATIC_PYRAMID:
|
||||
case VTK_LAGRANGE_TETRAHEDRON:
|
||||
case VTK_LAGRANGE_HEXAHEDRON:
|
||||
case VTK_LAGRANGE_WEDGE:
|
||||
case VTK_BEZIER_TETRAHEDRON:
|
||||
case VTK_BEZIER_HEXAHEDRON:
|
||||
case VTK_BEZIER_WEDGE:
|
||||
return 3;
|
||||
default:
|
||||
vtkNew<vtkGenericCell> cell;
|
||||
cell->SetCellType(type);
|
||||
return cell->GetCellDimension();
|
||||
}
|
||||
}
|
||||
|
||||
constexpr unsigned char MAX_CELL_DIM = 3;
|
||||
|
||||
void AllocatePointAttributes(vtkPointData* inPD, vtkPointData* outPD, vtkIdType nPoints)
|
||||
{
|
||||
for (vtkIdType iArr = 0; iArr < inPD->GetNumberOfArrays(); ++iArr) {
|
||||
auto inArr = inPD->GetAbstractArray(iArr);
|
||||
auto outArr = outPD->GetAbstractArray(inArr->GetName());
|
||||
if (!outArr) {
|
||||
vtkGenericWarningMacro(<< inArr->GetName() << " output array is nullptr");
|
||||
continue;
|
||||
}
|
||||
outArr->SetNumberOfComponents(inArr->GetNumberOfComponents());
|
||||
outArr->SetNumberOfTuples(nPoints);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char GetTopologicalDimension(vtkDataSet* ds)
|
||||
{
|
||||
vtkNew<vtkCellTypes> cTypes;
|
||||
ds->GetCellTypes(cTypes);
|
||||
unsigned char topoDim = 0;
|
||||
for (vtkIdType iC = 0; iC < cTypes->GetNumberOfTypes(); ++iC) {
|
||||
unsigned char dimC = static_cast<unsigned char>(GetDimension(cTypes->GetCellType(iC)));
|
||||
topoDim = std::max(topoDim, dimC);
|
||||
if (topoDim >= MAX_CELL_DIM) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (topoDim > MAX_CELL_DIM) {
|
||||
vtkErrorWithObjectMacro(
|
||||
nullptr,
|
||||
"Topological dimension of data set is larger than the maximal cell dimension");
|
||||
return MAX_CELL_DIM;
|
||||
}
|
||||
return topoDim;
|
||||
}
|
||||
|
||||
struct WeighingStrategy
|
||||
{
|
||||
virtual ~WeighingStrategy() = default;
|
||||
virtual vtkSmartPointer<vtkDoubleArray> ComputeWeights(vtkDataSet* ds,
|
||||
const std::vector<vtkIdType>& ptMap) = 0;
|
||||
};
|
||||
|
||||
struct FirstPointStrategy: public WeighingStrategy
|
||||
{
|
||||
vtkSmartPointer<vtkDoubleArray> ComputeWeights(vtkDataSet* ds,
|
||||
const std::vector<vtkIdType>& ptMap) override
|
||||
{
|
||||
if (ds->GetNumberOfPoints() != static_cast<vtkIdType>(ptMap.size())) {
|
||||
vtkGenericWarningMacro(
|
||||
"Number of points in dataset and number of entries in point map don't line up.");
|
||||
return nullptr;
|
||||
}
|
||||
vtkNew<vtkDoubleArray> weights;
|
||||
weights->SetNumberOfComponents(1);
|
||||
weights->SetNumberOfTuples(ds->GetNumberOfPoints());
|
||||
weights->Fill(0.0);
|
||||
|
||||
std::unordered_set<vtkIdType> firstPoints;
|
||||
for (vtkIdType iP = 0; iP < ds->GetNumberOfPoints(); ++iP) {
|
||||
if (firstPoints.find(ptMap[iP]) != firstPoints.end()) {
|
||||
continue;
|
||||
}
|
||||
firstPoints.insert(ptMap[iP]);
|
||||
weights->SetValue(iP, 1.0);
|
||||
}
|
||||
return weights;
|
||||
}
|
||||
};
|
||||
|
||||
struct AveragingStrategy: public WeighingStrategy
|
||||
{
|
||||
vtkSmartPointer<vtkDoubleArray> ComputeWeights(vtkDataSet* ds,
|
||||
const std::vector<vtkIdType>& ptMap) override
|
||||
{
|
||||
if (ds->GetNumberOfPoints() != static_cast<vtkIdType>(ptMap.size())) {
|
||||
vtkGenericWarningMacro(
|
||||
"Number of points in dataset and number of entries in point map don't line up.");
|
||||
return nullptr;
|
||||
}
|
||||
std::vector<double> counts(ds->GetNumberOfPoints(), 0.0);
|
||||
for (vtkIdType iP = 0; iP < ds->GetNumberOfPoints(); ++iP) {
|
||||
if (ptMap[iP] < 0) {
|
||||
continue;
|
||||
}
|
||||
counts[ptMap[iP]] += 1.0;
|
||||
}
|
||||
|
||||
vtkNew<vtkDoubleArray> weights;
|
||||
weights->SetNumberOfComponents(1);
|
||||
weights->SetNumberOfTuples(ds->GetNumberOfPoints());
|
||||
weights->Fill(0.0);
|
||||
|
||||
auto wRange = vtk::DataArrayValueRange<1>(weights);
|
||||
for (vtkIdType iP = 0; iP < ds->GetNumberOfPoints(); ++iP) {
|
||||
if (ptMap[iP] < 0) {
|
||||
continue;
|
||||
}
|
||||
wRange[iP] = (counts[ptMap[iP]] ? 1.0 / counts[ptMap[iP]] : 0.0);
|
||||
}
|
||||
|
||||
return weights;
|
||||
}
|
||||
};
|
||||
|
||||
struct SpatialDensityStrategy: public WeighingStrategy
|
||||
{
|
||||
vtkSmartPointer<vtkDoubleArray> ComputeWeights(vtkDataSet* ds,
|
||||
const std::vector<vtkIdType>& ptMap) override
|
||||
{
|
||||
if (ds->GetNumberOfPoints() != static_cast<vtkIdType>(ptMap.size())) {
|
||||
vtkGenericWarningMacro(
|
||||
"Number of points in dataset and number of entries in point map don't line up.");
|
||||
return nullptr;
|
||||
}
|
||||
// Get topological dimension of data set
|
||||
auto topoDim = GetTopologicalDimension(ds);
|
||||
// Calculate cell measures
|
||||
vtkSmartPointer<vtkDataArray> measures;
|
||||
{
|
||||
// this scope is so that any extra memory related to the cell size filter gets released
|
||||
// when no longer needed
|
||||
vtkNew<vtkCellSizeFilter> cellSizeFilter;
|
||||
cellSizeFilter->SetInputData(ds);
|
||||
cellSizeFilter->Update();
|
||||
auto output = vtkDataSet::SafeDownCast(cellSizeFilter->GetOutputDataObject(0));
|
||||
auto cData = output->GetCellData();
|
||||
if (!cData || !cData->HasArray("VertexCount") || !cData->HasArray("Length")
|
||||
|| !cData->HasArray("Area") || !cData->HasArray("Volume")) {
|
||||
vtkErrorWithObjectMacro(
|
||||
nullptr,
|
||||
"Could not find correct cell data in output of cell size filter");
|
||||
return nullptr;
|
||||
}
|
||||
switch (topoDim) {
|
||||
case 0:
|
||||
measures = cData->GetArray("VertexCount");
|
||||
break;
|
||||
case 1:
|
||||
measures = cData->GetArray("Length");
|
||||
break;
|
||||
case 2:
|
||||
measures = cData->GetArray("Area");
|
||||
break;
|
||||
case 3:
|
||||
measures = cData->GetArray("Volume");
|
||||
break;
|
||||
default:
|
||||
vtkErrorWithObjectMacro(nullptr,
|
||||
"Topological dimension of data set is higher than 3. "
|
||||
"Cannot deal with that.");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
// Distribute spatial density to points
|
||||
vtkNew<vtkDoubleArray> density;
|
||||
density->SetNumberOfComponents(1);
|
||||
density->SetNumberOfTuples(ds->GetNumberOfPoints());
|
||||
density->Fill(0.0);
|
||||
auto dRange = vtk::DataArrayValueRange<1>(density);
|
||||
auto mRange = vtk::DataArrayValueRange<1>(measures);
|
||||
if (ds->GetNumberOfCells() > 0) {
|
||||
vtkNew<vtkIdList> pointIdList;
|
||||
ds->GetCellPoints(0, pointIdList);
|
||||
}
|
||||
vtkSMPThreadLocalObject<vtkIdList> localPointIds;
|
||||
auto distribute = [&](vtkIdType begin, vtkIdType end) {
|
||||
for (vtkIdType iC = begin; iC < end; ++iC) {
|
||||
ds->GetCellPoints(iC, localPointIds.Local());
|
||||
double participation = mRange[iC] / localPointIds.Local()->GetNumberOfIds();
|
||||
for (vtkIdType iP = 0; iP < localPointIds.Local()->GetNumberOfIds(); ++iP) {
|
||||
dRange[localPointIds.Local()->GetId(iP)] += participation;
|
||||
}
|
||||
}
|
||||
};
|
||||
// For thread safety
|
||||
if (ds->GetNumberOfCells() > 0) {
|
||||
vtkNew<vtkIdList> buffer;
|
||||
ds->GetCellPoints(0, buffer);
|
||||
}
|
||||
distribute(0, ds->GetNumberOfCells());
|
||||
// Merits a dedicated struct with a reduce operation
|
||||
// collisions occuring in the += operation
|
||||
// vtkSMPTools::For(0, ds->GetNumberOfCells(), distribute);
|
||||
// Normalize spatial densities with respect to point map
|
||||
{
|
||||
std::vector<double> masses(*std::max_element(ptMap.begin(), ptMap.end()) + 1, 0);
|
||||
auto computeMasses = [&dRange, &masses, &ptMap](vtkIdType begin, vtkIdType end) {
|
||||
for (vtkIdType iP = begin; iP < end; ++iP) {
|
||||
if (ptMap[iP] < 0) {
|
||||
dRange[iP] = 0.0;
|
||||
continue;
|
||||
}
|
||||
masses[ptMap[iP]] += dRange[iP];
|
||||
}
|
||||
};
|
||||
computeMasses(0, ds->GetNumberOfPoints());
|
||||
// Merits a dedicated struct with a reduce operation
|
||||
// collisions occuring in the += operation
|
||||
// vtkSMPTools::For(0, ds->GetNumberOfPoints(), computeMasses);
|
||||
vtkSMPTools::For(0,
|
||||
ds->GetNumberOfPoints(),
|
||||
[&dRange, &masses, &ptMap](vtkIdType begin, vtkIdType end) {
|
||||
for (vtkIdType iP = begin; iP < end; ++iP) {
|
||||
if (ptMap[iP] < 0) {
|
||||
continue;
|
||||
}
|
||||
dRange[iP] =
|
||||
(masses[ptMap[iP]] != 0 ? dRange[iP] / masses[ptMap[iP]]
|
||||
: 0.0);
|
||||
}
|
||||
});
|
||||
}
|
||||
return density;
|
||||
}
|
||||
};
|
||||
|
||||
struct WeighingStrategyFactory
|
||||
{
|
||||
std::shared_ptr<WeighingStrategy> operator()(vtkCleanUnstructuredGrid::DataWeighingType dwt)
|
||||
{
|
||||
switch (dwt) {
|
||||
case vtkCleanUnstructuredGrid::FIRST_POINT:
|
||||
return std::make_shared<FirstPointStrategy>();
|
||||
case vtkCleanUnstructuredGrid::AVERAGING:
|
||||
return std::make_shared<AveragingStrategy>();
|
||||
case vtkCleanUnstructuredGrid::SPATIAL_DENSITY:
|
||||
return std::make_shared<SpatialDensityStrategy>();
|
||||
default:
|
||||
vtkGenericWarningMacro("Incorrect weighing strategy type passed to factory. "
|
||||
"defaulting to FIRST_POINT.");
|
||||
return std::make_shared<FirstPointStrategy>();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct WeighingWorklet
|
||||
{
|
||||
template<typename ArrayTypeIn, typename ArrayTypeOut>
|
||||
void operator()(ArrayTypeIn* inArray,
|
||||
ArrayTypeOut* outArray,
|
||||
vtkDoubleArray* weights,
|
||||
const std::vector<vtkIdType>& ptMap)
|
||||
{
|
||||
outArray->Fill(0);
|
||||
auto inRange = vtk::DataArrayTupleRange(inArray);
|
||||
auto outRange = vtk::DataArrayTupleRange(outArray);
|
||||
auto wRange = vtk::DataArrayValueRange<1>(weights);
|
||||
auto weighing = [&](vtkIdType begin, vtkIdType end) {
|
||||
for (vtkIdType iP = begin; iP < end; ++iP) {
|
||||
if (ptMap[iP] < 0) {
|
||||
continue;
|
||||
}
|
||||
auto inT = inRange[iP];
|
||||
auto outT = outRange[ptMap[iP]];
|
||||
for (vtkIdType iT = 0; iT < inArray->GetNumberOfComponents(); ++iT) {
|
||||
outT[iT] += wRange[iP] * inT[iT];
|
||||
}
|
||||
}
|
||||
};
|
||||
weighing(0, inArray->GetNumberOfTuples());
|
||||
// Merits a dedicated struct with a reduce operation
|
||||
// collisions occuring in the += operation
|
||||
// vtkSMPTools::For(0, inArray->GetNumberOfTuples(), weighing);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
void WeighingWorklet::operator()(vtkBitArray* inArray,
|
||||
vtkBitArray* outArray,
|
||||
vtkDoubleArray* vtkNotUsed(weights),
|
||||
const std::vector<vtkIdType>& ptMap)
|
||||
{
|
||||
outArray->Fill(0);
|
||||
for (vtkIdType iP = 0; iP < inArray->GetNumberOfValues(); ++iP) {
|
||||
if (ptMap[iP] < 0) {
|
||||
continue;
|
||||
}
|
||||
outArray->SetValue(ptMap[iP], inArray->GetValue(iP));
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
void WeighingWorklet::operator()(vtkStringArray* inArray,
|
||||
vtkStringArray* outArray,
|
||||
vtkDoubleArray* vtkNotUsed(weights),
|
||||
const std::vector<vtkIdType>& ptMap)
|
||||
{
|
||||
for (vtkIdType iP = 0; iP < inArray->GetNumberOfValues(); ++iP) {
|
||||
if (ptMap[iP] < 0) {
|
||||
continue;
|
||||
}
|
||||
outArray->SetValue(ptMap[iP], inArray->GetValue(iP));
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
void WeighingWorklet::operator()(vtkAbstractArray* inArray,
|
||||
vtkAbstractArray* outArray,
|
||||
vtkDoubleArray* vtkNotUsed(weights),
|
||||
const std::vector<vtkIdType>& ptMap)
|
||||
{
|
||||
for (vtkIdType iP = 0; iP < inArray->GetNumberOfTuples(); ++iP) {
|
||||
if (ptMap[iP] < 0) {
|
||||
continue;
|
||||
}
|
||||
outArray->InsertTuple(ptMap[iP], iP, inArray);
|
||||
}
|
||||
}
|
||||
|
||||
void WeightAttributes(vtkPointData* inPD,
|
||||
vtkPointData* outPD,
|
||||
vtkDoubleArray* weights,
|
||||
const std::vector<vtkIdType>& ptMap)
|
||||
{
|
||||
// better here to use a Dispatch2BySameArrayType, but that doesn't exist
|
||||
using Dispatcher = vtkArrayDispatch::Dispatch2BySameValueType<vtkArrayDispatch::AllTypes>;
|
||||
WeighingWorklet worker;
|
||||
for (vtkIdType iArr = 0; iArr < inPD->GetNumberOfArrays(); ++iArr) {
|
||||
auto inArr = inPD->GetArray(iArr);
|
||||
// if not data array check for abstract
|
||||
if (!inArr) {
|
||||
auto inAbsArr = inPD->GetAbstractArray(iArr);
|
||||
if (!inAbsArr) {
|
||||
vtkGenericWarningMacro("One of the arrays in the point data is nullptr.");
|
||||
continue;
|
||||
}
|
||||
auto outAbsArr = outPD->GetAbstractArray(inAbsArr->GetName());
|
||||
if (!outAbsArr) {
|
||||
vtkGenericWarningMacro("Output array " << inAbsArr->GetName() << " is nullptr.");
|
||||
continue;
|
||||
}
|
||||
// if string array go to dedicated path
|
||||
auto inStrArr = vtkStringArray::SafeDownCast(inAbsArr);
|
||||
if (inStrArr) {
|
||||
auto outStrArr = vtkStringArray::SafeDownCast(outAbsArr);
|
||||
if (!outStrArr) {
|
||||
vtkGenericWarningMacro("Output array "
|
||||
<< inStrArr->GetName()
|
||||
<< " is not the same type as input string array.");
|
||||
continue;
|
||||
}
|
||||
worker(inStrArr, outStrArr, weights, ptMap);
|
||||
continue;
|
||||
}
|
||||
worker(inAbsArr, outAbsArr, weights, ptMap);
|
||||
continue;
|
||||
}
|
||||
auto outArr = outPD->GetArray(inArr->GetName());
|
||||
if (!outArr) {
|
||||
vtkGenericWarningMacro("Output array " << inArr->GetName()
|
||||
<< " is nullptr or not a vtkDataArray.");
|
||||
continue;
|
||||
}
|
||||
if (!Dispatcher::Execute(inArr, outArr, worker, weights, ptMap)) {
|
||||
auto inBitArr = vtkBitArray::SafeDownCast(inArr);
|
||||
auto outBitArr = vtkBitArray::SafeDownCast(outArr);
|
||||
if (inBitArr && outBitArr) {
|
||||
worker(inBitArr, outBitArr, weights, ptMap);
|
||||
}
|
||||
worker(inArr, outArr, weights, ptMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
vtkStandardNewMacro(vtkCleanUnstructuredGrid);
|
||||
vtkCxxSetSmartPointerMacro(vtkCleanUnstructuredGrid, Locator, vtkIncrementalPointLocator);
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
vtkCleanUnstructuredGrid::vtkCleanUnstructuredGrid() = default;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
vtkCleanUnstructuredGrid::~vtkCleanUnstructuredGrid() = default;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void vtkCleanUnstructuredGrid::PrintSelf(ostream& os, vtkIndent indent)
|
||||
{
|
||||
this->Superclass::PrintSelf(os, indent);
|
||||
|
||||
if (this->Locator) {
|
||||
os << indent << "Locator: ";
|
||||
this->Locator->PrintSelf(os, indent.GetNextIndent());
|
||||
}
|
||||
else {
|
||||
os << indent << "Locator: none\n";
|
||||
}
|
||||
os << indent << "ToleranceIsAbsolute: " << (this->ToleranceIsAbsolute ? "On\n" : "Off\n");
|
||||
os << indent << "Tolerance: " << this->Tolerance << std::endl;
|
||||
os << indent << "AbsoluteTolerance: " << this->AbsoluteTolerance << std::endl;
|
||||
os << indent
|
||||
<< "RemovePointsWithoutCells: " << (this->RemovePointsWithoutCells ? "On\n" : "Off\n");
|
||||
os << indent << "OutputPointsPrecision: " << this->OutputPointsPrecision << std::endl;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
int vtkCleanUnstructuredGrid::RequestData(vtkInformation* vtkNotUsed(request),
|
||||
vtkInformationVector** inputVector,
|
||||
vtkInformationVector* outputVector)
|
||||
{
|
||||
vtkInformation* inInfo = inputVector[0]->GetInformationObject(0);
|
||||
vtkInformation* outInfo = outputVector->GetInformationObject(0);
|
||||
|
||||
vtkDataSet* input = vtkDataSet::SafeDownCast(inInfo->Get(vtkDataObject::DATA_OBJECT()));
|
||||
vtkUnstructuredGrid* output =
|
||||
vtkUnstructuredGrid::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()));
|
||||
|
||||
if (input->GetNumberOfCells() == 0) {
|
||||
// set up a ugrid with same data arrays as input, but
|
||||
// no points, cells or data.
|
||||
output->Allocate(1);
|
||||
output->GetPointData()->CopyAllocate(input->GetPointData(), VTK_CELL_SIZE);
|
||||
output->GetCellData()->CopyAllocate(input->GetCellData(), 1);
|
||||
vtkNew<vtkPoints> pts;
|
||||
output->SetPoints(pts);
|
||||
return 1;
|
||||
}
|
||||
|
||||
output->GetPointData()->CopyAllocate(input->GetPointData());
|
||||
output->GetCellData()->PassData(input->GetCellData());
|
||||
|
||||
// First, create a new points array that eliminate duplicate points.
|
||||
// Also create a mapping from the old point id to the new.
|
||||
vtkNew<vtkPoints> newPts;
|
||||
|
||||
// Set the desired precision for the points in the output.
|
||||
if (this->OutputPointsPrecision == vtkAlgorithm::DEFAULT_PRECISION) {
|
||||
// The logical behaviour would be to use the data type from the input.
|
||||
// However, input is a vtkDataSet, which has no point data type; only the
|
||||
// derived class vtkPointSet has a vtkPoints attribute, so only for that
|
||||
// the logical practice can be applied, while for others (currently
|
||||
// vtkImageData and vtkRectilinearGrid) the data type is the default
|
||||
// for vtkPoints - which is VTK_FLOAT.
|
||||
vtkPointSet* ps = vtkPointSet::SafeDownCast(input);
|
||||
if (ps) {
|
||||
newPts->SetDataType(ps->GetPoints()->GetDataType());
|
||||
}
|
||||
}
|
||||
else if (this->OutputPointsPrecision == vtkAlgorithm::SINGLE_PRECISION) {
|
||||
newPts->SetDataType(VTK_FLOAT);
|
||||
}
|
||||
else if (this->OutputPointsPrecision == vtkAlgorithm::DOUBLE_PRECISION) {
|
||||
newPts->SetDataType(VTK_DOUBLE);
|
||||
}
|
||||
|
||||
vtkIdType num = input->GetNumberOfPoints();
|
||||
vtkIdType id;
|
||||
vtkIdType newId;
|
||||
std::vector<vtkIdType> ptMap(num);
|
||||
double pt[3];
|
||||
|
||||
this->CreateDefaultLocator(input);
|
||||
if (this->ToleranceIsAbsolute) {
|
||||
this->Locator->SetTolerance(this->AbsoluteTolerance);
|
||||
}
|
||||
else {
|
||||
this->Locator->SetTolerance(this->Tolerance * input->GetLength());
|
||||
}
|
||||
double bounds[6];
|
||||
input->GetBounds(bounds);
|
||||
this->Locator->InitPointInsertion(newPts, bounds);
|
||||
|
||||
vtkIdType progressStep = num / 100;
|
||||
if (progressStep == 0) {
|
||||
progressStep = 1;
|
||||
}
|
||||
|
||||
vtkNew<vtkIdList> pointCells;
|
||||
for (id = 0; id < num; ++id) {
|
||||
if (id % progressStep == 0) {
|
||||
this->UpdateProgress(0.8 * ((float)id / num));
|
||||
}
|
||||
|
||||
bool insert = true;
|
||||
if (this->RemovePointsWithoutCells) {
|
||||
input->GetPointCells(id, pointCells);
|
||||
if (pointCells->GetNumberOfIds() == 0) {
|
||||
insert = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (insert) {
|
||||
input->GetPoint(id, pt);
|
||||
this->Locator->InsertUniquePoint(pt, newId);
|
||||
ptMap[id] = newId;
|
||||
}
|
||||
else {
|
||||
// Strictly speaking, this is not needed
|
||||
// as this is never accessed, but better not let
|
||||
// an id undefined.
|
||||
ptMap[id] = -1;
|
||||
}
|
||||
}
|
||||
output->SetPoints(newPts);
|
||||
|
||||
::WeighingStrategyFactory factory;
|
||||
auto strategy = factory(static_cast<DataWeighingType>(this->PointDataWeighingStrategy));
|
||||
auto weights = strategy->ComputeWeights(input, ptMap);
|
||||
auto inPD = input->GetPointData();
|
||||
auto outPD = output->GetPointData();
|
||||
::AllocatePointAttributes(inPD, outPD, output->GetNumberOfPoints());
|
||||
::WeightAttributes(inPD, outPD, weights, ptMap);
|
||||
|
||||
// Now copy the cells.
|
||||
vtkNew<vtkIdList> cellPoints;
|
||||
num = input->GetNumberOfCells();
|
||||
output->Allocate(num);
|
||||
for (id = 0; id < num; ++id) {
|
||||
if (id % progressStep == 0) {
|
||||
this->UpdateProgress(0.8 + 0.2 * (static_cast<float>(id) / num));
|
||||
}
|
||||
// special handling for polyhedron cells
|
||||
if (vtkUnstructuredGrid::SafeDownCast(input) && input->GetCellType(id) == VTK_POLYHEDRON) {
|
||||
vtkUnstructuredGrid::SafeDownCast(input)->GetFaceStream(id, cellPoints);
|
||||
vtkUnstructuredGrid::ConvertFaceStreamPointIds(cellPoints, ptMap.data());
|
||||
}
|
||||
else {
|
||||
input->GetCellPoints(id, cellPoints);
|
||||
for (int i = 0; i < cellPoints->GetNumberOfIds(); i++) {
|
||||
int cellPtId = cellPoints->GetId(i);
|
||||
newId = ptMap[cellPtId];
|
||||
cellPoints->SetId(i, newId);
|
||||
}
|
||||
}
|
||||
output->InsertNextCell(input->GetCellType(id), cellPoints);
|
||||
}
|
||||
|
||||
output->Squeeze();
|
||||
return 1;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
int vtkCleanUnstructuredGrid::FillInputPortInformation(int vtkNotUsed(port), vtkInformation* info)
|
||||
{
|
||||
info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkDataSet");
|
||||
return 1;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
vtkIncrementalPointLocator* vtkCleanUnstructuredGrid::GetLocator()
|
||||
{
|
||||
return this->Locator;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void vtkCleanUnstructuredGrid::CreateDefaultLocator(vtkDataSet* input)
|
||||
{
|
||||
double tol;
|
||||
if (this->ToleranceIsAbsolute) {
|
||||
tol = this->AbsoluteTolerance;
|
||||
}
|
||||
else {
|
||||
if (input) {
|
||||
tol = this->Tolerance * input->GetLength();
|
||||
}
|
||||
else {
|
||||
tol = this->Tolerance;
|
||||
}
|
||||
}
|
||||
|
||||
if (this->Locator.Get() == nullptr) {
|
||||
if (tol == 0.0) {
|
||||
this->Locator = vtkSmartPointer<vtkMergePoints>::New();
|
||||
}
|
||||
else {
|
||||
this->Locator = vtkSmartPointer<vtkPointLocator>::New();
|
||||
}
|
||||
}
|
||||
else {
|
||||
// check that the tolerance wasn't changed from zero to non-zero
|
||||
if ((tol > 0.0) && (this->GetLocator()->GetTolerance() == 0.0)) {
|
||||
this->Locator = vtkSmartPointer<vtkPointLocator>::New();
|
||||
}
|
||||
}
|
||||
}
|
||||
153
src/Mod/Fem/App/VTKExtensions/vtkCleanUnstructuredGrid.h
Normal file
153
src/Mod/Fem/App/VTKExtensions/vtkCleanUnstructuredGrid.h
Normal file
@@ -0,0 +1,153 @@
|
||||
// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
|
||||
// SPDX-FileCopyrightText: Copyright (c) Kitware, Inc.
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
/**
|
||||
* @class vtkCleanUnstructuredGrid
|
||||
* @brief merge duplicate points
|
||||
*
|
||||
*
|
||||
* vtkCleanUnstructuredGrid is a filter that takes unstructured grid data as
|
||||
* input and generates unstructured grid data as output. vtkCleanUnstructuredGrid can
|
||||
* merge duplicate points (with coincident coordinates) using the vtkMergePoints object
|
||||
* to merge points.
|
||||
*
|
||||
* @sa
|
||||
* vtkCleanPolyData
|
||||
*/
|
||||
|
||||
|
||||
#ifndef vtkCleanUnstructuredGrid_h
|
||||
#define vtkCleanUnstructuredGrid_h
|
||||
|
||||
#include "vtkFiltersGeneralModule.h" // For export macro
|
||||
#include "vtkSmartPointer.h"
|
||||
#include "vtkUnstructuredGridAlgorithm.h"
|
||||
|
||||
/*VTK_ABI_NAMESPACE_BEGIN*/
|
||||
|
||||
class vtkIncrementalPointLocator;
|
||||
class vtkDataSet;
|
||||
|
||||
class /*VTKFILTERSGENERAL_EXPORT*/ vtkCleanUnstructuredGrid: public vtkUnstructuredGridAlgorithm
|
||||
{
|
||||
public:
|
||||
static vtkCleanUnstructuredGrid* New();
|
||||
vtkTypeMacro(vtkCleanUnstructuredGrid, vtkUnstructuredGridAlgorithm);
|
||||
void PrintSelf(ostream& os, vtkIndent indent) override;
|
||||
|
||||
///@{
|
||||
/**
|
||||
* By default ToleranceIsAbsolute is false and Tolerance is
|
||||
* a fraction of Bounding box diagonal, if true, AbsoluteTolerance is
|
||||
* used when adding points to locator (merging)
|
||||
*/
|
||||
vtkSetMacro(ToleranceIsAbsolute, bool);
|
||||
vtkBooleanMacro(ToleranceIsAbsolute, bool);
|
||||
vtkGetMacro(ToleranceIsAbsolute, bool);
|
||||
///@}
|
||||
|
||||
///@{
|
||||
/**
|
||||
* Specify tolerance in terms of fraction of bounding box length.
|
||||
* Default is 0.0.
|
||||
*/
|
||||
vtkSetClampMacro(Tolerance, double, 0.0, 1.0);
|
||||
vtkGetMacro(Tolerance, double);
|
||||
///@}
|
||||
|
||||
///@{
|
||||
/**
|
||||
* Specify tolerance in absolute terms. Default is 1.0.
|
||||
*/
|
||||
vtkSetClampMacro(AbsoluteTolerance, double, 0.0, VTK_DOUBLE_MAX);
|
||||
vtkGetMacro(AbsoluteTolerance, double);
|
||||
///@}
|
||||
|
||||
///@{
|
||||
/**
|
||||
* Set/Get a spatial locator for speeding the search process. By
|
||||
* default an instance of vtkMergePoints is used.
|
||||
*/
|
||||
virtual void SetLocator(vtkIncrementalPointLocator* locator);
|
||||
virtual vtkIncrementalPointLocator* GetLocator();
|
||||
///@}
|
||||
|
||||
/**
|
||||
* Create default locator. Used to create one when none is specified.
|
||||
*/
|
||||
void CreateDefaultLocator(vtkDataSet* input = nullptr);
|
||||
|
||||
/**
|
||||
* Release locator
|
||||
*/
|
||||
void ReleaseLocator()
|
||||
{
|
||||
this->SetLocator(nullptr);
|
||||
}
|
||||
|
||||
///@{
|
||||
/**
|
||||
* Set/get the desired precision for the output types. See the documentation
|
||||
* for the vtkAlgorithm::DesiredOutputPrecision enum for an explanation of
|
||||
* the available precision settings.
|
||||
*/
|
||||
vtkSetMacro(OutputPointsPrecision, int);
|
||||
vtkGetMacro(OutputPointsPrecision, int);
|
||||
///@}
|
||||
|
||||
///@{
|
||||
/**
|
||||
* Set/Get whether to remove points that do not
|
||||
* have any cells associated with it.
|
||||
* Default is false
|
||||
*/
|
||||
vtkSetMacro(RemovePointsWithoutCells, bool);
|
||||
vtkGetMacro(RemovePointsWithoutCells, bool);
|
||||
vtkBooleanMacro(RemovePointsWithoutCells, bool);
|
||||
///@}
|
||||
|
||||
///@{
|
||||
/**
|
||||
* Set/Get the strategy used to weigh point data on merging points
|
||||
*
|
||||
* Possibilities:
|
||||
* - FIRST_POINT (int(0), default): the point with the lowest index imposes its data on to the
|
||||
* merged point
|
||||
* - AVERAGING (int(1)): a number average is performed on all the duplicate points
|
||||
* - SPATIAL_DENSITY (int(2)): an average by attached cell volume (i.e. for every cell the point
|
||||
* is connected to sum cell_volume/number_cell_points) is performed on the point data
|
||||
*/
|
||||
vtkGetMacro(PointDataWeighingStrategy, int);
|
||||
vtkSetClampMacro(PointDataWeighingStrategy, int, FIRST_POINT, NUMBER_OF_WEIGHING_TYPES - 1);
|
||||
///@}
|
||||
|
||||
enum DataWeighingType
|
||||
{
|
||||
FIRST_POINT = 0,
|
||||
AVERAGING,
|
||||
SPATIAL_DENSITY,
|
||||
NUMBER_OF_WEIGHING_TYPES
|
||||
};
|
||||
|
||||
protected:
|
||||
vtkCleanUnstructuredGrid();
|
||||
~vtkCleanUnstructuredGrid() override;
|
||||
|
||||
bool ToleranceIsAbsolute = false;
|
||||
double Tolerance = 0.0;
|
||||
double AbsoluteTolerance = 1.0;
|
||||
bool RemovePointsWithoutCells = false;
|
||||
vtkSmartPointer<vtkIncrementalPointLocator> Locator;
|
||||
int OutputPointsPrecision = vtkAlgorithm::DEFAULT_PRECISION;
|
||||
int PointDataWeighingStrategy = FIRST_POINT;
|
||||
|
||||
int RequestData(vtkInformation*, vtkInformationVector**, vtkInformationVector*) override;
|
||||
int FillInputPortInformation(int port, vtkInformation* info) override;
|
||||
|
||||
private:
|
||||
vtkCleanUnstructuredGrid(const vtkCleanUnstructuredGrid&) = delete;
|
||||
void operator=(const vtkCleanUnstructuredGrid&) = delete;
|
||||
};
|
||||
/*VTK_ABI_NAMESPACE_END*/
|
||||
#endif
|
||||
// VTK-HeaderTest-Exclude: vtkCleanUnstructuredGrid.h
|
||||
604
src/Mod/Fem/App/VTKExtensions/vtkSMPTools.h
Normal file
604
src/Mod/Fem/App/VTKExtensions/vtkSMPTools.h
Normal file
@@ -0,0 +1,604 @@
|
||||
/*=========================================================================
|
||||
|
||||
Program: Visualization Toolkit
|
||||
Module: vtkSMPTools.h
|
||||
|
||||
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
|
||||
All rights reserved.
|
||||
See Copyright.txt or http://www.kitware.com/Copyright.htm 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.
|
||||
|
||||
=========================================================================*/
|
||||
/**
|
||||
* @class vtkSMPTools
|
||||
* @brief A set of parallel (multi-threaded) utility functions.
|
||||
*
|
||||
* vtkSMPTools provides a set of utility functions that can
|
||||
* be used to parallelize parts of VTK code using multiple threads.
|
||||
* There are several back-end implementations of parallel functionality
|
||||
* (currently Sequential, TBB, OpenMP and STDThread) that actual execution is
|
||||
* delegated to.
|
||||
*
|
||||
* @sa
|
||||
* vtkSMPThreadLocal
|
||||
* vtkSMPThreadLocalObject
|
||||
*/
|
||||
|
||||
#ifndef vtkSMPTools_h
|
||||
#define vtkSMPTools_h
|
||||
|
||||
#include "vtkCommonCoreModule.h" // For export macro
|
||||
#include "vtkObject.h"
|
||||
|
||||
#include "SMP/Common/vtkSMPToolsAPI.h"
|
||||
#include "vtkSMPThreadLocal.h" // For Initialized
|
||||
|
||||
#include <functional> // For std::function
|
||||
#include <iterator> // For std::iterator
|
||||
#include <type_traits> // For std:::enable_if
|
||||
|
||||
#ifndef DOXYGEN_SHOULD_SKIP_THIS
|
||||
namespace vtk
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
namespace smp
|
||||
{
|
||||
template<typename T>
|
||||
class vtkSMPTools_Has_Initialize
|
||||
{
|
||||
typedef char (&no_type)[1];
|
||||
typedef char (&yes_type)[2];
|
||||
template<typename U, void (U::*)()>
|
||||
struct V
|
||||
{
|
||||
};
|
||||
template<typename U>
|
||||
static yes_type check(V<U, &U::Initialize>*);
|
||||
template<typename U>
|
||||
static no_type check(...);
|
||||
|
||||
public:
|
||||
static bool const value = sizeof(check<T>(nullptr)) == sizeof(yes_type);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class vtkSMPTools_Has_Initialize_const
|
||||
{
|
||||
typedef char (&no_type)[1];
|
||||
typedef char (&yes_type)[2];
|
||||
template<typename U, void (U::*)() const>
|
||||
struct V
|
||||
{
|
||||
};
|
||||
template<typename U>
|
||||
static yes_type check(V<U, &U::Initialize>*);
|
||||
template<typename U>
|
||||
static no_type check(...);
|
||||
|
||||
public:
|
||||
static bool const value = sizeof(check<T>(0)) == sizeof(yes_type);
|
||||
};
|
||||
|
||||
template<typename Functor, bool Init>
|
||||
struct vtkSMPTools_FunctorInternal;
|
||||
|
||||
template<typename Functor>
|
||||
struct vtkSMPTools_FunctorInternal<Functor, false>
|
||||
{
|
||||
Functor& F;
|
||||
vtkSMPTools_FunctorInternal(Functor& f)
|
||||
: F(f)
|
||||
{}
|
||||
void Execute(vtkIdType first, vtkIdType last)
|
||||
{
|
||||
this->F(first, last);
|
||||
}
|
||||
void For(vtkIdType first, vtkIdType last, vtkIdType grain)
|
||||
{
|
||||
auto& SMPToolsAPI = vtkSMPToolsAPI::GetInstance();
|
||||
SMPToolsAPI.For(first, last, grain, *this);
|
||||
}
|
||||
vtkSMPTools_FunctorInternal<Functor, false>&
|
||||
operator=(const vtkSMPTools_FunctorInternal<Functor, false>&);
|
||||
vtkSMPTools_FunctorInternal(const vtkSMPTools_FunctorInternal<Functor, false>&);
|
||||
};
|
||||
|
||||
template<typename Functor>
|
||||
struct vtkSMPTools_FunctorInternal<Functor, true>
|
||||
{
|
||||
Functor& F;
|
||||
vtkSMPThreadLocal<unsigned char> Initialized;
|
||||
vtkSMPTools_FunctorInternal(Functor& f)
|
||||
: F(f)
|
||||
, Initialized(0)
|
||||
{}
|
||||
void Execute(vtkIdType first, vtkIdType last)
|
||||
{
|
||||
unsigned char& inited = this->Initialized.Local();
|
||||
if (!inited) {
|
||||
this->F.Initialize();
|
||||
inited = 1;
|
||||
}
|
||||
this->F(first, last);
|
||||
}
|
||||
void For(vtkIdType first, vtkIdType last, vtkIdType grain)
|
||||
{
|
||||
auto& SMPToolsAPI = vtkSMPToolsAPI::GetInstance();
|
||||
SMPToolsAPI.For(first, last, grain, *this);
|
||||
this->F.Reduce();
|
||||
}
|
||||
vtkSMPTools_FunctorInternal<Functor, true>&
|
||||
operator=(const vtkSMPTools_FunctorInternal<Functor, true>&);
|
||||
vtkSMPTools_FunctorInternal(const vtkSMPTools_FunctorInternal<Functor, true>&);
|
||||
};
|
||||
|
||||
template<typename Functor>
|
||||
class vtkSMPTools_Lookup_For
|
||||
{
|
||||
static bool const init = vtkSMPTools_Has_Initialize<Functor>::value;
|
||||
|
||||
public:
|
||||
typedef vtkSMPTools_FunctorInternal<Functor, init> type;
|
||||
};
|
||||
|
||||
template<typename Functor>
|
||||
class vtkSMPTools_Lookup_For<Functor const>
|
||||
{
|
||||
static bool const init = vtkSMPTools_Has_Initialize_const<Functor>::value;
|
||||
|
||||
public:
|
||||
typedef vtkSMPTools_FunctorInternal<Functor const, init> type;
|
||||
};
|
||||
|
||||
template<typename Iterator, typename Functor, bool Init>
|
||||
struct vtkSMPTools_RangeFunctor;
|
||||
|
||||
template<typename Iterator, typename Functor>
|
||||
struct vtkSMPTools_RangeFunctor<Iterator, Functor, false>
|
||||
{
|
||||
Functor& F;
|
||||
Iterator& Begin;
|
||||
vtkSMPTools_RangeFunctor(Iterator& begin, Functor& f)
|
||||
: F(f)
|
||||
, Begin(begin)
|
||||
{}
|
||||
void operator()(vtkIdType first, vtkIdType last)
|
||||
{
|
||||
Iterator itFirst(Begin);
|
||||
std::advance(itFirst, first);
|
||||
Iterator itLast(itFirst);
|
||||
std::advance(itLast, last - first);
|
||||
this->F(itFirst, itLast);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Iterator, typename Functor>
|
||||
struct vtkSMPTools_RangeFunctor<Iterator, Functor, true>
|
||||
{
|
||||
Functor& F;
|
||||
Iterator& Begin;
|
||||
vtkSMPTools_RangeFunctor(Iterator& begin, Functor& f)
|
||||
: F(f)
|
||||
, Begin(begin)
|
||||
{}
|
||||
void Initialize()
|
||||
{
|
||||
this->F.Initialize();
|
||||
}
|
||||
void operator()(vtkIdType first, vtkIdType last)
|
||||
{
|
||||
Iterator itFirst(Begin);
|
||||
std::advance(itFirst, first);
|
||||
Iterator itLast(itFirst);
|
||||
std::advance(itLast, last - first);
|
||||
this->F(itFirst, itLast);
|
||||
}
|
||||
void Reduce()
|
||||
{
|
||||
this->F.Reduce();
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Iterator, typename Functor>
|
||||
class vtkSMPTools_Lookup_RangeFor
|
||||
{
|
||||
static bool const init = vtkSMPTools_Has_Initialize<Functor>::value;
|
||||
|
||||
public:
|
||||
typedef vtkSMPTools_RangeFunctor<Iterator, Functor, init> type;
|
||||
};
|
||||
|
||||
template<typename Iterator, typename Functor>
|
||||
class vtkSMPTools_Lookup_RangeFor<Iterator, Functor const>
|
||||
{
|
||||
static bool const init = vtkSMPTools_Has_Initialize_const<Functor>::value;
|
||||
|
||||
public:
|
||||
typedef vtkSMPTools_RangeFunctor<Iterator, Functor const, init> type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
using resolvedNotInt = typename std::enable_if<!std::is_integral<T>::value, void>::type;
|
||||
} // namespace smp
|
||||
} // namespace detail
|
||||
} // namespace vtk
|
||||
#endif // DOXYGEN_SHOULD_SKIP_THIS
|
||||
|
||||
class VTKCOMMONCORE_EXPORT vtkSMPTools
|
||||
{
|
||||
public:
|
||||
///@{
|
||||
/**
|
||||
* Execute a for operation in parallel. First and last
|
||||
* define the range over which to operate (which is defined
|
||||
* by the operator). The operation executed is defined by
|
||||
* operator() of the functor object. The grain gives the parallel
|
||||
* engine a hint about the coarseness over which to parallelize
|
||||
* the function (as defined by last-first of each execution of
|
||||
* operator() ).
|
||||
*/
|
||||
template<typename Functor>
|
||||
static void For(vtkIdType first, vtkIdType last, vtkIdType grain, Functor& f)
|
||||
{
|
||||
typename vtk::detail::smp::vtkSMPTools_Lookup_For<Functor>::type fi(f);
|
||||
fi.For(first, last, grain);
|
||||
}
|
||||
|
||||
template<typename Functor>
|
||||
static void For(vtkIdType first, vtkIdType last, vtkIdType grain, Functor const& f)
|
||||
{
|
||||
typename vtk::detail::smp::vtkSMPTools_Lookup_For<Functor const>::type fi(f);
|
||||
fi.For(first, last, grain);
|
||||
}
|
||||
///@}
|
||||
|
||||
///@{
|
||||
/**
|
||||
* Execute a for operation in parallel. First and last
|
||||
* define the range over which to operate (which is defined
|
||||
* by the operator). The operation executed is defined by
|
||||
* operator() of the functor object. The grain gives the parallel
|
||||
* engine a hint about the coarseness over which to parallelize
|
||||
* the function (as defined by last-first of each execution of
|
||||
* operator() ). Uses a default value for the grain.
|
||||
*/
|
||||
template<typename Functor>
|
||||
static void For(vtkIdType first, vtkIdType last, Functor& f)
|
||||
{
|
||||
vtkSMPTools::For(first, last, 0, f);
|
||||
}
|
||||
|
||||
template<typename Functor>
|
||||
static void For(vtkIdType first, vtkIdType last, Functor const& f)
|
||||
{
|
||||
vtkSMPTools::For(first, last, 0, f);
|
||||
}
|
||||
///@}
|
||||
|
||||
///@{
|
||||
/**
|
||||
* Execute a for operation in parallel. Begin and end iterators
|
||||
* define the range over which to operate (which is defined
|
||||
* by the operator). The operation executed is defined by
|
||||
* operator() of the functor object. The grain gives the parallel
|
||||
* engine a hint about the coarseness over which to parallelize
|
||||
* the function (as defined by last-first of each execution of
|
||||
* operator() ).
|
||||
*
|
||||
* Usage example:
|
||||
* \code
|
||||
* template<class IteratorT>
|
||||
* class ExampleFunctor
|
||||
* {
|
||||
* void operator()(IteratorT begin, IteratorT end)
|
||||
* {
|
||||
* for (IteratorT it = begin; it != end; ++it)
|
||||
* {
|
||||
* // Do stuff
|
||||
* }
|
||||
* }
|
||||
* };
|
||||
* ExampleFunctor<std::set<int>::iterator> worker;
|
||||
* vtkSMPTools::For(container.begin(), container.end(), 5, worker);
|
||||
* \endcode
|
||||
*
|
||||
* Lambda are also supported through Functor const&
|
||||
* function overload:
|
||||
* \code
|
||||
* vtkSMPTools::For(container.begin(), container.end(), 5,
|
||||
* [](std::set<int>::iterator begin, std::set<int>::iterator end) {
|
||||
* // Do stuff
|
||||
* });
|
||||
* \endcode
|
||||
*/
|
||||
template<typename Iter, typename Functor>
|
||||
static vtk::detail::smp::resolvedNotInt<Iter>
|
||||
For(Iter begin, Iter end, vtkIdType grain, Functor& f)
|
||||
{
|
||||
vtkIdType size = std::distance(begin, end);
|
||||
typename vtk::detail::smp::vtkSMPTools_Lookup_RangeFor<Iter, Functor>::type fi(begin, f);
|
||||
vtkSMPTools::For(0, size, grain, fi);
|
||||
}
|
||||
|
||||
template<typename Iter, typename Functor>
|
||||
static vtk::detail::smp::resolvedNotInt<Iter>
|
||||
For(Iter begin, Iter end, vtkIdType grain, Functor const& f)
|
||||
{
|
||||
vtkIdType size = std::distance(begin, end);
|
||||
typename vtk::detail::smp::vtkSMPTools_Lookup_RangeFor<Iter, Functor const>::type fi(begin,
|
||||
f);
|
||||
vtkSMPTools::For(0, size, grain, fi);
|
||||
}
|
||||
///@}
|
||||
|
||||
///@{
|
||||
/**
|
||||
* Execute a for operation in parallel. Begin and end iterators
|
||||
* define the range over which to operate (which is defined
|
||||
* by the operator). The operation executed is defined by
|
||||
* operator() of the functor object. Uses a default value
|
||||
* for the grain.
|
||||
*
|
||||
* Usage example:
|
||||
* \code
|
||||
* template<class IteratorT>
|
||||
* class ExampleFunctor
|
||||
* {
|
||||
* void operator()(IteratorT begin, IteratorT end)
|
||||
* {
|
||||
* for (IteratorT it = begin; it != end; ++it)
|
||||
* {
|
||||
* // Do stuff
|
||||
* }
|
||||
* }
|
||||
* };
|
||||
* ExampleFunctor<std::set<int>::iterator> worker;
|
||||
* vtkSMPTools::For(container.begin(), container.end(), worker);
|
||||
* \endcode
|
||||
*
|
||||
* Lambda are also supported through Functor const&
|
||||
* function overload:
|
||||
* \code
|
||||
* vtkSMPTools::For(container.begin(), container.end(),
|
||||
* [](std::set<int>::iterator begin, std::set<int>::iterator end) {
|
||||
* // Do stuff
|
||||
* });
|
||||
* \endcode
|
||||
*/
|
||||
template<typename Iter, typename Functor>
|
||||
static vtk::detail::smp::resolvedNotInt<Iter> For(Iter begin, Iter end, Functor& f)
|
||||
{
|
||||
vtkSMPTools::For(begin, end, 0, f);
|
||||
}
|
||||
|
||||
template<typename Iter, typename Functor>
|
||||
static vtk::detail::smp::resolvedNotInt<Iter> For(Iter begin, Iter end, Functor const& f)
|
||||
{
|
||||
vtkSMPTools::For(begin, end, 0, f);
|
||||
}
|
||||
///@}
|
||||
|
||||
/**
|
||||
* Get the backend in use.
|
||||
*/
|
||||
static const char* GetBackend();
|
||||
|
||||
/**
|
||||
* /!\ This method is not thread safe.
|
||||
* Change the backend in use.
|
||||
* The options can be: "Sequential", "STDThread", "TBB" or "OpenMP"
|
||||
*
|
||||
* VTK_SMP_BACKEND_IN_USE env variable can also be used to set the default SMPTools
|
||||
* backend, in that case SetBackend() doesn't need to be called.
|
||||
* The backend selected with SetBackend() have the priority over VTK_SMP_BACKEND_IN_USE.
|
||||
*
|
||||
* SetBackend() will return true if the backend was found and available.
|
||||
*/
|
||||
static bool SetBackend(const char* backend);
|
||||
|
||||
/**
|
||||
* /!\ This method is not thread safe.
|
||||
* Initialize the underlying libraries for execution. This is
|
||||
* not required as it is automatically defined by the libaries.
|
||||
* However, it can be used to control the maximum number of thread used.
|
||||
* Make sure to call it before the parallel operation.
|
||||
*
|
||||
* If Initialize is called without argument it will reset
|
||||
* to the maximum number of threads or use the VTK_SMP_MAX_THREADS
|
||||
* env variable if it is defined.
|
||||
*
|
||||
* Note: If VTK_SMP_MAX_THREADS env variable is defined the SMPTools will try
|
||||
* to use it to set the maximum number of threads. Initialize() doesn't
|
||||
* need to be called.
|
||||
*/
|
||||
static void Initialize(int numThreads = 0);
|
||||
|
||||
/**
|
||||
* Get the estimated number of threads being used by the backend.
|
||||
* This should be used as just an estimate since the number of threads may
|
||||
* vary dynamically and a particular task may not be executed on all the
|
||||
* available threads.
|
||||
*/
|
||||
static int GetEstimatedNumberOfThreads();
|
||||
|
||||
/**
|
||||
* /!\ This method is not thread safe.
|
||||
* If true enable nested parallelism for underlying backends.
|
||||
* When enabled the comportement is different for each backend:
|
||||
* - TBB support nested parallelism by default.
|
||||
* - For OpenMP, we set `omp_set_nested` to true so that it is supported.
|
||||
* - STDThread support nested parallelism by creating new threads pools.
|
||||
* - For Sequential nothing changes.
|
||||
*
|
||||
* Default to true
|
||||
*/
|
||||
static void SetNestedParallelism(bool isNested);
|
||||
|
||||
/**
|
||||
* Get true if the nested parallelism is enabled.
|
||||
*/
|
||||
static bool GetNestedParallelism();
|
||||
|
||||
/**
|
||||
* Return true if it is called from a parallel scope.
|
||||
*/
|
||||
static bool IsParallelScope();
|
||||
|
||||
/**
|
||||
* Structure used to specify configuration for LocalScope() method.
|
||||
* Several parameters can be configured:
|
||||
* - MaxNumberOfThreads set the maximum number of threads.
|
||||
* - Backend set a specific SMPTools backend.
|
||||
* - NestedParallelism, if true enable nested parallelism.
|
||||
*/
|
||||
struct Config
|
||||
{
|
||||
int MaxNumberOfThreads = 0;
|
||||
std::string Backend = vtk::detail::smp::vtkSMPToolsAPI::GetInstance().GetBackend();
|
||||
bool NestedParallelism = true;
|
||||
|
||||
Config()
|
||||
{}
|
||||
Config(int maxNumberOfThreads)
|
||||
: MaxNumberOfThreads(maxNumberOfThreads)
|
||||
{}
|
||||
Config(std::string backend)
|
||||
: Backend(backend)
|
||||
{}
|
||||
Config(bool nestedParallelism)
|
||||
: NestedParallelism(nestedParallelism)
|
||||
{}
|
||||
Config(int maxNumberOfThreads, std::string backend, bool nestedParallelism)
|
||||
: MaxNumberOfThreads(maxNumberOfThreads)
|
||||
, Backend(backend)
|
||||
, NestedParallelism(nestedParallelism)
|
||||
{}
|
||||
#ifndef DOXYGEN_SHOULD_SKIP_THIS
|
||||
Config(vtk::detail::smp::vtkSMPToolsAPI& API)
|
||||
: MaxNumberOfThreads(API.GetInternalDesiredNumberOfThread())
|
||||
, Backend(API.GetBackend())
|
||||
, NestedParallelism(API.GetNestedParallelism())
|
||||
{}
|
||||
#endif // DOXYGEN_SHOULD_SKIP_THIS
|
||||
};
|
||||
|
||||
/**
|
||||
* /!\ This method is not thread safe.
|
||||
* Change the number of threads locally within this scope and call a functor which
|
||||
* should contains a vtkSMPTools method.
|
||||
*
|
||||
* Usage example:
|
||||
* \code
|
||||
* vtkSMPTools::LocalScope(
|
||||
* vtkSMPTools::Config{ 4, "OpenMP", false }, [&]() { vtkSMPTools::For(0, size, worker); });
|
||||
* \endcode
|
||||
*/
|
||||
template<typename T>
|
||||
static void LocalScope(Config const& config, T&& lambda)
|
||||
{
|
||||
auto& SMPToolsAPI = vtk::detail::smp::vtkSMPToolsAPI::GetInstance();
|
||||
SMPToolsAPI.LocalScope<vtkSMPTools::Config>(config, lambda);
|
||||
}
|
||||
|
||||
/**
|
||||
* A convenience method for transforming data. It is a drop in replacement for
|
||||
* std::transform(), it does a unary operation on the input ranges. The data array must have the
|
||||
* same length. The performed transformation is defined by operator() of the functor object.
|
||||
*
|
||||
* Usage example with vtkDataArray:
|
||||
* \code
|
||||
* const auto range0 = vtk::DataArrayValueRange<1>(array0);
|
||||
* auto range1 = vtk::DataArrayValueRange<1>(array1);
|
||||
* vtkSMPTools::Transform(
|
||||
* range0.cbegin(), range0.cend(), range1.begin(), [](double x) { return x - 1; });
|
||||
* \endcode
|
||||
*
|
||||
* Please visit vtkDataArrayRange.h documentation for more information and optimisation.
|
||||
*/
|
||||
template<typename InputIt, typename OutputIt, typename Functor>
|
||||
static void Transform(InputIt inBegin, InputIt inEnd, OutputIt outBegin, Functor transform)
|
||||
{
|
||||
auto& SMPToolsAPI = vtk::detail::smp::vtkSMPToolsAPI::GetInstance();
|
||||
SMPToolsAPI.Transform(inBegin, inEnd, outBegin, transform);
|
||||
}
|
||||
|
||||
/**
|
||||
* A convenience method for transforming data. It is a drop in replacement for
|
||||
* std::transform(), it does a binary operation on the input ranges. The data array must have
|
||||
* the same length. The performed transformation is defined by operator() of the functor object.
|
||||
*
|
||||
* Usage example with vtkDataArray:
|
||||
* \code
|
||||
* const auto range0 = vtk::DataArrayValueRange<1>(array0);
|
||||
* auto range1 = vtk::DataArrayValueRange<1>(array1);
|
||||
* vtkSMPTools::Transform(
|
||||
* range0.cbegin(), range0.cend(), range1.cbegin(), range1.begin(),
|
||||
* [](double x, double y) { return x * y; });
|
||||
* \endcode
|
||||
*
|
||||
* Please visit vtkDataArrayRange.h documentation for more information and optimisation.
|
||||
*/
|
||||
template<typename InputIt1, typename InputIt2, typename OutputIt, typename Functor>
|
||||
static void Transform(InputIt1 inBegin1,
|
||||
InputIt1 inEnd,
|
||||
InputIt2 inBegin2,
|
||||
OutputIt outBegin,
|
||||
Functor transform)
|
||||
{
|
||||
auto& SMPToolsAPI = vtk::detail::smp::vtkSMPToolsAPI::GetInstance();
|
||||
SMPToolsAPI.Transform(inBegin1, inEnd, inBegin2, outBegin, transform);
|
||||
}
|
||||
|
||||
/**
|
||||
* A convenience method for filling data. It is a drop in replacement for std::fill(),
|
||||
* it assign the given value to the element in ranges.
|
||||
*
|
||||
* Usage example with vtkDataArray:
|
||||
* \code
|
||||
* // Fill range with its first tuple value
|
||||
* auto range = vtk::DataArrayTupleRange<1>(array);
|
||||
* const auto value = *range.begin();
|
||||
* vtkSMPTools::Fill(range.begin(), range.end(), value);
|
||||
* \endcode
|
||||
*
|
||||
* Please visit vtkDataArrayRange.h documentation for more information and optimisation.
|
||||
*/
|
||||
template<typename Iterator, typename T>
|
||||
static void Fill(Iterator begin, Iterator end, const T& value)
|
||||
{
|
||||
auto& SMPToolsAPI = vtk::detail::smp::vtkSMPToolsAPI::GetInstance();
|
||||
SMPToolsAPI.Fill(begin, end, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* A convenience method for sorting data. It is a drop in replacement for
|
||||
* std::sort(). Under the hood different methods are used. For example,
|
||||
* tbb::parallel_sort is used in TBB.
|
||||
*/
|
||||
template<typename RandomAccessIterator>
|
||||
static void Sort(RandomAccessIterator begin, RandomAccessIterator end)
|
||||
{
|
||||
auto& SMPToolsAPI = vtk::detail::smp::vtkSMPToolsAPI::GetInstance();
|
||||
SMPToolsAPI.Sort(begin, end);
|
||||
}
|
||||
|
||||
/**
|
||||
* A convenience method for sorting data. It is a drop in replacement for
|
||||
* std::sort(). Under the hood different methods are used. For example,
|
||||
* tbb::parallel_sort is used in TBB. This version of Sort() takes a
|
||||
* comparison class.
|
||||
*/
|
||||
template<typename RandomAccessIterator, typename Compare>
|
||||
static void Sort(RandomAccessIterator begin, RandomAccessIterator end, Compare comp)
|
||||
{
|
||||
auto& SMPToolsAPI = vtk::detail::smp::vtkSMPToolsAPI::GetInstance();
|
||||
SMPToolsAPI.Sort(begin, end, comp);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
// VTK-HeaderTest-Exclude: vtkSMPTools.h
|
||||
Reference in New Issue
Block a user