Mantid
Loading...
Searching...
No Matches
Algorithm.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#ifdef _MSC_VER
8#pragma warning(disable : 4250) // Disable warning regarding inheritance via
9 // dominance, we have no way around it with the
10 // design
11#endif
14#ifdef _MSC_VER
15#pragma warning(default : 4250)
16#endif
19
21#include <boost/python/bases.hpp>
22#include <boost/python/class.hpp>
23#include <boost/python/dict.hpp>
24#include <boost/python/exception_translator.hpp>
25#include <boost/python/overloads.hpp>
26#include <optional>
27// As of boost 1.67 raw_function.hpp tries to pass
28// through size_t types through to make_function
29// which accepts int type, emitting a warning
30#ifdef _MSC_VER
31#pragma warning(push)
32#pragma warning(disable : 4267)
33#endif
34#include <boost/python/raw_function.hpp>
35#ifdef _MSC_VER
36#pragma warning(pop)
37#endif
38#include <boost/python/register_ptr_to_python.hpp>
39#include <boost/python/scope.hpp>
40#include <boost/variant.hpp>
41#include <boost/variant/static_visitor.hpp>
42
43#include <H5Cpp.h>
44#include <cstddef>
45#include <string>
46#include <variant>
47#include <vector>
48
52using namespace boost::python;
53
55
56namespace {
57using PythonAlgorithm = AlgorithmAdapter<Algorithm>;
58
59// declarePyAlgProperty(property*,doc)
60using declarePropertyType1 = void (*)(boost::python::object &, Mantid::Kernel::Property *, const std::string &);
61// declarePyAlgProperty(name, defaultValue, validator, doc, direction)
62using declarePropertyType2 = void (*)(boost::python::object &, const std::string &, const boost::python::object &,
63 const boost::python::object &, const std::string &, const int);
64// declarePyAlgProperty(name, defaultValue, doc, direction)
65using declarePropertyType3 = void (*)(boost::python::object &, const std::string &, const boost::python::object &,
66 const std::string &, const int);
67// declarePyAlgProperty(name, defaultValue, direction)
68using declarePropertyType4 = void (*)(boost::python::object &, const std::string &, const boost::python::object &,
69 const int);
70
71GNU_DIAG_OFF("unused-local-typedef")
72// Ignore -Wconversion warnings coming from boost::python
73// Seen with GCC 7.1.1 and Boost 1.63.0
74GNU_DIAG_OFF("conversion")
75// Overload types
76// cppcheck-suppress unknownMacro
77BOOST_PYTHON_FUNCTION_OVERLOADS(declarePropertyType1_Overload, PythonAlgorithm::declarePyAlgProperty, 2, 3)
78BOOST_PYTHON_FUNCTION_OVERLOADS(declarePropertyType2_Overload, PythonAlgorithm::declarePyAlgProperty, 3, 6)
79BOOST_PYTHON_FUNCTION_OVERLOADS(declarePropertyType3_Overload, PythonAlgorithm::declarePyAlgProperty, 4, 5)
80
81GNU_DIAG_ON("conversion")
82GNU_DIAG_ON("unused-local-typedef")
83
84GNU_DIAG_OFF("maybe-uninitialized")
90void translateCancel(const Algorithm::CancelException &exc) {
91 UNUSED_ARG(exc);
92 PyErr_SetString(PyExc_KeyboardInterrupt, "");
93}
94
100void translateH5Exception(const H5::Exception &exc) {
101 auto handleFrame = [](unsigned int n, const H5E_error_t *err, void *ss_arg) -> herr_t {
102 std::stringstream &ss_ = *((std::stringstream *)ss_arg);
103
104 ss_ << " #" << n << ": " << err->desc << "\n";
105
106 return (herr_t)0;
107 };
108
109 std::stringstream ss;
110 exc.walkErrorStack(H5E_WALK_DOWNWARD, handleFrame, /*client_data*/ &ss);
111
112 PyErr_SetString(PyExc_RuntimeError, ss.str().c_str());
113}
114
115template <typename T> std::optional<T> extractArg(ssize_t index, const tuple &args) {
116 if (index < len(args)) {
117 return std::optional<T>(extract<T>(args[index]));
118 }
119 return std::nullopt;
120}
121
122template <typename T> void extractKwargs(const dict &kwargs, const std::string &keyName, std::optional<T> &out) {
123 if (!kwargs.has_key(keyName)) {
124 return;
125 }
126 if (out != std::nullopt) {
127 throw std::invalid_argument("Parameter called '" + keyName +
128 "' was specified twice."
129 " This must be either positional or a kwarg, but not both.");
130 }
131 out = std::optional<T>(extract<T>(kwargs.get(keyName)));
132}
133
134class SetPropertyVisitor final : public Mantid::PythonInterface::IPyTypeVisitor {
135public:
136 SetPropertyVisitor(Mantid::API::Algorithm_sptr &alg, std::string const &propName)
137 : m_alg(alg), m_propName(propName) {}
138
139 void operator()(bool value) const override { setProp(value); }
140 void operator()(int value) const override { setProp(value); }
141 void operator()(double value) const override { setProp(value); }
142 void operator()(std::string value) const override { m_alg->setPropertyValue(m_propName, value); }
143 void operator()(Mantid::API::Workspace_sptr ws) const override { m_alg->setProperty(m_propName, std::move(ws)); }
144
145 void operator()(std::vector<bool> value) const override { setProp(value); }
146 void operator()(std::vector<int> value) const override { setProp(value); }
147 void operator()(std::vector<double> value) const override { setProp(value); }
148 void operator()(std::vector<std::string> value) const override { setProp(value); }
149
150 using Mantid::PythonInterface::IPyTypeVisitor::operator();
151
152private:
153 template <typename T> void setProp(const T &val) const { m_alg->setProperty(m_propName, val); }
154
156 std::string const &m_propName;
157};
158
159// Signature createChildWithProps(self, name, startProgress, endProgress, enableLogging, version, **kwargs)
160object createChildWithProps(tuple args, dict kwargs) {
161 Mantid::API::Algorithm_sptr parentAlg = extract<Mantid::API::Algorithm_sptr>(args[0]);
162 auto name = extractArg<std::string>(1, args);
163 auto startProgress = extractArg<double>(2, args);
164 auto endProgress = extractArg<double>(3, args);
165 auto enableLogging = extractArg<bool>(4, args);
166 auto version = extractArg<int>(5, args);
167
168 const std::array<std::string, 6> reservedNames = {"name", "startProgress", "endProgress",
169 "enableLogging", "version", "StoreInADS"};
170
171 extractKwargs<std::string>(kwargs, reservedNames[0], name);
172 extractKwargs<double>(kwargs, reservedNames[1], startProgress);
173 extractKwargs<double>(kwargs, reservedNames[2], endProgress);
174 extractKwargs<bool>(kwargs, reservedNames[3], enableLogging);
175 extractKwargs<int>(kwargs, reservedNames[4], version);
176
177 if (!name.has_value()) {
178 throw std::invalid_argument("Please specify the algorithm name");
179 }
180 auto childAlg = parentAlg->createChildAlgorithm(name.value(), startProgress.value_or(-1), endProgress.value_or(-1),
181 enableLogging.value_or(true), version.value_or(-1));
182
183 if (kwargs.has_key(reservedNames[5])) {
184 // We set StoreInADS here if it hasn't been set before and it is present in kwargs
185 std::optional<bool> storeADS = std::nullopt;
186 extractKwargs<bool>(kwargs, reservedNames[5], storeADS);
187 childAlg->setAlwaysStoreInADS(storeADS.value_or(false));
188 }
189
190 const list keys = kwargs.keys();
191 for (int i = 0; i < len(keys); ++i) {
192 const std::string propName = extract<std::string>(keys[i]);
193
194 if (std::find(reservedNames.cbegin(), reservedNames.cend(), propName) != reservedNames.cend())
195 continue;
196
197 object curArg = kwargs[keys[i]];
198 if (curArg.is_none())
199 continue;
200
202 auto nativeObj = PyNativeTypeExtractor::convert(curArg);
203
204 boost::apply_visitor(SetPropertyVisitor(childAlg, propName), nativeObj);
205 }
206 return object(childAlg);
207}
208
209GNU_DIAG_ON("maybe-uninitialized")
210} // namespace
211
213 register_ptr_to_python<std::shared_ptr<Algorithm>>();
214 register_exception_translator<Algorithm::CancelException>(&translateCancel);
215 register_exception_translator<H5::Exception>(&translateH5Exception);
216
217 // Export Algorithm but the actual held type in Python is
218 // std::shared_ptr<AlgorithmAdapter>
219 // See
220 // http://wiki.python.org/moin/boost.python/HowTo#ownership_of_C.2B-.2B-_object_extended_in_Python
221 class_<Algorithm, bases<Mantid::API::IAlgorithm>, std::shared_ptr<PythonAlgorithm>, boost::noncopyable>(
222 "Algorithm", "Base class for all algorithms")
223 .def("fromString", &Algorithm::fromString, "Initialize the algorithm from a string representation")
224 .staticmethod("fromString")
225 .def("createChildAlgorithm", raw_function(&createChildWithProps, std::size_t(1)),
226 "Creates and intializes a named child algorithm. Output workspaces "
227 "are given a dummy name.")
228 .def("declareProperty", (declarePropertyType1)&PythonAlgorithm::declarePyAlgProperty,
229 declarePropertyType1_Overload((arg("self"), arg("prop"), arg("doc") = "")))
230 .def("enableHistoryRecordingForChild", &Algorithm::enableHistoryRecordingForChild, (arg("self"), arg("on")),
231 "Turns history recording on or off for an algorithm.")
232 .def("declareProperty", (declarePropertyType2)&PythonAlgorithm::declarePyAlgProperty,
233 declarePropertyType2_Overload((arg("self"), arg("name"), arg("defaultValue"), arg("validator") = object(),
234 arg("doc") = "", arg("direction") = Direction::Input),
235 "Declares a named property where the type is taken from "
236 "the type of the defaultValue and mapped to an appropriate C++ "
237 "type"))
238 .def("declareProperty", (declarePropertyType3)&PythonAlgorithm::declarePyAlgProperty,
239 declarePropertyType3_Overload(
240 (arg("self"), arg("name"), arg("defaultValue"), arg("doc") = "", arg("direction") = Direction::Input),
241 "Declares a named property where the type is taken from the "
242 "type "
243 "of the defaultValue and mapped to an appropriate C++ type"))
244 .def("declareProperty", (declarePropertyType4)&PythonAlgorithm::declarePyAlgProperty,
245 (arg("self"), arg("name"), arg("defaultValue"), arg("direction") = Direction::Input),
246 "Declares a named property where the type is taken from the type "
247 "of the defaultValue and mapped to an appropriate C++ type")
248 .def("declareOrReplaceProperty", &PythonAlgorithm::declareOrReplacePyAlgProperty,
249 (arg("self"), arg("name"), arg("defaultValue"), arg("validator") = object(), arg("doc") = "",
250 arg("direction") = Direction::Input),
251 "Declares or replaces a named property where the type is taken from "
252 "the type of the defaultValue and mapped to an appropriate C++ "
253 "type")
254 .def("getLogger", &PythonAlgorithm::getLogger, arg("self"), return_value_policy<reference_existing_object>(),
255 "Returns a reference to this algorithm's logger")
256 .def("log", &PythonAlgorithm::getLogger, arg("self"), return_value_policy<reference_existing_object>(),
257 "Returns a reference to this algorithm's logger") // Traditional name
258
259 // deprecated methods
260 .def("setWikiSummary", &PythonAlgorithm::setWikiSummary, (arg("self"), arg("summary")),
261 "(Deprecated.) Set summary for the help.");
262
263 // Prior to version 3.2 there was a separate C++ PythonAlgorithm class that
264 // inherited from Algorithm and the "PythonAlgorithm"
265 // name was a distinct class in Python from the Algorithm export. In 3.2 the
266 // need for the C++ PythonAlgorithm class
267 // was removed in favour of simply adapting the Algorithm base class. A lot of
268 // client code relies on the "PythonAlgorithm" name in
269 // Python so we simply add an alias of the Algorithm name to PythonAlgorithm
270 scope().attr("PythonAlgorithm") = scope().attr("Algorithm");
271}
std::string name
Definition Run.cpp:60
double value
The value of the point.
Definition FitMW.cpp:51
Algorithm *const m_alg
#define GET_POINTER_SPECIALIZATION(TYPE)
Definition GetPointer.h:17
std::map< DeltaEMode::Type, std::string > index
int herr_t
void export_leaf_classes()
#define UNUSED_ARG(x)
Function arguments are sometimes unused in certain implmentations but are required for documentation ...
Definition System.h:48
#define GNU_DIAG_ON(x)
#define GNU_DIAG_OFF(x)
This is a collection of macros for turning compiler warnings off in a controlled manner.
Base class from which all concrete algorithm classes should be derived.
Definition Algorithm.h:76
static IAlgorithm_sptr fromString(const std::string &input)
De-serialize an object from a string.
void setPropertyValue(const std::string &name, const std::string &value) override
Set the value of a property by string N.B.
void enableHistoryRecordingForChild(const bool on) override
Change the state of the history recording flag.
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
Base class for properties.
Definition Property.h:94
Provides a layer class for boost::python to allow C++ virtual functions to be overridden in a Python ...
virtual void operator()(bool value) const =0
std::shared_ptr< Workspace > Workspace_sptr
shared pointer to Mantid::API::Workspace
std::shared_ptr< Algorithm > Algorithm_sptr
Typedef for a shared pointer to an Algorithm.
Definition Algorithm.h:52
Describes the direction (within an algorithm) of a Property.
Definition Property.h:50
@ Input
An input workspace.
Definition Property.h:53