Newer
Older
// Mantid Repository : https://github.com/mantidproject/mantid
//
// Copyright © 2007 ISIS Rutherford Appleton Laboratory UKRI,
// NScD Oak Ridge National Laboratory, European Spallation Source
// & Institut Laue - Langevin
// SPDX - License - Identifier: GPL - 3.0 +
Peterson, Peter
committed
#ifndef MANTID_API_ALGORITHM_H_
#define MANTID_API_ALGORITHM_H_
#include <atomic>
Gigg, Martyn Anthony
committed
#include "MantidAPI/DllConfig.h"
Peterson, Peter
committed
#include "MantidAPI/IAlgorithm.h"
#include "MantidAPI/IndexTypeProperty.h"
#include "MantidKernel/IValidator.h"
Peterson, Peter
committed
#include "MantidKernel/PropertyManagerOwner.h"
// -- These headers will (most-likely) be used by every inheriting algorithm
#include "MantidAPI/AlgorithmFactory.h" //for the factory macro
Peterson, Peter
committed
#include "MantidAPI/Progress.h"
#include "MantidAPI/WorkspaceOpOverloads.h"
#include "MantidAPI/WorkspaceProperty.h"
#include "MantidKernel/EmptyValues.h"
#include "MantidKernel/MultiThreaded.h"
#include "MantidParallel/ExecutionMode.h"
#include "MantidParallel/StorageMode.h"
namespace boost {
template <class T> class weak_ptr;
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;
} // namespace Poco
Peterson, Peter
committed
namespace Indexing {
class SpectrumIndexSet;
}
namespace Parallel {
class Communicator;
}
Russell Taylor
committed
//----------------------------------------------------------------------
// Forward Declaration
//----------------------------------------------------------------------
class AlgorithmProxy;
class AlgorithmHistory;
Russell Taylor
committed
/**
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
*/
class MANTID_API_DLL Algorithm : public IAlgorithm,
public Kernel::PropertyManagerOwner {
Russell Taylor
committed
public:
/// Base class for algorithm notifications
class MANTID_API_DLL AlgorithmNotification : public Poco::Notification {
Russell Taylor
committed
public:
AlgorithmNotification(const Algorithm *const alg);
const IAlgorithm *algorithm() const;
Russell Taylor
committed
private:
const IAlgorithm *const m_algorithm; ///< The algorithm
Russell Taylor
committed
};
/// StartedNotification is sent when the algorithm begins execution.
class MANTID_API_DLL StartedNotification : public AlgorithmNotification {
Russell Taylor
committed
public:
StartedNotification(const Algorithm *const alg);
std::string name() const override;
Russell Taylor
committed
};
/// FinishedNotification is sent after the algorithm finishes its execution
class MANTID_API_DLL FinishedNotification : public AlgorithmNotification {
Russell Taylor
committed
public:
FinishedNotification(const Algorithm *const alg, bool res);
std::string name() const override;
bool success; ///< true if the finished algorithm was successful or false if
/// it failed.
Russell Taylor
committed
};
/// An algorithm can report its progress by sending ProgressNotification. Use
Janik Zikovsky
committed
/// Algorithm::progress(double) function to send a progress notification.
class MANTID_API_DLL ProgressNotification : public AlgorithmNotification {
Russell Taylor
committed
public:
Janik Zikovsky
committed
/// Constructor
ProgressNotification(const Algorithm *const alg, double p,
const std::string &msg, double estimatedTime,
int progressPrecision);
std::string name() const override;
double progress; ///< Current progress. Value must be between 0 and 1.
std::string message; ///< Message sent with notification
double estimatedTime; ///< Estimated time to completion
int progressPrecision; ///< Digits of precision to the progress (after the
/// decimal).
Russell Taylor
committed
};
/// ErrorNotification is sent when an exception is caught during execution of
/// the algorithm.
class MANTID_API_DLL ErrorNotification : public AlgorithmNotification {
Russell Taylor
committed
public:
/// Constructor
ErrorNotification(const Algorithm *const alg, const std::string &str);
std::string name() const override;
std::string what; ///< message string
Russell Taylor
committed
};
/// 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
Russell Taylor
committed
/// and throws CancelException if needed.
class MANTID_API_DLL CancelException : public std::exception {
Russell Taylor
committed
public:
/// Returns the message string.
const char *what() const noexcept override;
Russell Taylor
committed
};
//============================================================================
Russell Taylor
committed
Algorithm();
Algorithm(const Algorithm &) = delete;
Algorithm &operator=(const Algorithm &) = delete;
/** @name Algorithm Information */
/// function to return a name of the algorithm, must be overridden in all
/// algorithms
const std::string name() const override = 0;
/// function to return a version of the algorithm, must be overridden in all
/// algorithms
int version() const override = 0;
/// function returns a summary message that will be displayed in the default
/// GUI, and in the help.
const std::string summary() const override = 0;
/// function to return a category of the algorithm. A default implementation
/// is provided
const std::string category() const override { return "Misc"; }
/// Function to return all of the categories that contain this algorithm
const std::vector<std::string> categories() const override;
/// Function to return the separator token for the category string. A default
/// implementation ';' is provided
const std::string categorySeparator() const override { return ";"; }
/// Function to return all of the seeAlso (these are not validated) algorithms
/// related to this algorithm.A default implementation is provided.
const std::vector<std::string> seeAlso() const override { return {}; };
/// function to return any aliases to the algorithm; A default implementation
/// is provided
const std::string alias() const override { return ""; }
/// function to return URL for algorithm documentation; A default
/// implementation is provided.
/// Override if the algorithm is not part of the Mantid distribution.
const std::string helpURL() const override { return ""; }
template <typename T, typename = typename std::enable_if<std::is_convertible<
T *, MatrixWorkspace *>::value>::type>
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 ||
std::is_convertible<T2 *, std::vector<int64_t> *>::value>::type>
void setWorkspaceInputProperties(const std::string &name,
const boost::shared_ptr<T1> &wksp,
IndexType type, const T2 &list);
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 ||
std::is_convertible<T2 *, std::vector<int64_t> *>::value>::type>
void setWorkspaceInputProperties(const std::string &name,
const std::string &wsName, IndexType type,
const T2 &list);
const std::string workspaceMethodName() const override;
const std::vector<std::string> workspaceMethodOn() const override;
const std::string workspaceMethodInputProperty() const override;
/// Algorithm ID. Unmanaged algorithms return 0 (or NULL?) values. Managed
/// ones have non-zero.
AlgorithmID getAlgorithmID() const override { return m_algorithmID; }
Russell Taylor
committed
/** @name IAlgorithm methods */
void initialize() override;
bool execute() override;
void executeAsChildAlg() override;
std::map<std::string, std::string> validateInputs() override;
bool isInitialized() const override;
bool isExecuted() const override;
bool isRunning() const override;
Russell Taylor
committed
using Kernel::PropertyManagerOwner::getProperty;
bool isChild() const override;
void setChild(const bool isChild) override;
void enableHistoryRecordingForChild(const bool on) override;
bool isRecordingHistoryForChild() { return m_recordHistoryForChild; }
void setAlwaysStoreInADS(const bool doStore) override;
bool getAlwaysStoreInADS() const override;
void setRethrows(const bool rethrow) override;
Russell Taylor
committed
/** @name Asynchronous Execution */
Poco::ActiveResult<bool> executeAsync() override;
Russell Taylor
committed
/// Add an observer for a notification
void addObserver(const Poco::AbstractObserver &observer) const override;
Russell Taylor
committed
/// Remove an observer
void removeObserver(const Poco::AbstractObserver &observer) const override;
Russell Taylor
committed
/// Raises the cancel flag.
void cancel() override;
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;
/// disable Logging of start and end messages
void setAlgStartupLogging(const bool enabled) override;
/// get the state of Logging of start and end messages
bool getAlgStartupLogging() const override;
Russell Taylor
committed
/// setting the child start progress
void setChildStartProgress(const double startProgress) const override {
m_startChildProgress = startProgress;
}
/// setting the child end progress
void setChildEndProgress(const double endProgress) const override {
m_endChildProgress = endProgress;
}
Russell Taylor
committed
Gigg, Martyn Anthony
committed
/** @name Serialization functions */
//@{
/// Serialize an object to a string
std::string toString() const override;
/// Serialize an object to a json object
::Json::Value toJson() const;
Gigg, Martyn Anthony
committed
/// De-serialize an object from a string
static IAlgorithm_sptr fromString(const std::string &input);
Gigg, Martyn Anthony
committed
/// Construct an object from a history entry
static IAlgorithm_sptr fromHistory(const AlgorithmHistory &history);
Gigg, Martyn Anthony
committed
//@}
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);
void setupAsChildAlgorithm(boost::shared_ptr<Algorithm> algorithm,
const double startProgress = -1.,
const double endProgress = -1.,
const bool enableLogging = true);
Janik Zikovsky
committed
/// set whether we wish to track the child algorithm's history and pass it the
/// parent object to fill.
void trackAlgorithmHistory(boost::shared_ptr<AlgorithmHistory> parentHist);
using WorkspaceVector = std::vector<boost::shared_ptr<Workspace>>;
void findWorkspaceProperties(WorkspaceVector &inputWorkspaces,
WorkspaceVector &outputWorkspaces) const;
// ------------------ For WorkspaceGroups ------------------------------------
virtual bool checkGroups();
virtual bool processGroups();
void copyNonWorkspaceProperties(IAlgorithm *alg, int periodNum);
const Parallel::Communicator &communicator() const;
void setCommunicator(const Parallel::Communicator &communicator);
protected:
Russell Taylor
committed
/// Virtual method - must be overridden by concrete algorithm
virtual void init() = 0;
/// Virtual method - must be overridden by concrete algorithm
virtual void exec() = 0;
void exec(Parallel::ExecutionMode executionMode);
virtual void execDistributed();
virtual void execMasterOnly();
virtual Parallel::ExecutionMode getParallelExecutionMode(
const std::map<std::string, Parallel::StorageMode> &storageModes) const;
/// Returns a semi-colon separated list of workspace types to attach this
/// algorithm
virtual const std::string workspaceMethodOnTypes() const { return ""; }
void cacheWorkspaceProperties();
Russell Taylor
committed
friend class AlgorithmProxy;
void initializeFromProxy(const AlgorithmProxy &);
Russell Taylor
committed
void setInitialized();
void setExecuted(bool state);
void store();
/** @name Progress Reporting functions */
Russell Taylor
committed
friend class Progress;
void progress(double p, const std::string &msg = "",
double estimatedTime = 0.0, int progressPrecision = 0);
Russell Taylor
committed
void interruption_point();
/// Return a reference to the algorithm's notification dispatcher
Poco::NotificationCenter ¬ificationCenter() const;
/// Observation slot for child algorithm progress notification messages, these
/// are scaled and then signalled for this algorithm.
void handleChildProgressNotification(
const Poco::AutoPtr<ProgressNotification> &pNf);
/// Return a reference to the algorithm's object that is reporting progress
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);
/// checks the property is a workspace property
bool isWorkspaceProperty(const Kernel::Property *const prop) const;
Peterson, Peter
committed
/// get whether we are tracking the history for this algorithm,
bool trackingHistory();
/// Copy workspace history for input workspaces to output workspaces and
/// record the history for ths algorithm
virtual void fillHistory();
Russell Taylor
committed
/// Set to true to stop execution
std::atomic<bool> m_cancel;
/// Set if an exception is thrown, and not caught, within a parallel region
std::atomic<bool> m_parallelException;
friend class WorkspaceHistory; // Allow workspace history loading to adjust
// g_execCount
static size_t
g_execCount; ///< Counter to keep track of algorithm execution order
Russell Taylor
committed
virtual void setOtherProperties(IAlgorithm *alg,
const std::string &propertyName,
const std::string &propertyValue,
int periodNum);
/// All the WorkspaceProperties that are Input or InOut. Set in execute()
std::vector<IWorkspaceProperty *> m_inputWorkspaceProps;
/// Pointer to the history for the algorithm being executed
boost::shared_ptr<AlgorithmHistory> m_history;
/// Logger for this algorithm
Kernel::Logger m_log;
Kernel::Logger &g_log;
/// Pointer to the parent history object (if set)
boost::shared_ptr<AlgorithmHistory> m_parentHistory;
/// One vector of workspaces for each input workspace property
std::vector<WorkspaceVector> m_groups;
/// Size of the group(s) being processed
size_t m_groupSize;
Federico Montesino Pouzols
committed
/// distinguish between base processGroups() and overriden/algorithm specific
/// versions
bool m_usingBaseProcessGroups = false;
template <typename T, const int AllowedIndexTypes = IndexType::WorkspaceIndex,
typename... WSPropArgs,
typename = typename std::enable_if<
std::is_convertible<T *, MatrixWorkspace *>::value>::type>
void declareWorkspaceInputProperties(const std::string &propertyName,
const std::string &doc,
WSPropArgs &&... wsPropArgs);
private:
template <typename T1, typename T2, typename WsType>
void doSetInputProperties(const std::string &name, const T1 &wksp,
IndexType type, const T2 &list);
void lockWorkspaces();
void unlockWorkspaces();
void linkHistoryWithLastChild();
Janik Zikovsky
committed
bool executeAsyncImpl(const Poco::Void &i);
Russell Taylor
committed
bool doCallProcessGroups(Mantid::Types::Core::DateAndTime &start_time);
Federico Montesino Pouzols
committed
// Report that the algorithm has completed.
void reportCompleted(const double &duration,
const bool groupProcessing = false);
void registerFeatureUsage() const;
Parallel::ExecutionMode getExecutionMode() const;
std::map<std::string, Parallel::StorageMode>
getInputWorkspaceStorageModes() const;
void setupSkipValidationMasterOnly();
bool hasAnADSValidator(const Mantid::Kernel::IValidator_sptr propProp) const;
void constructWorkspaceVectorForHistoryHelper(
std::vector<Workspace_sptr> &inputWorkspaces,
std::vector<Workspace_sptr> &outputWorkspaces,
const unsigned int direction, std::string ¤tWS) const;
// --------------------- Private Members -----------------------------------
/// Poco::ActiveMethod used to implement asynchronous execution.
Poco::ActiveMethod<bool, Poco::Void, Algorithm,
Poco::ActiveStarter<Algorithm>> *m_executeAsync;
/// Sends notifications to observers. Observers can subscribe to
/// notificationCenter
/// using Poco::NotificationCenter::addObserver(...);
mutable Poco::NotificationCenter *m_notificationCenter;
/// Child algorithm progress observer
mutable Poco::NObserver<Algorithm, ProgressNotification> *m_progressObserver;
bool m_isInitialized; ///< Algorithm has been initialized flag
bool m_isExecuted; ///< Algorithm is executed flag
bool m_isChildAlgorithm; ///< Algorithm is a child algorithm
bool m_recordHistoryForChild; ///< Flag to indicate whether history should be
/// recorded. Applicable to child algs only
bool m_alwaysStoreInADS; ///< Always store in the ADS, even for child algos
bool m_runningAsync; ///< Algorithm is running asynchronously
std::atomic<bool> m_running; ///< Algorithm is running
Russell Taylor
committed
bool m_rethrow; ///< Algorithm should rethrow exceptions while executing
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
/// 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
std::vector<boost::weak_ptr<IAlgorithm>> m_ChildAlgorithms; ///< A list of
/// weak pointers
/// to any child
/// algorithms
/// created
Gigg, Martyn Anthony
committed
/// Vector of all the workspaces that have been read-locked
WorkspaceVector m_readLockedWorkspaces;
/// Vector of all the workspaces that have been write-locked
WorkspaceVector m_writeLockedWorkspaces;
/// All the WorkspaceProperties that are Output or InOut. Set in execute()
std::vector<IWorkspaceProperty *> m_outputWorkspaceProps;
/// All the WorkspaceProperties that are Output (not inOut). Set in execute()
std::vector<IWorkspaceProperty *> m_pureOutputWorkspaceProps;
/// Pointer to the WorkspaceGroup (if any) for each input workspace property
std::vector<boost::shared_ptr<WorkspaceGroup>> m_groupWorkspaces;
/// If only one input is a group, this is its index. -1 if they are all groups
int m_singleGroup;
/// All the groups have similar names (group_1, group_2 etc.)
bool m_groupsHaveSimilarNames;
std::vector<std::string> m_reservedList;
/// (MPI) communicator used when executing the algorithm.
std::unique_ptr<Parallel::Communicator> m_communicator;
Russell Taylor
committed
};
Peterson, Peter
committed
/// Typedef for a shared pointer to an Algorithm
using Algorithm_sptr = boost::shared_ptr<Algorithm>;
Peterson, Peter
committed
Russell Taylor
committed
} // namespace API
Peterson, Peter
committed
} // namespace Mantid
/* 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.
*/
#define DECLARE_ALGORITHM(classname) \
namespace { \
Mantid::Kernel::RegistrationHelper register_alg_##classname(( \
(Mantid::API::AlgorithmFactory::Instance().subscribe<classname>()), 0)); \
}
Peterson, Peter
committed
#endif /*MANTID_API_ALGORITHM_H_*/