Merge branch 'master' of https://gitlab.kitware.com/vtk/vtk-m into gridEval

This commit is contained in:
Dave Pugmire 2019-03-14 13:40:33 -04:00
commit 6edda87c3a
38 changed files with 1192 additions and 177 deletions

@ -24,6 +24,8 @@
#
# vtkm_rendering Target that contains all the rendering code
#
# vtkm_filter Target that contains all of VTK-m filters
#
# vtkm::tbb Target that contains tbb related link information
# implicitly linked to by `vtkm_cont` if tbb is enabled
#

@ -27,7 +27,7 @@ def debug(str):
if (doDebug): print(str)
# Parses "*** vtkm::Float64 ***************" --> vtkm::Float64
typeParser = re.compile("\\*{3} ([^*]+) \\*{15}")
typeParser = re.compile("\\*{3} ([^*]+) on device ([^*]+) \\*{15}")
# Parses "Benchmark 'Benchmark name' results:" --> Benchmark name
nameParser = re.compile("Benchmark '([^-]+)' results:")

@ -239,7 +239,8 @@ class BenchmarkFilters
{
Timer timer{ DeviceAdapter() };
timer.Start();
this->Filter.Execute(InputDataSet, BenchmarkFilterPolicy());
auto result = this->Filter.Execute(InputDataSet, BenchmarkFilterPolicy());
(void)result;
return timer.GetElapsedTime();
}
@ -327,7 +328,8 @@ class BenchmarkFilters
{
Timer timer{ DeviceAdapter() };
timer.Start();
this->Filter.Execute(InputDataSet, BenchmarkFilterPolicy());
auto result = this->Filter.Execute(InputDataSet, BenchmarkFilterPolicy());
(void)result;
return timer.GetElapsedTime();
}
@ -366,7 +368,8 @@ class BenchmarkFilters
{
Timer timer{ DeviceAdapter() };
timer.Start();
this->Filter.Execute(InputDataSet, BenchmarkFilterPolicy());
auto result = this->Filter.Execute(InputDataSet, BenchmarkFilterPolicy());
(void)result;
return timer.GetElapsedTime();
}
@ -392,7 +395,8 @@ class BenchmarkFilters
{
Timer timer{ DeviceAdapter() };
timer.Start();
this->Filter.Execute(InputDataSet, BenchmarkFilterPolicy());
auto result = this->Filter.Execute(InputDataSet, BenchmarkFilterPolicy());
(void)result;
return timer.GetElapsedTime();
}
@ -417,7 +421,8 @@ class BenchmarkFilters
{
Timer timer{ DeviceAdapter() };
timer.Start();
this->Filter.Execute(InputDataSet, BenchmarkFilterPolicy());
auto result = this->Filter.Execute(InputDataSet, BenchmarkFilterPolicy());
(void)result;
return timer.GetElapsedTime();
}
@ -445,7 +450,8 @@ class BenchmarkFilters
{
Timer timer{ DeviceAdapter() };
timer.Start();
this->Filter.Execute(InputDataSet, BenchmarkFilterPolicy());
auto result = this->Filter.Execute(InputDataSet, BenchmarkFilterPolicy());
(void)result;
return timer.GetElapsedTime();
}
@ -472,7 +478,8 @@ class BenchmarkFilters
{
Timer timer{ DeviceAdapter() };
timer.Start();
this->Filter.Execute(InputDataSet, BenchmarkFilterPolicy());
auto result = this->Filter.Execute(InputDataSet, BenchmarkFilterPolicy());
(void)result;
return timer.GetElapsedTime();
}
@ -515,7 +522,8 @@ class BenchmarkFilters
{
Timer timer{ DeviceAdapter() };
timer.Start();
this->Filter.Execute(InputDataSet, BenchmarkFilterPolicy());
auto result = this->Filter.Execute(InputDataSet, BenchmarkFilterPolicy());
(void)result;
return timer.GetElapsedTime();
}
@ -560,7 +568,8 @@ class BenchmarkFilters
{
Timer timer{ DeviceAdapter() };
timer.Start();
this->Filter.Execute(InputDataSet, BenchmarkFilterPolicy());
auto result = this->Filter.Execute(InputDataSet, BenchmarkFilterPolicy());
(void)result;
return timer.GetElapsedTime();
}
@ -595,7 +604,8 @@ class BenchmarkFilters
{
Timer timer{ DeviceAdapter() };
timer.Start();
this->Filter.Execute(InputDataSet, BenchmarkFilterPolicy());
auto result = this->Filter.Execute(InputDataSet, BenchmarkFilterPolicy());
(void)result;
return timer.GetElapsedTime();
}
@ -621,7 +631,8 @@ class BenchmarkFilters
{
Timer timer{ DeviceAdapter() };
timer.Start();
this->Filter.Execute(InputDataSet, BenchmarkFilterPolicy());
auto result = this->Filter.Execute(InputDataSet, BenchmarkFilterPolicy());
(void)result;
return timer.GetElapsedTime();
}

@ -0,0 +1,4 @@
# VTK-m provides a vtkm_filter target
VTK-m now provides a `vtkm_filter` that contains pre-built components
of filters for consuming projects.

@ -0,0 +1,26 @@
# Add point merge capabilities to CleanGrid filter
We have added a `PointMerge` worklet that uses a virtual grid approach to
identify nearby points. The worklet works by creating a very fine but
sparsely represented locator grid. It then groups points by grid bins and
finds those within a specified radius.
This functionality has been integrated into the `CleanGrid` filter. The
following flags have been added to `CleanGrid` to modify the behavior of
point merging.
* `Set`/`GetMergePoints` - a flag to turn on/off the merging of
duplicated coincident points. This extra operation will find points
spatially located near each other and merge them together.
* `Set`/`GetTolerance` - Defines the tolerance used when determining
whether two points are considered coincident. If the
`ToleranceIsAbsolute` flag is false (the default), then this tolerance
is scaled by the diagonal of the points. This parameter is only used
when merge points is on.
* `Set`/`GetToleranceIsAbsolute` - When ToleranceIsAbsolute is false (the
default) then the tolerance is scaled by the diagonal of the bounds of
the dataset. If true, then the tolerance is taken as the actual
distance to use. This parameter is only used when merge points is on.
* `Set`/`GetFastMerge` - 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.

@ -26,24 +26,24 @@ namespace vtkm
namespace cont
{
#define _VTKM_ARRAYHANDLE_INSTANTIATE(Type) \
#define VTKM_ARRAYHANDLE_INSTANTIATE(Type) \
template class VTKM_CONT_EXPORT ArrayHandle<Type, StorageTagBasic>; \
template class VTKM_CONT_EXPORT ArrayHandle<vtkm::Vec<Type, 2>, StorageTagBasic>; \
template class VTKM_CONT_EXPORT ArrayHandle<vtkm::Vec<Type, 3>, StorageTagBasic>; \
template class VTKM_CONT_EXPORT ArrayHandle<vtkm::Vec<Type, 4>, StorageTagBasic>;
_VTKM_ARRAYHANDLE_INSTANTIATE(char)
_VTKM_ARRAYHANDLE_INSTANTIATE(vtkm::Int8)
_VTKM_ARRAYHANDLE_INSTANTIATE(vtkm::UInt8)
_VTKM_ARRAYHANDLE_INSTANTIATE(vtkm::Int16)
_VTKM_ARRAYHANDLE_INSTANTIATE(vtkm::UInt16)
_VTKM_ARRAYHANDLE_INSTANTIATE(vtkm::Int32)
_VTKM_ARRAYHANDLE_INSTANTIATE(vtkm::UInt32)
_VTKM_ARRAYHANDLE_INSTANTIATE(vtkm::Int64)
_VTKM_ARRAYHANDLE_INSTANTIATE(vtkm::UInt64)
_VTKM_ARRAYHANDLE_INSTANTIATE(vtkm::Float32)
_VTKM_ARRAYHANDLE_INSTANTIATE(vtkm::Float64)
VTKM_ARRAYHANDLE_INSTANTIATE(char)
VTKM_ARRAYHANDLE_INSTANTIATE(vtkm::Int8)
VTKM_ARRAYHANDLE_INSTANTIATE(vtkm::UInt8)
VTKM_ARRAYHANDLE_INSTANTIATE(vtkm::Int16)
VTKM_ARRAYHANDLE_INSTANTIATE(vtkm::UInt16)
VTKM_ARRAYHANDLE_INSTANTIATE(vtkm::Int32)
VTKM_ARRAYHANDLE_INSTANTIATE(vtkm::UInt32)
VTKM_ARRAYHANDLE_INSTANTIATE(vtkm::Int64)
VTKM_ARRAYHANDLE_INSTANTIATE(vtkm::UInt64)
VTKM_ARRAYHANDLE_INSTANTIATE(vtkm::Float32)
VTKM_ARRAYHANDLE_INSTANTIATE(vtkm::Float64)
#undef _VTKM_ARRAYHANDLE_INSTANTIATE
#undef VTKM_ARRAYHANDLE_INSTANTIATE
}
} // end vtkm::cont

