Commit 6aa99aec authored by Kenneth Moreland's avatar Kenneth Moreland

Add ability to remove degenerate cells in CleanGrid

parent 5688375c
......@@ -378,6 +378,13 @@ inline vtkm::cont::DataSet MakeTestDataSet::Make3DUniformDataSet3(const vtkm::Id
vtkm::cont::DataSetFieldAdd dsf;
dsf.AddPointField(dataSet, "pointvar", pointvar);
vtkm::Id numCells = (dims[0] - 1) * (dims[1] - 1) * (dims[2] - 1);
dsf.AddCellField(
dataSet,
"cellvar",
vtkm::cont::make_ArrayHandleCounting(vtkm::Float64(0), vtkm::Float64(1), numCells));
return dataSet;
}
......
......@@ -23,6 +23,7 @@
#include <vtkm/filter/FilterDataSet.h>
#include <vtkm/worklet/PointMerge.h>
#include <vtkm/worklet/RemoveDegenerateCells.h>
#include <vtkm/worklet/RemoveUnusedPoints.h>
namespace vtkm
......@@ -77,6 +78,12 @@ public:
VTKM_CONT bool GetToleranceIsAbsolute() const { return this->ToleranceIsAbsolute; }
VTKM_CONT void SetToleranceIsAbsolute(bool flag) { this->ToleranceIsAbsolute = flag; }
/// Determine whether a cell is degenerate (that is, has repeated points that drops
/// its dimensionalit) and removes them. This is on by default.
///
VTKM_CONT bool GetRemoveDegenerateCells() const { return this->RemoveDegenerateCells; }
VTKM_CONT void SetRemoveDegenerateCells(bool flag) { this->RemoveDegenerateCells = flag; }
/// When FastMerge is true (the default), some corners are cut when computing
/// coincident points. The point merge will go faster but the tolerance will not
/// be strictly followed.
......@@ -103,14 +110,18 @@ private:
bool MergePoints;
vtkm::Float64 Tolerance;
bool ToleranceIsAbsolute;
bool RemoveDegenerateCells;
bool FastMerge;
vtkm::worklet::RemoveUnusedPoints PointCompactor;
vtkm::worklet::RemoveDegenerateCells CellCompactor;
vtkm::worklet::PointMerge PointMerger;
};
}
} // namespace vtkm::filter
#ifndef vtk_m_filter_CleanGrid_hxx
#include <vtkm/filter/CleanGrid.hxx>
#endif
#endif //vtk_m_filter_CleanGrid_h
......@@ -38,6 +38,7 @@ inline VTKM_CONT CleanGrid::CleanGrid()
, MergePoints(true)
, Tolerance(1.0e-6)
, ToleranceIsAbsolute(false)
, RemoveDegenerateCells(true)
, FastMerge(true)
{
}
......@@ -52,15 +53,24 @@ inline VTKM_CONT vtkm::cont::DataSet CleanGrid::DoExecute(const vtkm::cont::Data
VecId numCellSets = static_cast<VecId>(inData.GetNumberOfCellSets());
std::vector<CellSetType> outputCellSets(numCellSets);
VecId activeCoordIndex = static_cast<VecId>(this->GetActiveCoordinateSystemIndex());
// Do a deep copy of the cells to new CellSetExplicit structures
for (VecId cellSetIndex = 0; cellSetIndex < numCellSets; ++cellSetIndex)
{
vtkm::cont::DynamicCellSet inCellSet =
inData.GetCellSet(static_cast<vtkm::IdComponent>(cellSetIndex));
if (inCellSet.IsType<CellSetType>())
{
// Is expected type, do a shallow copy
outputCellSets[cellSetIndex] = inCellSet.Cast<CellSetType>();
}
else
{
vtkm::worklet::CellDeepCopy::Run(vtkm::filter::ApplyPolicy(inCellSet, policy),
outputCellSets[cellSetIndex]);
}
}
VecId numCoordSystems = static_cast<VecId>(inData.GetNumberOfCoordinateSystems());
std::vector<vtkm::cont::CoordinateSystem> outputCoordinateSystems(numCoordSystems);
......@@ -99,8 +109,7 @@ inline VTKM_CONT vtkm::cont::DataSet CleanGrid::DoExecute(const vtkm::cont::Data
// Optionally find and merge coincident points
if (this->GetMergePoints())
{
vtkm::cont::CoordinateSystem activeCoordSystem =
outputCoordinateSystems[static_cast<VecId>(this->GetActiveCoordinateSystemIndex())];
vtkm::cont::CoordinateSystem activeCoordSystem = outputCoordinateSystems[activeCoordIndex];
vtkm::Bounds bounds = activeCoordSystem.GetBounds();
vtkm::Float64 delta = this->GetTolerance();
......@@ -116,7 +125,7 @@ inline VTKM_CONT vtkm::cont::DataSet CleanGrid::DoExecute(const vtkm::cont::Data
for (VecId coordSystemIndex = 0; coordSystemIndex < numCoordSystems; ++coordSystemIndex)
{
if (coordSystemIndex == static_cast<VecId>(this->GetActiveCoordinateSystemIndex()))
if (coordSystemIndex == activeCoordIndex)
{
outputCoordinateSystems[coordSystemIndex] = activeCoordSystem;
}
......@@ -134,6 +143,12 @@ inline VTKM_CONT vtkm::cont::DataSet CleanGrid::DoExecute(const vtkm::cont::Data
}
}
// Optionally remove degenerate cells
if (this->GetRemoveDegenerateCells())
{
outputCellSets[activeCoordIndex] = this->CellCompactor.Run(outputCellSets[activeCoordIndex]);
}
// Construct resulting data set with new cell sets
vtkm::cont::DataSet outData;
for (VecId cellSetIndex = 0; cellSetIndex < numCellSets; cellSetIndex++)
......@@ -174,6 +189,10 @@ inline VTKM_CONT bool CleanGrid::DoMapField(
}
result.AddField(fieldMeta.AsField(compactedArray));
}
else if (fieldMeta.IsCellField() && this->GetRemoveDegenerateCells())
{
result.AddField(fieldMeta.AsField(this->CellCompactor.ProcessCellField(input)));
}
else
{
result.AddField(fieldMeta.AsField(input));
......
......@@ -97,6 +97,7 @@ void TestPointMerging()
std::cout << "Clean grid without any merging" << std::endl;
cleanGrid.SetCompactPointFields(false);
cleanGrid.SetMergePoints(false);
cleanGrid.SetRemoveDegenerateCells(false);
vtkm::cont::DataSet noMerging = cleanGrid.Execute(inData);
VTKM_TEST_ASSERT(noMerging.GetCellSet().GetNumberOfCells() == originalNumCells);
VTKM_TEST_ASSERT(noMerging.GetCellSet().GetNumberOfPoints() == originalNumPoints);
......@@ -104,6 +105,7 @@ void TestPointMerging()
originalNumPoints);
VTKM_TEST_ASSERT(noMerging.GetField("pointvar").GetData().GetNumberOfValues() ==
originalNumPoints);
VTKM_TEST_ASSERT(noMerging.GetField("cellvar").GetData().GetNumberOfValues() == originalNumCells);
std::cout << "Clean grid by merging very close points" << std::endl;
cleanGrid.SetMergePoints(true);
......@@ -116,6 +118,8 @@ void TestPointMerging()
closeMergeNumPoints);
VTKM_TEST_ASSERT(closeMerge.GetField("pointvar").GetData().GetNumberOfValues() ==
closeMergeNumPoints);
VTKM_TEST_ASSERT(closeMerge.GetField("cellvar").GetData().GetNumberOfValues() ==
originalNumCells);
std::cout << "Clean grid by merging very close points with fast merge" << std::endl;
cleanGrid.SetFastMerge(true);
......@@ -126,6 +130,8 @@ void TestPointMerging()
closeMergeNumPoints);
VTKM_TEST_ASSERT(closeFastMerge.GetField("pointvar").GetData().GetNumberOfValues() ==
closeMergeNumPoints);
VTKM_TEST_ASSERT(closeFastMerge.GetField("cellvar").GetData().GetNumberOfValues() ==
originalNumCells);
std::cout << "Clean grid with largely separated points" << std::endl;
cleanGrid.SetFastMerge(false);
......@@ -138,8 +144,9 @@ void TestPointMerging()
farMergeNumPoints);
VTKM_TEST_ASSERT(farMerge.GetField("pointvar").GetData().GetNumberOfValues() ==
farMergeNumPoints);
VTKM_TEST_ASSERT(farMerge.GetField("cellvar").GetData().GetNumberOfValues() == originalNumCells);
std::cout << "Clean grid with largerly separated points quickly" << std::endl;
std::cout << "Clean grid with largely separated points quickly" << std::endl;
cleanGrid.SetFastMerge(true);
vtkm::cont::DataSet farFastMerge = cleanGrid.Execute(inData);
constexpr vtkm::Id farFastMergeNumPoints = 19;
......@@ -149,6 +156,22 @@ void TestPointMerging()
farFastMergeNumPoints);
VTKM_TEST_ASSERT(farFastMerge.GetField("pointvar").GetData().GetNumberOfValues() ==
farFastMergeNumPoints);
VTKM_TEST_ASSERT(farFastMerge.GetField("cellvar").GetData().GetNumberOfValues() ==
originalNumCells);
std::cout << "Clean grid with largely separated points quickly with degenerate cells"
<< std::endl;
cleanGrid.SetRemoveDegenerateCells(true);
vtkm::cont::DataSet noDegenerateCells = cleanGrid.Execute(inData);
constexpr vtkm::Id numNonDegenerateCells = 33;
VTKM_TEST_ASSERT(noDegenerateCells.GetCellSet().GetNumberOfCells() == numNonDegenerateCells);
VTKM_TEST_ASSERT(noDegenerateCells.GetCellSet().GetNumberOfPoints() == farFastMergeNumPoints);
VTKM_TEST_ASSERT(noDegenerateCells.GetCoordinateSystem().GetData().GetNumberOfValues() ==
farFastMergeNumPoints);
VTKM_TEST_ASSERT(noDegenerateCells.GetField("pointvar").GetData().GetNumberOfValues() ==
farFastMergeNumPoints);
VTKM_TEST_ASSERT(noDegenerateCells.GetField("cellvar").GetData().GetNumberOfValues() ==
numNonDegenerateCells);
}
void RunTest()
......
......@@ -65,6 +65,7 @@ set(headers
PointMerge.h
PointTransform.h
Probe.h
RemoveDegenerateCells.h
RemoveUnusedPoints.h
ScalarsToColors.h
ScatterCounting.h
......
......@@ -6,9 +6,9 @@
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2014 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
// Copyright 2019 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
// Copyright 2019 UT-Battelle, LLC.
// Copyright 2019 Los Alamos National Security.
//
// Under the terms of Contract DE-NA0003525 with NTESS,
// the U.S. Government retains certain rights in this software.
......
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2019 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
// Copyright 2019 UT-Battelle, LLC.
// Copyright 2019 Los Alamos National Security.
//
// Under the terms of Contract DE-NA0003525 with NTESS,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#ifndef vtk_m_worklet_RemoveDegeneratePolygons_h
#define vtk_m_worklet_RemoveDegeneratePolygons_h
#include <vtkm/worklet/DispatcherMapTopology.h>
#include <vtkm/cont/ArrayCopy.h>
#include <vtkm/cont/ArrayHandleIndex.h>
#include <vtkm/cont/CellSetExplicit.h>
#include <vtkm/cont/CellSetPermutation.h>
#include <vtkm/worklet/CellDeepCopy.h>
#include <vtkm/CellTraits.h>
#include <vtkm/exec/CellFace.h>
namespace vtkm
{
namespace worklet
{
struct RemoveDegenerateCells
{
struct IdentifyDegenerates : vtkm::worklet::WorkletMapPointToCell
{
using ControlSignature = void(CellSetIn, FieldOutCell);
using ExecutionSignature = _2(CellShape, FromIndices);
using InputDomain = _1;
template <vtkm::IdComponent dimensionality, typename CellShapeTag, typename PointVecType>
VTKM_EXEC bool CheckForDimensionality(vtkm::CellTopologicalDimensionsTag<dimensionality>,
CellShapeTag,
PointVecType&& pointIds) const
{
const vtkm::IdComponent numPoints = pointIds.GetNumberOfComponents();
vtkm::IdComponent numUnduplicatedPoints = 0;
for (vtkm::IdComponent localPointId = 0; localPointId < numPoints; ++localPointId)
{
++numUnduplicatedPoints;
if (numUnduplicatedPoints >= dimensionality + 1)
{
return true;
}
while (((localPointId < numPoints - 1) &&
(pointIds[localPointId] == pointIds[localPointId + 1])) ||
((localPointId == numPoints - 1) && (pointIds[localPointId] == pointIds[0])))
{
// Skip over any repeated points. Assume any repeated points are adjacent.
++localPointId;
}
}
return false;
}
template <typename CellShapeTag, typename PointVecType>
VTKM_EXEC bool CheckForDimensionality(vtkm::CellTopologicalDimensionsTag<0>,
CellShapeTag,
PointVecType&&)
{
return true;
}
template <typename CellShapeTag, typename PointVecType>
VTKM_EXEC bool CheckForDimensionality(vtkm::CellTopologicalDimensionsTag<3>,
CellShapeTag shape,
PointVecType&& pointIds)
{
const vtkm::IdComponent numFaces = vtkm::exec::CellFaceNumberOfFaces(shape, *this);
vtkm::Id numValidFaces = 0;
for (vtkm::IdComponent faceId = 0; faceId < numFaces; ++faceId)
{
if (this->CheckForDimensionality(
vtkm::CellTopologicalDimensionsTag<2>(), vtkm::CellShapeTagPolygon(), pointIds))
{
++numValidFaces;
if (numValidFaces > 2)
{
return true;
}
}
}
return false;
}
template <typename CellShapeTag, typename PointIdVec>
VTKM_EXEC bool operator()(CellShapeTag shape, const PointIdVec& pointIds) const
{
using Traits = vtkm::CellTraits<CellShapeTag>;
return this->CheckForDimensionality(
typename Traits::TopologicalDimensionsTag(), shape, pointIds);
}
template <typename PointIdVec>
VTKM_EXEC bool operator()(vtkm::CellShapeTagGeneric shape, PointIdVec&& pointIds) const
{
bool passCell = true;
switch (shape.Id)
{
vtkmGenericCellShapeMacro(passCell = (*this)(CellShapeTag(), pointIds));
default:
// Raise an error for unknown cell type? Pass if we don't know.
passCell = true;
}
return passCell;
}
};
template <typename CellSetType>
vtkm::cont::CellSetExplicit<> Run(const CellSetType& cellSet)
{
vtkm::cont::ArrayHandle<bool> passFlags;
DispatcherMapTopology<IdentifyDegenerates> dispatcher;
dispatcher.Invoke(cellSet, passFlags);
vtkm::cont::ArrayHandleCounting<vtkm::Id> indices =
vtkm::cont::make_ArrayHandleCounting(vtkm::Id(0), vtkm::Id(1), passFlags.GetNumberOfValues());
vtkm::cont::Algorithm::CopyIf(
vtkm::cont::ArrayHandleIndex(passFlags.GetNumberOfValues()), passFlags, this->ValidCellIds);
vtkm::cont::CellSetPermutation<CellSetType> permutation(
this->ValidCellIds, cellSet, cellSet.GetName());
vtkm::cont::CellSetExplicit<> output;
vtkm::worklet::CellDeepCopy::Run(permutation, output);
return output;
}
struct CallWorklet
{
template <typename CellSetType>
void operator()(const CellSetType& cellSet,
RemoveDegenerateCells& self,
vtkm::cont::CellSetExplicit<>& output) const
{
output = self.Run(cellSet);
}
};
template <typename CellSetList>
vtkm::cont::CellSetExplicit<> Run(const vtkm::cont::DynamicCellSetBase<CellSetList>& cellSet)
{
vtkm::cont::CellSetExplicit<> output;
cellSet.CastAndCall(CallWorklet(), *this, output);
return output;
}
template <typename ValueType, typename StorageTag>
vtkm::cont::ArrayHandle<ValueType> ProcessCellField(
const vtkm::cont::ArrayHandle<ValueType, StorageTag> in) const
{
// Use a temporary permutation array to simplify the mapping:
auto tmp = vtkm::cont::make_ArrayHandlePermutation(this->ValidCellIds, in);
// Copy into an array with default storage:
vtkm::cont::ArrayHandle<ValueType> result;
vtkm::cont::ArrayCopy(tmp, result);
return result;
}
private:
vtkm::cont::ArrayHandle<vtkm::Id> ValidCellIds;
};
}
}
#endif //vtk_m_worklet_RemoveDegeneratePolygons_h
......@@ -26,7 +26,7 @@
#include <vtkm/cont/Algorithm.h>
#include <vtkm/cont/ArrayCopy.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ArrayHandleCounting.h>
#include <vtkm/cont/ArrayHandleIndex.h>
#include <vtkm/cont/ArrayHandlePermutation.h>
#include <vtkm/cont/CellSetPermutation.h>
#include <vtkm/cont/DynamicCellSet.h>
......@@ -150,14 +150,13 @@ public:
throw vtkm::cont::ErrorBadValue("Expecting point or cell field.");
}
vtkm::cont::ArrayHandleCounting<vtkm::Id> indices =
vtkm::cont::make_ArrayHandleCounting(vtkm::Id(0), vtkm::Id(1), passFlags.GetNumberOfValues());
vtkm::cont::Algorithm::CopyIf(indices, passFlags, this->ValidCellIds);
vtkm::cont::Algorithm::CopyIf(
vtkm::cont::ArrayHandleIndex(passFlags.GetNumberOfValues()), passFlags, this->ValidCellIds);
return OutputType(this->ValidCellIds, cellSet, cellSet.GetName());
}
template <typename CellSetList, typename FieldArrayType, typename UnaryPredicate>
template <typename FieldArrayType, typename UnaryPredicate>
struct CallWorklet
{
vtkm::cont::DynamicCellSet& Output;
......@@ -192,8 +191,7 @@ public:
const vtkm::cont::Field::Association fieldType,
const UnaryPredicate& predicate)
{
using Worker =
CallWorklet<CellSetList, vtkm::cont::ArrayHandle<ValueType, StorageType>, UnaryPredicate>;
using Worker = CallWorklet<vtkm::cont::ArrayHandle<ValueType, StorageType>, UnaryPredicate>;
vtkm::cont::DynamicCellSet output;
Worker worker(output, *this, field, fieldType, predicate);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment