diff --git a/vtkm/filter/Threshold.h b/vtkm/filter/Threshold.h index 2c48e0418..25462d2e7 100644 --- a/vtkm/filter/Threshold.h +++ b/vtkm/filter/Threshold.h @@ -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 VTKM_CONT vtkm::cont::DataSet DoExecute(const vtkm::cont::DataSet& input, const vtkm::cont::ArrayHandle& field, @@ -66,6 +75,7 @@ public: private: double LowerValue = 0; double UpperValue = 0; + bool ReturnAllInRange = false; vtkm::worklet::Threshold Worklet; }; diff --git a/vtkm/filter/Threshold.hxx b/vtkm/filter/Threshold.hxx index 26dc0478e..7779adb1a 100644 --- a/vtkm/filter/Threshold.hxx +++ b/vtkm/filter/Threshold.hxx @@ -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); diff --git a/vtkm/filter/testing/UnitTestThresholdFilter.cxx b/vtkm/filter/testing/UnitTestThresholdFilter.cxx index 17111ae8f..e7573cf07 100644 --- a/vtkm/filter/testing/UnitTestThresholdFilter.cxx +++ b/vtkm/filter/testing/UnitTestThresholdFilter.cxx @@ -10,7 +10,6 @@ #include #include - #include #include @@ -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 cellFieldArray; - output.GetField("cellvar").GetData().AsArrayHandle(cellFieldArray); + vtkm::cont::ArrayHandle 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 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 cellFieldArray; - output.GetField("cellvar").GetData().AsArrayHandle(cellFieldArray); + vtkm::cont::ArrayHandle 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 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(); } diff --git a/vtkm/worklet/Threshold.h b/vtkm/worklet/Threshold.h index f9eb38aed..57b1dc5a1 100644 --- a/vtkm/worklet/Threshold.h +++ b/vtkm/worklet/Threshold.h @@ -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 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& field, const vtkm::cont::Field::Association fieldType, - const UnaryPredicate& predicate) + const UnaryPredicate& predicate, + const bool returnAllInRange = false) { using OutputType = vtkm::cont::CellSetPermutation; @@ -102,7 +116,7 @@ public: using ThresholdWorklet = ThresholdByPointField; vtkm::cont::ArrayHandle passFlags; - ThresholdWorklet worklet(predicate); + ThresholdWorklet worklet(predicate, returnAllInRange); DispatcherMapTopology 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& cellSet, const vtkm::cont::ArrayHandle& field, const vtkm::cont::Field::Association fieldType, - const UnaryPredicate& predicate) + const UnaryPredicate& predicate, + const bool returnAllInRange = false) { using Worker = CallWorklet, 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; diff --git a/vtkm/worklet/testing/UnitTestThreshold.cxx b/vtkm/worklet/testing/UnitTestThreshold.cxx index 4077f912a..a3abb9445 100644 --- a/vtkm/worklet/testing/UnitTestThreshold.cxx +++ b/vtkm/worklet/testing/UnitTestThreshold.cxx @@ -10,14 +10,16 @@ #include +#include #include #include -#include - #include #include #include +#include +#include +#include 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 + VTKM_EXEC bool operator()(const T& value) const + { + + return value >= static_cast(this->Lower) && value <= static_cast(this->Upper); + } + + //Needed to work with ArrayHandleVirtual + template + VTKM_EXEC bool operator()( + const vtkm::internal::ArrayPortalValueReference& value) const + { + using T = typename PortalType::ValueType; + return value.Get() >= static_cast(this->Lower) && value.Get() <= static_cast(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; @@ -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 cellvar; - dataset.GetField("cellvar").GetData().AsArrayHandle(cellvar); - vtkm::cont::ArrayHandle 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 cellvar; + dataset.GetField("cellvar").GetData().AsArrayHandle(cellvar); + vtkm::cont::ArrayHandle 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 cellvar; + dataset.GetField("cellvar").GetData().AsArrayHandle(cellvar); + vtkm::cont::ArrayHandle 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; @@ -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 cellvar; - dataset.GetField("cellvar").GetData().AsArrayHandle(cellvar); - vtkm::cont::ArrayHandle 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 cellvar; + dataset.GetField("cellvar").GetData().AsArrayHandle(cellvar); + vtkm::cont::ArrayHandle 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 cellvar; + dataset.GetField("cellvar").GetData().AsArrayHandle(cellvar); + vtkm::cont::ArrayHandle 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(); } };