@ -748,7 +748,7 @@ namespace vtkm
namespace cont
{
#define _VTKM_ARRAYHANDLE_EXPORT(Type) \
#define VTKM_ARRAYHANDLE_EXPORT(Type) \
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandle<Type, StorageTagBasic>; \
extern template class VTKM_CONT_TEMPLATE_EXPORT \
ArrayHandle<vtkm::Vec<Type, 2>, StorageTagBasic>; \
@ -756,19 +756,19 @@ namespace cont
ArrayHandle<vtkm::Vec<Type, 3>, StorageTagBasic>; \
extern template class VTKM_CONT_TEMPLATE_EXPORT ArrayHandle<vtkm::Vec<Type, 4>, StorageTagBasic>;
_VTKM_ARRAYHANDLE_EXPORT(char)
_VTKM_ARRAYHANDLE_EXPORT(vtkm::Int8)
_VTKM_ARRAYHANDLE_EXPORT(vtkm::UInt8)
_VTKM_ARRAYHANDLE_EXPORT(vtkm::Int16)
_VTKM_ARRAYHANDLE_EXPORT(vtkm::UInt16)
_VTKM_ARRAYHANDLE_EXPORT(vtkm::Int32)
_VTKM_ARRAYHANDLE_EXPORT(vtkm::UInt32)
_VTKM_ARRAYHANDLE_EXPORT(vtkm::Int64)
_VTKM_ARRAYHANDLE_EXPORT(vtkm::UInt64)
_VTKM_ARRAYHANDLE_EXPORT(vtkm::Float32)
_VTKM_ARRAYHANDLE_EXPORT(vtkm::Float64)
VTKM_ARRAYHANDLE_EXPORT(char)
VTKM_ARRAYHANDLE_EXPORT(vtkm::Int8)
VTKM_ARRAYHANDLE_EXPORT(vtkm::UInt8)
VTKM_ARRAYHANDLE_EXPORT(vtkm::Int16)
VTKM_ARRAYHANDLE_EXPORT(vtkm::UInt16)
VTKM_ARRAYHANDLE_EXPORT(vtkm::Int32)
VTKM_ARRAYHANDLE_EXPORT(vtkm::UInt32)
VTKM_ARRAYHANDLE_EXPORT(vtkm::Int64)
VTKM_ARRAYHANDLE_EXPORT(vtkm::UInt64)
VTKM_ARRAYHANDLE_EXPORT(vtkm::Float32)
VTKM_ARRAYHANDLE_EXPORT(vtkm::Float64)
#undef _VTKM_ARRAYHANDLE_EXPORT
#undef VTKM_ARRAYHANDLE_EXPORT
}
} // end vtkm::cont

@ -32,12 +32,12 @@ namespace exec
namespace internal
{
template <typename _SourcePortalType, vtkm::IdComponent _NUM_COMPONENTS>
template <typename PortalType, vtkm::IdComponent N_COMPONENTS>
class VTKM_ALWAYS_EXPORT ArrayPortalGroupVec
{
public:
static constexpr vtkm::IdComponent NUM_COMPONENTS = _NUM_COMPONENTS;
using SourcePortalType = _SourcePortalType;
static constexpr vtkm::IdComponent NUM_COMPONENTS = N_COMPONENTS;
using SourcePortalType = PortalType;
using ComponentType = typename std::remove_const<typename SourcePortalType::ValueType>::type;
using ValueType = vtkm::Vec<ComponentType, NUM_COMPONENTS>;

@ -199,7 +199,7 @@ InitializeResult Initialize(int& argc, char* argv[], InitializeOptions opts)
for (int i = 0; i < parse.nonOptionsCount(); i++)
{
config.Arguments.push_back(std::string(parse.nonOption(i)));
config.Arguments.emplace_back(parse.nonOption(i));
}
}

@ -309,23 +309,25 @@ void* StorageBasicBase::GetCapacityPointer() const
return static_cast<void*>(v);
}
#define _VTKM_STORAGE_INSTANTIATE(Type) \
#define VTKM_STORAGE_INSTANTIATE(Type) \
template class VTKM_CONT_EXPORT Storage<Type, StorageTagBasic>; \
template class VTKM_CONT_EXPORT Storage<vtkm::Vec<Type, 2>, StorageTagBasic>; \
template class VTKM_CONT_EXPORT Storage<vtkm::Vec<Type, 3>, StorageTagBasic>; \
template class VTKM_CONT_EXPORT Storage<vtkm::Vec<Type, 4>, StorageTagBasic>;
_VTKM_STORAGE_INSTANTIATE(char)
_VTKM_STORAGE_INSTANTIATE(vtkm::Int8)
_VTKM_STORAGE_INSTANTIATE(vtkm::UInt8)
_VTKM_STORAGE_INSTANTIATE(vtkm::Int16)
_VTKM_STORAGE_INSTANTIATE(vtkm::UInt16)
_VTKM_STORAGE_INSTANTIATE(vtkm::Int32)
_VTKM_STORAGE_INSTANTIATE(vtkm::UInt32)
_VTKM_STORAGE_INSTANTIATE(vtkm::Int64)
_VTKM_STORAGE_INSTANTIATE(vtkm::UInt64)
_VTKM_STORAGE_INSTANTIATE(vtkm::Float32)
_VTKM_STORAGE_INSTANTIATE(vtkm::Float64)
VTKM_STORAGE_INSTANTIATE(char)
VTKM_STORAGE_INSTANTIATE(vtkm::Int8)
VTKM_STORAGE_INSTANTIATE(vtkm::UInt8)
VTKM_STORAGE_INSTANTIATE(vtkm::Int16)
VTKM_STORAGE_INSTANTIATE(vtkm::UInt16)
VTKM_STORAGE_INSTANTIATE(vtkm::Int32)
VTKM_STORAGE_INSTANTIATE(vtkm::UInt32)
VTKM_STORAGE_INSTANTIATE(vtkm::Int64)
VTKM_STORAGE_INSTANTIATE(vtkm::UInt64)
VTKM_STORAGE_INSTANTIATE(vtkm::Float32)
VTKM_STORAGE_INSTANTIATE(vtkm::Float64)
#undef VTKM_STORAGE_INSTANTIATE
}
}
} // namespace vtkm::cont::internal

@ -234,23 +234,25 @@ namespace internal
/// \cond
/// Make doxygen ignore this section
#define _VTKM_STORAGE_EXPORT(Type) \
#define VTKM_STORAGE_EXPORT(Type) \
extern template class VTKM_CONT_TEMPLATE_EXPORT Storage<Type, StorageTagBasic>; \
extern template class VTKM_CONT_TEMPLATE_EXPORT Storage<vtkm::Vec<Type, 2>, StorageTagBasic>; \
extern template class VTKM_CONT_TEMPLATE_EXPORT Storage<vtkm::Vec<Type, 3>, StorageTagBasic>; \
extern template class VTKM_CONT_TEMPLATE_EXPORT Storage<vtkm::Vec<Type, 4>, StorageTagBasic>;
_VTKM_STORAGE_EXPORT(char)
_VTKM_STORAGE_EXPORT(vtkm::Int8)
_VTKM_STORAGE_EXPORT(vtkm::UInt8)
_VTKM_STORAGE_EXPORT(vtkm::Int16)
_VTKM_STORAGE_EXPORT(vtkm::UInt16)
_VTKM_STORAGE_EXPORT(vtkm::Int32)
_VTKM_STORAGE_EXPORT(vtkm::UInt32)
_VTKM_STORAGE_EXPORT(vtkm::Int64)
_VTKM_STORAGE_EXPORT(vtkm::UInt64)
_VTKM_STORAGE_EXPORT(vtkm::Float32)
_VTKM_STORAGE_EXPORT(vtkm::Float64)
VTKM_STORAGE_EXPORT(char)
VTKM_STORAGE_EXPORT(vtkm::Int8)
VTKM_STORAGE_EXPORT(vtkm::UInt8)
VTKM_STORAGE_EXPORT(vtkm::Int16)
VTKM_STORAGE_EXPORT(vtkm::UInt16)
VTKM_STORAGE_EXPORT(vtkm::Int32)
VTKM_STORAGE_EXPORT(vtkm::UInt32)
VTKM_STORAGE_EXPORT(vtkm::Int64)
VTKM_STORAGE_EXPORT(vtkm::UInt64)
VTKM_STORAGE_EXPORT(vtkm::Float32)
VTKM_STORAGE_EXPORT(vtkm::Float64)
#undef VTKM_STORAGE_EXPORT
/// \endcond
}
}

