49 #include "../utility/utility.h"
50 #include "../utility/numutil.h"
56 #define PARSER_MAXVARS 100
64 "Evaluated value of the function for the current variable values.");
71 "Value of derivative of the function for the current variable values");
78 "Value of time-derivative of the function for the current variable values");
86 "Sends request for input variable from a field on target object");
98 "Result of the function evaluation with current variable values.",
102 "Derivative of the function at given variable values. This is calulated"
103 " using 5-point stencil "
104 " <http://en.wikipedia.org/wiki/Five-point_stencil> at current value of"
105 " independent variable. Note that unlike hand-calculated derivatives,"
106 " numerical derivatives are not exact.",
110 "Derivative of the function at given variable values. This is computed"
111 " as the difference of the current and previous value of the function"
112 " divided by the time step.",
116 "Mode of operation: \n"
117 " 1: only the function value will be sent out.\n"
118 " 2: only the derivative with respect to the independent variable will be sent out.\n"
119 " 3: only rate (time derivative) will be sent out.\n"
120 " anything else: all three, value, derivative and rate will be sent out.\n",
125 "When *false*, disables event-driven calculation and turns on "
126 "Process-driven calculations. \n"
127 "When *true*, enables event-driven calculation and turns off "
128 "Process-driven calculations. \n"
129 "Defaults to *false*. \n",
134 "When *false*, disables function evaluation at reinit, and "
135 "just emits a value of zero to any message targets. \n"
136 "When *true*, does a function evaluation at reinit and sends "
137 "the computed value to any message targets. \n"
138 "Defaults to *false*. \n",
143 "Mathematical expression defining the function. The underlying parser\n"
144 "is muParser. In addition to the available functions and operators from\n"
145 "muParser, some more functions are added.\n"
147 "Name args explanation\n"
148 "sin 1 sine function\n"
149 "cos 1 cosine function\n"
150 "tan 1 tangens function\n"
151 "asin 1 arcus sine function\n"
152 "acos 1 arcus cosine function\n"
153 "atan 1 arcus tangens function\n"
154 "sinh 1 hyperbolic sine function\n"
155 "cosh 1 hyperbolic cosine\n"
156 "tanh 1 hyperbolic tangens function\n"
157 "asinh 1 hyperbolic arcus sine function\n"
158 "acosh 1 hyperbolic arcus tangens function\n"
159 "atanh 1 hyperbolic arcur tangens function\n"
160 "log2 1 logarithm to the base 2\n"
161 "log10 1 logarithm to the base 10\n"
162 "log 1 logarithm to the base 10\n"
163 "ln 1 logarithm to base e (2.71828...)\n"
164 "exp 1 e raised to the power of x\n"
165 "sqrt 1 square root of a value\n"
166 "sign 1 sign function -1 if x<0; 1 if x>0\n"
167 "rint 1 round to nearest integer\n"
168 "abs 1 absolute value\n"
169 "min var. min of all arguments\n"
170 "max var. max of all arguments\n"
171 "sum var. sum of all arguments\n"
172 "avg var. mean value of all arguments\n"
173 "rand 1 rand(seed), random float between 0 and 1, \n"
174 " if seed = -1, then a 'random' seed is created.\n"
175 "rand2 3 rand(a, b, seed), random float between a and b, \n"
176 " if seed = -1, a 'random' seed is created using either\n"
177 " by random_device or by reading system clock\n"
179 "Op meaning priority\n"
183 "<= less or equal 4\n"
184 ">= greater or equal 4\n"
191 "* multiplication 6\n"
193 "^ raise x to the power of y 7\n"
194 "% floating point modulo 7\n"
196 "?: if then else operator C++ style syntax\n",
203 "Number of variables used by Function.",
210 "Input variables to the function. These can be passed via messages.",
219 "Constants used in the function. These must be assigned before"
220 " specifying the function expression.",
226 "Variable values received from target fields by requestOut",
231 "Index of independent variable. Differentiation is done based on this. Defaults"
232 " to the first assigned variable.",
240 "Handles process call, updates internal time stamp.",
243 "Handles reinit call.",
248 "This is a shared message to receive Process messages "
249 "from the scheduler objects."
250 "The first entry in the shared msg is a MsgDest "
251 "for the Process operation. It has a single argument, "
252 "ProcInfo, which holds lots of information about current "
253 "time, thread, dt and so on. The second entry is a MsgDest "
254 "for the Reinit operation. It also uses ProcInfo. ",
255 processShared,
sizeof( processShared ) /
sizeof(
Finfo* )
264 static Finfo *functionFinfos[] =
284 static string doc[] =
287 "Author",
"Subhasis Ray",
289 "General purpose function calculator using real numbers.\n"
290 "It can parse mathematical expression defining a function and evaluate"
291 " it and/or its derivative for specified variable values."
292 "You can assign expressions of the form::\n"
294 "f(c0, c1, ..., cM, x0, x1, ..., xN, y0,..., yP ) \n"
296 " where `ci`'s are constants and `xi`'s and `yi`'s are variables."
298 "The constants must be defined before setting the expression and"
299 " variables are connected via messages. The constants can have any"
300 " name, but the variable names must be of the form x{i} or y{i}"
301 " where i is increasing integer starting from 0.\n"
302 " The variables can be input from other moose objects."
303 " Such variables must be named `x{i}` in the expression and the source"
304 " field is connected to Function.x[i]'s `input` destination field.\n"
305 " In case the input variable is not available as a source field, but is"
306 " a value field, then the value can be requested by connecting the"
307 " `requestOut` message to the `get{Field}` destination on the target"
308 " object. Such variables must be specified in the expression as y{i}"
309 " and connecting the messages should happen in the same order as the"
311 " This class handles only real numbers (C-double). Predefined constants"
312 " are: pi=3.141592..., e=2.718281..."
319 sizeof(functionFinfos) /
sizeof(
Finfo*),
322 sizeof(doc)/
sizeof(
string));
330 _value(0.0), _rate(0.0), _mode(1),
331 _useTrigger( false ), _doEvalAtReinit( false ), _stoich(0)
340 }
catch (mu::Parser::exception_type &e) {
349 void Function::extendMuParser(
void )
356 _parser.DefineOprt( _T(
"%"), &Function::muCallbackFMod, 7, mu::EOprtAssociativity::oaRIGHT, 0);
361 _lastValue(rhs._lastValue),
362 _value(rhs._value), _rate(rhs._rate),
364 _useTrigger( rhs._useTrigger),
374 mu::valmap_type cmap = rhs.
_parser.GetConst();
376 mu::valmap_type::const_iterator item = cmap.begin();
377 for (; item!=cmap.end(); ++item){
378 _parser.DefineConst(item->first, item->second);
386 for (
unsigned int ii = 0; ii < rhs.
_varbuf.size(); ++ii){
390 for (
unsigned int ii = 0; ii < rhs.
_pullbuf.size(); ++ii){
408 mu::valmap_type cmap = rhs.
_parser.GetConst();
410 mu::valmap_type::const_iterator item = cmap.begin();
411 for (; item!=cmap.end(); ++item){
412 _parser.DefineConst(item->first, item->second);
418 for (
unsigned int ii = 0; ii < rhs.
_varbuf.size(); ++ii){
422 for (
unsigned int ii = 0; ii < rhs.
_pullbuf.size(); ++ii){
439 for (
unsigned int ii = 0; ii <
_varbuf.size(); ++ii){
445 for (
unsigned int ii = 0; ii <
_pullbuf.size(); ++ii){
455 cout <<
"Error occurred in parser.\n"
456 <<
"Message: " << e.GetMsg() <<
"\n"
457 <<
"Formula: " << e.GetExpr() <<
"\n"
458 <<
"Token: " << e.GetToken() <<
"\n"
459 <<
"Position: " << e.GetPos() <<
"\n"
460 <<
"Error code: " << e.GetCode() << endl;
486 string strname(name);
488 if (strname[0] ==
'x'){
489 int index = atoi(strname.substr(1).c_str());
490 if ((
unsigned)index >=
function->_varbuf.size()){
491 function->_varbuf.resize(index+1, 0);
492 for (
int ii = 0; ii <= index; ++ii){
493 if (function->_varbuf[ii] == 0){
494 function->_varbuf[ii] =
new Variable();
497 function->_numVar =
function->_varbuf.size();
499 ret = &(
function->_varbuf[index]->value);
500 }
else if (strname[0] ==
'y'){
501 int index = atoi(strname.substr(1).c_str());
502 if ((
unsigned)index >=
function->_pullbuf.size()){
503 function->_pullbuf.resize(index+1, 0 );
504 for (
int ii = 0; ii <= index; ++ii){
505 if (function->_pullbuf[ii] == 0){
506 function->_pullbuf[ii] =
new double();
510 ret =
function->_pullbuf[index];
511 }
else if (strname ==
"t"){
514 cerr <<
"Got an undefined symbol: " << name << endl
515 <<
"Variables must be named xi, yi, where i is integer index."
516 <<
" You must define the constants beforehand using LookupField c: c[name]"
519 throw mu::ParserError(
"Undefined constant.");
568 mu::varmap_type vars;
571 }
catch (mu::Parser::exception_type &e) {
572 cerr <<
"Error setting expression on: " << eref.
objId().
path() << endl;
582 }
catch (mu::Parser::exception_type &e){
590 cout <<
"Error: " << e.
objId().
path() <<
"::getExpr() - invalid parser state" << endl;
630 cout <<
"Error: Function::getValue() - invalid state" << endl;
635 }
catch (mu::Parser::exception_type &e){
644 cout <<
"Error: Function::getValue() - invalid state" << endl;
661 vector < double > ret(
_pullbuf.size());
662 for (
unsigned int ii = 0; ii < ret.size(); ++ii){
672 cout <<
"Error: Function::getDerivative() - invalid state" << endl;
675 mu::varmap_type variables =
_parser.GetVar();
676 mu::varmap_type::const_iterator item = variables.find(
_independent);
677 if (item != variables.end()){
679 value =
_parser.Diff(item->second, *(item->second));
680 }
catch (mu::Parser::exception_type &e){
690 for (
unsigned int ii = 0; ii < num; ++ii){
704 cout <<
"varbuf[" << index <<
"]->setValue(" << value <<
")\n";
706 _varbuf[index]->setValue(value);
708 cerr <<
"Function: index " << index <<
" out of bounds." << endl;
718 cout <<
"Warning: Function::getVar: index: "
719 << ii <<
" is out of range: "
726 _parser.DefineConst(name, value);
731 mu::valmap_type cmap =
_parser.GetConst();
733 mu::valmap_type::const_iterator it = cmap.find(name);
734 if (it != cmap.end()){
746 vector < double > databuf;
748 for (
unsigned int ii = 0;
749 (ii < databuf.size()) && (ii <
_pullbuf.size());
786 cout <<
"Error: Function::reinit() - invalid parser state. Will do nothing." << endl;
790 cout <<
"Error: no expression set. Will do nothing." << endl;
826 cerr <<
"Callback: " << a <<
" " << b << endl;
bool getDoEvalAtReinit() const
virtual void innerSetExpr(const Eref &e, string expr)
string getIndependent() const
Function & operator=(const Function rhs)
void setConst(string name, double value)
static const double TriggerThreshold
static SrcFinfo1< double > * valueOut()
friend double * _functionAddVar(const char *name, void *data)
vector< double * > _pullbuf
double getDerivative() const
static DestFinfo dummy("dummy","This Finfo is a dummy. If you are reading this you have used an invalid index", 0)
void setUseTrigger(bool useTrigger)
void setMode(unsigned int mode)
double * _functionAddVar(const char *name, void *data)
void _showError(mu::Parser::exception_type &e) const
static SrcFinfo1< double > * derivativeOut()
void setIndependent(string index)
unsigned int getNumVar() const
void setDoEvalAtReinit(bool doEvalAtReinit)
void process(const Eref &e, ProcPtr p)
vector< double > getY() const
static const Cinfo * initCinfo()
void setVar(unsigned int index, double value)
string getExpr(const Eref &e) const
vector< Variable * > _varbuf
static const Cinfo * functionCinfo
void setExpr(const Eref &e, string expr)
static const Cinfo * initCinfo()
void reinit(const Eref &e, ProcPtr p)
static SrcFinfo1< double > * rateOut()
static const Cinfo * initCinfo()
std::string trim(const std::string myString, const string &delimiters)
Variable * getVar(unsigned int ii)
unsigned int getMode() const
double getConst(string name) const
bool getUseTrigger() const
void setNumVar(unsigned int num)
static SrcFinfo1< vector< double > * > * requestOut()