12#include <boost/python/class.hpp>
13#include <boost/python/list.hpp>
14#include <boost/variant/apply_visitor.hpp>
17#define PY_ARRAY_UNIQUE_SYMBOL API_ARRAY_API
18#define NO_IMPORT_ARRAY
19#include <numpy/arrayobject.h>
23using PythonInterface::callMethod;
24using PythonInterface::callMethodNoCheck;
25using PythonInterface::UndefinedAttributeError;
32 AttrVisitor(IFunction::Attribute &attrToUpdate) :
m_attr(attrToUpdate) {}
35 void operator()(
long value)
const override {
m_attr.setValue(
static_cast<int>(
value)); }
37 void operator()(std::string
value)
const override {
m_attr.setValue(std::move(
value)); }
40 void operator()(std::vector<bool>)
const override {
throw std::invalid_argument(
m_errorMsg); }
41 void operator()(std::vector<long>
value)
const override {
45 std::vector<double> doubleVals(
value.cbegin(),
value.cend());
46 m_attr.setValue(std::move(doubleVals));
48 void operator()(std::vector<double>
value)
const override {
m_attr.setValue(std::move(
value)); }
49 void operator()(std::vector<std::string>)
const override {
throw std::invalid_argument(
m_errorMsg); }
51 using Mantid::PythonInterface::IPyTypeVisitor::operator();
55 const std::string
m_errorMsg =
"Invalid attribute. Allowed types=float,int,str,bool,list(float),list(int)";
64IFunction::Attribute createAttributeFromPythonValue(IFunction::Attribute attrToUpdate,
const object &
value) {
69 boost::apply_visitor(AttrVisitor(attrToUpdate), variantObj);
82 :
m_self(self), m_functionName(
std::move(functionMethod)), m_derivName(
std::move(derivMethod)),
85 throw std::runtime_error(
"Function does not define an init method.");
87 throw std::runtime_error(
"Function does not define a " +
m_functionName +
" method.");
100 return callMethod<std::string>(
getSelf(),
"category");
115 attr = createAttributeFromPythonValue(attr, defaultValue);
118 callMethod<void, std::string, object>(
getSelf(),
"setAttributeValue",
name, defaultValue);
131 const boost::python::object &validator) {
136 c_validator = boost::python::extract<Mantid::Kernel::IValidator_sptr>(validator);
137 }
catch (boost::python::error_already_set &) {
138 throw std::invalid_argument(
"Cannot extract Validator from object ");
140 attr = createAttributeFromPythonValue(attr, defaultValue);
143 callMethod<void, std::string, object>(
getSelf(),
"setAttributeValue",
name, defaultValue);
168 std::string type = attr.
type();
169 PyObject *result(
nullptr);
171 result = to_python_value<const int &>()(attr.
asInt());
172 else if (type ==
"double")
173 result = to_python_value<const double &>()(attr.
asDouble());
174 else if (type ==
"std::string")
175 result = to_python_value<const std::string &>()(attr.
asString());
176 else if (type ==
"bool")
177 result = to_python_value<const bool &>()(attr.
asBool());
178 else if (type ==
"std::vector<double>")
179 result = to_python_value<const std::vector<double> &>()(attr.
asVector());
181 throw std::runtime_error(
"Unknown attribute type, cannot convert C++ type "
182 "to Python. Contact developement team.");
206 callMethod<void, std::string, object>(
getSelf(),
"setAttributeValue", attName,
value);
221 boost::python::list list;
222 for (
const auto &fun : functions) {
236 return callMethod<double, size_t>(
getSelf(),
"activeParameter", i);
251 callMethod<void, size_t, double>(
getSelf(),
"setActiveParameter", i,
value);
270 Py_intptr_t dims[1] = {
static_cast<Py_intptr_t
>(nData)};
271 PyObject *xvals = WrapReadOnly::apply<double>::createFromArray(xValues, 1, dims);
280 PyObject_CallMethod(
getSelf(),
const_cast<char *
>(
m_functionName.c_str()),
const_cast<char *
>(
"(O)"), xvals);
282 if (PyErr_Occurred()) {
286 if (PyArray_Check(result)) {
289 if (PyArray_TYPE(nparray) == NPY_DOUBLE) {
290 std::memcpy(
static_cast<void *
>(out), PyArray_DATA(nparray), nData *
sizeof(npy_double));
295 std::string err(
"Unsupported numpy data type: '");
296 err.append(
dtype->typeobj->tp_name).append(
"'. Currently only numpy.float64 is supported.");
297 throw std::runtime_error(err);
300 std::string err(
"Expected ");
302 .append(
" to return a numpy array, however an ")
303 .append(result->ob_type->tp_name)
304 .append(
" was returned.");
305 throw std::runtime_error(err);
322 Py_intptr_t dims[1] = {
static_cast<Py_intptr_t
>(nData)};
323 PyObject *xvals = WrapReadOnly::apply<double>::createFromArray(xValues, 1, dims);
324 PyObject *jacobian = boost::python::to_python_value<API::Jacobian *>()(out);
331 PyObject_CallMethod(
getSelf(),
const_cast<char *
>(
m_derivName.c_str()),
const_cast<char *
>(
"(OO)"), xvals, jacobian);
332 if (PyErr_Occurred())
double value
The value of the point.
const std::string m_errorMsg
IFunction::Attribute & m_attr
tagPyArrayObject PyArrayObject
_PyArray_Descr PyArray_Descr
std::string dtype(Mantid::Kernel::PropertyWithValue< HeldType > &self)
std::unique_ptr< ConceptT > m_self
#define UNUSED_ARG(x)
Function arguments are sometimes unused in certain implmentations but are required for documentation ...
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.
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.