@ -212,14 +212,14 @@ namespace cont
/// ArrayPortalFromIterators. Returns the original array rather than
/// the portal wrapped in an \c IteratorFromArrayPortal.
///
template <typename _IteratorType>
class ArrayPortalToIterators<vtkm::cont::internal::ArrayPortalFromIterators<_IteratorType>>
template <typename IterType>
class ArrayPortalToIterators<vtkm::cont::internal::ArrayPortalFromIterators<IterType>>
{
using PortalType = vtkm::cont::internal::ArrayPortalFromIterators<_IteratorType>;
using PortalType = vtkm::cont::internal::ArrayPortalFromIterators<IterType>;
public:
#if !defined(VTKM_MSVC) || (defined(_ITERATOR_DEBUG_LEVEL) && _ITERATOR_DEBUG_LEVEL == 0)
using IteratorType = _IteratorType;
using IteratorType = IterType;
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_CONT
@ -233,7 +233,7 @@ public:
// The MSVC compiler issues warnings when using raw pointer math when in
// debug mode. To keep the compiler happy (and add some safety checks),
// wrap the iterator in checked_array_iterator.
using IteratorType = stdext::checked_array_iterator<_IteratorType>;
using IteratorType = stdext::checked_array_iterator<IterType>;
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_CONT

@ -40,8 +40,8 @@
// Wrap all '#pragma omp ...' calls in this macro so we can disable them in
// non-omp builds and avoid a multitude of 'ignoring pragma..." warnings.
#ifdef _OPENMP
#define _VTKM_OPENMP_DIRECTIVE_IMPL(fullDir) _Pragma(#fullDir)
#define VTKM_OPENMP_DIRECTIVE(dir) _VTKM_OPENMP_DIRECTIVE_IMPL(omp dir)
#define VTKM_OPENMP_DIRECTIVE_IMPL(fullDir) _Pragma(#fullDir)
#define VTKM_OPENMP_DIRECTIVE(dir) VTKM_OPENMP_DIRECTIVE_IMPL(omp dir)
#else // _OPENMP
#define VTKM_OPENMP_DIRECTIVE(directive)
#endif // _OPENMP

@ -495,7 +495,7 @@ VTKM_CONT static T ReducePortals(InputPortalType inputPortal,
// Define this to print out timing information from the reduction and join
// operations in the tbb ReduceByKey algorithm:
//#define _VTKM_DEBUG_TBB_RBK
//#define VTKM_DEBUG_TBB_RBK
template <typename KeysInPortalType,
typename ValuesInPortalType,
@ -554,7 +554,7 @@ struct ReduceByKeyBody
ValuesOutPortalType ValuesOutPortal;
BinaryOperationType BinaryOperation;
Range Ranges;
#ifdef _VTKM_DEBUG_TBB_RBK
#ifdef VTKM_DEBUG_TBB_RBK
double ReduceTime;
double JoinTime;
#endif
@ -570,7 +570,7 @@ struct ReduceByKeyBody
, KeysOutPortal(keysOutPortal)
, ValuesOutPortal(valuesOutPortal)
, BinaryOperation(binaryOperation)
#ifdef _VTKM_DEBUG_TBB_RBK
#ifdef VTKM_DEBUG_TBB_RBK
, ReduceTime(0)
, JoinTime(0)
#endif
@ -584,7 +584,7 @@ struct ReduceByKeyBody
, KeysOutPortal(body.KeysOutPortal)
, ValuesOutPortal(body.ValuesOutPortal)
, BinaryOperation(body.BinaryOperation)
#ifdef _VTKM_DEBUG_TBB_RBK
#ifdef VTKM_DEBUG_TBB_RBK
, ReduceTime(0)
, JoinTime(0)
#endif
@ -595,9 +595,9 @@ struct ReduceByKeyBody
void operator()(const ::tbb::blocked_range<vtkm::Id>& range)
{
#ifdef _VTKM_DEBUG_TBB_RBK
#ifdef VTKM_DEBUG_TBB_RBK
::tbb::tick_count startTime = ::tbb::tick_count::now();
#endif // _VTKM_DEBUG_TBB_RBK
#endif // VTKM_DEBUG_TBB_RBK
if (range.empty())
{
return;
@ -714,7 +714,7 @@ struct ReduceByKeyBody
this->Ranges.OutputEnd = writePos;
#ifdef _VTKM_DEBUG_TBB_RBK
#ifdef VTKM_DEBUG_TBB_RBK
::tbb::tick_count endTime = ::tbb::tick_count::now();
double time = (endTime - startTime).seconds();
this->ReduceTime += time;
@ -735,7 +735,7 @@ struct ReduceByKeyBody
using KeysIteratorType = typename KeysIteratorsType::IteratorType;
using ValuesIteratorType = typename ValuesIteratorsType::IteratorType;
#ifdef _VTKM_DEBUG_TBB_RBK
#ifdef VTKM_DEBUG_TBB_RBK
::tbb::tick_count startTime = ::tbb::tick_count::now();
#endif
@ -775,7 +775,7 @@ struct ReduceByKeyBody
this->Ranges.OutputEnd += srcEnd - srcBegin;
this->Ranges.AssertSane();
#ifdef _VTKM_DEBUG_TBB_RBK
#ifdef VTKM_DEBUG_TBB_RBK
::tbb::tick_count endTime = ::tbb::tick_count::now();
double time = (endTime - startTime).seconds();
this->JoinTime += rhs.JoinTime + time;
@ -820,13 +820,13 @@ VTKM_CONT vtkm::Id ReduceByKeyPortals(KeysInPortalType keysInPortal,
body(keysInPortal, valuesInPortal, keysOutPortal, valuesOutPortal, wrappedBinaryOp);
::tbb::blocked_range<vtkm::Id> range(0, inputLength, TBB_GRAIN_SIZE);
#ifdef _VTKM_DEBUG_TBB_RBK
#ifdef VTKM_DEBUG_TBB_RBK
std::cerr << "\n\nTBB ReduceByKey:\n";
#endif
::tbb::parallel_reduce(range, body);
#ifdef _VTKM_DEBUG_TBB_RBK
#ifdef VTKM_DEBUG_TBB_RBK
std::cerr << "Total reduce time: " << body.ReduceTime << "s\n";
std::cerr << "Total join time: " << body.JoinTime << "s\n";
std::cerr << "\nend\n";
@ -839,8 +839,8 @@ VTKM_CONT vtkm::Id ReduceByKeyPortals(KeysInPortalType keysInPortal,
return body.Ranges.OutputEnd;
}
#ifdef _VTKM_DEBUG_TBB_RBK
#undef _VTKM_DEBUG_TBB_RBK
#ifdef VTKM_DEBUG_TBB_RBK
#undef VTKM_DEBUG_TBB_RBK
#endif
template <class InputPortalType, class OutputPortalType, class BinaryOperationType>

@ -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;
}

@ -22,6 +22,8 @@
#include <vtkm/filter/FilterDataSet.h>
#include <vtkm/worklet/PointMerge.h>
#include <vtkm/worklet/RemoveDegenerateCells.h>
#include <vtkm/worklet/RemoveUnusedPoints.h>
namespace vtkm
@ -52,10 +54,42 @@ public:
/// 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; }
VTKM_CONT bool GetCompactPointFields() const { return this->CompactPointFields; }
VTKM_CONT void SetCompactPointFields(bool flag) { this->CompactPointFields = flag; }
/// When the MergePoints flag is true, the filter will identify any coincident
/// points and merge them together. The distance two points can be to considered
/// coincident is set with the tolerance flags. This is on by default.
///
VTKM_CONT bool GetMergePoints() const { return this->MergePoints; }
VTKM_CONT void SetMergePoints(bool flag) { this->MergePoints = flag; }
/// Defines the tolerance used when determining whether two points are considered
/// coincident. If the ToleranceIsAbsolute flag is false (the default), then this
/// tolerance is scaled by the diagonal of the points.
///
VTKM_CONT vtkm::Float64 GetTolerance() const { return this->Tolerance; }
VTKM_CONT void SetTolerance(vtkm::Float64 tolerance) { this->Tolerance = tolerance; }
/// When ToleranceIsAbsolute is false (the default) then the tolerance is scaled
/// by the diagonal of the bounds of the dataset. If true, then the tolerance is
/// taken as the actual distance to use.
///
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.
///
VTKM_CONT bool GetFastMerge() const { return this->FastMerge; }
VTKM_CONT void SetFastMerge(bool flag) { this->FastMerge = flag; }
template <typename Policy>
VTKM_CONT vtkm::cont::DataSet DoExecute(const vtkm::cont::DataSet& inData,
@ -73,12 +107,21 @@ public:
private:
bool CompactPointFields;
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

@ -18,6 +18,11 @@
// this software.
//============================================================================
#ifndef vtk_m_filter_CleanGrid_hxx
#define vtk_m_filter_CleanGrid_hxx
#include <vtkm/filter/CleanGrid.h>
#include <vtkm/worklet/CellDeepCopy.h>
#include <vtkm/worklet/RemoveUnusedPoints.h>
@ -30,6 +35,11 @@ namespace filter
inline VTKM_CONT CleanGrid::CleanGrid()
: CompactPointFields(true)
, MergePoints(true)
, Tolerance(1.0e-6)
, ToleranceIsAbsolute(false)
, RemoveDegenerateCells(true)
, FastMerge(true)
{
}
@ -41,17 +51,35 @@ inline VTKM_CONT vtkm::cont::DataSet CleanGrid::DoExecute(const vtkm::cont::Data
using VecId = std::vector<CellSetType>::size_type;
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++)
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]);
}
}
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);
// Start with a shallow copy of the coordinate systems
for (VecId coordSystemIndex = 0; coordSystemIndex < numCoordSystems; ++coordSystemIndex)
{
outputCoordinateSystems[coordSystemIndex] =
inData.GetCoordinateSystem(static_cast<vtkm::IdComponent>(coordSystemIndex));
}
// Optionally adjust the cell set indices to remove all unused points
@ -64,10 +92,61 @@ inline VTKM_CONT vtkm::cont::DataSet CleanGrid::DoExecute(const vtkm::cont::Data
}
this->PointCompactor.FindPointsEnd();
for (VecId cellSetIndex = 0; cellSetIndex < numCellSets; cellSetIndex++)
for (VecId cellSetIndex = 0; cellSetIndex < numCellSets; ++cellSetIndex)
{
outputCellSets[cellSetIndex] = this->PointCompactor.MapCellSet(outputCellSets[cellSetIndex]);
}
for (VecId coordSystemIndex = 0; coordSystemIndex < numCoordSystems; ++coordSystemIndex)
{
outputCoordinateSystems[coordSystemIndex] =
vtkm::cont::CoordinateSystem(outputCoordinateSystems[coordSystemIndex].GetName(),
this->PointCompactor.MapPointFieldDeep(
outputCoordinateSystems[coordSystemIndex].GetData()));
}
}
// Optionally find and merge coincident points
if (this->GetMergePoints())
{
vtkm::cont::CoordinateSystem activeCoordSystem = outputCoordinateSystems[activeCoordIndex];
vtkm::Bounds bounds = activeCoordSystem.GetBounds();
vtkm::Float64 delta = this->GetTolerance();
if (!this->GetToleranceIsAbsolute())
{
delta *=
vtkm::Magnitude(vtkm::make_Vec(bounds.X.Length(), bounds.Y.Length(), bounds.Z.Length()));
}
auto coordArray = activeCoordSystem.GetData();
this->PointMerger.Run(delta, this->GetFastMerge(), bounds, coordArray);
activeCoordSystem = vtkm::cont::CoordinateSystem(activeCoordSystem.GetName(), coordArray);
for (VecId coordSystemIndex = 0; coordSystemIndex < numCoordSystems; ++coordSystemIndex)
{
if (coordSystemIndex == activeCoordIndex)
{
outputCoordinateSystems[coordSystemIndex] = activeCoordSystem;
}
else
{
outputCoordinateSystems[coordSystemIndex] = vtkm::cont::CoordinateSystem(
outputCoordinateSystems[coordSystemIndex].GetName(),
this->PointMerger.MapPointField(outputCoordinateSystems[coordSystemIndex].GetData()));
}
}
for (VecId cellSetIndex = 0; cellSetIndex < numCellSets; ++cellSetIndex)
{
outputCellSets[cellSetIndex] = this->PointMerger.MapCellSet(outputCellSets[cellSetIndex]);
}
}
// Optionally remove degenerate cells
if (this->GetRemoveDegenerateCells())
{
outputCellSets[activeCoordIndex] = this->CellCompactor.Run(outputCellSets[activeCoordIndex]);
}
// Construct resulting data set with new cell sets
@ -78,27 +157,9 @@ inline VTKM_CONT vtkm::cont::DataSet CleanGrid::DoExecute(const vtkm::cont::Data
}
// 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 automatically 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++)
for (VecId coordSystemIndex = 0; coordSystemIndex < numCoordSystems; ++coordSystemIndex)
{
vtkm::cont::CoordinateSystem coordSystem = inData.GetCoordinateSystem(coordSystemIndex);
if (this->GetCompactPointFields())
{
auto outArray = this->MapPointField(coordSystem.GetData());
outData.AddCoordinateSystem(vtkm::cont::CoordinateSystem(coordSystem.GetName(), outArray));
}
else
{
outData.AddCoordinateSystem(coordSystem);
}
outData.AddCoordinateSystem(outputCoordinateSystems[coordSystemIndex]);
}
return outData;
@ -111,11 +172,27 @@ inline VTKM_CONT bool CleanGrid::DoMapField(
const vtkm::filter::FieldMetadata& fieldMeta,
vtkm::filter::PolicyBase<Policy>)
{
if (this->GetCompactPointFields() && fieldMeta.IsPointField())
if (fieldMeta.IsPointField() && (this->GetCompactPointFields() || this->GetMergePoints()))
{
vtkm::cont::ArrayHandle<ValueType> compactedArray = this->MapPointField(input);
vtkm::cont::ArrayHandle<ValueType> compactedArray;
if (this->GetCompactPointFields())
{
compactedArray = this->PointCompactor.MapPointFieldDeep(input);
if (this->GetMergePoints())
{
compactedArray = this->PointMerger.MapPointField(compactedArray);
}
}
else if (this->GetMergePoints())
{
compactedArray = this->PointMerger.MapPointField(input);
}
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));
@ -123,14 +200,7 @@ inline VTKM_CONT bool CleanGrid::DoMapField(
return true;
}
}
}
template <typename ValueType, typename Storage>
inline VTKM_CONT vtkm::cont::ArrayHandle<ValueType> CleanGrid::MapPointField(
const vtkm::cont::ArrayHandle<ValueType, Storage>& inArray) const
{
VTKM_ASSERT(this->GetCompactPointFields());
return this->PointCompactor.MapPointFieldDeep(inArray);
}
}
}
#endif //vtk_m_filter_CleanGrid_hxx

