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
17#ifdef _MSC_VER
18#pragma warning(default : 4250)
19#endif
22
23#include <boost/optional.hpp>
24#include <boost/python/bases.hpp>
25#include <boost/python/class.hpp>
26#include <boost/python/dict.hpp>
27#include <boost/python/exception_translator.hpp>
28#include <boost/python/overloads.hpp>
29// As of boost 1.67 raw_function.hpp tries to pass
30// through size_t types through to make_function
31// which accepts int type, emitting a warning
32#ifdef _MSC_VER
33#pragma warning(push)
34#pragma warning(disable : 4267)
35#endif
36#include <boost/python/raw_function.hpp>
37#ifdef _MSC_VER
38#pragma warning(pop)
39#endif
40#include <boost/python/register_ptr_to_python.hpp>
41#include <boost/python/scope.hpp>
42#include <boost/variant.hpp>
43#include <boost/variant/static_visitor.hpp>
44
45#include <cstddef>
46#include <string>
47#include <variant>
48#include <vector>
49
56using namespace boost::python;
57
62
63namespace {
64using PythonAlgorithm = AlgorithmAdapter<Algorithm>;
65using PythonSerialAlgorithm = AlgorithmAdapter<SerialAlgorithm>;
66using PythonParallelAlgorithm = AlgorithmAdapter<ParallelAlgorithm>;
67using PythonDistributedAlgorithm = AlgorithmAdapter<DistributedAlgorithm>;
68
69// declarePyAlgProperty(property*,doc)
70using declarePropertyType1 = void (*)(boost::python::object &, Mantid::Kernel::Property *, const std::string &);
71// declarePyAlgProperty(name, defaultValue, validator, doc, direction)
72using declarePropertyType2 = void (*)(boost::python::object &, const std::string &, const boost::python::object &,
73 const boost::python::object &, const std::string &, const int);
74// declarePyAlgProperty(name, defaultValue, doc, direction)
75using declarePropertyType3 = void (*)(boost::python::object &, const std::string &, const boost::python::object &,
76 const std::string &, const int);
77// declarePyAlgProperty(name, defaultValue, direction)
78using declarePropertyType4 = void (*)(boost::python::object &, const std::string &, const boost::python::object &,
79 const int);
80
81GNU_DIAG_OFF("unused-local-typedef")
82// Ignore -Wconversion warnings coming from boost::python
83// Seen with GCC 7.1.1 and Boost 1.63.0
84GNU_DIAG_OFF("conversion")
85// Overload types
86BOOST_PYTHON_FUNCTION_OVERLOADS(declarePropertyType1_Overload, PythonAlgorithm::declarePyAlgProperty, 2, 3)
87BOOST_PYTHON_FUNCTION_OVERLOADS(declarePropertyType2_Overload, PythonAlgorithm::declarePyAlgProperty, 3, 6)
88BOOST_PYTHON_FUNCTION_OVERLOADS(declarePropertyType3_Overload, PythonAlgorithm::declarePyAlgProperty, 4, 5)
89
90GNU_DIAG_ON("conversion")
91GNU_DIAG_ON("unused-local-typedef")
92
98void translateCancel(const Algorithm::CancelException &exc) {
99 UNUSED_ARG(exc);
100 PyErr_SetString(PyExc_KeyboardInterrupt, "");
101}
102
103template <typename T> boost::optional<T> extractArg(ssize_t index, const tuple &args) {
104 if (index < len(args)) {
105 return boost::optional<T>(extract<T>(args[index]));
106 }
107 return boost::none;
108}
109
110template <typename T> void extractKwargs(const dict &kwargs, const std::string &keyName, boost::optional<T> &out) {
111 if (!kwargs.has_key(keyName)) {
112 return;
113 }
114 if (out != boost::none) {
115 throw std::invalid_argument("Parameter called '" + keyName +
116 "' was specified twice."
117 " This must be either positional or a kwarg, but not both.");
118 }
119 out = boost::optional<T>(extract<T>(kwargs.get(keyName)));
120}
121
122class SetPropertyVisitor final : public Mantid::PythonInterface::IPyTypeVisitor {
123public:
124 SetPropertyVisitor(Mantid::API::Algorithm_sptr &alg, std::string const &propName)
125 : m_alg(alg), m_propName(propName) {}
126
127 void operator()(bool value) const override { setProp(value); }
128 void operator()(long value) const override { setProp(static_cast<int>(value)); }
129 void operator()(double value) const override { setProp(value); }
130 void operator()(std::string value) const override { m_alg->setPropertyValue(m_propName, value); }
131 void operator()(Mantid::API::Workspace_sptr ws) const override { m_alg->setProperty(m_propName, std::move(ws)); }
132
133 void operator()(std::vector<bool> value) const override { setProp(value); }
134 void operator()(std::vector<long> value) const override { setProp(value); }
135 void operator()(std::vector<double> value) const override { setProp(value); }
136 void operator()(std::vector<std::string> value) const override { setProp(value); }
137
138 using Mantid::PythonInterface::IPyTypeVisitor::operator();
139
140private:
141 template <typename T> void setProp(const T &val) const { m_alg->setProperty(m_propName, val); }
142
144 std::string const &m_propName;
145};
146
147// Signature createChildWithProps(self, name, startProgress, endProgress, enableLogging, version, **kwargs)
148object createChildWithProps(tuple args, dict kwargs) {
149 Mantid::API::Algorithm_sptr parentAlg = extract<Mantid::API::Algorithm_sptr>(args[0]);
150 auto name = extractArg<std::string>(1, args);
151 auto startProgress = extractArg<double>(2, args);
152 auto endProgress = extractArg<double>(3, args);
153 auto enableLogging = extractArg<bool>(4, args);
154 auto version = extractArg<int>(5, args);
155
156 const std::array<std::string, 5> reservedNames = {"name", "startProgress", "endProgress", "enableLogging", "version"};
157
158 extractKwargs<std::string>(kwargs, reservedNames[0], name);
159 extractKwargs<double>(kwargs, reservedNames[1], startProgress);
160 extractKwargs<double>(kwargs, reservedNames[2], endProgress);
161 extractKwargs<bool>(kwargs, reservedNames[3], enableLogging);
162 extractKwargs<int>(kwargs, reservedNames[4], version);
163
164 if (!name.is_initialized()) {
165 throw std::invalid_argument("Please specify the algorithm name");
166 }
167 auto childAlg = parentAlg->createChildAlgorithm(name.value(), startProgress.value_or(-1), endProgress.value_or(-1),
168 enableLogging.value_or(true), version.value_or(-1));
169
170 const list keys = kwargs.keys();
171 for (int i = 0; i < len(keys); ++i) {
172 const std::string propName = extract<std::string>(keys[i]);
173
174 if (std::find(reservedNames.cbegin(), reservedNames.cend(), propName) != reservedNames.cend())
175 continue;
176
177 object curArg = kwargs[keys[i]];
178 if (!curArg)
179 continue;
180
182 auto nativeObj = PyNativeTypeExtractor::convert(curArg);
183
184 boost::apply_visitor(SetPropertyVisitor(childAlg, propName), nativeObj);
185 }
186 return object(childAlg);
187}
188
189} // namespace
190
192 register_ptr_to_python<std::shared_ptr<Algorithm>>();
193 register_exception_translator<Algorithm::CancelException>(&translateCancel);
194
195 // Export Algorithm but the actual held type in Python is
196 // std::shared_ptr<AlgorithmAdapter>
197 // See
198 // http://wiki.python.org/moin/boost.python/HowTo#ownership_of_C.2B-.2B-_object_extended_in_Python
199 class_<Algorithm, bases<Mantid::API::IAlgorithm>, std::shared_ptr<PythonAlgorithm>, boost::noncopyable>(
200 "Algorithm", "Base class for all algorithms")
201 .def("fromString", &Algorithm::fromString, "Initialize the algorithm from a string representation")
202 .staticmethod("fromString")
203 .def("createChildAlgorithm", raw_function(&createChildWithProps, std::size_t(1)),
204 "Creates and intializes a named child algorithm. Output workspaces "
205 "are given a dummy name.")
206 .def("declareProperty", (declarePropertyType1)&PythonAlgorithm::declarePyAlgProperty,
207 declarePropertyType1_Overload((arg("self"), arg("prop"), arg("doc") = "")))
208 .def("enableHistoryRecordingForChild", &Algorithm::enableHistoryRecordingForChild, (arg("self"), arg("on")),
209 "Turns history recording on or off for an algorithm.")
210 .def("declareProperty", (declarePropertyType2)&PythonAlgorithm::declarePyAlgProperty,
211 declarePropertyType2_Overload((arg("self"), arg("name"), arg("defaultValue"), arg("validator") = object(),
212 arg("doc") = "", arg("direction") = Direction::Input),
213 "Declares a named property where the type is taken from "
214 "the type of the defaultValue and mapped to an appropriate C++ "
215 "type"))
216 .def("declareProperty", (declarePropertyType3)&PythonAlgorithm::declarePyAlgProperty,
217 declarePropertyType3_Overload(
218 (arg("self"), arg("name"), arg("defaultValue"), arg("doc") = "", arg("direction") = Direction::Input),
219 "Declares a named property where the type is taken from the "
220 "type "
221 "of the defaultValue and mapped to an appropriate C++ type"))
222 .def("declareProperty", (declarePropertyType4)&PythonAlgorithm::declarePyAlgProperty,
223 (arg("self"), arg("name"), arg("defaultValue"), arg("direction") = Direction::Input),
224 "Declares a named property where the type is taken from the type "
225 "of the defaultValue and mapped to an appropriate C++ type")
226 .def("getLogger", &PythonAlgorithm::getLogger, arg("self"), return_value_policy<reference_existing_object>(),
227 "Returns a reference to this algorithm's logger")
228 .def("log", &PythonAlgorithm::getLogger, arg("self"), return_value_policy<reference_existing_object>(),
229 "Returns a reference to this algorithm's logger") // Traditional name
230
231 // deprecated methods
232 .def("setWikiSummary", &PythonAlgorithm::setWikiSummary, (arg("self"), arg("summary")),
233 "(Deprecated.) Set summary for the help.");
234
235 // Prior to version 3.2 there was a separate C++ PythonAlgorithm class that
236 // inherited from Algorithm and the "PythonAlgorithm"
237 // name was a distinct class in Python from the Algorithm export. In 3.2 the
238 // need for the C++ PythonAlgorithm class
239 // was removed in favour of simply adapting the Algorithm base class. A lot of
240 // client code relies on the "PythonAlgorithm" name in
241 // Python so we simply add an alias of the Algorithm name to PythonAlgorithm
242 scope().attr("PythonAlgorithm") = scope().attr("Algorithm");
243}
244
246 register_ptr_to_python<std::shared_ptr<SerialAlgorithm>>();
247 register_exception_translator<SerialAlgorithm::CancelException>(&translateCancel);
248 class_<SerialAlgorithm, bases<Mantid::API::Algorithm>, std::shared_ptr<PythonSerialAlgorithm>, boost::noncopyable>(
249 "SerialAlgorithm", "Base class for simple serial algorithms");
250 scope().attr("PythonSerialAlgorithm") = scope().attr("SerialAlgorithm");
251}
252
254 register_ptr_to_python<std::shared_ptr<ParallelAlgorithm>>();
255 register_exception_translator<ParallelAlgorithm::CancelException>(&translateCancel);
256 class_<ParallelAlgorithm, bases<Mantid::API::Algorithm>, std::shared_ptr<PythonParallelAlgorithm>,
257 boost::noncopyable>("ParallelAlgorithm", "Base class for simple parallel algorithms");
258 scope().attr("PythonParallelAlgorithm") = scope().attr("ParallelAlgorithm");
259}
260
262 register_ptr_to_python<std::shared_ptr<DistributedAlgorithm>>();
263 register_exception_translator<DistributedAlgorithm::CancelException>(&translateCancel);
264 class_<DistributedAlgorithm, bases<Mantid::API::Algorithm>, std::shared_ptr<PythonDistributedAlgorithm>,
265 boost::noncopyable>("DistributedAlgorithm", "Base class for simple distributed algorithms");
266 scope().attr("PythonDistributedAlgorithm") = scope().attr("DistributedAlgorithm");
267}
double value
The value of the point.
Definition: FitMW.cpp:51
#define GET_POINTER_SPECIALIZATION(TYPE)
Definition: GetPointer.h:17
std::map< DeltaEMode::Type, std::string > index
Definition: DeltaEMode.cpp:19
void export_ParallelAlgorithm()
Definition: Algorithm.cpp:253
void export_leaf_classes()
Definition: Algorithm.cpp:191
void export_SerialAlgorithm()
Definition: Algorithm.cpp:245
void export_DistributedAlgorithm()
Definition: Algorithm.cpp:261
#define UNUSED_ARG(x)
Function arguments are sometimes unused in certain implmentations but are required for documentation ...
Definition: System.h:64
#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:85
static IAlgorithm_sptr fromString(const std::string &input)
De-serialize an object from a string.
Definition: Algorithm.cpp:967
void enableHistoryRecordingForChild(const bool on) override
Change the state of the history recording flag.
Definition: Algorithm.cpp:176
Base class for algorithms that treat all spectra independently, i.e., we can trivially parallelize ov...
Base class for algorithms that can run in parallel on all MPI ranks but not in a distributed fashion.
Base class for algorithms that can only run serially (Parallel::ExecutionMode::MasterOnly) in an MPI ...
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
Definition: Workspace_fwd.h:20
std::shared_ptr< Algorithm > Algorithm_sptr
Typedef for a shared pointer to an Algorithm.
Definition: Algorithm.h:61
Describes the direction (within an algorithm) of a Property.
Definition: Property.h:50
@ Input
An input workspace.
Definition: Property.h:53