Algorithm.h 21.4 KB
Newer Older
1
2
3
// Mantid Repository : https://github.com/mantidproject/mantid
//
// Copyright © 2007 ISIS Rutherford Appleton Laboratory UKRI,
4
5
//   NScD Oak Ridge National Laboratory, European Spallation Source,
//   Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6
// SPDX - License - Identifier: GPL - 3.0 +
7
#pragma once
8

9
10
#include <atomic>

11
#include "MantidAPI/DllConfig.h"
12
#include "MantidAPI/IAlgorithm.h"
13
#include "MantidAPI/IndexTypeProperty.h"
14
#include "MantidKernel/IValidator.h"
15
#include "MantidKernel/PropertyManagerOwner.h"
16
17

// -- These headers will (most-likely) be used by every inheriting algorithm
18
#include "MantidAPI/AlgorithmFactory.h" //for the factory macro
19
#include "MantidAPI/Progress.h"
20
#include "MantidAPI/WorkspaceOpOverloads.h"
21
#include "MantidAPI/WorkspaceProperty.h"
22
#include "MantidKernel/EmptyValues.h"
23
#include "MantidKernel/MultiThreaded.h"
24

25
26
#include "MantidParallel/ExecutionMode.h"
#include "MantidParallel/StorageMode.h"
27
28
namespace boost {
template <class T> class weak_ptr;
29
}
30

31
32
33
34
35
36
namespace Poco {
template <class R, class A, class O, class S> class ActiveMethod;
template <class O> class ActiveStarter;
class NotificationCenter;
template <class C, class N> class NObserver;
class Void;
37
} // namespace Poco
38

Nick Draper's avatar
Nick Draper committed
39
40
41
42
namespace Json {
class Value;
}

