Mantid
Loading...
Searching...
No Matches
BatchAlgorithmRunner.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 +
7
12
15#include "MantidKernel/Logger.h"
16
17#include <memory>
18#include <utility>
19
20using namespace Mantid::API;
21
22namespace {
23Mantid::Kernel::Logger g_log("BatchAlgorithmRunner");
24
25// Throw if any of the given properties do not exist in the algorithm's declared property names
26void throwIfAnyPropertiesInvalid(IAlgorithm_sptr alg, Mantid::API::IAlgorithmRuntimeProps const &props) {
27 auto allowedPropNames = alg->getDeclaredPropertyNames();
28 auto propNamesToUpdate = props.getDeclaredPropertyNames();
29
30 // Note that for std::set_difference the lists need to be sorted
31 std::sort(allowedPropNames.begin(), allowedPropNames.end());
32 std::sort(propNamesToUpdate.begin(), propNamesToUpdate.end());
33
34 std::vector<std::string> invalidProps;
35 std::set_difference(propNamesToUpdate.cbegin(), propNamesToUpdate.cend(), allowedPropNames.cbegin(),
36 allowedPropNames.cend(), std::back_inserter(invalidProps));
37
38 if (invalidProps.size() > 0) {
39 const auto invalidPropsStr = std::accumulate(std::next(invalidProps.cbegin()), invalidProps.cend(), invalidProps[0],
40 [](const auto &a, const auto &b) { return a + "," + b; });
41 throw Mantid::Kernel::Exception::NotFoundError("Invalid Properties given: ", invalidPropsStr);
42 }
43}
44} // namespace
45
46namespace MantidQt::API {
47
49 : QObject(parent), m_algorithms(), m_currentAlgorithm(), m_stopOnFailure(true), m_cancelRequested(false),
50 m_notificationCenter(), m_batchCompleteObserver(*this, &BatchAlgorithmRunner::handleBatchComplete),
51 m_batchCancelledObserver(*this, &BatchAlgorithmRunner::handleBatchCancelled),
52 m_algorithmStartedObserver(*this, &BatchAlgorithmRunner::handleAlgorithmStarted),
53 m_algorithmCompleteObserver(*this, &BatchAlgorithmRunner::handleAlgorithmComplete),
54 m_algorithmErrorObserver(*this, &BatchAlgorithmRunner::handleAlgorithmError),
55 m_executeAsync(this, &BatchAlgorithmRunner::executeBatchAsyncImpl) {}
56
63
72
81
90
97 this->addAlgorithm(algo, std::make_unique<AlgorithmRuntimeProps>());
98}
99
107void BatchAlgorithmRunner::addAlgorithm(const IAlgorithm_sptr &algo, std::unique_ptr<IAlgorithmRuntimeProps> props) {
108 m_algorithms.emplace_back(std::make_unique<ConfiguredAlgorithm>(algo, std::move(props)));
109
110 g_log.debug() << "Added algorithm \"" << m_algorithms.back()->algorithm()->name() << "\" to batch queue\n";
111}
112
118void BatchAlgorithmRunner::setQueue(std::deque<IConfiguredAlgorithm_sptr> algorithms) {
119 g_log.debug() << "Set batch queue to algorithm list:\n";
120 for (auto const &algorithm : algorithms)
121 g_log.debug() << algorithm->algorithm()->name() << "\n";
122
123 std::lock_guard<std::recursive_mutex> lock(m_executeMutex);
124 m_algorithms = std::move(algorithms);
125}
126
131 std::lock_guard<std::recursive_mutex> lock(m_executeMutex);
132 m_algorithms.clear();
133}
134
139 std::lock_guard<std::recursive_mutex> lock(m_executeMutex);
140 return m_algorithms.size();
141}
142
150 Poco::ActiveResult<bool> result = m_executeAsync(Poco::Void());
151 result.wait();
153 return result.data();
154}
155
163
170 std::deque<IConfiguredAlgorithm_sptr> algorithmDeque;
171 algorithmDeque.emplace_back(std::move(algorithm));
172 setQueue(std::move(algorithmDeque));
174}
175
180 // If not currently executing, notify straight away that the batch has been
181 // cancelled. Otherwise, set a flag so that it will be cancelled after the
182 // current algorithm finishes processing
183 if (m_executeMutex.try_lock()) {
184 m_executeMutex.unlock();
188 } else {
189 setCancelRequested(true);
190 }
191}
192
201
203 std::lock_guard<std::recursive_mutex> lock(m_cancelMutex);
204 return m_cancelRequested;
205}
206
210bool BatchAlgorithmRunner::executeBatchAsyncImpl(const Poco::Void & /*unused*/) {
211 std::lock_guard<std::recursive_mutex> lock(m_executeMutex);
212
213 bool errorFlag = false;
214 for (auto const &it : m_algorithms) {
215 if (cancelRequested()) {
216 g_log.information("Stopping batch algorithm execution: cancelled");
217 break;
218 }
219
220 // Try to execute the algorithm
221 if (!executeAlgo(it)) {
222 g_log.warning() << "Got error from algorithm \"" << m_currentAlgorithm->name() << "\"\n";
223
224 // Stop executing the entire batch if appropriate
225 if (m_stopOnFailure) {
226 g_log.warning("Stopping batch algorithm because of execution error");
227 errorFlag = true;
228 break;
229 }
230 } else {
231 g_log.information() << "Algorithm \"" << m_currentAlgorithm->name() << "\" finished\n";
232 }
233 }
234
235 // Notify observers
236 if (cancelRequested())
238 else
239 postNotification(new BatchCompleteNotification(false, errorFlag));
240
241 resetState();
242
243 return !errorFlag;
244}
245
253 try {
254 m_currentAlgorithm = algorithm->algorithm();
255 auto const &props = algorithm->getAlgorithmRuntimeProps();
256 if (algorithm->validatePropsPreExec()) {
257 throwIfAnyPropertiesInvalid(m_currentAlgorithm, props);
258 }
259
260 // Assign the properties to be set at runtime
261 m_currentAlgorithm->updatePropertyValues(props);
262
263 g_log.information() << "Starting next algorithm in queue: " << m_currentAlgorithm->name() << "\n";
264
265 // Start algorithm running
267 auto result = m_currentAlgorithm->execute();
268
269 if (!result) {
270 auto message = std::string("Algorithm") + algorithm->algorithm()->name() + std::string(" execution failed");
271 postNotification(new AlgorithmErrorNotification(algorithm, message));
272 } else {
274 }
275
276 return result;
277 }
278 // If a property name was given that does not match a property
279 catch (Mantid::Kernel::Exception::NotFoundError &notFoundEx) {
280 UNUSED_ARG(notFoundEx);
281 g_log.warning("Algorithm property does not exist.\nStopping queue execution.");
282 postNotification(new AlgorithmErrorNotification(algorithm, notFoundEx.what()));
283 return false;
284 }
285 // If a property was assigned a value of the wrong type
286 catch (std::invalid_argument &invalidArgEx) {
287 UNUSED_ARG(invalidArgEx);
288 g_log.warning("Algorithm property given value of incorrect type.\nStopping "
289 "queue execution.");
290 postNotification(new AlgorithmErrorNotification(algorithm, invalidArgEx.what()));
291 return false;
292 }
293 // For anything else that could go wrong
294 catch (std::exception &ex) {
295 g_log.warning("Error starting batch algorithm");
296 postNotification(new AlgorithmErrorNotification(algorithm, ex.what()));
297 return false;
298 } catch (...) {
299 g_log.warning("Unknown error starting next batch algorithm");
300 postNotification(new AlgorithmErrorNotification(algorithm, "Unknown error starting algorithm"));
301 return false;
302 }
303}
304
305void BatchAlgorithmRunner::postNotification(Poco::Notification *notification) {
306 std::lock_guard<std::recursive_mutex> lock(m_notificationMutex);
307 m_notificationCenter.postNotification(notification);
308}
309
311 std::lock_guard<std::recursive_mutex> lock(m_cancelMutex);
312 m_cancelRequested = cancel;
313}
314
320void BatchAlgorithmRunner::handleBatchComplete(const Poco::AutoPtr<BatchCompleteNotification> &pNf) {
321 bool inProgress = pNf->isInProgress();
322 if (!inProgress) {
323 // Notify UI elements
324 emit batchComplete(pNf->hasError());
325 }
326}
327
328void BatchAlgorithmRunner::handleBatchCancelled(const Poco::AutoPtr<BatchCancelledNotification> &pNf) {
329 UNUSED_ARG(pNf);
330 // Notify UI elements
331 emit batchCancelled();
332}
333
334void BatchAlgorithmRunner::handleAlgorithmStarted(const Poco::AutoPtr<AlgorithmStartedNotification> &pNf) {
335 // Notify UI elements
336 emit algorithmStarted(pNf->algorithm());
337}
338
339void BatchAlgorithmRunner::handleAlgorithmComplete(const Poco::AutoPtr<AlgorithmCompleteNotification> &pNf) {
340 // Notify UI elements
341 emit algorithmComplete(pNf->algorithm());
342}
343
344void BatchAlgorithmRunner::handleAlgorithmError(const Poco::AutoPtr<AlgorithmErrorNotification> &pNf) {
345 auto errorMessage = pNf->errorMessage();
346 // Notify UI elements
347 emit algorithmError(pNf->algorithm(), errorMessage);
348}
349} // namespace MantidQt::API
#define UNUSED_ARG(x)
Function arguments are sometimes unused in certain implmentations but are required for documentation ...
Definition System.h:48
Algorithm runner for execution of a queue of algorithms.
void handleAlgorithmComplete(const Poco::AutoPtr< AlgorithmCompleteNotification > &pNf)
bool m_cancelRequested
User has requested to cancel processing.
void handleBatchCancelled(const Poco::AutoPtr< BatchCancelledNotification > &pNf)
void algorithmStarted(MantidQt::API::IConfiguredAlgorithm_sptr algorithm)
Mantid::API::IAlgorithm_sptr m_currentAlgorithm
The current algorithm being executed.
void setQueue(std::deque< IConfiguredAlgorithm_sptr > algorithm)
Set the queue of algorithms.
void handleBatchComplete(const Poco::AutoPtr< BatchCompleteNotification > &pNf)
Handlers for notifications.
std::deque< IConfiguredAlgorithm_sptr > m_algorithms
The queue of algorithms to be executed.
BatchAlgorithmRunner(QObject *parent=nullptr)
bool m_stopOnFailure
If execution should be stopped on algorithm failure.
void resetState()
Reset state ready for executing a new batch.
void stopOnFailure(bool stopOnFailure)
Sets if the execuion should be stopped if an error is detected.
void handleAlgorithmError(const Poco::AutoPtr< AlgorithmErrorNotification > &pNf)
void cancelBatch()
Request to cancel processing the batch.
bool executeBatch()
Executes the batch, waits for the result and returns it.
Poco::NObserver< BatchAlgorithmRunner, AlgorithmStartedNotification > m_algorithmStartedObserver
Poco::NObserver< BatchAlgorithmRunner, BatchCompleteNotification > m_batchCompleteObserver
Observer for notifications.
void executeAlgorithmAsync(IConfiguredAlgorithm_sptr algorithm)
Starts a single algorithm and returns immediately.
void executeBatchAsync()
Starts the batch executing and returns immediately.
void postNotification(Poco::Notification *notification)
Post a poco notification.
Poco::NotificationCenter m_notificationCenter
Notification center used to handle notifications from active method.
void handleAlgorithmStarted(const Poco::AutoPtr< AlgorithmStartedNotification > &pNf)
bool executeAlgo(const IConfiguredAlgorithm_sptr &algorithm)
Sets up and executes an algorithm.
Poco::ActiveMethod< bool, Poco::Void, BatchAlgorithmRunner, Poco::ActiveStarter< BatchAlgorithmRunner > > m_executeAsync
Active method to run batch runner on separate thread.
Poco::NObserver< BatchAlgorithmRunner, AlgorithmErrorNotification > m_algorithmErrorObserver
void algorithmError(MantidQt::API::IConfiguredAlgorithm_sptr algorithm, std::string errorMessage)
void algorithmComplete(MantidQt::API::IConfiguredAlgorithm_sptr algorithm)
Poco::NObserver< BatchAlgorithmRunner, AlgorithmCompleteNotification > m_algorithmCompleteObserver
void batchComplete(bool error)
Emitted when a batch has finished executing.
void clearQueue()
Clears all algorithms from queue.
bool executeBatchAsyncImpl(const Poco::Void &)
Implementation of algorithm runner.
Poco::NObserver< BatchAlgorithmRunner, BatchCancelledNotification > m_batchCancelledObserver
void addAlgorithm(const Mantid::API::IAlgorithm_sptr &algo)
Adds an algorithm to the execution queue.
Exception for when an item is not found in a collection.
Definition Exception.h:145
const char * what() const noexcept override
Writes out the range and limits.
virtual std::vector< std::string > getDeclaredPropertyNames() const noexcept=0
Get the list of managed property names.
The Logger class is in charge of the publishing messages from the framework through various channels.
Definition Logger.h:51
void debug(const std::string &msg)
Logs at debug level.
Definition Logger.cpp:145
void warning(const std::string &msg)
Logs at warning level.
Definition Logger.cpp:117
void information(const std::string &msg)
Logs at information level.
Definition Logger.cpp:136
std::shared_ptr< IConfiguredAlgorithm > IConfiguredAlgorithm_sptr
std::shared_ptr< IAlgorithm > IAlgorithm_sptr
shared pointer to Mantid::API::IAlgorithm
Kernel::Logger g_log("ExperimentInfo")
static logger object