-
Notifications
You must be signed in to change notification settings - Fork 121
/
UserFunction.cpp
122 lines (99 loc) · 3.23 KB
/
UserFunction.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
//----------------------------------------------------------------------
// Includes
//----------------------------------------------------------------------
#include "MantidCurveFitting/Functions/UserFunction.h"
#include "MantidAPI/FunctionFactory.h"
#include <boost/tokenizer.hpp>
#include "MantidGeometry/muParser_Silent.h"
namespace Mantid {
namespace CurveFitting {
namespace Functions {
using namespace CurveFitting;
// Register the class into the function factory
DECLARE_FUNCTION(UserFunction)
using namespace Kernel;
using namespace API;
/// Constructor
UserFunction::UserFunction()
: m_parser(new mu::Parser()), m_x(0.), m_x_set(false) {}
/// Destructor
UserFunction::~UserFunction() { delete m_parser; }
/** Static callback function used by MuParser to initialize variables implicitly
@param varName :: The name of a new variable
@param pufun :: Pointer to the function
*/
double *UserFunction::AddVariable(const char *varName, void *pufun) {
UserFunction &fun = *reinterpret_cast<UserFunction *>(pufun);
if (std::string(varName) != "x") {
try {
fun.declareParameter(varName, 0.0);
} catch (...) {
}
} else {
fun.m_x_set = true;
fun.m_x = 0.;
}
return &fun.m_x;
}
/** Declare fit parameters using muParser's implicit variable initialization.
* @param attName :: Attribute name, must be "Formula"
* @param value :: The attribute value. For "Formula" it must be a mu::Parser
* expression string
*/
void UserFunction::setAttribute(const std::string &attName,
const Attribute &value) {
IFunction::setAttribute(attName, value);
if (attName != "Formula") {
return;
}
m_x_set = false;
clearAllParameters();
try {
mu::Parser tmp_parser;
tmp_parser.SetVarFactory(AddVariable, this);
m_formula = value.asString();
tmp_parser.SetExpr(m_formula);
// Call Eval() to implicitly initialize the variables
tmp_parser.Eval();
} catch (...) {
// Formula may be edited by a GUI component
return;
}
if (!m_x_set) {
// Formula may be edited by a GUI component
return;
}
m_parser->ClearVar();
m_parser->DefineVar("x", &m_x);
for (size_t i = 0; i < nParams(); i++) {
m_parser->DefineVar(parameterName(i), getParameterAddress(i));
}
m_parser->SetExpr(m_formula);
}
/** Calculate the fitting function.
* @param out :: A pointer to the output fitting function buffer. The buffer
* must be large enough to receive nData double values.
* The fitting procedure will try to minimise Sum(out[i]^2)
* @param xValues :: The array of nData x-values.
* @param nData :: The size of the fitted data.
*/
void UserFunction::function1D(double *out, const double *xValues,
const size_t nData) const {
for (size_t i = 0; i < nData; i++) {
m_x = xValues[i];
out[i] = m_parser->Eval();
}
}
/**
* @param domain :: the space on which the function acts
* @param jacobian :: the set of partial derivatives of the function with respect
* to the
* fitting parameters
*/
void UserFunction::functionDeriv(const API::FunctionDomain &domain,
API::Jacobian &jacobian) {
calNumericalDeriv(domain, jacobian);
}
} // namespace Functions
} // namespace CurveFitting
} // namespace Mantid