Updating threshold to return all or part in range.

This commit is contained in:
James 2021-08-31 15:33:45 -04:00
parent d28bdec48d
commit 0e6228bbd8
5 changed files with 260 additions and 72 deletions

@ -45,6 +45,15 @@ public:
VTKM_CONT
vtkm::Float64 GetUpperThreshold() const { return this->UpperValue; }
//If using scalars from point data, all scalars for all points in a cell must
//satisfy the threshold criterion if AllScalars is set. Otherwise, just a
//single scalar value satisfying the threshold criterion will extract the cell.
VTKM_CONT
void SetAllInRange(bool value) { this->ReturnAllInRange = value; }
VTKM_CONT
bool GetAllInRange() const { return this->ReturnAllInRange; }
template <typename T, typename StorageType, typename DerivedPolicy>
VTKM_CONT vtkm::cont::DataSet DoExecute(const vtkm::cont::DataSet& input,
const vtkm::cont::ArrayHandle<T, StorageType>& field,
@ -66,6 +75,7 @@ public:
private:
double LowerValue = 0;
double UpperValue = 0;
bool ReturnAllInRange = false;
vtkm::worklet::Threshold Worklet;
};

@ -71,7 +71,8 @@ vtkm::cont::DataSet Threshold::DoExecute(const vtkm::cont::DataSet& input,
this->Worklet.Run(vtkm::filter::ApplyPolicyCellSet(cells, policy, *this),
field,
fieldMeta.GetAssociation(),
predicate);
predicate,
this->GetAllInRange());
vtkm::cont::DataSet output;
output.SetCellSet(cellOut);