43
namespace Mantid {
44
45
46
namespace Indexing {
class SpectrumIndexSet;
}
47
48
49
namespace Parallel {
class Communicator;
}
50
namespace API {
51
52
53
//----------------------------------------------------------------------
// Forward Declaration
//----------------------------------------------------------------------
54
class AlgorithmHistory;
55
class WorkspaceHistory;
56
57

/**
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
Base class from which all concrete algorithm classes should be derived.
In order for a concrete algorithm class to do anything
useful the methods init() & exec()  should be overridden.

Further text from Gaudi file.......
The base class provides utility methods for accessing
standard services (event data service etc.); for declaring
properties which may be configured by the job options
service; and for creating Child Algorithms.
The only base class functionality which may be used in the
constructor of a concrete algorithm is the declaration of
member variables as properties. All other functionality,
i.e. the use of services and the creation of Child Algorithms,
may be used only in initialise() and afterwards (see the
Gaudi user guide).

@author Russell Taylor, Tessella Support Services plc
@author Based on the Gaudi class of the same name (see
http://proj-gaudi.web.cern.ch/proj-gaudi/)
@date 12/09/2007
*/
79
80
class MANTID_API_DLL Algorithm : public IAlgorithm,
                                 public Kernel::PropertyManagerOwner {
81
82
public:
  /// Base class for algorithm notifications
Peterson, Peter's avatar
Peterson, Peter committed
83
  class MANTID_API_DLL AlgorithmNotification : public Poco::Notification {
84
  public:
85
86
    AlgorithmNotification(const Algorithm *const alg);
    const IAlgorithm *algorithm() const;
Peterson, Peter's avatar
Peterson, Peter committed
87

88
  private:
89
    const IAlgorithm *const m_algorithm; ///< The algorithm
90
91
92
  };

  /// StartedNotification is sent when the algorithm begins execution.
Peterson, Peter's avatar
Peterson, Peter committed
93
  class MANTID_API_DLL StartedNotification : public AlgorithmNotification {
94
  public:
95
96
    StartedNotification(const Algorithm *const alg);
    std::string name() const override;
97
98
99
  };

  /// FinishedNotification is sent after the algorithm finishes its execution
Peterson, Peter's avatar
Peterson, Peter committed
100
  class MANTID_API_DLL FinishedNotification : public AlgorithmNotification {
101
  public:
102
103
    FinishedNotification(const Algorithm *const alg, bool res);
    std::string name() const override;
104
    bool success; ///< true if the finished algorithm was successful or false if
105
                  /// it failed.
106
107
108
  };

  /// An algorithm can report its progress by sending ProgressNotification. Use
109
  /// Algorithm::progress(double) function to send a progress notification.
Peterson, Peter's avatar
Peterson, Peter committed
110
  class MANTID_API_DLL ProgressNotification : public AlgorithmNotification {
111
  public:
112
    /// Constructor
113
114
    ProgressNotification(const Algorithm *const alg, double p,
                         const std::string &msg, double estimatedTime,
115
116
                         int progressPrecision);
    std::string name() const override;
117
118
    double progress;       ///< Current progress. Value must be between 0 and 1.
    std::string message;   ///< Message sent with notification
LamarMoore's avatar
LamarMoore committed
119
120
    double estimatedTime;  ///< Estimated time to completion
    int progressPrecision; ///< Digits of precision to the progress (after the
121
                           /// decimal).
122
123
  };

124
125
  /// ErrorNotification is sent when an exception is caught during execution of
  /// the algorithm.
Peterson, Peter's avatar
Peterson, Peter committed
126
  class MANTID_API_DLL ErrorNotification : public AlgorithmNotification {
127
128
  public:
    /// Constructor
129
130
    ErrorNotification(const Algorithm *const alg, const std::string &str);
    std::string name() const override;
131
    std::string what; ///< message string
132
133
  };

134
135
136
137
138
139
  /// CancelException is thrown to cancel execution of the algorithm. Use
  /// Algorithm::cancel() to
  /// terminate an algorithm. The execution will only be stopped if
  /// Algorithm::exec() method calls
  /// periodically Algorithm::interuption_point() which checks if
  /// Algorithm::cancel() has been called
140
  /// and throws CancelException if needed.
Peterson, Peter's avatar
Peterson, Peter committed
141
  class MANTID_API_DLL CancelException : public std::exception {
142
143
  public:
    /// Returns the message string.
144
    const char *what() const noexcept override;
145
146
  };

147
  //============================================================================
148
  Algorithm();
149
150
  Algorithm(const Algorithm &) = delete;
  Algorithm &operator=(const Algorithm &) = delete;
151
  ~Algorithm() override;
152
153

  /** @name Algorithm Information */
154
155
  /// function to return a name of the algorithm, must be overridden in all
  /// algorithms
156
  const std::string name() const override = 0;
157
158
  /// function to return a version of the algorithm, must be overridden in all
  /// algorithms
159
  int version() const override = 0;
160
161
  /// function returns a summary message that will be displayed in the default
  /// GUI, and in the help.
162
  const std::string summary() const override = 0;
163
164
  /// function to return a category of the algorithm. A default implementation
  /// is provided
165
  const std::string category() const override { return "Misc"; }
Nick Draper's avatar
Nick Draper committed
166
  /// Function to return all of the categories that contain this algorithm
167
  const std::vector<std::string> categories() const override;
168
169
  /// Function to return the separator token for the category string. A default
  /// implementation ';' is provided
170
  const std::string categorySeparator() const override { return ";"; }
Nick Draper's avatar
Nick Draper committed
171
172
  /// Function to return all of the seeAlso (these are not validated) algorithms
  /// related to this algorithm.A default implementation is provided.
173
  const std::vector<std::string> seeAlso() const override { return {}; };
174
175
  /// function to return any aliases to the algorithm;  A default implementation
  /// is provided
176
  const std::string alias() const override { return ""; }
177

178
  /// function to return URL for algorithm documentation; A default
Jose Borreguero's avatar
Jose Borreguero committed
179
180
  /// implementation is provided.
  /// Override if the algorithm is not part of the Mantid distribution.
181
182
  const std::string helpURL() const override { return ""; }

183
184
  template <typename T, typename = typename std::enable_if<std::is_convertible<
                            T *, MatrixWorkspace *>::value>::type>
LamarMoore's avatar
LamarMoore committed
185
  std::tuple<boost::shared_ptr<T>, Indexing::SpectrumIndexSet>
LamarMoore's avatar
LamarMoore committed
186
  getWorkspaceAndIndices(const std::string &name) const;
187

LamarMoore's avatar
LamarMoore committed
188
189
190
191
192
  template <typename T1, typename T2,
            typename = typename std::enable_if<
                std::is_convertible<T1 *, MatrixWorkspace *>::value>::type,
            typename = typename std::enable_if<
                std::is_convertible<T2 *, std::string *>::value ||
193
                std::is_convertible<T2 *, std::vector<int64_t> *>::value>::type>
LamarMoore's avatar
LamarMoore committed
194
195
196
  void setWorkspaceInputProperties(const std::string &name,
                                   const boost::shared_ptr<T1> &wksp,
                                   IndexType type, const T2 &list);
197

LamarMoore's avatar
LamarMoore committed
198
199
200
201
202
  template <typename T1, typename T2,
            typename = typename std::enable_if<
                std::is_convertible<T1 *, MatrixWorkspace *>::value>::type,
            typename = typename std::enable_if<
                std::is_convertible<T2 *, std::string *>::value ||
203
                std::is_convertible<T2 *, std::vector<int64_t> *>::value>::type>
LamarMoore's avatar
LamarMoore committed
204
205
206
  void setWorkspaceInputProperties(const std::string &name,
                                   const std::string &wsName, IndexType type,
                                   const T2 &list);
207

208
209
210
  const std::string workspaceMethodName() const override;
  const std::vector<std::string> workspaceMethodOn() const override;
  const std::string workspaceMethodInputProperty() const override;
211

212
213
  /// Algorithm ID. Unmanaged algorithms return 0 (or NULL?) values. Managed
  /// ones have non-zero.
214
  AlgorithmID getAlgorithmID() const override { return m_algorithmID; }
215

216
  /** @name IAlgorithm methods */
217
  void initialize() override;
218
  bool execute() override final;
219
220
  void executeAsChildAlg() override;
  std::map<std::string, std::string> validateInputs() override;
221
222
223
224
225

  /// Gets the current execution state
  ExecutionState executionState() const override;
  /// Gets the current result State
  ResultState resultState() const override;
226
227
228
  bool isInitialized() const override;
  bool isExecuted() const override;
  bool isRunning() const override;
229

230
231
  using Kernel::PropertyManagerOwner::getProperty;

232
233
234
  bool isChild() const override;
  void setChild(const bool isChild) override;
  void enableHistoryRecordingForChild(const bool on) override;
235
  bool isRecordingHistoryForChild() { return m_recordHistoryForChild; }
236
  void setAlwaysStoreInADS(const bool doStore) override;
237
  bool getAlwaysStoreInADS() const override;
238
  void setRethrows(const bool rethrow) override;
239

240
  /** @name Asynchronous Execution */
241
  Poco::ActiveResult<bool> executeAsync() override;
242

243
  /// Add an observer for a notification
244
  void addObserver(const Poco::AbstractObserver &observer) const override;
245
246

  /// Remove an observer
247
  void removeObserver(const Poco::AbstractObserver &observer) const override;
248

249
  /// Raises the cancel flag.
250
  void cancel() override;
251
252
253
254
255
256
257
  bool getCancel() const;

  Kernel::Logger &getLogger() const;
  void setLogging(const bool value) override;
  bool isLogging() const override;
  void setLoggingOffset(const int value) override;
  int getLoggingOffset() const override;
Nick Draper's avatar
Nick Draper committed
258
  /// disable Logging of start and end messages
259
  void setAlgStartupLogging(const bool enabled) override;
Nick Draper's avatar
Nick Draper committed
260
  /// get the state of Logging of start and end messages
261
  bool getAlgStartupLogging() const override;
262

263
  /// setting the child start progress
264
  void setChildStartProgress(const double startProgress) const override {
265
266
    m_startChildProgress = startProgress;
  }
267
  /// setting the child end progress
268
  void setChildEndProgress(const double endProgress) const override {
269
270
    m_endChildProgress = endProgress;
  }
271

272
273
274
  /** @name Serialization functions */
  //@{
  /// Serialize an object to a string
275
  std::string toString() const override;
Nick Draper's avatar
Nick Draper committed
276
  /// Serialize an object to a json object
277
  ::Json::Value toJson() const override;
278
  /// De-serialize an object from a string
279
  static IAlgorithm_sptr fromString(const std::string &input);
280
281
  /// De-serialize an object from a Json
  static IAlgorithm_sptr fromJson(const Json::Value &input);
282
  /// Construct an object from a history entry
283
  static IAlgorithm_sptr fromHistory(const AlgorithmHistory &history);
284
285
  //@}

286
287
288
289
  virtual boost::shared_ptr<Algorithm> createChildAlgorithm(
      const std::string &name, const double startProgress = -1.,
      const double endProgress = -1., const bool enableLogging = true,
      const int &version = -1);
290
291
292
293
  void setupAsChildAlgorithm(boost::shared_ptr<Algorithm> algorithm,
                             const double startProgress = -1.,
                             const double endProgress = -1.,
                             const bool enableLogging = true);
294

295
296
  /// set whether we wish to track the child algorithm's history and pass it the
  /// parent object to fill.
297
298
  void trackAlgorithmHistory(boost::shared_ptr<AlgorithmHistory> parentHist);

299
  using WorkspaceVector = std::vector<boost::shared_ptr<Workspace>>;
300

301
302
  void findWorkspaces(WorkspaceVector &workspaces, unsigned int direction,
                      bool checkADS = false) const;
303
304
305
306
307
308

  // ------------------ For WorkspaceGroups ------------------------------------
  virtual bool checkGroups();

  virtual bool processGroups();

309
  void copyNonWorkspaceProperties(IAlgorithm *alg, int periodNum);
310

311
312
313
  const Parallel::Communicator &communicator() const;
  void setCommunicator(const Parallel::Communicator &communicator);

314
protected:
315
316
317
318
  /// Virtual method - must be overridden by concrete algorithm
  virtual void init() = 0;
  /// Virtual method - must be overridden by concrete algorithm
  virtual void exec() = 0;
319

320
321
322
323
324
325
326
  void exec(Parallel::ExecutionMode executionMode);
  virtual void execDistributed();
  virtual void execMasterOnly();

  virtual Parallel::ExecutionMode getParallelExecutionMode(
      const std::map<std::string, Parallel::StorageMode> &storageModes) const;

327
328
  /// Returns a semi-colon separated list of workspace types to attach this
  /// algorithm
329
330
  virtual const std::string workspaceMethodOnTypes() const { return ""; }

331
  void cacheWorkspaceProperties();
332
  void cacheInputWorkspaceHistories();
333

Nick Draper's avatar
Nick Draper committed
334
335
336
337
  void setExecutionState(
      const ExecutionState state); ///< Sets the current execution state
  void
  setResultState(const ResultState state); ///< Sets the result execution state
338

339
340
  void store();

341
  /** @name Progress Reporting functions */
342
  friend class Progress;
343
344
  void progress(double p, const std::string &msg = "",
                double estimatedTime = 0.0, int progressPrecision = 0);
345
346
  void interruption_point();

347
  /// Return a reference to the algorithm's notification dispatcher
348
  Poco::NotificationCenter &notificationCenter() const;
349

350
351
352
353
  /// Observation slot for child algorithm progress notification messages, these
  /// are scaled and then signalled for this algorithm.
  void handleChildProgressNotification(
      const Poco::AutoPtr<ProgressNotification> &pNf);
354
  /// Return a reference to the algorithm's object that is reporting progress
355
356
357
358
359
  const Poco::AbstractObserver &progressObserver() const;

  /// checks that the value was not set by users, uses the value in empty
  /// double/int.
  template <typename NumT> static bool isEmpty(const NumT toCheck);
360

361
362
  /// checks the property is a workspace property
  bool isWorkspaceProperty(const Kernel::Property *const prop) const;
363

364
365
  /// get whether we are tracking the history for this algorithm,
  bool trackingHistory();
366
367
  /// Copy workspace history for input workspaces to output workspaces and
  /// record the history for ths algorithm
368
  virtual void fillHistory();
369

370
  /// Set to true to stop execution
371
  std::atomic<bool> m_cancel;
372
  /// Set if an exception is thrown, and not caught, within a parallel region
373
  std::atomic<bool> m_parallelException;
374

375
376
377
378
  friend class WorkspaceHistory; // Allow workspace history loading to adjust
                                 // g_execCount
  static size_t
      g_execCount; ///< Counter to keep track of algorithm execution order
379

380
381
382
383
  virtual void setOtherProperties(IAlgorithm *alg,
                                  const std::string &propertyName,
                                  const std::string &propertyValue,
                                  int periodNum);
384
385
386

  /// All the WorkspaceProperties that are Input or InOut. Set in execute()
  std::vector<IWorkspaceProperty *> m_inputWorkspaceProps;
387
388
  /// Pointer to the history for the algorithm being executed
  boost::shared_ptr<AlgorithmHistory> m_history;
389

Gigg, Martyn Anthony's avatar
Gigg, Martyn Anthony committed
390
391
392
393
  /// Logger for this algorithm
  Kernel::Logger m_log;
  Kernel::Logger &g_log;

394
395
396
  /// Pointer to the parent history object (if set)
  boost::shared_ptr<AlgorithmHistory> m_parentHistory;

397
398
399
  /// One vector of workspaces for each input workspace property. A group is
  /// unrolled to its constituent members
  std::vector<WorkspaceVector> m_unrolledInputWorkspaces;
400
401
  /// Size of the group(s) being processed
  size_t m_groupSize;
402
403
404
  /// distinguish between base processGroups() and overriden/algorithm specific
  /// versions
  bool m_usingBaseProcessGroups = false;
405

406
407
  template <typename T, const int AllowedIndexTypes = IndexType::WorkspaceIndex,
            typename... WSPropArgs,
408
409
            typename = typename std::enable_if<
                std::is_convertible<T *, MatrixWorkspace *>::value>::type>
410
411
412
  void declareWorkspaceInputProperties(const std::string &propertyName,
                                       const std::string &doc,
                                       WSPropArgs &&... wsPropArgs);
LamarMoore's avatar
LamarMoore committed
413

414
private:
415
  template <typename T1, typename T2, typename WsType>
LamarMoore's avatar
LamarMoore committed
416
417
  void doSetInputProperties(const std::string &name, const T1 &wksp,
                            IndexType type, const T2 &list);
418
419
420
  void lockWorkspaces();
  void unlockWorkspaces();

421
  void linkHistoryWithLastChild();
422

423
  void logAlgorithmInfo() const;
424

425
426
  bool executeInternal();

427
  bool executeAsyncImpl(const Poco::Void &i);
428

429
  bool doCallProcessGroups(Mantid::Types::Core::DateAndTime &start_time);
430

431
  void fillHistory(const std::vector<Workspace_sptr> &outputWorkspaces);
432

433
  // Report that the algorithm has completed.
434
435
  void reportCompleted(const double &duration,
                       const bool groupProcessing = false);
436

437
  void registerFeatureUsage() const;
Nick Draper's avatar
Nick Draper committed
438

439
440
441
  Parallel::ExecutionMode getExecutionMode() const;
  std::map<std::string, Parallel::StorageMode>
  getInputWorkspaceStorageModes() const;
442
  void setupSkipValidationMasterOnly();
443

LamarMoore's avatar
LamarMoore committed
444
445
  bool isCompoundProperty(const std::string &name) const;

446
  // --------------------- Private Members -----------------------------------
447
  /// Poco::ActiveMethod used to implement asynchronous execution.
448
  std::unique_ptr<Poco::ActiveMethod<bool, Poco::Void, Algorithm,
Sam Jenkins's avatar
Sam Jenkins committed
449
450
                                     Poco::ActiveStarter<Algorithm>>>
      m_executeAsync;
451

452
453
  /// Sends notifications to observers. Observers can subscribe to
  /// notificationCenter
454
  /// using Poco::NotificationCenter::addObserver(...);
455
  mutable std::unique_ptr<Poco::NotificationCenter> m_notificationCenter;
456
  /// Child algorithm progress observer
Sam Jenkins's avatar
Sam Jenkins committed
457
458
  mutable std::unique_ptr<Poco::NObserver<Algorithm, ProgressNotification>>
      m_progressObserver;
459

460
  std::atomic<ExecutionState> m_executionState; ///< the current execution state
Nick Draper's avatar
Nick Draper committed
461
462
463
  std::atomic<ResultState> m_resultState;       ///< the current result State
  bool m_isExecuted;                            ///< Algorithm is executed flag
  bool m_isChildAlgorithm;      ///< Algorithm is a child algorithm
464
  bool m_recordHistoryForChild; ///< Flag to indicate whether history should be
465
                                /// recorded. Applicable to child algs only
466
  bool m_alwaysStoreInADS; ///< Always store in the ADS, even for child algos
467
  bool m_runningAsync;     ///< Algorithm is running asynchronously
468
  bool m_rethrow; ///< Algorithm should rethrow exceptions while executing
469
470
471
472
  bool m_isAlgStartupLoggingEnabled; /// Whether to log alg startup and
                                     /// closedown messages from the base class
                                     /// (default = true)
  mutable double m_startChildProgress; ///< Keeps value for algorithm's progress
473
474
475
476
                                       /// at start of an Child Algorithm
  mutable double m_endChildProgress;   ///< Keeps value for algorithm's progress
                                       /// at Child Algorithm's finish
  AlgorithmID m_algorithmID;           ///< Algorithm ID for managed algorithms
477
  std::vector<boost::weak_ptr<IAlgorithm>> m_ChildAlgorithms; ///< A list of
478
479
480
481
                                                              /// weak pointers
                                                              /// to any child
                                                              /// algorithms
                                                              /// created
482

483
  /// Vector of all the workspaces that have been read-locked
484
  WorkspaceVector m_readLockedWorkspaces;
485
  /// Vector of all the workspaces that have been write-locked
486
  WorkspaceVector m_writeLockedWorkspaces;
487

488
  /// All the WorkspaceProperties that are Output or InOut. Set in execute()
489
  std::vector<IWorkspaceProperty *> m_outputWorkspaceProps;
490
491
  /// All the WorkspaceProperties that are Output (not inOut). Set in execute()
  std::vector<IWorkspaceProperty *> m_pureOutputWorkspaceProps;
492

493
  /// Pointer to the WorkspaceGroup (if any) for each input workspace property
494
  std::vector<boost::shared_ptr<WorkspaceGroup>> m_groupWorkspaces;
495
496
  /// If only one input is a group, this is its index. -1 if they are all groups
  int m_singleGroup;
497
498
  /// All the groups have similar names (group_1, group_2 etc.)
  bool m_groupsHaveSimilarNames;
499
500
501
  /// Store a pointer to the input workspace histories so they can be copied to
  /// the outputs to avoid anything being overwritten
  std::vector<Workspace_sptr> m_inputWorkspaceHistories;
502

503
  /// Reserved property names
504
  std::vector<std::string> m_reservedList;
LamarMoore's avatar
LamarMoore committed
505

506
  /// (MPI) communicator used when executing the algorithm.
507
  std::unique_ptr<Parallel::Communicator> m_communicator;
508
};
509

510
/// Typedef for a shared pointer to an Algorithm
511
using Algorithm_sptr = boost::shared_ptr<Algorithm>;
512

513
} // namespace API
514
515
} // namespace Mantid

516
517
518
519
520
/* Used to register classes into the factory. creates a global object in an
 * anonymous namespace. The object itself does nothing, but the comma operator
 * is used in the call to its constructor to effect a call to the factory's
 * subscribe method.
 */
521
522
523
524
525
#define DECLARE_ALGORITHM(classname)                                           \
  namespace {                                                                  \
  Mantid::Kernel::RegistrationHelper register_alg_##classname((                \
      (Mantid::API::AlgorithmFactory::Instance().subscribe<classname>()), 0)); \
  }