From f3588ba16c463732498f181558a26a9f2a362872 Mon Sep 17 00:00:00 2001 From: Martyn Gigg Date: Tue, 1 Apr 2014 10:41:58 +0100 Subject: [PATCH] Allow the type of log to be specified in AddTimeSeriesLog Refs #9227 --- .../Algorithms/src/AddTimeSeriesLog.cpp | 67 +++++++++++++++---- .../Algorithms/test/AddTimeSeriesLogTest.h | 55 +++++++++++---- 2 files changed, 97 insertions(+), 25 deletions(-) diff --git a/Code/Mantid/Framework/Algorithms/src/AddTimeSeriesLog.cpp b/Code/Mantid/Framework/Algorithms/src/AddTimeSeriesLog.cpp index ffb9d3216834..49c091335378 100644 --- a/Code/Mantid/Framework/Algorithms/src/AddTimeSeriesLog.cpp +++ b/Code/Mantid/Framework/Algorithms/src/AddTimeSeriesLog.cpp @@ -1,7 +1,11 @@ /*WIKI* Creates/updates a time-series log entry on a chosen workspace. The given timestamp & value are appended to the named log entry. If the named entry does not exist then a new log is created. A time stamp must be given in -ISO8601 format, e.g. 2010-09-14T04:20:12." +ISO8601 format, e.g. 2010-09-14T04:20:12. + +By default, the given value is interpreted as a double and a double series is either created or expected. However, +if the "Type" is set to "int" then the value is interpreted as an integer and an integer is either created +or expected. *WIKI*/ /*WIKI_USAGE* '''Python''' @@ -16,8 +20,9 @@ ISO8601 format, e.g. 2010-09-14T04:20:12." #include "MantidAlgorithms/AddTimeSeriesLog.h" #include "MantidKernel/DateTimeValidator.h" -#include "MantidKernel/TimeSeriesProperty.h" #include "MantidKernel/MandatoryValidator.h" +#include "MantidKernel/ListValidator.h" +#include "MantidKernel/TimeSeriesProperty.h" namespace Mantid { @@ -26,6 +31,38 @@ namespace Mantid using namespace API; using namespace Kernel; + namespace + { + /** + * Creates/updates the named log on the given run. The template type + * specifies either the type of TimeSeriesProperty that is expected to + * exist or the type that will be created + * @param run A reference to the run object that stores the logs + * @param name The name of the log that is to be either created or updated + * @param time A time string in ISO format, passed to the DateAndTime constructor + * @param value The value at the given time + */ + template + void createOrUpdate(API::Run& run, const std::string & name, + const std::string & time, const T value) + { + TimeSeriesProperty *timeSeries(NULL); + if(run.hasProperty(name)) + { + timeSeries = dynamic_cast*>(run.getLogData(name)); + if(!timeSeries) throw std::invalid_argument("Log '" + name + "' already exists but the values are a different type."); + } + else + { + timeSeries = new TimeSeriesProperty(name); + run.addProperty(timeSeries); + } + timeSeries->addValue(time, value); + } + + } + + // Register the algorithm into the AlgorithmFactory DECLARE_ALGORITHM(AddTimeSeriesLog) @@ -66,6 +103,14 @@ namespace Mantid auto nonEmtpyDbl = boost::make_shared>(); declareProperty("Value", EMPTY_DBL(), nonEmtpyDbl, "The value for the log at the given time", Direction::Input); + + auto optionsValidator = boost::make_shared>(); + optionsValidator->addAllowedValue("double"); + optionsValidator->addAllowedValue("int"); + declareProperty("Type", "double", optionsValidator, + "An optional type for the given value. A double value with a Type=int will have " + "the fractional part chopped off.", + Direction::Input); } //---------------------------------------------------------------------------------------------- @@ -75,26 +120,22 @@ namespace Mantid void AddTimeSeriesLog::exec() { MatrixWorkspace_sptr logWS = getProperty("Workspace"); + auto &run = logWS->mutableRun(); std::string name = getProperty("Name"); std::string time = getProperty("Time"); - double value = getProperty("Value"); + double valueAsDouble = getProperty("Value"); + std::string type = getProperty("Type"); + bool asInt = (type == "int"); - auto & run = logWS->mutableRun(); - TimeSeriesProperty *timeSeries(NULL); - if(run.hasProperty(name)) + if(asInt) { - timeSeries = dynamic_cast*>(run.getLogData(name)); - if(!timeSeries) throw std::invalid_argument("Log '" + name + "' already exists but is not a time series."); + createOrUpdate(run, name, time, static_cast(valueAsDouble)); } else { - timeSeries = new TimeSeriesProperty(name); - run.addProperty(timeSeries); + createOrUpdate(run, name, time, valueAsDouble); } - timeSeries->addValue(time, value); } - - } // namespace Algorithms } // namespace Mantid diff --git a/Code/Mantid/Framework/Algorithms/test/AddTimeSeriesLogTest.h b/Code/Mantid/Framework/Algorithms/test/AddTimeSeriesLogTest.h index 4e6d7031cf6b..d898d1ee812d 100644 --- a/Code/Mantid/Framework/Algorithms/test/AddTimeSeriesLogTest.h +++ b/Code/Mantid/Framework/Algorithms/test/AddTimeSeriesLogTest.h @@ -8,31 +8,49 @@ class AddTimeSeriesLogTest : public CxxTest::TestSuite { +private: + enum LogType { Double, Integer }; + public: // This pair of boilerplate methods prevent the suite being created statically // This means the constructor isn't called when running other tests static AddTimeSeriesLogTest *createSuite() { return new AddTimeSeriesLogTest(); } static void destroySuite( AddTimeSeriesLogTest *suite ) { delete suite; } - void test_Workspace2D() + void test_defaults_create_a_double_type_series() { auto ws = WorkspaceCreationHelper::Create2DWorkspace(10,10); TS_ASSERT_THROWS_NOTHING(executeAlgorithm(ws, "Test Name", "2010-09-14T04:20:12", 20.0)); - checkLogWithEntryExists(ws, "Test Name", "2010-09-14T04:20:12", 20.0, 0); + checkLogWithEntryExists(ws, "Test Name", "2010-09-14T04:20:12", 20.0, 0); TS_ASSERT_THROWS_NOTHING(executeAlgorithm(ws, "Test Name", "2010-09-14T04:20:19", 40.0)); - checkLogWithEntryExists(ws, "Test Name", "2010-09-14T04:20:19", 40.0, 1); + checkLogWithEntryExists(ws, "Test Name", "2010-09-14T04:20:19", 40.0, 1); + } + + void test_forcing_to_int_creates_int_from_double() + { + auto ws = WorkspaceCreationHelper::Create2DWorkspace(10,10); + TS_ASSERT_THROWS_NOTHING(executeAlgorithm(ws, "Test Name", "2010-09-14T04:20:12", 20.5, Integer)); + + checkLogWithEntryExists(ws, "Test Name", "2010-09-14T04:20:12", 20, 0); + TS_ASSERT_THROWS_NOTHING(executeAlgorithm(ws, "Test Name", "2010-09-14T04:20:19", 40.0, Integer)); + checkLogWithEntryExists(ws, "Test Name", "2010-09-14T04:20:19", 40, 1); } - void test_EventWorkspace() + void test_algorithm_only_accepts_int_or_double_as_Type() { - auto ws = WorkspaceCreationHelper::CreateEventWorkspace(10,10); - TS_ASSERT_THROWS_NOTHING(executeAlgorithm(ws, "Test Name", "2010-09-14T04:20:12", 20.0)); - checkLogWithEntryExists(ws, "Test Name", "2010-09-14T04:20:12", 20.0, 0); - TS_ASSERT_THROWS_NOTHING(executeAlgorithm(ws, "Test Name", "2010-09-14T04:20:19", 40.0)); - checkLogWithEntryExists(ws, "Test Name", "2010-09-14T04:20:19", 40.0, 1); + Mantid::Algorithms::AddTimeSeriesLog alg; + TS_ASSERT_THROWS_NOTHING(alg.initialize()); + + const Mantid::Kernel::Property *prop = alg.getProperty("Type"); + const auto allowedValues = prop->allowedValues(); + + TS_ASSERT_EQUALS(2, allowedValues.size()); + TS_ASSERT_EQUALS(1, allowedValues.count("int")); + TS_ASSERT_EQUALS(1, allowedValues.count("double")); } + //-------------------------- Failure cases ------------------------------------ void test_empty_log_name_not_allowed() { @@ -76,10 +94,21 @@ class AddTimeSeriesLogTest : public CxxTest::TestSuite TS_ASSERT_THROWS(executeAlgorithm(ws, "Test Name", "2010-09-14T04:20:12", 20.0), std::invalid_argument); } + void test_algorithm_fails_if_time_series_exists_but_it_is_incorrect_type() + { + auto ws = WorkspaceCreationHelper::Create2DWorkspace(10,10); + auto & run = ws->mutableRun(); + const std::string logName = "DoubleSeries"; + auto *timeSeries = new Mantid::Kernel::TimeSeriesProperty(logName); + timeSeries->addValue("2010-09-14T04:20:12", 20.0); + run.addLogData(timeSeries); + TS_ASSERT_THROWS(executeAlgorithm(ws, logName, "2010-09-14T04:20:30", 30, Integer), std::invalid_argument); + } + private: void executeAlgorithm(Mantid::API::MatrixWorkspace_sptr testWS, const std::string & logName, const std::string & logTime, - const double logValue) + const double logValue, const LogType type = Double) { //execute algorithm Mantid::Algorithms::AddTimeSeriesLog alg; @@ -91,12 +120,14 @@ class AddTimeSeriesLogTest : public CxxTest::TestSuite alg.setPropertyValue("Name", logName); alg.setPropertyValue("Time", logTime); alg.setProperty("Value", logValue); + if(type == Integer) alg.setProperty("Type", "int"); alg.setRethrows(true); alg.execute(); } + template void checkLogWithEntryExists(Mantid::API::MatrixWorkspace_sptr testWS, const std::string & logName, const std::string & logTime, - const double logValue, const size_t position) + const T logValue, const size_t position) { using Mantid::Kernel::DateAndTime; using Mantid::Kernel::TimeSeriesProperty; @@ -105,7 +136,7 @@ class AddTimeSeriesLogTest : public CxxTest::TestSuite TSM_ASSERT("Run does not contain the expected log entry", run.hasProperty(logName)); auto *prop = run.getLogData(logName); - auto *timeSeries = dynamic_cast*>(prop); + auto *timeSeries = dynamic_cast*>(prop); TSM_ASSERT("A log entry with the given name exists but it is not a time series", timeSeries); auto times = timeSeries->timesAsVector(); TS_ASSERT(times.size() >= position + 1);