Implement CleanGrid filter

This commit is contained in:
Kenneth Moreland 2016-11-06 15:15:22 -07:00
parent ce338d1484
commit c6cd9d02ba
8 changed files with 480 additions and 35 deletions

@ -359,6 +359,34 @@ struct DynamicTransformTraits<
} // namespace internal
namespace internal {
/// Checks to see if the given object is a dynamic cell set. It contains a
/// typedef named \c type that is either std::true_type or std::false_type.
/// Both of these have a typedef named value with the respective boolean value.
///
template<typename T>
struct DynamicCellSetCheck
{
using type = std::false_type;
};
template<typename CellSetList>
struct DynamicCellSetCheck<vtkm::cont::DynamicCellSetBase<CellSetList> >
{
using type = std::true_type;
};
#define VTKM_IS_DYNAMIC_CELL_SET(T) \
VTKM_STATIC_ASSERT(::vtkm::cont::internal::DynamicCellSetCheck<T>::type::value)
#define VTKM_IS_DYNAMIC_OR_STATIC_CELL_SET(T) \
VTKM_STATIC_ASSERT( \
::vtkm::cont::internal::CellSetCheck<T>::type::value || \
::vtkm::cont::internal::DynamicCellSetCheck<T>::type::value)
} // namespace internal
}
} // namespace vtkm::cont

