-
Notifications
You must be signed in to change notification settings - Fork 122
/
StartLiveData.cpp
236 lines (199 loc) · 9.03 KB
/
StartLiveData.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
// Mantid Repository : https://github.com/mantidproject/mantid
//
// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
// NScD Oak Ridge National Laboratory, European Spallation Source,
// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
// SPDX - License - Identifier: GPL - 3.0 +
#include "MantidLiveData/StartLiveData.h"
#include "MantidAPI/AlgorithmManager.h"
#include "MantidAPI/AlgorithmProperty.h"
#include "MantidAPI/LiveListenerFactory.h"
#include "MantidAPI/Workspace.h"
#include "MantidKernel/ArrayBoundedValidator.h"
#include "MantidKernel/ArrayProperty.h"
#include "MantidLiveData/LoadLiveData.h"
#include "MantidLiveData/MonitorLiveData.h"
#include "MantidTypes/Core/DateAndTime.h"
#include <Poco/ActiveResult.h>
#include <memory>
using namespace Mantid::Kernel;
using namespace Mantid::API;
using Mantid::Types::Core::DateAndTime;
namespace Mantid::LiveData {
// Register the algorithm into the AlgorithmFactory
DECLARE_ALGORITHM(StartLiveData)
namespace {
/// name for a group of properties that get copied from the listener
const char *listenerPropertyGroup = "ListenerProperties";
} // namespace
//----------------------------------------------------------------------------------------------
/// Algorithm's name for identification. @see Algorithm::name
const std::string StartLiveData::name() const { return "StartLiveData"; }
/// Algorithm's version for identification. @see Algorithm::version
int StartLiveData::version() const { return 1; }
//----------------------------------------------------------------------------------------------
/** Initialize the algorithm's properties.
*/
void StartLiveData::init() {
declareProperty(std::make_unique<PropertyWithValue<bool>>("FromNow", true, Direction::Input),
"Process live data starting from the current time only.");
declareProperty(std::make_unique<PropertyWithValue<bool>>("FromStartOfRun", false, Direction::Input),
"Record live data, but go back to the the start of the run and process "
"all data since then.");
declareProperty(std::make_unique<PropertyWithValue<bool>>("FromTime", false, Direction::Input),
"Record live data, but go back to a specific time and process all data "
"since then.\n"
"You must specify the StartTime property if this is checked.");
declareProperty(std::make_unique<PropertyWithValue<double>>("UpdateEvery", 30.0, Direction::Input),
"Frequency of updates, in seconds. Default 30.\n"
"If you specify 0, MonitorLiveData will not launch and you will get only "
"one chunk.");
// Initialize the properties common to LiveDataAlgorithm.
initProps();
declareProperty(
std::make_unique<AlgorithmProperty>("MonitorLiveData", std::make_shared<NullValidator>(), Direction::Output),
"A handle to the MonitorLiveData algorithm instance that "
"continues to read live data after this algorithm "
"completes.");
}
/**
* After Listener or Connection properties are set, copy any properties that
* the listener may have to this algorithm.
*
* @param propName Name of property that was just set
*/
void StartLiveData::afterPropertySet(const std::string &propName) {
// If any of these properties change, the listener class might change
if (propName == "Instrument" || propName == "Listener" || propName == "Connection") {
// Properties of old listener, if any, need to be removed
removeListenerProperties();
// Get temp instance of listener for this instrument with current properties
auto listener = createLiveListener();
// Copy over properties of listener to this algorithm
copyListenerProperties(listener);
}
}
/**
* Copies properties from an ILiveListener to this algorithm. This makes them
* appear in the "listener properties" group on the StartLiveData custom dialog.
*
* @param listener ILiveListener from which to copy properties
*/
void StartLiveData::copyListenerProperties(const std::shared_ptr<ILiveListener> &listener) {
// Add clones of listener's properties to this algorithm
for (auto listenerProp : listener->getProperties()) {
auto prop = std::unique_ptr<Property>(listenerProp->clone());
prop->setGroup(listenerPropertyGroup);
declareProperty(std::move(prop));
}
}
/**
* Removes previously copied ILiveListener properties.
*/
void StartLiveData::removeListenerProperties() {
std::vector<std::string> propertiesToRemove;
// Find properties tagged with the listener property group
for (const auto &prop : getProperties()) {
if (prop->getGroup() == listenerPropertyGroup) {
propertiesToRemove.emplace_back(prop->name());
}
}
// Remove identified properties
for (const auto &prop : propertiesToRemove) {
removeProperty(prop);
}
}
//----------------------------------------------------------------------------------------------
/** Execute the algorithm.
*/
void StartLiveData::exec() {
// Validate the inputs
bool FromNow = getProperty("FromNow");
bool FromStartOfRun = getProperty("FromStartOfRun");
bool FromTime = getProperty("FromTime");
int numChecked = 0;
if (FromNow)
numChecked++;
if (FromStartOfRun)
numChecked++;
if (FromTime)
numChecked++;
if (numChecked != 1)
throw std::runtime_error("Please check exactly one of FromNow, FromStartOfRun, FromTime.");
// Adjust the StartTime if you are starting from run/now.
if (FromNow)
this->setPropertyValue("StartTime", "1990-01-01T00:00:00");
// Use the epoch value for the start time, as documented in
// ILiveListener::start.
else if (FromStartOfRun)
// At this point, we don't know when the start of the run was. Set the
// requested time
// to 1 second past the epoch, which is sure to be before that. We're then
// relying
// on the concrete live listener to never give data from before the current
// run.
// So far, any that give historical data behave like this but there's no way
// to enforce it.
this->setPropertyValue("StartTime", "1990-01-01T00:00:01");
else {
// Validate the StartTime property. Don't allow times from the future
DateAndTime reqStartTime(this->getPropertyValue("StartTime"));
// DateAndTime will throw an exception if it can't interpret the string, so
// we don't need to test for that condition.
// check for a requested time in the future
if (reqStartTime > DateAndTime::getCurrentTime()) {
g_log.error("Requested start time in the future. Resetting to current time.");
this->setPropertyValue("StartTime", "1990-01-01T00:00:00");
}
}
// Get the listener (and start listening) as early as possible
ILiveListener_sptr listener = this->getLiveListener();
// Issue a warning if historical data has been requested but the listener does
// not support it.
// This is only for event data; histogram data is by its nature historical and
// specifying a time is meaningless.
if (!FromNow && !listener->supportsHistory() && listener->buffersEvents()) {
g_log.error("Requested start time is in the past, but this instrument does "
"not support historical data. "
"The effective start time is therefore 'now'.");
}
auto loadAlg = std::dynamic_pointer_cast<LoadLiveData>(createChildAlgorithm("LoadLiveData"));
if (!loadAlg)
throw std::logic_error("Error creating LoadLiveData - contact the Mantid developer team");
// Copy settings from THIS to LoadAlg
loadAlg->copyPropertyValuesFrom(*this);
// Force replacing the output workspace on the first run, to clear out old
// junk.
loadAlg->setPropertyValue("AccumulationMethod", "Replace");
// Give the listener directly to LoadLiveData (don't re-create it)
loadAlg->setLiveListener(listener);
// Run the LoadLiveData for the first time.
loadAlg->executeAsChildAlg();
// Copy the output workspace properties from LoadLiveData
Workspace_sptr outWS = loadAlg->getProperty("OutputWorkspace");
this->setProperty("OutputWorkspace", outWS);
Workspace_sptr accumWS = loadAlg->getProperty("AccumulationWorkspace");
this->setProperty("AccumulationWorkspace", accumWS);
double UpdateEvery = this->getProperty("UpdateEvery");
if (UpdateEvery > 0) {
// Create the MonitorLiveData
IAlgorithm_sptr algBase = AlgorithmManager::Instance().create("MonitorLiveData", -1);
auto *monitorAlg = dynamic_cast<MonitorLiveData *>(algBase.get());
if (!monitorAlg)
throw std::runtime_error("Error creating the MonitorLiveData algorithm");
// Copy settings from THIS to monitorAlg
monitorAlg->initialize();
monitorAlg->copyPropertyValuesFrom(*this);
monitorAlg->setProperty("UpdateEvery", UpdateEvery);
// Give the listener directly to LoadLiveData (don't re-create it)
monitorAlg->setLiveListener(listener);
// Check for possible cancellation
interruption_point();
// Launch asyncronously
monitorAlg->executeAsync();
// Set the output property that passes back a handle to the ongoing live
// algorithm
setProperty("MonitorLiveData", algBase);
}
}
} // namespace Mantid::LiveData