14#include <boost/python/class.hpp>
15#include <boost/python/list.hpp>
16#include <boost/variant/apply_visitor.hpp>
19#define PY_ARRAY_UNIQUE_SYMBOL API_ARRAY_API
20#define NO_IMPORT_ARRAY
21#include <numpy/arrayobject.h>
25using PythonInterface::callMethod;
26using PythonInterface::callMethodNoCheck;
27using PythonInterface::UndefinedAttributeError;
34 AttrVisitor(IFunction::Attribute &attrToUpdate) :
m_attr(attrToUpdate) {}
39 void operator()(std::string
value)
const override {
m_attr.setValue(std::move(
value)); }
42 void operator()(std::vector<bool>)
const override {
throw std::invalid_argument(
m_errorMsg); }
43 void operator()(std::vector<int>
value)
const override {
47 std::vector<double> doubleVals(
value.cbegin(),
value.cend());
48 m_attr.setValue(std::move(doubleVals));
50 void operator()(std::vector<double>
value)
const override {
m_attr.setValue(std::move(
value)); }
51 void operator()(std::vector<std::string>)
const override {
throw std::invalid_argument(
m_errorMsg); }
53 using Mantid::PythonInterface::IPyTypeVisitor::operator();
57 const std::string
m_errorMsg =
"Invalid attribute. Allowed types=float,int,str,bool,list(float),list(int)";
66IFunction::Attribute createAttributeFromPythonValue(IFunction::Attribute attrToUpdate,
const object &
value) {
71 boost::apply_visitor(AttrVisitor(attrToUpdate), variantObj);
84 :
m_self(self), m_functionName(
std::move(functionMethod)), m_derivName(
std::move(derivMethod)),
87 throw std::runtime_error(
"Function does not define an init method.");
89 throw std::runtime_error(
"Function does not define a " +
m_functionName +
" method.");
102 return callMethod<std::string>(
getSelf(),
"category");
117 attr = createAttributeFromPythonValue(attr, defaultValue);
120 callMethod<void, std::string, object>(
getSelf(),
"setAttributeValue",
name, defaultValue);
134 const
boost::python::
object &validator) {
139 c_validator = boost::python::extract<Mantid::Kernel::IValidator_sptr>(validator);
140 }
catch (boost::python::error_already_set &) {
141 throw std::invalid_argument(
"Cannot extract Validator from object ");
143 attr = createAttributeFromPythonValue(attr, defaultValue);
146 callMethod<void, std::string, object>(getSelf(),
"setAttributeValue",
name, defaultValue);
161 return getAttributeValue(self, attr);
172 std::string type = attr.
type();
173 PyObject *result(
nullptr);
176 result = to_python_value<const int &>()(attr.
asInt());
177 else if (type ==
"double")
178 result = to_python_value<const double &>()(attr.
asDouble());
179 else if (type ==
"std::string")
180 result = to_python_value<const std::string &>()(attr.
asString());
181 else if (type ==
"bool")
182 result = to_python_value<const bool &>()(attr.
asBool());
183 else if (type ==
"std::vector<double>")
184 result = to_python_value<const std::vector<double> &>()(attr.
asVector());
186 throw std::runtime_error(
"Unknown attribute type, cannot convert C++ type "
187 "to Python. Contact developement team.");
212 callMethod<void, std::string, object>(self,
"setAttributeValue", attName,
value);
227 boost::python::list list;
228 for (
const auto &fun : functions) {
242 return callMethod<double, size_t>(
getSelf(),
"activeParameter", i);
257 callMethod<void, size_t, double>(
getSelf(),
"setActiveParameter", i,
value);
276 Py_intptr_t dims[1] = {
static_cast<Py_intptr_t
>(nData)};
277 PyObject *xvals = WrapReadOnly::apply<double>::createFromArray(xValues, 1, dims);
286 PyObject_CallMethod(
getSelf(),
const_cast<char *
>(
m_functionName.c_str()),
const_cast<char *
>(
"(O)"), xvals);
288 if (PyErr_Occurred()) {
292 if (PyArray_Check(result)) {
295 if (PyArray_TYPE(nparray) == NPY_DOUBLE) {
296 std::memcpy(
static_cast<void *
>(out), PyArray_DATA(nparray), nData *
sizeof(npy_double));
301 std::string err(
"Unsupported numpy data type: '");
302 err.append(dtype->typeobj->tp_name).append(
"'. Currently only numpy.float64 is supported.");
303 throw std::runtime_error(err);
306 std::string err(
"Expected ");
308 .append(
" to return a numpy array, however an ")
309 .append(result->ob_type->tp_name)
310 .append(
" was returned.");
311 throw std::runtime_error(err);
328 Py_intptr_t dims[1] = {
static_cast<Py_intptr_t
>(nData)};
329 PyObject *xvals = WrapReadOnly::apply<double>::createFromArray(xValues, 1, dims);
330 PyObject *jacobian = boost::python::to_python_value<API::Jacobian *>()(out);
337 PyObject_CallMethod(
getSelf(),
const_cast<char *
>(
m_derivName.c_str()),
const_cast<char *
>(
"(OO)"), xvals, jacobian);
338 if (PyErr_Occurred())
double value
The value of the point.
const std::string m_errorMsg
IFunction::Attribute & m_attr
Mantid::API::IFunction::Attribute Attribute
tagPyArrayObject PyArrayObject
_PyArray_Descr PyArray_Descr
std::unique_ptr< ConceptT > m_self
#define UNUSED_ARG(x)
Function arguments are sometimes unused in certain implmentations but are required for documentation ...
#define GNU_DIAG_OFF(x)
This is a collection of macros for turning compiler warnings off in a controlled manner.
Attribute is a non-fitting parameter.
std::vector< double > asVector() const
Returns vector<double> if attribute is vector<double>, throws exception otherwise.
int asInt() const
Returns int value if attribute is a int, throws exception otherwise.
std::string asString() const
Returns string value if attribute is a string, throws exception otherwise.
double asDouble() const
Returns double value if attribute is a double, throws exception otherwise.
bool asBool() const
Returns bool value if attribute is a bool, throws exception otherwise.
std::string type() const
Returns type of the attribute.
This is an interface to a fitting function - a semi-abstarct class.
virtual Attribute getAttribute(const std::string &name) const
Return a value of attribute attName.
void declareAttribute(const std::string &name, const API::IFunction::Attribute &defaultValue)
Declare a single attribute.
virtual const std::string category() const
The categories the Fit function belong to.
virtual void setAttribute(const std::string &name, const Attribute &)
Set a value to attribute attName.
virtual double activeParameter(size_t i) const
Value of i-th active parameter.
virtual bool hasAttribute(const std::string &name) const
Check if attribute attName exists.
virtual std::vector< std::shared_ptr< IFunction > > createEquivalentFunctions() const
Split this function (if needed) into a list of independent functions.
void storeAttributeValue(const std::string &name, const API::IFunction::Attribute &value)
Store an attribute's value.
virtual void setActiveParameter(size_t i, double value)
Set new value of i-th active parameter.
Represents the Jacobian in IFitFunction::functionDeriv.
Defines a structure for acquiring/releasing the Python GIL using the RAII pattern.
Provides a layer to hook into the protected functions of IFunction.
void init() override
Declare all attributes & parameters.
IFunctionAdapter(PyObject *self, std::string functionMethod, std::string derivMethod)
A constructor that looks like a Python init method.
static void setAttributePythonValue(IFunction &self, const std::string &name, const boost::python::object &value)
Set the attribute's value.
static boost::python::list createPythonEquivalentFunctions(const IFunction &self)
Split this function (if needed) into a list of independent functions.
std::string name() const override
Returns the name of the function.
void evaluateFunction(double *out, const double *xValues, const size_t nData) const
Evaluate the function by calling the overridden method.
PyObject * getSelf() const
void evaluateDerivative(API::Jacobian *out, const double *xValues, const size_t nData) const
Evaluate the derivative by calling the overridden method.
const std::string category() const override
Specify a category for the function.
void setAttribute(const std::string &attName, const API::IFunction::Attribute &attr) override
Called by the framework when an attribute has been set.
std::string m_functionName
The name of the method to evaluate the function.
std::string m_derivName
The name of the method to evaluate the derivative.
void setActiveParameter(size_t i, double value) override
Override this method to make fitted parameters different from the declared.
void declareAttribute(const std::string &name, const boost::python::object &defaultValue)
Declare an attribute with an initial value.
double activeParameter(size_t i) const override
Override this method to make fitted parameters different from the declared.
static PyObject * getAttributeValue(const IFunction &self, const std::string &name)
Get a named attribute value.
Exception type that captures the current Python error state as a generic C++ exception for any genera...
std::shared_ptr< Workspace > Workspace_sptr
shared pointer to Mantid::API::Workspace
std::shared_ptr< IValidator > IValidator_sptr
A shared_ptr to an IValidator.
bool MANTID_PYTHONINTERFACE_CORE_DLL typeHasAttribute(PyObject *obj, const char *attr)
This namespace contains helper functions for classes that are overridden in Python.
Defines an exception for an undefined attribute.