@ -100,6 +100,7 @@ inline VTKM_CONT vtkm::cont::DataSet ExternalFaces::DoExecute(
if (this->CompactPoints)
{
this->Compactor.SetCompactPointFields(true);
this->Compactor.SetMergePoints(false);
return this->Compactor.DoExecute(output, GetCellSetExplicitPolicy(policy));
}
else

@ -80,6 +80,7 @@ inline vtkm::cont::DataSet ExtractPoints::DoExecute(const vtkm::cont::DataSet& i
if (this->CompactPoints)
{
this->Compactor.SetCompactPointFields(true);
this->Compactor.SetMergePoints(false);
return this->Compactor.DoExecute(output, GetCellSetSingleTypePolicy(policy));
}
else

@ -65,7 +65,6 @@ public:
private:
vtkm::Id Stride;
bool CompactPoints;
vtkm::filter::CleanGrid Compactor;
vtkm::worklet::Mask Worklet;
};
}

@ -73,6 +73,7 @@ inline VTKM_CONT vtkm::cont::DataSet MaskPoints::DoExecute(
if (this->CompactPoints)
{
this->Compactor.SetCompactPointFields(true);
this->Compactor.SetMergePoints(false);
return this->Compactor.DoExecute(output, GetCellSetSingleTypePolicy(policy));
}
else

@ -198,6 +198,7 @@ inline VTKM_CONT vtkm::cont::DataSet ThresholdPoints::DoExecute(
if (this->CompactPoints)
{
this->Compactor.SetCompactPointFields(true);
this->Compactor.SetMergePoints(true);
return this->Compactor.DoExecute(output, GetCellSetSingleTypePolicy(policy));
}
else

@ -20,6 +20,8 @@
#include <vtkm/filter/CleanGrid.h>
#include <vtkm/filter/MarchingCubes.h>
#include <vtkm/cont/testing/MakeTestDataSet.h>
#include <vtkm/cont/testing/Testing.h>
@ -37,46 +39,167 @@ void TestUniformGrid(vtkm::filter::CleanGrid clean)
clean.SetFieldsToPass({ "pointvar", "cellvar" });
vtkm::cont::DataSet outData = clean.Execute(inData);
VTKM_TEST_ASSERT(outData.HasField("pointvar"), "Failed to map point field");
VTKM_TEST_ASSERT(outData.HasField("cellvar"), "Failed to map point field");
VTKM_TEST_ASSERT(outData.HasField("cellvar"), "Failed to map cell field");
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_TEST_ASSERT(outCellSet.GetNumberOfPoints() == 6,
"Wrong number of points: ",
outCellSet.GetNumberOfPoints());
VTKM_TEST_ASSERT(
outCellSet.GetNumberOfCells() == 2, "Wrong number of cells: ", outCellSet.GetNumberOfCells());
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");
VTKM_TEST_ASSERT((cellIds == vtkm::Vec<vtkm::Id, 4>(0, 1, 4, 3)), "Bad cell ids: ", cellIds);
outCellSet.GetIndices(1, cellIds);
VTKM_TEST_ASSERT((cellIds == vtkm::Vec<vtkm::Id, 4>(1, 2, 5, 4)), "Bad cell ids");
VTKM_TEST_ASSERT((cellIds == vtkm::Vec<vtkm::Id, 4>(1, 2, 5, 4)), "Bad cell ids: ", cellIds);
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(outPointField.GetNumberOfValues() == 6,
"Wrong point field size: ",
outPointField.GetNumberOfValues());
VTKM_TEST_ASSERT(test_equal(outPointField.GetPortalConstControl().Get(1), 20.1),
"Bad point field value");
"Bad point field value: ",
outPointField.GetPortalConstControl().Get(1));
VTKM_TEST_ASSERT(test_equal(outPointField.GetPortalConstControl().Get(4), 50.1),
"Bad point field value");
"Bad point field value: ",
outPointField.GetPortalConstControl().Get(1));
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");
"Bad cell field value",
outCellField.GetPortalConstControl().Get(0));
VTKM_TEST_ASSERT(test_equal(outCellField.GetPortalConstControl().Get(1), 200.1),
"Bad cell field value");
"Bad cell field value",
outCellField.GetPortalConstControl().Get(0));
}
void TestPointMerging()
{
vtkm::cont::testing::MakeTestDataSet makeDataSet;
vtkm::cont::DataSet baseData = makeDataSet.Make3DUniformDataSet3(vtkm::Id3(4, 4, 4));
vtkm::filter::MarchingCubes marchingCubes;
marchingCubes.SetIsoValue(0.05);
marchingCubes.SetMergeDuplicatePoints(false);
marchingCubes.SetActiveField("pointvar");
vtkm::cont::DataSet inData = marchingCubes.Execute(baseData);
constexpr vtkm::Id originalNumPoints = 228;
constexpr vtkm::Id originalNumCells = 76;
VTKM_TEST_ASSERT(inData.GetCellSet().GetNumberOfPoints() == originalNumPoints);
VTKM_TEST_ASSERT(inData.GetCellSet().GetNumberOfCells() == originalNumCells);
vtkm::filter::CleanGrid cleanGrid;
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);
VTKM_TEST_ASSERT(noMerging.GetCoordinateSystem().GetData().GetNumberOfValues() ==
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);
cleanGrid.SetFastMerge(false);
vtkm::cont::DataSet closeMerge = cleanGrid.Execute(inData);
constexpr vtkm::Id closeMergeNumPoints = 62;
VTKM_TEST_ASSERT(closeMerge.GetCellSet().GetNumberOfCells() == originalNumCells);
VTKM_TEST_ASSERT(closeMerge.GetCellSet().GetNumberOfPoints() == closeMergeNumPoints);
VTKM_TEST_ASSERT(closeMerge.GetCoordinateSystem().GetData().GetNumberOfValues() ==
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);
vtkm::cont::DataSet closeFastMerge = cleanGrid.Execute(inData);
VTKM_TEST_ASSERT(closeFastMerge.GetCellSet().GetNumberOfCells() == originalNumCells);
VTKM_TEST_ASSERT(closeFastMerge.GetCellSet().GetNumberOfPoints() == closeMergeNumPoints);
VTKM_TEST_ASSERT(closeFastMerge.GetCoordinateSystem().GetData().GetNumberOfValues() ==
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);
cleanGrid.SetTolerance(0.1);
vtkm::cont::DataSet farMerge = cleanGrid.Execute(inData);
constexpr vtkm::Id farMergeNumPoints = 36;
VTKM_TEST_ASSERT(farMerge.GetCellSet().GetNumberOfCells() == originalNumCells);
VTKM_TEST_ASSERT(farMerge.GetCellSet().GetNumberOfPoints() == farMergeNumPoints);
VTKM_TEST_ASSERT(farMerge.GetCoordinateSystem().GetData().GetNumberOfValues() ==
farMergeNumPoints);
VTKM_TEST_ASSERT(farMerge.GetField("pointvar").GetData().GetNumberOfValues() ==
farMergeNumPoints);
VTKM_TEST_ASSERT(farMerge.GetField("cellvar").GetData().GetNumberOfValues() == originalNumCells);
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;
VTKM_TEST_ASSERT(farFastMerge.GetCellSet().GetNumberOfCells() == originalNumCells);
VTKM_TEST_ASSERT(farFastMerge.GetCellSet().GetNumberOfPoints() == farFastMergeNumPoints);
VTKM_TEST_ASSERT(farFastMerge.GetCoordinateSystem().GetData().GetNumberOfValues() ==
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()
{
vtkm::filter::CleanGrid clean;
std::cout << "*** Test wqith compact point fields on" << std::endl;
std::cout << "*** Test with compact point fields on merge points off" << std::endl;
clean.SetCompactPointFields(true);
clean.SetMergePoints(false);
TestUniformGrid(clean);
std::cout << "*** Test wqith compact point fields off" << std::endl;
std::cout << "*** Test with compact point fields off merge points off" << std::endl;
clean.SetCompactPointFields(false);
clean.SetMergePoints(false);
TestUniformGrid(clean);
std::cout << "*** Test with compact point fields on merge points on" << std::endl;
clean.SetCompactPointFields(true);
clean.SetMergePoints(true);
TestUniformGrid(clean);
std::cout << "*** Test with compact point fields off merge points on" << std::endl;
clean.SetCompactPointFields(false);
clean.SetMergePoints(true);
TestUniformGrid(clean);
std::cout << "*** Test point merging" << std::endl;
TestPointMerging();
}
} // anonymous namespace