@ -20,6 +20,7 @@
set(headers
CellAverage.h
CleanGrid.h
Clip.h
ExternalFaces.h
FieldMetadata.h
@ -42,6 +43,7 @@ set(headers
set(header_template_sources
CellAverage.hxx
CleanGrid.hxx
Clip.hxx
ExternalFaces.hxx
FilterCell.hxx

96
vtkm/filter/CleanGrid.h Normal file

@ -0,0 +1,96 @@
//============================================================================
// 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 2016 Sandia Corporation.
// Copyright 2016 UT-Battelle, LLC.
// Copyright 2016 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// 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_filter_CleanGrid_h
#define vtk_m_filter_CleanGrid_h
#include <vtkm/filter/FilterDataSet.h>
#include <vtkm/worklet/RemoveUnusedPoints.h>
namespace vtkm {
namespace filter {
/// \brief Clean a mesh to an unstructured grid
///
/// This filter takes a data set and essentially copies it into a new data set.
/// The newly constructed data set will have the same cells as the input and
/// the topology will be stored in a \c CellSetExplicit<>. The filter will also
/// optionally remove all unused points.
///
/// Note that the result of \c CleanGrid is not necessarily smaller than the
/// input. For example, "cleaning" a data set with a \c CellSetStructured
/// topology will actually result in a much larger data set.
///
/// \todo Add a feature to merge points that are coincident or within a
/// tolerance.
///
class CleanGrid : public vtkm::filter::FilterDataSet<CleanGrid>
{
public:
VTKM_CONT
CleanGrid();
/// When the CompactPointFields flag is true, the filter will identify any
/// points that are not used by the topology. This is on by default.
///
VTKM_CONT
bool GetCompactPointFields() const { return this->CompactPointFields; }
VTKM_CONT
void SetCompactPointFields(bool flag)
{
this->CompactPointFields = flag;
}
template<typename Policy, typename Device>
VTKM_CONT
vtkm::filter::ResultDataSet
DoExecute(const vtkm::cont::DataSet &inData,
vtkm::filter::PolicyBase<Policy>,
Device);
template<typename ValueType,
typename Storage,
typename Policy,
typename Device>
VTKM_CONT
bool DoMapField(vtkm::filter::ResultDataSet& result,
const vtkm::cont::ArrayHandle<ValueType, Storage>& input,
const vtkm::filter::FieldMetadata& fieldMeta,
vtkm::filter::PolicyBase<Policy>,
Device);
template<typename ValueType, typename Storage, typename Device>
VTKM_CONT
vtkm::cont::ArrayHandle<ValueType>
CompactPointArray(
const vtkm::cont::ArrayHandle<ValueType,Storage> &inArray, Device) const;
private:
bool CompactPointFields;
vtkm::worklet::RemoveUnusedPoints PointCompactor;
};
}
} // namespace vtkm::filter
#include <vtkm/filter/CleanGrid.hxx>
#endif //vtk_m_filter_CleanGrid_h

179
vtkm/filter/CleanGrid.hxx Normal file

@ -0,0 +1,179 @@
//============================================================================
// 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 2016 Sandia Corporation.
// Copyright 2016 UT-Battelle, LLC.
// Copyright 2016 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// 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.
//============================================================================
#include <vtkm/filter/CleanGrid.h>
#include <vtkm/worklet/CellDeepCopy.h>
#include <vtkm/worklet/RemoveUnusedPoints.h>
#include <vector>
namespace vtkm {
namespace filter {
namespace detail {
template<typename Device>
struct CleanCompactPointArrayFunctor
{
vtkm::cont::DataSet &OutDataSet;
std::string Name;
const vtkm::filter::CleanGrid *Self;
CleanCompactPointArrayFunctor(vtkm::cont::DataSet &outDataSet,
const std::string &name,
const vtkm::filter::CleanGrid *self)
: OutDataSet(outDataSet), Name(name), Self(self)
{ }
template<typename ArrayHandleType>
void operator()(const ArrayHandleType &coordSystemArray) const
{
VTKM_IS_ARRAY_HANDLE(ArrayHandleType);
vtkm::cont::ArrayHandle<typename ArrayHandleType::ValueType> outArray =
this->Self->CompactPointArray(coordSystemArray, Device());
this->OutDataSet.AddCoordinateSystem(
vtkm::cont::CoordinateSystem(this->Name, outArray));
}
};
} // namespace detail
VTKM_CONT
CleanGrid::CleanGrid()
: CompactPointFields(true)
{ }
template<typename Policy, typename Device>
VTKM_CONT
vtkm::filter::ResultDataSet
CleanGrid::DoExecute(const vtkm::cont::DataSet &inData,
vtkm::filter::PolicyBase<Policy>,
Device)
{
VTKM_IS_DEVICE_ADAPTER_TAG(Device);
using CellSetType = vtkm::cont::CellSetExplicit<>;
using VecId = std::vector<CellSetType>::size_type;
VecId numCellSets = static_cast<VecId>(inData.GetNumberOfCellSets());
std::vector<CellSetType> outputCellSets(numCellSets);
// 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));
vtkm::worklet::CellDeepCopy::Run(
vtkm::filter::ApplyPolicy(inCellSet, Policy()),
outputCellSets[cellSetIndex],
Device());
}
// Optionally adjust the cell set indices to remove all unused points
if (this->GetCompactPointFields())
{
this->PointCompactor.FindPointsStart(Device());
for (VecId cellSetIndex = 0; cellSetIndex < numCellSets; cellSetIndex++)
{
this->PointCompactor.FindPoints(outputCellSets[cellSetIndex], Device());
}
this->PointCompactor.FindPointsEnd(Device());
for (VecId cellSetIndex = 0; cellSetIndex < numCellSets; cellSetIndex++)
{
outputCellSets[cellSetIndex] =
this->PointCompactor.MapCellSet(outputCellSets[cellSetIndex], Device());
}
}
// Construct resulting data set with new cell sets
vtkm::cont::DataSet outData;
for (VecId cellSetIndex = 0; cellSetIndex < numCellSets; cellSetIndex++)
{
outData.AddCellSet(outputCellSets[cellSetIndex]);
}
// Pass the coordinate systems
// TODO: This is very awkward. First of all, there is no support for dealing
// with coordinate systems at all. That is fine if you are computing a new
// coordinate system, but a pain if you are deriving the coordinate system
// array. Second, why is it that coordinate systems are automtically mapped
// but other fields are not? Why shouldn't the Execute of a filter also set
// up all the fields of the output data set?
for (vtkm::IdComponent coordSystemIndex = 0;
coordSystemIndex < inData.GetNumberOfCoordinateSystems();
coordSystemIndex++)
{
vtkm::cont::CoordinateSystem coordSystem =
inData.GetCoordinateSystem(coordSystemIndex);
vtkm::filter::ApplyPolicy(coordSystem,
Policy(),
vtkm::filter::FilterTraits<CleanGrid>())
.CastAndCall(detail::CleanCompactPointArrayFunctor<Device>(
outData,coordSystem.GetName(),this));
}
return outData;
}
template<typename ValueType,
typename Storage,
typename Policy,
typename Device>
VTKM_CONT
bool CleanGrid::DoMapField(
vtkm::filter::ResultDataSet& result,
const vtkm::cont::ArrayHandle<ValueType, Storage>& input,
const vtkm::filter::FieldMetadata& fieldMeta,
vtkm::filter::PolicyBase<Policy>,
Device)
{
if (this->GetCompactPointFields() && fieldMeta.IsPointField())
{
vtkm::cont::ArrayHandle<ValueType> compactedArray =
this->CompactPointArray(input, Device());
result.GetDataSet().AddField(fieldMeta.AsField(compactedArray));
}
else
{
result.GetDataSet().AddField(fieldMeta.AsField(input));
}
return true;
}
template<typename ValueType, typename Storage, typename Device>
VTKM_CONT
vtkm::cont::ArrayHandle<ValueType>
CleanGrid::CompactPointArray(
const vtkm::cont::ArrayHandle<ValueType,Storage> &inArray, Device) const
{
VTKM_ASSERT(this->GetCompactPointFields());
return this->PointCompactor.MapPointFieldDeep(inArray, Device());
}
}
}

@ -21,6 +21,7 @@
set(unit_tests
UnitTestFieldMetadata.cxx
UnitTestCellAverageFilter.cxx
UnitTestCleanGrid.cxx
UnitTestClipFilter.cxx
UnitTestExternalFacesFilter.cxx
UnitTestHistogramFilter.cxx

@ -0,0 +1,94 @@
//============================================================================
// 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 2016 Sandia Corporation.
// Copyright 2016 UT-Battelle, LLC.
// Copyright 2016 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// 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.
//============================================================================
#include <vtkm/filter/CleanGrid.h>
#include <vtkm/cont/testing/MakeTestDataSet.h>
#include <vtkm/cont/testing/Testing.h>
namespace {
void TestUniformGrid()
{
std::cout << "Testing 'clean' uniform grid." << std::endl;
vtkm::cont::testing::MakeTestDataSet makeData;
vtkm::cont::DataSet inData = makeData.Make2DUniformDataSet0();
vtkm::filter::CleanGrid clean;
vtkm::filter::ResultDataSet result = clean.Execute(inData);
VTKM_TEST_ASSERT(result.IsValid(), "Filter failed to execute");
bool success;
success = clean.MapFieldOntoOutput(result, inData.GetField("pointvar"));
VTKM_TEST_ASSERT(success, "Failed to map point field");
success = clean.MapFieldOntoOutput(result, inData.GetField("cellvar"));
VTKM_TEST_ASSERT(success, "Failed to map cell field");
vtkm::cont::DataSet outData = result.GetDataSet();
vtkm::cont::CellSetExplicit<> outCellSet;
outData.GetCellSet().CopyTo(outCellSet);
VTKM_TEST_ASSERT(outCellSet.GetNumberOfPoints() == 6, "Wrong number of points");
VTKM_TEST_ASSERT(outCellSet.GetNumberOfCells() == 2, "Wrong number of cells");
vtkm::Vec<vtkm::Id,4> cellIds;
outCellSet.GetIndices(0, cellIds);
VTKM_TEST_ASSERT((cellIds == vtkm::Vec<vtkm::Id,4>(0, 1, 4, 3)),
"Bad cell ids");
outCellSet.GetIndices(1, cellIds);
VTKM_TEST_ASSERT((cellIds == vtkm::Vec<vtkm::Id,4>(1, 2, 5, 4)),
"Bad cell ids");
vtkm::cont::ArrayHandle<vtkm::Float32> outPointField;
outData.GetField("pointvar").GetData().CopyTo(outPointField);
VTKM_TEST_ASSERT(outPointField.GetNumberOfValues() == 6,
"Wrong point field size.");
VTKM_TEST_ASSERT(
test_equal(outPointField.GetPortalConstControl().Get(1), 20.1),
"Bad point field value");
VTKM_TEST_ASSERT(
test_equal(outPointField.GetPortalConstControl().Get(4), 50.1),
"Bad point field value");
vtkm::cont::ArrayHandle<vtkm::Float32> outCellField;
outData.GetField("cellvar").GetData().CopyTo(outCellField);
VTKM_TEST_ASSERT(outCellField.GetNumberOfValues() == 2,
"Wrong cell field size.");
VTKM_TEST_ASSERT(
test_equal(outCellField.GetPortalConstControl().Get(0), 100.1),
"Bad cell field value");
VTKM_TEST_ASSERT(
test_equal(outCellField.GetPortalConstControl().Get(1), 200.1),
"Bad cell field value");
}
void RunTest()
{
TestUniformGrid();
}
} // anonymous namespace
int UnitTestCleanGrid(int, char *[])
{
return vtkm::cont::testing::Testing::Run(RunTest);
}

@ -23,6 +23,7 @@
#include <vtkm/cont/ArrayHandleConstant.h>
#include <vtkm/cont/ArrayHandleGroupVecVariable.h>
#include <vtkm/cont/CellSetExplicit.h>
#include <vtkm/cont/DynamicCellSet.h>
#include <vtkm/worklet/DispatcherMapTopology.h>
#include <vtkm/worklet/WorkletMapTopology.h>
@ -87,7 +88,7 @@ struct CellDeepCopy
vtkm::cont::CellSetExplicit<ShapeStorage,NumIndicesStorage,ConnectivityStorage,OffsetsStorage> &outCellSet,
Device)
{
VTKM_IS_CELL_SET(InCellSetType);
VTKM_IS_DYNAMIC_OR_STATIC_CELL_SET(InCellSetType);
vtkm::cont::ArrayHandle<vtkm::IdComponent,NumIndicesStorage> numIndices;
@ -120,7 +121,7 @@ struct CellDeepCopy
static vtkm::cont::CellSetExplicit<>
Run(const InCellSetType &inCellSet, Device)
{
VTKM_IS_CELL_SET(InCellSetType);
VTKM_IS_DYNAMIC_OR_STATIC_CELL_SET(InCellSetType);
vtkm::cont::CellSetExplicit<> outCellSet;
Run(inCellSet, outCellSet, Device());

@ -84,6 +84,10 @@ public:
};
public:
VTKM_CONT
RemoveUnusedPoints()
{ }
template<typename ShapeStorage,
typename NumIndicesStorage,
typename ConnectivityStorage,
@ -92,8 +96,65 @@ public:
VTKM_CONT
RemoveUnusedPoints(const vtkm::cont::CellSetExplicit<ShapeStorage,NumIndicesStorage,ConnectivityStorage,OffsetsStorage> &inCellSet,
Device)
: PointScatter(MakeMaskArray(inCellSet,Device()),Device(),true)
{ }
{
this->FindPointsStart(Device());
this->FindPoints(inCellSet, Device());
this->FindPointsEnd(Device());
}
/// Get this class ready for identifying the points used by cell sets.
///
template<typename Device>
VTKM_CONT
void FindPointsStart(Device)
{
this->MaskArray.ReleaseResources();
}
/// Analyze the given cell set to find all points that are used. Unused
/// points are those that are not found in any cell sets passed to this
/// method.
///
template<typename ShapeStorage,
typename NumIndicesStorage,
typename ConnectivityStorage,
typename OffsetsStorage,
typename Device>
VTKM_CONT
void FindPoints(const vtkm::cont::CellSetExplicit<ShapeStorage,NumIndicesStorage,ConnectivityStorage,OffsetsStorage> &inCellSet,
Device)
{
using Algorithm = vtkm::cont::DeviceAdapterAlgorithm<Device>;
if (this->MaskArray.GetNumberOfValues() < 1)
{
// Initialize mask array to 0.
Algorithm::Copy(
vtkm::cont::ArrayHandleConstant<vtkm::IdComponent>(0, inCellSet.GetNumberOfPoints()),
this->MaskArray);
}
VTKM_ASSERT(
this->MaskArray.GetNumberOfValues() == inCellSet.GetNumberOfPoints());
vtkm::worklet::DispatcherMapField<GeneratePointMask,Device> dispatcher;
dispatcher.Invoke(
inCellSet.GetConnectivityArray(vtkm::TopologyElementTagPoint(),
vtkm::TopologyElementTagCell()),
this->MaskArray);
}
/// Compile the information collected from calls to \c FindPointsInCellSet to
/// ready this class for mapping cell sets and fields.
///
template<typename Device>
VTKM_CONT
void FindPointsEnd(Device)
{
this->PointScatter.reset(
new vtkm::worklet::ScatterCounting(this->MaskArray, Device(), true));
this->MaskArray.ReleaseResources();
}
/// \brief Map cell indices
///
@ -109,24 +170,26 @@ public:
VTKM_CONT
vtkm::cont::CellSetExplicit<ShapeStorage,NumIndicesStorage,VTKM_DEFAULT_CONNECTIVITY_STORAGE_TAG,OffsetsStorage>
MapCellSet(const vtkm::cont::CellSetExplicit<ShapeStorage,NumIndicesStorage,ConnectivityStorage,OffsetsStorage> &inCellSet,
Device)
Device) const
{
using FromTopology = vtkm::TopologyElementTagPoint;
using ToTopology = vtkm::TopologyElementTagCell;
using NewConnectivityStorage = VTKM_DEFAULT_CONNECTIVITY_STORAGE_TAG;
VTKM_ASSERT(this->PointScatter);
vtkm::cont::ArrayHandle<vtkm::Id,NewConnectivityStorage>
newConnectivityArray;
vtkm::worklet::DispatcherMapField<TransformPointIndices,Device> dispatcher;
dispatcher.Invoke(
inCellSet.GetConnectivityArray(FromTopology(), ToTopology()),
this->PointScatter.GetInputToOutputMap(),
this->PointScatter->GetInputToOutputMap(),
newConnectivityArray);
vtkm::Id numberOfPoints =
this->PointScatter.GetOutputToInputMap().GetNumberOfValues();
this->PointScatter->GetOutputToInputMap().GetNumberOfValues();
vtkm::cont::CellSetExplicit<ShapeStorage,NumIndicesStorage,NewConnectivityStorage,OffsetsStorage>
outCellSet(numberOfPoints, inCellSet.GetName());
outCellSet.Fill(inCellSet.GetShapesArray(FromTopology(),ToTopology()),
@ -149,10 +212,12 @@ public:
template<typename InArrayHandle>
VTKM_CONT
vtkm::cont::ArrayHandlePermutation<vtkm::cont::ArrayHandle<vtkm::Id>,InArrayHandle>
MapPointFieldShallow(const InArrayHandle &inArray)
MapPointFieldShallow(const InArrayHandle &inArray) const
{
VTKM_ASSERT(this->PointScatter);
return vtkm::cont::make_ArrayHandlePermutation(
this->PointScatter.GetOutputToInputMap(), inArray);
this->PointScatter->GetOutputToInputMap(), inArray);
}
/// \brief Maps a point field from the original points to the new reduced points
@ -168,7 +233,7 @@ public:
VTKM_CONT
void MapPointFieldDeep(const InArrayHandle &inArray,
OutArrayHandle &outArray,
Device)
Device) const
{
VTKM_IS_ARRAY_HANDLE(InArrayHandle);
VTKM_IS_ARRAY_HANDLE(OutArrayHandle);
@ -190,7 +255,7 @@ public:
///
template<typename InArrayHandle, typename Device>
vtkm::cont::ArrayHandle<typename InArrayHandle::ValueType>
MapPointFieldDeep(const InArrayHandle &inArray, Device)
MapPointFieldDeep(const InArrayHandle &inArray, Device) const
{
VTKM_IS_ARRAY_HANDLE(InArrayHandle);
VTKM_IS_DEVICE_ADAPTER_TAG(Device);
@ -202,32 +267,11 @@ public:
}
private:
vtkm::cont::ArrayHandle<vtkm::IdComponent> MaskArray;
/// Manages how the original point indices map to the new point indices.
///
vtkm::worklet::ScatterCounting PointScatter;
template<typename CellSetType, typename Device>
VTKM_CONT
static vtkm::cont::ArrayHandle<vtkm::IdComponent>
MakeMaskArray(const CellSetType &inCellSet, Device)
{
using Algorithm = vtkm::cont::DeviceAdapterAlgorithm<Device>;
vtkm::cont::ArrayHandle<vtkm::IdComponent> maskArray;
// Initialize mask array to 0.
Algorithm::Copy(
vtkm::cont::ArrayHandleConstant<vtkm::IdComponent>(0, inCellSet.GetNumberOfPoints()),
maskArray);
vtkm::worklet::DispatcherMapField<GeneratePointMask,Device> dispatcher;
dispatcher.Invoke(
inCellSet.GetConnectivityArray(vtkm::TopologyElementTagPoint(),
vtkm::TopologyElementTagCell()),
maskArray);
return maskArray;
}
std::shared_ptr<vtkm::worklet::ScatterCounting> PointScatter;
};
}