@ -10,7 +10,6 @@
#include <vtkm/cont/testing/MakeTestDataSet.h>
#include <vtkm/cont/testing/Testing.h>
#include <vtkm/filter/CleanGrid.h>
#include <vtkm/filter/Threshold.h>
@ -22,28 +21,55 @@ namespace
class TestingThreshold
{
public:
void TestRegular2D() const
void TestRegular2D(bool returnAllInRange) const
{
std::cout << "Testing threshold on 2D regular dataset" << std::endl;
vtkm::cont::DataSet dataset = MakeTestDataSet().Make2DUniformDataSet0();
vtkm::filter::Threshold threshold;
threshold.SetLowerThreshold(60.1);
threshold.SetUpperThreshold(60.1);
if (returnAllInRange)
{
std::cout << "Testing threshold on 2D regular dataset returning values 'all in range'"
<< std::endl;
threshold.SetLowerThreshold(10);
threshold.SetUpperThreshold(60);
}
else
{
std::cout << "Testing threshold on 2D regular dataset returning values 'part in range'"
<< std::endl;
threshold.SetLowerThreshold(60);
threshold.SetUpperThreshold(61);
}
threshold.SetAllInRange(returnAllInRange);
threshold.SetActiveField("pointvar");
threshold.SetFieldsToPass("cellvar");
auto output = threshold.Execute(dataset);
VTKM_TEST_ASSERT(output.GetNumberOfFields() == 1,
"Wrong number of fields in the output dataset");
if (returnAllInRange)
{
VTKM_TEST_ASSERT(output.GetNumberOfFields() == 1,
"Wrong number of fields in the output dataset");
vtkm::cont::ArrayHandle<vtkm::Float32> cellFieldArray;
output.GetField("cellvar").GetData().AsArrayHandle(cellFieldArray);
vtkm::cont::ArrayHandle<vtkm::Float32> cellFieldArray;
output.GetField("cellvar").GetData().AsArrayHandle(cellFieldArray);
VTKM_TEST_ASSERT(cellFieldArray.GetNumberOfValues() == 1 &&
cellFieldArray.ReadPortal().Get(0) == 200.1f,
"Wrong cell field data");
VTKM_TEST_ASSERT(cellFieldArray.GetNumberOfValues() == 1 &&
cellFieldArray.ReadPortal().Get(0) == 100.1f,
"Wrong cell field data");
}
else
{
VTKM_TEST_ASSERT(output.GetNumberOfFields() == 1,
"Wrong number of fields in the output dataset");
vtkm::cont::ArrayHandle<vtkm::Float32> cellFieldArray;
output.GetField("cellvar").GetData().AsArrayHandle(cellFieldArray);
VTKM_TEST_ASSERT(cellFieldArray.GetNumberOfValues() == 1 &&
cellFieldArray.ReadPortal().Get(0) == 200.1f,
"Wrong cell field data");
}
// Make sure that the resulting data set can be successfully passed to another
// simple filter using the cell set.
@ -51,29 +77,58 @@ public:
clean.Execute(output);
}
void TestRegular3D() const
void TestRegular3D(bool returnAllInRange) const
{
std::cout << "Testing threshold on 3D regular dataset" << std::endl;
vtkm::cont::DataSet dataset = MakeTestDataSet().Make3DUniformDataSet0();
vtkm::filter::Threshold threshold;
threshold.SetLowerThreshold(20.1);
threshold.SetUpperThreshold(20.1);
if (returnAllInRange)
{
std::cout << "Testing threshold on 3D regular dataset returning values 'all in range'"
<< std::endl;
threshold.SetLowerThreshold(10.1);
threshold.SetUpperThreshold(180);
}
else
{
std::cout << "Testing threshold on 3D regular dataset returning values 'part in range'"
<< std::endl;
threshold.SetLowerThreshold(20);
threshold.SetUpperThreshold(21);
}
threshold.SetAllInRange(returnAllInRange);
threshold.SetActiveField("pointvar");
threshold.SetFieldsToPass("cellvar");
auto output = threshold.Execute(dataset);
VTKM_TEST_ASSERT(output.GetNumberOfFields() == 1,
"Wrong number of fields in the output dataset");
if (returnAllInRange)
{
VTKM_TEST_ASSERT(output.GetNumberOfFields() == 1,
"Wrong number of fields in the output dataset");
vtkm::cont::ArrayHandle<vtkm::Float32> cellFieldArray;
output.GetField("cellvar").GetData().AsArrayHandle(cellFieldArray);
vtkm::cont::ArrayHandle<vtkm::Float32> cellFieldArray;
output.GetField("cellvar").GetData().AsArrayHandle(cellFieldArray);
VTKM_TEST_ASSERT(cellFieldArray.GetNumberOfValues() == 2 &&
cellFieldArray.ReadPortal().Get(0) == 100.1f &&
cellFieldArray.ReadPortal().Get(1) == 100.2f,
"Wrong cell field data");
VTKM_TEST_ASSERT(cellFieldArray.GetNumberOfValues() == 3 &&
cellFieldArray.ReadPortal().Get(0) == 100.1f &&
cellFieldArray.ReadPortal().Get(1) == 100.2f &&
cellFieldArray.ReadPortal().Get(2) == 100.3f,
"Wrong cell field data");
}
else
{
VTKM_TEST_ASSERT(output.GetNumberOfFields() == 1,
"Wrong number of fields in the output dataset");
vtkm::cont::ArrayHandle<vtkm::Float32> cellFieldArray;
output.GetField("cellvar").GetData().AsArrayHandle(cellFieldArray);
VTKM_TEST_ASSERT(cellFieldArray.GetNumberOfValues() == 2 &&
cellFieldArray.ReadPortal().Get(0) == 100.1f &&
cellFieldArray.ReadPortal().Get(1) == 100.2f,
"Wrong cell field data");
}
// Make sure that the resulting data set can be successfully passed to another
// simple filter using the cell set.
@ -88,8 +143,8 @@ public:
vtkm::filter::Threshold threshold;
threshold.SetLowerThreshold(20.1);
threshold.SetUpperThreshold(20.1);
threshold.SetLowerThreshold(20);
threshold.SetUpperThreshold(21);
threshold.SetActiveField("pointvar");
threshold.SetFieldsToPass("cellvar");
auto output = threshold.Execute(dataset);
@ -118,7 +173,7 @@ public:
vtkm::filter::Threshold threshold;
threshold.SetLowerThreshold(500.1);
threshold.SetLowerThreshold(500);
threshold.SetUpperThreshold(500.1);
threshold.SetActiveField("pointvar");
threshold.SetFieldsToPass("cellvar");
@ -140,8 +195,10 @@ public:
void operator()() const
{
this->TestRegular2D();
this->TestRegular3D();
this->TestRegular2D(false);
this->TestRegular2D(true);
this->TestRegular3D(false);
this->TestRegular3D(true);
this->TestExplicit3D();
this->TestExplicit3DZeroResults();
}

@ -48,28 +48,41 @@ public:
VTKM_CONT
ThresholdByPointField()
: Predicate()
, ReturnAllInRange()
{
}
VTKM_CONT
explicit ThresholdByPointField(const UnaryPredicate& predicate)
explicit ThresholdByPointField(const UnaryPredicate& predicate, const bool& returnAllInRange)
: Predicate(predicate)
, ReturnAllInRange(returnAllInRange)
{
}
template <typename ScalarsVecType>
VTKM_EXEC bool operator()(const ScalarsVecType& scalars, vtkm::Id count) const
{
bool pass = false;
bool pass;
if (this->ReturnAllInRange)
pass = true;
else
pass = false;
for (vtkm::IdComponent i = 0; i < count; ++i)
{
pass |= this->Predicate(scalars[i]);
//Only pass a cell if it meets the validity requirement
//"all in range" or "part on range"
if (this->ReturnAllInRange)
pass &= this->Predicate(scalars[i]);
else
pass |= this->Predicate(scalars[i]);
}
return pass;
}
private:
UnaryPredicate Predicate;
bool ReturnAllInRange;
};
struct ThresholdCopy : public vtkm::worklet::WorkletMapField
@ -91,7 +104,8 @@ public:
const CellSetType& cellSet,
const vtkm::cont::ArrayHandle<ValueType, StorageType>& field,
const vtkm::cont::Field::Association fieldType,
const UnaryPredicate& predicate)
const UnaryPredicate& predicate,
const bool returnAllInRange = false)
{
using OutputType = vtkm::cont::CellSetPermutation<CellSetType>;
@ -102,7 +116,7 @@ public:
using ThresholdWorklet = ThresholdByPointField<UnaryPredicate>;
vtkm::cont::ArrayHandle<bool> passFlags;
ThresholdWorklet worklet(predicate);
ThresholdWorklet worklet(predicate, returnAllInRange);
DispatcherMapTopology<ThresholdWorklet> dispatcher(worklet);
dispatcher.Invoke(cellSet, field, passFlags);
@ -136,17 +150,20 @@ public:
const FieldArrayType& Field;
const vtkm::cont::Field::Association FieldType;
const UnaryPredicate& Predicate;
const bool ReturnAllInRange;
CallWorklet(vtkm::cont::DynamicCellSet& output,
vtkm::worklet::Threshold& worklet,
const FieldArrayType& field,
const vtkm::cont::Field::Association fieldType,
const UnaryPredicate& predicate)
const UnaryPredicate& predicate,
const bool returnAllInRange)
: Output(output)
, Worklet(worklet)
, Field(field)
, FieldType(fieldType)
, Predicate(predicate)
, ReturnAllInRange(returnAllInRange)
{
}
@ -154,8 +171,8 @@ public:
void operator()(const CellSetType& cellSet) const
{
// Copy output to an explicit grid so that other units can guess what this is.
this->Output = vtkm::worklet::CellDeepCopy::Run(
this->Worklet.Run(cellSet, this->Field, this->FieldType, this->Predicate));
this->Output = vtkm::worklet::CellDeepCopy::Run(this->Worklet.Run(
cellSet, this->Field, this->FieldType, this->Predicate, this->ReturnAllInRange));
}
};
@ -163,12 +180,13 @@ public:
vtkm::cont::DynamicCellSet Run(const vtkm::cont::DynamicCellSetBase<CellSetList>& cellSet,
const vtkm::cont::ArrayHandle<ValueType, StorageType>& field,
const vtkm::cont::Field::Association fieldType,
const UnaryPredicate& predicate)
const UnaryPredicate& predicate,
const bool returnAllInRange = false)
{
using Worker = CallWorklet<vtkm::cont::ArrayHandle<ValueType, StorageType>, UnaryPredicate>;
vtkm::cont::DynamicCellSet output;
Worker worker(output, *this, field, fieldType, predicate);
Worker worker(output, *this, field, fieldType, predicate, returnAllInRange);
cellSet.CastAndCall(worker);
return output;

@ -10,14 +10,16 @@
#include <vtkm/worklet/Threshold.h>
#include <vtkm/cont/ArrayPortalToIterators.h>
#include <vtkm/cont/testing/MakeTestDataSet.h>
#include <vtkm/cont/testing/Testing.h>
#include <vtkm/cont/ArrayPortalToIterators.h>
#include <algorithm>
#include <iostream>
#include <vector>
#include <vtkm/cont/ArrayPortalToIterators.h>
#include <vtkm/cont/testing/MakeTestDataSet.h>
#include <vtkm/cont/testing/Testing.h>
namespace
{
@ -41,15 +43,49 @@ private:
vtkm::Float32 Value;
};
class ThresholdRange
{
public:
VTKM_CONT
ThresholdRange() {}
ThresholdRange(const vtkm::Float64& lower, const vtkm::Float64& upper)
: Lower(lower)
, Upper(upper)
{
}
void SetLowerValue(const vtkm::Float64& lower) { Lower = lower; }
void SetUpperValue(const vtkm::Float64& upper) { Upper = upper; }
template <typename T>
VTKM_EXEC bool operator()(const T& value) const
{
return value >= static_cast<T>(this->Lower) && value <= static_cast<T>(this->Upper);
}
//Needed to work with ArrayHandleVirtual
template <typename PortalType>
VTKM_EXEC bool operator()(
const vtkm::internal::ArrayPortalValueReference<PortalType>& value) const
{
using T = typename PortalType::ValueType;
return value.Get() >= static_cast<T>(this->Lower) && value.Get() <= static_cast<T>(this->Upper);
}
private:
vtkm::Float64 Lower;
vtkm::Float64 Upper;
};
using vtkm::cont::testing::MakeTestDataSet;
class TestingThreshold
{
public:
void TestUniform2D() const
void TestUniform2D(bool returnAllInRange) const
{
std::cout << "Testing threshold on 2D uniform dataset" << std::endl;
using CellSetType = vtkm::cont::CellSetStructured<2>;
using OutCellSetType = vtkm::cont::CellSetPermutation<CellSetType>;
@ -62,24 +98,54 @@ public:
dataset.GetField("pointvar").GetData().AsArrayHandle(pointvar);
vtkm::worklet::Threshold threshold;
OutCellSetType outCellSet =
threshold.Run(cellset, pointvar, vtkm::cont::Field::Association::POINTS, HasValue(60.1f));
ThresholdRange predicate;
VTKM_TEST_ASSERT(outCellSet.GetNumberOfCells() == 1, "Wrong number of cells");
if (returnAllInRange)
{
std::cout << "Testing threshold on 2D uniform dataset returning values 'all in range'"
<< std::endl;
predicate.SetLowerValue(10);
predicate.SetUpperValue(60);
}
else
{
std::cout << "Testing threshold on 2D uniform dataset returning values 'part in range'"
<< std::endl;
predicate.SetLowerValue(60);
predicate.SetUpperValue(61);
}
vtkm::cont::ArrayHandle<vtkm::Float32> cellvar;
dataset.GetField("cellvar").GetData().AsArrayHandle(cellvar);
vtkm::cont::ArrayHandle<vtkm::Float32> cellFieldArray = threshold.ProcessCellField(cellvar);
OutCellSetType outCellSet = threshold.Run(
cellset, pointvar, vtkm::cont::Field::Association::POINTS, predicate, returnAllInRange);
VTKM_TEST_ASSERT(cellFieldArray.GetNumberOfValues() == 1 &&
cellFieldArray.ReadPortal().Get(0) == 200.1f,
"Wrong cell field data");
if (returnAllInRange)
{
VTKM_TEST_ASSERT(outCellSet.GetNumberOfCells() == 1, "Wrong number of cells");
vtkm::cont::ArrayHandle<vtkm::Float32> cellvar;
dataset.GetField("cellvar").GetData().AsArrayHandle(cellvar);
vtkm::cont::ArrayHandle<vtkm::Float32> cellFieldArray = threshold.ProcessCellField(cellvar);
VTKM_TEST_ASSERT(cellFieldArray.GetNumberOfValues() == 1 &&
cellFieldArray.ReadPortal().Get(0) == 100.1f,
"Wrong cell field data");
}
else
{
VTKM_TEST_ASSERT(outCellSet.GetNumberOfCells() == 1, "Wrong number of cells");
vtkm::cont::ArrayHandle<vtkm::Float32> cellvar;
dataset.GetField("cellvar").GetData().AsArrayHandle(cellvar);
vtkm::cont::ArrayHandle<vtkm::Float32> cellFieldArray = threshold.ProcessCellField(cellvar);
VTKM_TEST_ASSERT(cellFieldArray.GetNumberOfValues() == 1 &&
cellFieldArray.ReadPortal().Get(0) == 200.1f,
"Wrong cell field data");
}
}
void TestUniform3D() const
void TestUniform3D(bool returnAllInRange) const
{
std::cout << "Testing threshold on 3D uniform dataset" << std::endl;
using CellSetType = vtkm::cont::CellSetStructured<3>;
using OutCellSetType = vtkm::cont::CellSetPermutation<CellSetType>;
@ -92,19 +158,53 @@ public:
dataset.GetField("pointvar").GetData().AsArrayHandle(pointvar);
vtkm::worklet::Threshold threshold;
OutCellSetType outCellSet =
threshold.Run(cellset, pointvar, vtkm::cont::Field::Association::POINTS, HasValue(20.1f));
ThresholdRange predicate;
VTKM_TEST_ASSERT(outCellSet.GetNumberOfCells() == 2, "Wrong number of cells");
if (returnAllInRange)
{
std::cout << "Testing threshold on 3D uniform dataset returning values 'all in range'"
<< std::endl;
predicate.SetLowerValue(10.1);
predicate.SetUpperValue(180);
}
else
{
std::cout << "Testing threshold on 3D uniform dataset returning values 'part in range'"
<< std::endl;
predicate.SetLowerValue(20);
predicate.SetUpperValue(21);
}
vtkm::cont::ArrayHandle<vtkm::Float32> cellvar;
dataset.GetField("cellvar").GetData().AsArrayHandle(cellvar);
vtkm::cont::ArrayHandle<vtkm::Float32> cellFieldArray = threshold.ProcessCellField(cellvar);
OutCellSetType outCellSet = threshold.Run(
cellset, pointvar, vtkm::cont::Field::Association::POINTS, predicate, returnAllInRange);
VTKM_TEST_ASSERT(cellFieldArray.GetNumberOfValues() == 2 &&
cellFieldArray.ReadPortal().Get(0) == 100.1f &&
cellFieldArray.ReadPortal().Get(1) == 100.2f,
"Wrong cell field data");
if (returnAllInRange)
{
VTKM_TEST_ASSERT(outCellSet.GetNumberOfCells() == 3, "Wrong number of cells");
vtkm::cont::ArrayHandle<vtkm::Float32> cellvar;
dataset.GetField("cellvar").GetData().AsArrayHandle(cellvar);
vtkm::cont::ArrayHandle<vtkm::Float32> cellFieldArray = threshold.ProcessCellField(cellvar);
VTKM_TEST_ASSERT(cellFieldArray.GetNumberOfValues() == 3 &&
cellFieldArray.ReadPortal().Get(0) == 100.1f &&
cellFieldArray.ReadPortal().Get(1) == 100.2f &&
cellFieldArray.ReadPortal().Get(2) == 100.3f,
"Wrong cell field data");
}
else
{
VTKM_TEST_ASSERT(outCellSet.GetNumberOfCells() == 2, "Wrong number of cells");
vtkm::cont::ArrayHandle<vtkm::Float32> cellvar;
dataset.GetField("cellvar").GetData().AsArrayHandle(cellvar);
vtkm::cont::ArrayHandle<vtkm::Float32> cellFieldArray = threshold.ProcessCellField(cellvar);
VTKM_TEST_ASSERT(cellFieldArray.GetNumberOfValues() == 2 &&
cellFieldArray.ReadPortal().Get(0) == 100.1f &&
cellFieldArray.ReadPortal().Get(1) == 100.2f,
"Wrong cell field data");
}
}
void TestExplicit3D() const
@ -137,8 +237,10 @@ public:
void operator()() const
{
this->TestUniform2D();
this->TestUniform3D();
this->TestUniform2D(false);
this->TestUniform2D(true);
this->TestUniform3D(false);
this->TestUniform3D(true);
this->TestExplicit3D();
}
};