@ -35,6 +35,8 @@ vtkm::cont::DataSet MakeDataTestSet1()
vtkm::cont::DataSet ds = MakeTestDataSet().Make3DUniformDataSet1();
vtkm::filter::CleanGrid clean;
clean.SetCompactPointFields(false);
clean.SetMergePoints(false);
return clean.Execute(ds);
}

@ -503,6 +503,7 @@ void TestMarchingCubesNormals()
std::cout << "\tUnstructured dataset\n";
vtkm::filter::CleanGrid makeUnstructured;
makeUnstructured.SetCompactPointFields(false);
makeUnstructured.SetMergePoints(false);
makeUnstructured.SetFieldsToPass("pointvar");
auto result = makeUnstructured.Execute(dataset);
TestNormals(result, false);

@ -25,7 +25,6 @@
#include <vtkm/cont/DataSetBuilderUniform.h>
#include <vtkm/cont/DataSetFieldAdd.h>
#include <vtkm/cont/testing/Testing.h>
#include <vtkm/filter/CleanGrid.h>
#include <vtkm/filter/ZFPCompressor1D.h>
#include <vtkm/filter/ZFPCompressor2D.h>

@ -63,7 +63,7 @@ struct ArrayPortalValueReference
VTKM_SUPPRESS_EXEC_WARNINGS
VTKM_EXEC_CONT
operator ValueType(void) const { return this->Portal.Get(this->Index); }
operator ValueType(void) const { return this->Get(); }
// Declaring Set as const seems a little weird because we are changing the value. But remember
// that ArrayPortalReference is only a reference class. The reference itself does not change,

@ -84,10 +84,10 @@
// just constexpr
#if defined(VTKM_CUDA_VERSION_MAJOR) && (VTKM_CUDA_VERSION_MAJOR < 8)
#define VTKM_STATIC_CONSTEXPR_ARRAY constexpr
// cuda 8+ doesn't support static constexpr pointers/fixed size arrays
// cuda 8-9 doesn't support static constexpr pointers/fixed size arrays
// that exist inside methods or classes, so in those cases we gracefully
// fall back to static const
#elif defined(VTKM_CUDA_VERSION_MAJOR) && (VTKM_CUDA_VERSION_MAJOR >= 8)
#elif defined(VTKM_CUDA_VERSION_MAJOR) && (VTKM_CUDA_VERSION_MAJOR < 10)
#define VTKM_STATIC_CONSTEXPR_ARRAY static const
#else
#define VTKM_STATIC_CONSTEXPR_ARRAY static constexpr

