Skip to content

Commit

Permalink
Allow IFunction1D::functionDeriv1D to be overridden in Python.
Browse files Browse the repository at this point in the history
If it is not overridden then it calls the base class method. Refs #970
  • Loading branch information
martyngigg committed Apr 17, 2013
1 parent b0c2197 commit 3361fdd
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,18 @@ namespace Mantid
void function1D(double* out, const double* xValues, const size_t nData) const;
/// Python-type signature
boost::python::object function1D(const boost::python::object & xvals) const;

/// Derivatives of function with respect to active parameters (C++ override)
void functionDeriv1D(API::Jacobian* out, const double* xValues, const size_t nData);
///@}

private:
/// The PyObject must be supplied to construct the object
DISABLE_DEFAULT_CONSTRUCT(IFunction1DAdapter);
DISABLE_COPY_AND_ASSIGN(IFunction1DAdapter);

/// Flag if the functionDeriv1D method is overridden (avoids multiple checks)
bool m_derivOveridden;
};
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ namespace Mantid

/// Required to solve compiler ambiguity between IPeakFunction & IFunction1DAdapter
void function1D(double* out, const double* xValues, const size_t nData) const { IPeakFunction::function1D(out,xValues,nData); }
/// Required to solve compiler ambiguity between IPeakFunction & IFunction1DAdapter
void functionDeriv1D(API::Jacobian* out, const double* xValues, const size_t nData) { IPeakFunction::functionDeriv1D(out,xValues,nData); }

/// Implemented Base-class method
void functionLocal(double* out, const double* xValues, const size_t nData) const;
Expand All @@ -72,7 +74,6 @@ namespace Mantid
/// Python signature
void functionDerivLocal(const boost::python::object & xvals, boost::python::object & jacobian);


private:
/// The PyObject must be supplied to construct the object
DISABLE_DEFAULT_CONSTRUCT(IPeakFunctionAdapter);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@ namespace Mantid
* * @param self A reference to the calling Python object
*/
IFunction1DAdapter::IFunction1DAdapter(PyObject* self)
: API::ParamFunction(), API::IFunction1D(), IFunctionAdapter(self)
: API::ParamFunction(), API::IFunction1D(), IFunctionAdapter(self), m_derivOveridden(false)
{
m_derivOveridden = Environment::typeHasAttribute(self, "functionDeriv1D");
}

/**
Expand Down Expand Up @@ -74,5 +75,36 @@ namespace Mantid
{
return CallMethod1<object,object>::dispatchWithException(getSelf(), "function1D", xvals);
}

/**
* If a Python override exists then call that, otherwise call the base class method
* @param out The Jacobian matrix storing the partial derivatives of the function w.r.t to the parameters
* @param xValues The input X values
* @param nData The size of the two arrays
*/
void IFunction1DAdapter::functionDeriv1D(API::Jacobian* out, const double* xValues, const size_t nData)
{
if(m_derivOveridden)
{
using namespace Converters;
// GIL must be held while numpy wrappers are destroyed as they access Python
// state information
Environment::GlobalInterpreterLock gil;

Py_intptr_t dims[1] = { static_cast<Py_intptr_t>(nData) } ;
PyObject *xvals = WrapReadOnly::apply<double>::createFromArray(xValues, 1,dims);
PyObject *jacobian = boost::python::to_python_value<API::Jacobian*>()(out);

// Deliberately avoids using the CallMethod wrappers. They lock the GIL again and
// will check for each function call whether the wrapped method exists. It also avoid unnecessary construction of
// boost::python::objects when using boost::python::call_method
PyEval_CallMethod(getSelf(), "functionDerivLocal", "(OO)", xvals,jacobian);
}
else
{
IFunction1D::functionDeriv1D(out,xValues,nData);
}
}

}
}

0 comments on commit 3361fdd

Please sign in to comment.