Mantid
Loading...
Searching...
No Matches
ChangeTimeZero.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
10#include "MantidAPI/Run.h"
18#include "MantidKernel/System.h"
20
21#include <boost/lexical_cast.hpp>
22#include <memory>
23#include <utility>
24
25namespace Mantid::Algorithms {
26
27// Register the algorithm into the AlgorithmFactory
28DECLARE_ALGORITHM(ChangeTimeZero)
29
30using namespace Mantid::Kernel;
31using namespace Mantid::API;
32using std::size_t;
33using Types::Core::DateAndTime;
34
35namespace {
41bool isTimeSeries(Mantid::Kernel::Property *prop) {
42 auto isTimeSeries = false;
43 if (dynamic_cast<Mantid::Kernel::ITimeSeriesProperty *>(prop)) {
44 isTimeSeries = true;
45 }
46 return isTimeSeries;
47}
48} // namespace
49
53 declareProperty(std::make_unique<WorkspaceProperty<MatrixWorkspace>>("InputWorkspace", "", Direction::Input),
54 "An input workspace.");
55 declareProperty<double>("RelativeTimeOffset", m_defaultTimeShift, "A relative time offset in seconds.");
56
57 declareProperty("AbsoluteTimeOffset", m_defaultAbsoluteTimeShift,
58 "An absolute time offset as an ISO8601 string "
59 "(YYYY-MM-DDTHH:MM::SS, eg 2013-10-25T13:58:03).");
60
61 declareProperty(std::make_unique<WorkspaceProperty<MatrixWorkspace>>("OutputWorkspace", "", Direction::Output),
62 "An output workspace.");
63}
64
68 MatrixWorkspace_sptr in_ws = getProperty("InputWorkspace");
69
70 // Create a new target workspace if it does not exist
71 const double progressStartCreateOutputWs = 0.0;
72 const double progressStopCreateOutputWs = 0.3;
73
74 MatrixWorkspace_sptr out_ws = createOutputWS(in_ws, progressStartCreateOutputWs, progressStopCreateOutputWs);
75
76 // Get the time shift in seconds
77 auto timeShift = getTimeShift(out_ws);
78
79 // Set up remaining progress points
80 const double progressStartShiftTimeLogs = progressStopCreateOutputWs;
81
82 double progressStopShiftTimeLogs =
83 std::dynamic_pointer_cast<Mantid::API::IEventWorkspace>(out_ws) ? progressStartShiftTimeLogs + 0.1 : 1.0;
84
85 const double progressStartShiftNeutrons = progressStopShiftTimeLogs;
86 const double progressStopShiftNeutrons = 1.0;
87
88 // Change the time of the logs.
89 // Initialize progress reporting.
90 shiftTimeOfLogs(out_ws, timeShift, progressStartShiftTimeLogs, progressStopShiftTimeLogs);
91
92 // Change the time stamps on the neutrons
93 shiftTimeOfNeutrons(out_ws, timeShift, progressStartShiftNeutrons, progressStopShiftNeutrons);
94
95 setProperty("OutputWorkspace", out_ws);
96}
97
106 double stopProgress) {
107 MatrixWorkspace_sptr output = getProperty("OutputWorkspace");
108 // Check whether input == output to see whether a new workspace is required.
109 if (input != output) {
110 auto duplicate = createChildAlgorithm("CloneWorkspace", startProgress, stopProgress);
111 duplicate->initialize();
112 duplicate->setProperty<API::Workspace_sptr>("InputWorkspace", std::dynamic_pointer_cast<API::Workspace>(input));
113 duplicate->execute();
114 API::Workspace_sptr temp = duplicate->getProperty("OutputWorkspace");
115 output = std::dynamic_pointer_cast<API::MatrixWorkspace>(temp);
116 }
117 return output;
118}
119
127 double timeShift;
128 // Check if we are dealing with an absolute time
129 std::string timeOffset = getProperty("AbsoluteTimeOffset");
130 if (isAbsoluteTimeShift(timeOffset)) {
131 DateAndTime desiredTime(timeOffset);
132 DateAndTime originalTime(getStartTimeFromWorkspace(ws));
133 timeShift = DateAndTime::secondsFromDuration(desiredTime - originalTime);
134 } else {
135 timeShift = getProperty("RelativeTimeOffset");
136 }
137 return timeShift;
138}
139
148 double startProgress, double stopProgress) {
149 // We need to change the entries for each log which can be:
150 // 1. any time series: here we change the time values
151 // 2. string properties: here we change the values if they are ISO8601 times
152 auto logs = ws->mutableRun().getLogData();
153 Progress prog(this, startProgress, stopProgress, logs.size());
154 for (auto &log : logs) {
155 if (isTimeSeries(log)) {
156 shiftTimeInLogForTimeSeries(ws, log, timeShift);
157
158 } else if (auto stringProperty = dynamic_cast<PropertyWithValue<std::string> *>(log)) {
159 shiftTimeOfLogForStringProperty(stringProperty, timeShift);
160 }
161
162 prog.report(name());
163 }
164}
165
173 Mantid::Kernel::Property *prop, double timeShift) const {
174 if (auto timeSeries = dynamic_cast<Mantid::Kernel::ITimeSeriesProperty *>(prop)) {
175 auto newlog = timeSeries->cloneWithTimeShift(timeShift);
176 ws->mutableRun().addProperty(newlog, true);
177 }
178}
179
186 // Parse the log entry and replace all ISO8601 strings with an adjusted value
187 auto value = logEntry->value();
188 if (checkForDateTime(value)) {
189 DateAndTime dateTime(value);
190 DateAndTime shiftedTime = dateTime + timeShift;
191 logEntry->setValue(shiftedTime.toISO8601String());
192 }
193}
194
203 double startProgress, double stopProgress) {
204 if (auto eventWs = std::dynamic_pointer_cast<Mantid::API::IEventWorkspace>(ws)) {
205 // Use the change pulse time algorithm to change the neutron time stamp
206 auto alg = createChildAlgorithm("ChangePulsetime", startProgress, stopProgress);
207 alg->initialize();
208 alg->setProperty("InputWorkspace", eventWs);
209 alg->setProperty("OutputWorkspace", eventWs);
210 alg->setProperty("TimeOffset", timeShift);
211 alg->execute();
212 }
213}
214
221 auto run = ws->run();
222 // Check for the first good frame in the log
224 try {
225 goodFrame = run.getTimeSeriesProperty<double>("proton_charge");
226 } catch (const std::invalid_argument &) {
227 throw std::invalid_argument("ChangeTimeZero: The log needs a proton_charge "
228 "time series to determine the zero time.");
229 }
230
231 DateAndTime startTime;
232 if (goodFrame->size() > 0) {
233 startTime = goodFrame->firstTime();
234 }
235
236 return startTime;
237}
238
243std::map<std::string, std::string> ChangeTimeZero::validateInputs() {
244 std::map<std::string, std::string> invalidProperties;
245
246 // Check the time offset for either a value or a date time
247 double relativeTimeOffset = getProperty("RelativeTimeOffset");
248 std::string absoluteTimeOffset = getProperty("AbsoluteTimeOffset");
249
250 auto isRelative = isRelativeTimeShift(relativeTimeOffset);
251 auto absoluteTimeInput = absoluteTimeOffset != m_defaultAbsoluteTimeShift;
252 auto isAbsolute = isAbsoluteTimeShift(absoluteTimeOffset);
253
254 // If both inputs are being used, then return straight away.
255 if (isRelative && absoluteTimeInput) {
256 invalidProperties.emplace("RelativeTimeOffset", "You can either specify a relative time shift or "
257 "an absolute time shift.");
258 invalidProperties.emplace("AbsoluteTimeOffset", "You can either specify a relative time shift or "
259 "an absolute time shift.");
260
261 return invalidProperties;
262 } else if (!isRelative && !isAbsolute) {
263 invalidProperties.emplace("RelativeTimeOffset", "TimeOffset must either be a numeric "
264 "value or a ISO8601 (YYYY-MM-DDTHH:MM::SS) date-time stamp.");
265 invalidProperties.emplace("AbsoluteTimeOffset", "TimeOffset must either be a numeric "
266 "value or a ISO8601 (YYYY-MM-DDTHH:MM::SS) date-time stamp.");
267 }
268
269 // If we are dealing with an absolute time we need to ensure that the
270 // proton_charge entry exists
271 if (isAbsolute) {
272 MatrixWorkspace_sptr ws = getProperty("InputWorkspace");
273 if (ws) {
274 auto run = ws->run();
275 try {
276 run.getTimeSeriesProperty<double>("proton_charge");
277 } catch (...) {
278 invalidProperties.emplace("InputWorkspace", "A TimeOffset with an absolute time requires the "
279 "input workspace to have a proton_charge property in "
280 "its log.");
281 }
282 }
283 }
284
285 return invalidProperties;
286}
287
292bool ChangeTimeZero::checkForDouble(const std::string &val) const {
293 auto isDouble = false;
294 try {
295 boost::lexical_cast<double>(val);
296 isDouble = true;
297 } catch (boost::bad_lexical_cast const &) {
298 }
299 return isDouble;
300}
301
307bool ChangeTimeZero::checkForDateTime(const std::string &val) const {
308 auto isDateTime = false;
309 // Hedge for bad lexical casts in the DateTimeValidator
310 try {
312 isDateTime = validator.isValid(val).empty();
313 } catch (...) {
314 isDateTime = false;
315 }
316 return isDateTime;
317}
318
324bool ChangeTimeZero::isRelativeTimeShift(double offset) const { return offset != m_defaultTimeShift; }
325
331bool ChangeTimeZero::isAbsoluteTimeShift(const std::string &offset) const {
332 return offset != m_defaultAbsoluteTimeShift && checkForDateTime(offset);
333}
334
335} // namespace Mantid::Algorithms
#define DECLARE_ALGORITHM(classname)
Definition: Algorithm.h:576
double value
The value of the point.
Definition: FitMW.cpp:51
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
Definition: Algorithm.cpp:1913
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
Definition: Algorithm.cpp:2076
virtual std::shared_ptr< Algorithm > createChildAlgorithm(const std::string &name, const double startProgress=-1., const double endProgress=-1., const bool enableLogging=true, const int &version=-1)
Create a Child Algorithm.
Definition: Algorithm.cpp:842
Helper class for reporting progress from algorithms.
Definition: Progress.h:25
A property class for workspaces.
double getTimeShift(const API::MatrixWorkspace_sptr &ws) const
Get the time shift.
bool checkForDouble(const std::string &val) const
Can the string be transformed to double.
Mantid::API::MatrixWorkspace_sptr createOutputWS(const Mantid::API::MatrixWorkspace_sptr &input, double startProgress, double stopProgress)
Create the output workspace.
void init() override
Initialise the properties.
void shiftTimeOfLogForStringProperty(Mantid::Kernel::PropertyWithValue< std::string > *logEntry, double timeShift) const
Time shift the log of a string property.
void shiftTimeInLogForTimeSeries(const Mantid::API::MatrixWorkspace_sptr &ws, Mantid::Kernel::Property *prop, double timeShift) const
Time shift the log of a double series property.
void shiftTimeOfLogs(const Mantid::API::MatrixWorkspace_sptr &ws, double timeShift, double startProgress, double stopProgress)
Shift the time of the logs.
bool isRelativeTimeShift(double offset) const
Checks if a relative offset has been set.
Mantid::Types::Core::DateAndTime getStartTimeFromWorkspace(const Mantid::API::MatrixWorkspace_sptr &ws) const
Get the date and time of the first good frame of a workspace.
void exec() override
Run the algorithm.
const std::string name() const override
Algorithm's name for identification.
bool isAbsoluteTimeShift(const std::string &offset) const
Checks if an absolute offset has been set.
bool checkForDateTime(const std::string &val) const
Can the string be transformed to a DateTime.
void shiftTimeOfNeutrons(const Mantid::API::MatrixWorkspace_sptr &ws, double timeShift, double startProgress, double stopProgress)
Shift the time of the neutrons.
std::map< std::string, std::string > validateInputs() override
Check the inputs.
const std::string m_defaultAbsoluteTimeShift
Checks that a string contains a timestamp in ISO 8601 format (YYYY-MM-DDTHH:MM:SS....
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
A non-templated interface to a TimeSeriesProperty.
void report()
Increments the loop counter by 1, then sends the progress notification on behalf of its algorithm.
Definition: ProgressBase.h:51
The concrete, templated class for properties.
std::string setValue(const std::string &value) override
Set the value of the property via a string.
std::string value() const override
Returns the value of the property as a string.
Base class for properties.
Definition: Property.h:94
A specialised Property class for holding a series of time-value pairs.
int size() const override
Returns the number of values at UNIQUE time intervals in the time series.
Types::Core::DateAndTime firstTime() const
Returns the first time regardless of filter.
std::shared_ptr< Workspace > Workspace_sptr
shared pointer to Mantid::API::Workspace
Definition: Workspace_fwd.h:20
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
@ Input
An input workspace.
Definition: Property.h:53
@ Output
An output workspace.
Definition: Property.h:54