@ -33,13 +33,13 @@ namespace internal
/// track of the types of all parameters and the associated features of the
/// worklet. \c Invocation is a class that manages all these types.
///
template <typename _ParameterInterface,
typename _ControlInterface,
typename _ExecutionInterface,
vtkm::IdComponent _InputDomainIndex,
typename _OutputToInputMapType = vtkm::internal::NullType,
typename _VisitArrayType = vtkm::internal::NullType,
typename _ThreadToOutputMapType = vtkm::internal::NullType>
template <typename ParameterInterface_,
typename ControlInterface_,
typename ExecutionInterface_,
vtkm::IdComponent InputDomainIndex_,
typename OutputToInputMapType_ = vtkm::internal::NullType,
typename VisitArrayType_ = vtkm::internal::NullType,
typename ThreadToOutputMapType_ = vtkm::internal::NullType>
struct Invocation
{
/// \brief The types of the parameters
@ -47,7 +47,7 @@ struct Invocation
/// \c ParameterInterface is (expected to be) a \c FunctionInterface class
/// that lists the types of the parameters for the invocation.
///
using ParameterInterface = _ParameterInterface;
using ParameterInterface = ParameterInterface_;
/// \brief The tags of the \c ControlSignature.
///
@ -55,7 +55,7 @@ struct Invocation
/// represents the \c ControlSignature of a worklet (although dispatchers
/// might modify the control signature to provide auxiliary information).
///
using ControlInterface = _ControlInterface;
using ControlInterface = ControlInterface_;
/// \brief The tags of the \c ExecutionSignature.
///
@ -63,7 +63,7 @@ struct Invocation
/// represents the \c ExecutionSignature of a worklet (although dispatchers
/// might modify the execution signature to provide auxiliary information).
///
using ExecutionInterface = _ExecutionInterface;
using ExecutionInterface = ExecutionInterface_;
/// \brief The index of the input domain.
///
@ -71,7 +71,7 @@ struct Invocation
/// constituent element of the input (such as the points or cells). This
/// index points to the parameter that defines this input domain.
///
static constexpr vtkm::IdComponent InputDomainIndex = _InputDomainIndex;
static constexpr vtkm::IdComponent InputDomainIndex = InputDomainIndex_;
/// \brief An array representing the output to input map.
///
@ -80,7 +80,7 @@ struct Invocation
/// represented with a map where each output points to an input that creates
/// it.
///
using OutputToInputMapType = _OutputToInputMapType;
using OutputToInputMapType = OutputToInputMapType_;
/// \brief An array containing visit indices.
///
@ -89,7 +89,7 @@ struct Invocation
/// multiple outputs may point to the same input. The visit index uniquely
/// identifies which instance each is.
///
using VisitArrayType = _VisitArrayType;
using VisitArrayType = VisitArrayType_;
/// \brief An array representing the thread to output map.
///
@ -97,7 +97,7 @@ struct Invocation
/// prevent the worklet to be run on masked-out elements of the output. This
/// is represented with a map where each thread points to an output it creates.
///
using ThreadToOutputMapType = _ThreadToOutputMapType;
using ThreadToOutputMapType = ThreadToOutputMapType_;
/// \brief Default Invocation constructors that holds the given parameters
/// by reference.

@ -24,7 +24,7 @@ add_library(vtkm_diy INTERFACE)
vtkm_get_kit_name(kit_name kit_dir)
# diy needs C++11
target_compile_features(vtkm_diy INTERFACE cxx_auto_type)
target_compile_features(vtkm_diy INTERFACE cxx_std_11)
# placeholder to support external DIY
set(VTKM_USE_EXTERNAL_DIY OFF)

@ -24,7 +24,7 @@ add_library(vtkm_loguru INTERFACE)
vtkm_get_kit_name(kit_name kit_dir)
# taotuple needs C++11
target_compile_features(vtkm_loguru INTERFACE cxx_auto_type)
target_compile_features(vtkm_loguru INTERFACE cxx_std_11)
target_include_directories(vtkm_loguru INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>

@ -24,7 +24,7 @@ add_library(vtkm_taotuple INTERFACE)
vtkm_get_kit_name(kit_name kit_dir)
# taotuple needs C++11
target_compile_features(vtkm_taotuple INTERFACE cxx_auto_type)
target_compile_features(vtkm_taotuple INTERFACE cxx_std_11)
target_include_directories(vtkm_taotuple INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>

@ -62,8 +62,10 @@ set(headers
ParticleAdvection.h
PointAverage.h
PointElevation.h
PointMerge.h
PointTransform.h
Probe.h
RemoveDegenerateCells.h
RemoveUnusedPoints.h
ScalarsToColors.h
ScatterCounting.h

@ -76,11 +76,11 @@ enum class KeysSortType
/// Keys structure is reused for all the \c Invoke. This is more efficient than
/// creating a different \c Keys structure for each \c Invoke.
///
template <typename _KeyType>
template <typename T>
class VTKM_ALWAYS_EXPORT Keys
{
public:
using KeyType = _KeyType;
using KeyType = T;
using KeyArrayHandleType = vtkm::cont::ArrayHandle<KeyType>;
VTKM_CONT
@ -272,8 +272,8 @@ private:
}
};
template <typename _KeyType>
VTKM_CONT Keys<_KeyType>::Keys() = default;
template <typename T>
VTKM_CONT Keys<T>::Keys() = default;
}
} // namespace vtkm::worklet

502
vtkm/worklet/PointMerge.h Normal file

@ -0,0 +1,502 @@
//============================================================================
// 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_PointMerge_h
#define vtk_m_worklet_PointMerge_h
#include <vtkm/worklet/AverageByKey.h>
#include <vtkm/worklet/DispatcherMapField.h>
#include <vtkm/worklet/DispatcherReduceByKey.h>
#include <vtkm/worklet/Invoker.h>
#include <vtkm/worklet/Keys.h>
#include <vtkm/worklet/RemoveUnusedPoints.h>
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/worklet/WorkletReduceByKey.h>
#include <vtkm/cont/ArrayCopy.h>
#include <vtkm/cont/ArrayHandleIndex.h>
#include <vtkm/cont/ArrayHandlePermutation.h>
#include <vtkm/cont/ArrayHandleVirtual.h>
#include <vtkm/cont/CellSetExplicit.h>
#include <vtkm/cont/ExecutionAndControlObjectBase.h>
#include <vtkm/Bounds.h>
#include <vtkm/Hash.h>
#include <vtkm/Math.h>
#include <vtkm/VectorAnalysis.h>
namespace vtkm
{
namespace worklet
{
class PointMerge
{
public:
// This class can take point worldCoords as inputs and return the bin index of the enclosing bin.
class BinLocator : public vtkm::cont::ExecutionAndControlObjectBase
{
vtkm::Vec<vtkm::Float64, 3> Offset;
vtkm::Vec<vtkm::Float64, 3> Scale;
#ifdef VTKM_USE_64BIT_IDS
// IEEE double precision floating point as 53 bits for the significand, so it would not be
// possible to represent a number with more precision than that. We also back off a few bits to
// avoid potential issues with numerical imprecision in the scaling.
static constexpr vtkm::IdComponent BitsPerDimension = 50;
#else
static constexpr vtkm::IdComponent BitsPerDimension = 31;
#endif
static constexpr vtkm::Id MaxBinsPerDimension =
static_cast<vtkm::Id>((1LL << BitsPerDimension) - 1);
public:
VTKM_CONT BinLocator()
: Offset(0.0)
, Scale(0.0)
{
}
VTKM_CONT
static vtkm::Vec<vtkm::Float64, 3> ComputeBinWidths(const vtkm::Bounds& bounds,
vtkm::Float64 delta)
{
const vtkm::Vec<vtkm::Float64, 3> boundLengths(
bounds.X.Length() + delta, bounds.Y.Length() + delta, bounds.Z.Length() + delta);
vtkm::Vec<vtkm::Float64, 3> binWidths;
for (vtkm::IdComponent dimIndex = 0; dimIndex < 3; ++dimIndex)
{
if (boundLengths[dimIndex] > vtkm::Epsilon64())
{
vtkm::Float64 minBinWidth = boundLengths[dimIndex] / (MaxBinsPerDimension - 1);
if (minBinWidth < (2 * delta))
{
// We can accurately represent delta with the precision of the bin indices. The bin
// size is 2*delta, which means we scale the (offset) point coordinates by 1/delta to
// get the bin index.
binWidths[dimIndex] = 2.0 * delta;
}
else
{
// Scale the (offset) point coordinates by 1/minBinWidth, which will give us bin
// indices between 0 and MaxBinsPerDimension - 1.
binWidths[dimIndex] = minBinWidth;
}
}
else
{
// Bounds are essentially 0 in this dimension. The scale does not matter so much.
binWidths[dimIndex] = 1.0;
}
}
return binWidths;
}
// Constructs a BinLocator such that all bins are at least 2*delta large. The bins might be
// made larger than that if there would be too many bins for the precision of vtkm::Id.
VTKM_CONT
BinLocator(const vtkm::Bounds& bounds, vtkm::Float64 delta = 0.0)
: Offset(bounds.X.Min, bounds.Y.Min, bounds.Z.Min)
{
const vtkm::Vec<vtkm::Float64, 3> binWidths = ComputeBinWidths(bounds, delta);
this->Scale = vtkm::Vec<vtkm::Float64, 3>(1.0) / binWidths;
}
// Shifts the grid by delta in the specified directions. This will allow the bins to cover
// neighbors that straddled the boundaries of the original.
VTKM_CONT
BinLocator ShiftBins(const vtkm::Bounds& bounds,
vtkm::Float64 delta,
const vtkm::Vec<bool, 3>& directions)
{
const vtkm::Vec<vtkm::Float64, 3> binWidths = ComputeBinWidths(bounds, delta);
BinLocator shiftedLocator(*this);
for (vtkm::IdComponent dimIndex = 0; dimIndex < 3; ++dimIndex)
{
if (directions[dimIndex])
{
shiftedLocator.Offset[dimIndex] -= (0.5 * binWidths[dimIndex]);
}
}
return shiftedLocator;
}
template <typename T>
VTKM_EXEC_CONT vtkm::Id3 FindBin(const vtkm::Vec<T, 3>& worldCoords) const
{
vtkm::Vec<vtkm::Float64, 3> relativeCoords = (worldCoords - this->Offset) * this->Scale;
return vtkm::Id3(vtkm::Floor(relativeCoords));
}
// Because this class is a POD, we can reuse it in both control and execution environments.
template <typename Device>
BinLocator PrepareForExecution(Device) const
{
return *this;
}
BinLocator PrepareForControl() const { return *this; }
};
// Converts point coordinates to a hash that represents the bin.
struct CoordsToHash : public vtkm::worklet::WorkletMapField
{
using ControlSignature = void(FieldIn pointCoordinates,
ExecObject binLocator,
FieldOut hashesOut);
using ExecutionSignature = void(_1, _2, _3);
template <typename T>
VTKM_EXEC void operator()(const vtkm::Vec<T, 3>& coordiantes,
const BinLocator binLocator,
vtkm::HashType& hashOut) const
{
vtkm::Id3 binId = binLocator.FindBin(coordiantes);
hashOut = vtkm::Hash(binId);
}
};
class FindNeighbors : public vtkm::worklet::WorkletReduceByKey
{
vtkm::Float64 DeltaSquared;
bool FastCheck;
public:
VTKM_CONT
FindNeighbors(bool fastCheck = true, vtkm::Float64 delta = vtkm::Epsilon64())
: DeltaSquared(delta * delta)
, FastCheck(fastCheck)
{
}
using ControlSignature = void(KeysIn keys,
ValuesInOut pointIndices,
ValuesInOut pointCoordinates,
ExecObject binLocator,
ValuesOut neighborIndices);
using ExecutionSignature = void(_2, _3, _4, _5);
template <typename IndexVecInType, typename CoordinateVecInType, typename IndexVecOutType>
VTKM_EXEC void operator()(IndexVecInType& pointIndices,
CoordinateVecInType& pointCoordinates,
const BinLocator& binLocator,
IndexVecOutType& neighborIndices) const
{
// For each point we are going to find all points close enough to be considered neighbors. We
// record the neighbors by filling in the same index into neighborIndices. That is, if two
// items in neighborIndices have the same value, they should be considered neighbors.
// Otherwise, they should not. We will use the "local" index, which refers to index in the
// vec-like objects passed into this worklet. This allows us to quickly identify the local
// point without sorting through the global indices.
using CoordType = typename CoordinateVecInType::ComponentType;
vtkm::IdComponent numPoints = pointIndices.GetNumberOfComponents();
VTKM_ASSERT(numPoints == pointCoordinates.GetNumberOfComponents());
VTKM_ASSERT(numPoints == neighborIndices.GetNumberOfComponents());
// Initially, set every point to be its own neighbor.
for (vtkm::IdComponent i = 0; i < numPoints; ++i)
{
neighborIndices[i] = i;
}
// Iterate over every point and look for neighbors. Only need to look to numPoints-1 since we
// only need to check points after the current index (earlier points are already checked).
for (vtkm::IdComponent i = 0; i < (numPoints - 1); ++i)
{
CoordType p0 = pointCoordinates[i];
vtkm::Id3 bin0 = binLocator.FindBin(p0);
// Check all points after this one. (All those before already checked themselves to this.)
for (vtkm::IdComponent j = i + 1; j < numPoints; ++j)
{
if (neighborIndices[i] == neighborIndices[j])
{
// We have already identified these points as neighbors. Can skip the check.
continue;
}
CoordType p1 = pointCoordinates[j];
vtkm::Id3 bin1 = binLocator.FindBin(p1);
// Check to see if these points should be considered neighbors. First, check to make sure
// that they are in the same bin. If they are not, then they cannot be neighbors. Next,
// check the FastCheck flag. If fast checking is on, then all points in the same bin are
// considered neighbors. Otherwise, check that the distance is within the specified
// delta. If so, mark them as neighbors.
if ((bin0 == bin1) &&
(this->FastCheck || (this->DeltaSquared >= vtkm::MagnitudeSquared(p0 - p1))))
{
// The two points should be merged. But we also might need to merge larger
// neighborhoods.
if (neighborIndices[j] == j)
{
// Second point not yet merged into another neighborhood. We can just take it.
neighborIndices[j] = neighborIndices[i];
}
else
{
// The second point is already part of a neighborhood. Merge the neighborhood with
// the largest index into the neighborhood with the smaller index.
vtkm::IdComponent neighborhoodToGrow;
vtkm::IdComponent neighborhoodToAbsorb;
if (neighborIndices[i] < neighborIndices[j])
{
neighborhoodToGrow = neighborIndices[i];
neighborhoodToAbsorb = neighborIndices[j];
}
else
{
neighborhoodToGrow = neighborIndices[j];
neighborhoodToAbsorb = neighborIndices[i];
}
// Change all neighborhoodToAbsorb indices to neighborhoodToGrow.
for (vtkm::IdComponent k = neighborhoodToAbsorb; k < numPoints; ++k)
{
if (neighborIndices[k] == neighborhoodToAbsorb)
{
neighborIndices[k] = neighborhoodToGrow;
}
}
}
} // if merge points
} // for each p1
} // for each p0
// We have finished grouping neighbors. neighborIndices contains a unique local index for
// each neighbor group. Now find the average (centroid) point coordinates for each group and
// write those coordinates back into the coordinates array. Also modify the point indices
// so that all indices of a group are the same. (This forms a map from old point indices to
// merged point indices.)
for (vtkm::IdComponent i = 0; i < numPoints; ++i)
{
vtkm::IdComponent neighborhood = neighborIndices[i];
if (i == neighborhood)
{
// Found a new group. Find the centroid.
CoordType centroid = pointCoordinates[i];
vtkm::IdComponent numInGroup = 1;
for (vtkm::IdComponent j = i + 1; j < numPoints; ++j)
{
if (neighborhood == neighborIndices[j])
{
centroid = centroid + pointCoordinates[j];
++numInGroup;
}
}
centroid = centroid / numInGroup;
// Now that we have the centroid, write new point coordinates and index.
vtkm::Id groupIndex = pointIndices[i];
pointCoordinates[i] = centroid;
for (vtkm::IdComponent j = i + 1; j < numPoints; ++j)
{
if (neighborhood == neighborIndices[j])
{
pointCoordinates[j] = centroid;
pointIndices[j] = groupIndex;
}
}
}
}
}
};
struct BuildPointInputToOutputMap : vtkm::worklet::WorkletReduceByKey
{
using ControlSignature = void(KeysIn, ValuesOut PointInputToOutputMap);
using ExecutionSignature = void(InputIndex, _2);
template <typename MapPortalType>
VTKM_EXEC void operator()(vtkm::Id newIndex, MapPortalType outputIndices) const
{
const vtkm::IdComponent numIndices = outputIndices.GetNumberOfComponents();
for (vtkm::IdComponent i = 0; i < numIndices; ++i)
{
outputIndices[i] = newIndex;
}
}
};
private:
template <typename T>
VTKM_CONT static void RunOneIteration(
vtkm::Float64 delta, // Distance to consider two points coincident
bool fastCheck, // If true, approximate distances are used
const BinLocator& binLocator, // Used to find nearby points
vtkm::cont::ArrayHandle<vtkm::Vec<T, 3>>& points, // coordinates, modified to merge close
vtkm::cont::ArrayHandle<vtkm::Id> indexNeighborMap) // identifies each neighbor group, updated
{
Invoker invoker;
vtkm::cont::ArrayHandle<vtkm::HashType> hashes;
invoker(CoordsToHash(), points, binLocator, hashes);
vtkm::worklet::Keys<HashType> keys(hashes);
// Really just scratch space
vtkm::cont::ArrayHandle<vtkm::IdComponent> neighborIndices;
invoker(
FindNeighbors(fastCheck, delta), keys, indexNeighborMap, points, binLocator, neighborIndices);
}
public:
template <typename T>
VTKM_CONT void Run(
vtkm::Float64 delta, // Distance to consider two points coincident
bool fastCheck, // If true, approximate distances are used
const vtkm::Bounds& bounds, // Bounds of points
vtkm::cont::ArrayHandle<vtkm::Vec<T, 3>>& points) // coordinates, modified to merge close
{
Invoker invoker;
BinLocator binLocator(bounds, delta);
vtkm::cont::ArrayHandle<vtkm::Id> indexNeighborMap;
vtkm::cont::ArrayCopy(vtkm::cont::ArrayHandleIndex(points.GetNumberOfValues()),
indexNeighborMap);
this->RunOneIteration(delta, fastCheck, binLocator, points, indexNeighborMap);
if (!fastCheck)
{
// Run the algorithm again after shifting the bins to capture nearby points that straddled
// the previous bins.
this->RunOneIteration(delta,
fastCheck,
binLocator.ShiftBins(bounds, delta, vtkm::make_Vec(true, false, false)),
points,
indexNeighborMap);
this->RunOneIteration(delta,
fastCheck,
binLocator.ShiftBins(bounds, delta, vtkm::make_Vec(false, true, false)),
points,
indexNeighborMap);
this->RunOneIteration(delta,
fastCheck,
binLocator.ShiftBins(bounds, delta, vtkm::make_Vec(false, false, true)),
points,
indexNeighborMap);
this->RunOneIteration(delta,
fastCheck,
binLocator.ShiftBins(bounds, delta, vtkm::make_Vec(true, true, false)),
points,
indexNeighborMap);
this->RunOneIteration(delta,
fastCheck,
binLocator.ShiftBins(bounds, delta, vtkm::make_Vec(true, false, true)),
points,
indexNeighborMap);
this->RunOneIteration(delta,
fastCheck,
binLocator.ShiftBins(bounds, delta, vtkm::make_Vec(false, true, true)),
points,
indexNeighborMap);
this->RunOneIteration(delta,
fastCheck,
binLocator.ShiftBins(bounds, delta, vtkm::make_Vec(true, true, true)),
points,
indexNeighborMap);
}
this->MergeKeys = vtkm::worklet::Keys<vtkm::Id>(indexNeighborMap);
invoker(BuildPointInputToOutputMap(), this->MergeKeys, this->PointInputToOutputMap);
// Need to pull out the unique point coordiantes
vtkm::cont::ArrayHandle<vtkm::Vec<T, 3>> uniquePointCoordinates;
vtkm::cont::ArrayCopy(
vtkm::cont::make_ArrayHandlePermutation(this->MergeKeys.GetUniqueKeys(), points),
uniquePointCoordinates);
points = uniquePointCoordinates;
}
VTKM_CONT void Run(
vtkm::Float64 delta, // Distance to consider two points coincident
bool fastCheck, // If true, approximate distances are used
const vtkm::Bounds& bounds, // Bounds of points
vtkm::cont::ArrayHandleVirtualCoordinates& points) // coordinates, modified to merge close
{
// Get a cast to a concrete set of point coordiantes so that it can be modified in place
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::FloatDefault, 3>> concretePoints;
if (points.IsType<decltype(concretePoints)>())
{
concretePoints = points.Cast<decltype(concretePoints)>();
}
else
{
vtkm::cont::ArrayCopy(points, concretePoints);
}
Run(delta, fastCheck, bounds, concretePoints);
// Make sure that the modified points are reflected back in the virtual array.
points = vtkm::cont::ArrayHandleVirtualCoordinates(concretePoints);
}
template <typename ShapeStorage,
typename NumIndicesStorage,
typename ConnectivityStorage,
typename OffsetsStorage>
VTKM_CONT vtkm::cont::CellSetExplicit<ShapeStorage,
NumIndicesStorage,
VTKM_DEFAULT_CONNECTIVITY_STORAGE_TAG,
OffsetsStorage>
MapCellSet(const vtkm::cont::CellSetExplicit<ShapeStorage,
NumIndicesStorage,
ConnectivityStorage,
OffsetsStorage>& inCellSet) const
{
return vtkm::worklet::RemoveUnusedPoints::MapCellSet(
inCellSet, this->PointInputToOutputMap, this->MergeKeys.GetInputRange());
}
template <typename InArrayHandle, typename OutArrayHandle>
VTKM_CONT void MapPointField(const InArrayHandle& inArray, OutArrayHandle& outArray) const
{
VTKM_IS_ARRAY_HANDLE(InArrayHandle);
VTKM_IS_ARRAY_HANDLE(OutArrayHandle);
vtkm::worklet::AverageByKey::Run(this->MergeKeys, inArray, outArray);
}
template <typename InArrayHandle>
VTKM_CONT vtkm::cont::ArrayHandle<typename InArrayHandle::ValueType> MapPointField(
const InArrayHandle& inArray) const
{
VTKM_IS_ARRAY_HANDLE(InArrayHandle);
vtkm::cont::ArrayHandle<typename InArrayHandle::ValueType> outArray;
this->MapPointField(inArray, outArray);
return outArray;
}
private:
vtkm::worklet::Keys<vtkm::Id> MergeKeys;
vtkm::cont::ArrayHandle<vtkm::Id> PointInputToOutputMap;
};
}
} // namespace vtkm::worklet
#endif //vtk_m_worklet_PointMerge_h

@ -0,0 +1,186 @@
//============================================================================
// 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

@ -141,7 +141,7 @@ public:
/// \brief Map cell indices
///
/// Given a cell set (typically the same one passed to the constructor) and
/// Given a cell set (typically the same one passed to the constructor)
/// returns a new cell set with cell points transformed to use the indices of
/// the new reduced point arrays.
///
@ -157,22 +157,54 @@ public:
NumIndicesStorage,
ConnectivityStorage,
OffsetsStorage>& inCellSet) const
{
VTKM_ASSERT(this->PointScatter);
return MapCellSet(inCellSet,
this->PointScatter->GetInputToOutputMap(),
this->PointScatter->GetOutputToInputMap().GetNumberOfValues());
}
/// \brief Map cell indices
///
/// Given a cell set (typically the same one passed to the constructor) and
/// an array that maps point indices from an old set of indices to a new set,
/// returns a new cell set with cell points transformed to use the indices of
/// the new reduced point arrays.
///
/// This helper method can be used by external items that do similar operations
/// that remove points or otherwise rearange points in a cell set. If points
/// were removed by calling \c FindPoints, then you should use the other form
/// of \c MapCellSet.
///
template <typename ShapeStorage,
typename NumIndicesStorage,
typename ConnectivityStorage,
typename OffsetsStorage,
typename MapStorage>
VTKM_CONT static vtkm::cont::CellSetExplicit<ShapeStorage,
NumIndicesStorage,
VTKM_DEFAULT_CONNECTIVITY_STORAGE_TAG,
OffsetsStorage>
MapCellSet(const vtkm::cont::CellSetExplicit<ShapeStorage,
NumIndicesStorage,
ConnectivityStorage,
OffsetsStorage>& inCellSet,
const vtkm::cont::ArrayHandle<vtkm::Id, MapStorage>& inputToOutputPointMap,
vtkm::Id numberOfPoints)
{
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> dispatcher;
dispatcher.Invoke(inCellSet.GetConnectivityArray(FromTopology(), ToTopology()),
this->PointScatter->GetInputToOutputMap(),
inputToOutputPointMap,
newConnectivityArray);
vtkm::Id numberOfPoints = this->PointScatter->GetOutputToInputMap().GetNumberOfValues();
vtkm::cont::
CellSetExplicit<ShapeStorage, NumIndicesStorage, NewConnectivityStorage, OffsetsStorage>
outCellSet(inCellSet.GetName());

@ -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);