From 86d622e224c4bbdb0fade03d4869c16068c916e5 Mon Sep 17 00:00:00 2001 From: Russell Taylor Date: Tue, 11 Dec 2012 12:09:44 -0500 Subject: [PATCH] Re #6267. Add a validateInputs method and tests. Adds cross-checking of parameters, such as the log actually existing in the given workspace and being of a valid type. --- .../inc/MantidAlgorithms/FilterByLogValue.h | 3 +- .../Algorithms/src/FilterByLogValue.cpp | 38 +++++++++-- .../Algorithms/test/FilterByLogValueTest.h | 67 ++++++++++++++++++- 3 files changed, 101 insertions(+), 7 deletions(-) diff --git a/Code/Mantid/Framework/Algorithms/inc/MantidAlgorithms/FilterByLogValue.h b/Code/Mantid/Framework/Algorithms/inc/MantidAlgorithms/FilterByLogValue.h index 23ee9f12d0d7..c565e60bd1c5 100644 --- a/Code/Mantid/Framework/Algorithms/inc/MantidAlgorithms/FilterByLogValue.h +++ b/Code/Mantid/Framework/Algorithms/inc/MantidAlgorithms/FilterByLogValue.h @@ -47,13 +47,14 @@ class DLLExport FilterByLogValue : public API::Algorithm /// Algorithm's category for identification overriding a virtual method virtual const std::string category() const { return "Events\\EventFiltering";} + std::map validateInputs(); + private: /// Sets documentation strings for this algorithm virtual void initDocs(); // Implement abstract Algorithm methods void init(); void exec(); - }; } // namespace Algorithms diff --git a/Code/Mantid/Framework/Algorithms/src/FilterByLogValue.cpp b/Code/Mantid/Framework/Algorithms/src/FilterByLogValue.cpp index 9a25fc8b272c..23cda108f7b1 100644 --- a/Code/Mantid/Framework/Algorithms/src/FilterByLogValue.cpp +++ b/Code/Mantid/Framework/Algorithms/src/FilterByLogValue.cpp @@ -42,6 +42,7 @@ times of the pulses to be rejected. For example, this call will filter out veto #include "MantidKernel/BoundedValidator.h" #include "MantidKernel/ITimeSeriesProperty.h" #include "MantidKernel/ListValidator.h" +#include "MantidKernel/MandatoryValidator.h" namespace Mantid { @@ -92,13 +93,13 @@ void FilterByLogValue::init() new WorkspaceProperty("OutputWorkspace","",Direction::Output), "The name to use for the output workspace" ); - declareProperty("LogName", "", + declareProperty("LogName", "", boost::make_shared>(), "Name of the sample log to use to filter.\n" "For example, the pulse charge is recorded in 'ProtonCharge'."); - declareProperty("MinimumValue", 0.0, "Minimum log value for which to keep events."); + declareProperty("MinimumValue", Mantid::EMPTY_DBL(), "Minimum log value for which to keep events."); - declareProperty("MaximumValue", 0.0, "Maximum log value for which to keep events."); + declareProperty("MaximumValue", Mantid::EMPTY_DBL(), "Maximum log value for which to keep events."); auto min = boost::make_shared >(); min->setLower(0.0); @@ -122,6 +123,35 @@ void FilterByLogValue::init() } +std::map FilterByLogValue::validateInputs() +{ + std::map errors; + + // Check that the log exists for the given input workspace + EventWorkspace_const_sptr inputWS = this->getProperty("InputWorkspace"); + std::string logname = getPropertyValue("LogName"); + try { + ITimeSeriesProperty * log = dynamic_cast( inputWS->run().getLogData(logname) ); + if ( log == NULL ) + { + errors["LogName"] = "'" + logname + "' is not a time-series log."; + return errors; + } + } catch ( Exception::NotFoundError& ) { + errors["LogName"] = "The log '" + logname + "' does not exist in the workspace '" + inputWS->name() + "'."; + return errors; + } + + const double min = getProperty("MinimumValue"); + const double max = getProperty("MaximumValue"); + if ( !isEmpty(min) && !isEmpty(max) && (max < min) ) + { + errors["MinimumValue"] = "MinimumValue must not be larger than MaximumValue"; + errors["MaximumValue"] = "MinimumValue must not be larger than MaximumValue"; + } + + return errors; +} //----------------------------------------------------------------------- /** Executes the algorithm @@ -155,7 +185,7 @@ void FilterByLogValue::exec() // Now make the splitter vector TimeSplitterType splitter; //This'll throw an exception if the log doesn't exist. That is good. - Kernel::ITimeSeriesProperty * log = dynamic_cast( inputWS->run().getLogData(logname) ); + ITimeSeriesProperty * log = dynamic_cast( inputWS->run().getLogData(logname) ); if (log) { if (PulseFilter) diff --git a/Code/Mantid/Framework/Algorithms/test/FilterByLogValueTest.h b/Code/Mantid/Framework/Algorithms/test/FilterByLogValueTest.h index 9e9f50288339..3495b1b91d67 100644 --- a/Code/Mantid/Framework/Algorithms/test/FilterByLogValueTest.h +++ b/Code/Mantid/Framework/Algorithms/test/FilterByLogValueTest.h @@ -32,9 +32,8 @@ class FilterByLogValueTest : public CxxTest::TestSuite static FilterByLogValueTest *createSuite() { return new FilterByLogValueTest(); } static void destroySuite( FilterByLogValueTest *suite ) { delete suite; } - FilterByLogValueTest() + FilterByLogValueTest() : inputWS("eventWS") { - inputWS = "eventWS"; } @@ -113,7 +112,71 @@ class FilterByLogValueTest : public CxxTest::TestSuite AnalysisDataService::Instance().remove(inputWS); } + void test_validators() + { + FilterByLogValue alg; + TS_ASSERT_THROWS_NOTHING( alg.initialize() ); + + // InputWorkspace has to be an EventWorkspace + TS_ASSERT_THROWS( alg.setProperty("InputWorkspace", WorkspaceCreationHelper::Create2DWorkspace(1,1)), std::invalid_argument ); + TS_ASSERT_THROWS_NOTHING( alg.setProperty("InputWorkspace", WorkspaceCreationHelper::CreateEventWorkspace()) ); + // LogName must not be empty + TS_ASSERT_THROWS( alg.setProperty("LogName",""), std::invalid_argument ); + + // TimeTolerance cannot be negative + TS_ASSERT_THROWS( alg.setProperty("TimeTolerance", -0.1), std::invalid_argument ); + // ... but it can be zero + TS_ASSERT_THROWS_NOTHING( alg.setProperty("TimeTolerance", 0.0) ); + + // LogBoundary must be one of "Centre" and "Left" + TS_ASSERT_THROWS( alg.setProperty("LogBoundary", ""), std::invalid_argument ); + TS_ASSERT_THROWS( alg.setProperty("LogBoundary", "Middle"), std::invalid_argument ); + TS_ASSERT_THROWS_NOTHING( alg.setProperty("LogBoundary", "Left") ); + TS_ASSERT_THROWS_NOTHING( alg.setProperty("LogBoundary", "Centre") ); + } + + void test_validateInputs() + { + // Create and event workspace. We don't care what data is in it. + EventWorkspace_sptr ws = WorkspaceCreationHelper::CreateEventWorkspace(); + // Add a single-number log + ws->mutableRun().addProperty("SingleValue",5); + // Add a time-series property + auto tsp = new TimeSeriesProperty("TSP"); + tsp->addValue(DateAndTime::getCurrentTime(),9.9); + ws->mutableRun().addLogData(tsp); + + FilterByLogValue alg; + TS_ASSERT_THROWS_NOTHING( alg.initialize() ); + TS_ASSERT_THROWS_NOTHING( alg.setProperty("InputWorkspace",ws) ); + + // Check protest when non-existent log is set + TS_ASSERT_THROWS_NOTHING( alg.setProperty("LogName", "NotThere") ); + auto errorMap = alg.validateInputs(); + TS_ASSERT_EQUALS( errorMap.size(), 1); + TS_ASSERT_EQUALS( errorMap.begin()->first, "LogName" ); + + // Check protest when single-value log is set + TS_ASSERT_THROWS_NOTHING( alg.setProperty("LogName", "SingleValue") ); + errorMap = alg.validateInputs(); + TS_ASSERT_EQUALS( errorMap.size(), 1); + TS_ASSERT_EQUALS( errorMap.begin()->first, "LogName" ); + + // Check protest when tsp log given, but min value greate than max + TS_ASSERT_THROWS_NOTHING( alg.setProperty("LogName", "TSP") ); + TS_ASSERT_THROWS_NOTHING( alg.setProperty("MinimumValue", 2.0) ); + TS_ASSERT_THROWS_NOTHING( alg.setProperty("MaximumValue", 1.0) ); + errorMap = alg.validateInputs(); + TS_ASSERT_EQUALS( errorMap.size(), 2); + TS_ASSERT_EQUALS( errorMap.begin()->first, "MaximumValue" ); + TS_ASSERT_EQUALS( errorMap.rbegin()->first, "MinimumValue" ); + + // Check it's happy when that's been remedied + TS_ASSERT_THROWS_NOTHING( alg.setProperty("MaximumValue", 3.0) ); + errorMap = alg.validateInputs(); + TS_ASSERT( errorMap.empty() ); + } /** Create a workspace with: * events at times 0,1,2,...99