18 #ifndef LIBMESH_PARSED_FUNCTION_H 19 #define LIBMESH_PARSED_FUNCTION_H 24 #ifdef LIBMESH_HAVE_FPARSER 33 #include "libmesh/fparser_ad.hh" 58 template <
typename Output=Number,
typename OutputGradient=Gradient>
64 const std::vector<std::string> * additional_vars=
nullptr,
65 const std::vector<Output> * initial_vals=
nullptr);
99 const Real time = 0)
override;
107 const Real time = 0);
110 const Real time = 0);
116 virtual Output
component (
unsigned int i,
125 virtual Output &
getVarAddress(
const std::string & variable_name);
127 virtual std::unique_ptr<FunctionBase<Output>>
clone()
const override;
161 std::size_t
find_name (
const std::string & varname,
162 const std::string & expr)
const;
174 const Real time = 0);
179 inline Output
eval(FunctionParserADBase<Output> & parser,
180 const std::string & libmesh_dbg_var(function_name),
181 unsigned int libmesh_dbg_var(component_idx))
const;
185 std::vector<FunctionParserADBase<Output>>
parsers;
208 template <
typename Output,
typename OutputGradient>
211 const std::vector<std::string> * additional_vars,
212 const std::vector<Output> * initial_vals) :
216 _spacetime (LIBMESH_DIM+1 + (additional_vars ? additional_vars->size() : 0)),
217 _valid_derivatives (true),
218 _additional_vars (additional_vars ? *additional_vars :
std::vector<
std::string>()),
219 _initial_vals (initial_vals ? *initial_vals :
std::vector<Output>())
222 this->reparse(expression);
223 this->_initialized =
true;
227 template <
typename Output,
typename OutputGradient>
244 for (std::size_t i=0; i < _additional_vars.size(); ++i)
246 variables +=
"," + _additional_vars[i];
249 _spacetime[LIBMESH_DIM+1 + i] =
250 (i < _initial_vals.size()) ? _initial_vals[i] : 0;
253 this->partial_reparse(expression);
255 this->_is_time_dependent = this->expression_is_time_dependent(expression);
258 template <
typename Output,
typename OutputGradient>
263 set_spacetime(p, time);
264 return eval(parsers[0],
"f", 0);
267 template <
typename Output,
typename OutputGradient>
272 set_spacetime(p, time);
273 return eval(dt_parsers[0],
"df/dt", 0);
276 template <
typename Output,
typename OutputGradient>
282 set_spacetime(p, time);
284 grad(0) = eval(dx_parsers[0],
"df/dx", 0);
286 grad(1) = eval(dy_parsers[0],
"df/dy", 0);
289 grad(2) = eval(dz_parsers[0],
"df/dz", 0);
295 template <
typename Output,
typename OutputGradient>
303 set_spacetime(p, time);
305 unsigned int size = output.size();
307 libmesh_assert_equal_to (size, parsers.size());
311 for (
unsigned int i=0; i != size; ++i)
312 output(i) = eval(parsers[i],
"f", i);
319 template <
typename Output,
typename OutputGradient>
326 set_spacetime(p, time);
327 libmesh_assert_less (i, parsers.size());
331 libmesh_assert_less(i, parsers.size());
332 return eval(parsers[i],
"f", i);
338 template <
typename Output,
typename OutputGradient>
343 const std::vector<std::string>::iterator it =
344 std::find(_additional_vars.begin(), _additional_vars.end(), variable_name);
346 if (it == _additional_vars.end())
347 libmesh_error_msg(
"ERROR: Requested variable not found in parsed function");
350 return _spacetime[_spacetime.size() - (_additional_vars.end() - it)];
354 template <
typename Output,
typename OutputGradient>
356 std::unique_ptr<FunctionBase<Output>>
359 return libmesh_make_unique<ParsedFunction>(_expression,
364 template <
typename Output,
typename OutputGradient>
369 libmesh_assert_greater (_subexpressions.size(), 0);
372 bool found_var_name =
false;
374 Output old_var_value(0.);
376 for (
const auto & subexpression : _subexpressions)
378 const std::size_t varname_i =
379 find_name(inline_var_name, subexpression);
380 if (varname_i == std::string::npos)
383 const std::size_t assignment_i =
384 subexpression.find(
":", varname_i+1);
386 libmesh_assert_not_equal_to(assignment_i, std::string::npos);
388 libmesh_assert_equal_to(subexpression[assignment_i+1],
'=');
389 for (std::size_t i = varname_i+1; i != assignment_i; ++i)
390 libmesh_assert_equal_to(subexpression[i],
' ');
392 std::size_t end_assignment_i =
393 subexpression.find(
";", assignment_i+1);
395 libmesh_assert_not_equal_to(end_assignment_i, std::string::npos);
397 std::string new_subexpression =
398 subexpression.substr(0, end_assignment_i+1) +
401 #ifdef LIBMESH_HAVE_FPARSER 404 FunctionParserADBase<Output> fp;
405 fp.AddConstant(
"NaN", std::numeric_limits<Real>::quiet_NaN());
406 fp.AddConstant(
"pi", std::acos(
Real(-1)));
407 fp.AddConstant(
"e", std::exp(
Real(1)));
408 if (fp.Parse(new_subexpression, variables) != -1)
410 (
"ERROR: FunctionParser is unable to parse modified expression: " 411 << new_subexpression <<
'\n' << fp.ErrorMsg());
413 Output new_var_value = this->eval(fp, new_subexpression, 0);
415 return new_var_value;
419 libmesh_assert_equal_to(old_var_value, new_var_value);
423 old_var_value = new_var_value;
424 found_var_name =
true;
429 libmesh_error_msg(
"ERROR: This functionality requires fparser!");
433 libmesh_assert(found_var_name);
434 return old_var_value;
438 template <
typename Output,
typename OutputGradient>
444 libmesh_assert_greater (_subexpressions.size(), 0);
447 bool found_var_name =
false;
449 for (
auto & subexpression : _subexpressions)
451 const std::size_t varname_i =
452 find_name(inline_var_name, subexpression);
453 if (varname_i == std::string::npos)
457 found_var_name =
true;
459 const std::size_t assignment_i =
460 subexpression.find(
":", varname_i+1);
462 libmesh_assert_not_equal_to(assignment_i, std::string::npos);
464 libmesh_assert_equal_to(subexpression[assignment_i+1],
'=');
465 for (std::size_t i = varname_i+1; i != assignment_i; ++i)
466 libmesh_assert_equal_to(subexpression[i],
' ');
468 std::size_t end_assignment_i =
469 subexpression.find(
";", assignment_i+1);
471 libmesh_assert_not_equal_to(end_assignment_i, std::string::npos);
473 std::ostringstream new_subexpression;
474 new_subexpression << subexpression.substr(0, assignment_i+2)
475 << std::setprecision(std::numeric_limits<Output>::digits10+2)
476 #ifdef LIBMESH_USE_COMPLEX_NUMBERS 477 <<
'(' << newval.real() <<
'+' 478 << newval.imag() <<
'i' <<
')' 482 << subexpression.substr(end_assignment_i,
484 subexpression = new_subexpression.str();
487 libmesh_assert(found_var_name);
489 std::string new_expression;
491 for (
const auto & subexpression : _subexpressions)
493 new_expression +=
'{';
494 new_expression += subexpression;
495 new_expression +=
'}';
498 this->partial_reparse(new_expression);
502 template <
typename Output,
typename OutputGradient>
507 _expression = expression;
508 _subexpressions.
clear();
511 size_t nextstart = 0,
end = 0;
513 while (
end != std::string::npos)
517 if (nextstart >= expression.size())
522 if (expression[nextstart] ==
'{')
525 end = expression.find(
'}', nextstart);
529 end = std::string::npos;
533 _subexpressions.push_back
534 (expression.substr(nextstart, (
end == std::string::npos) ?
535 std::string::npos :
end - nextstart));
538 if (_subexpressions.back().empty())
539 libmesh_error_msg(
"ERROR: FunctionParser is unable to parse empty expression.\n");
543 FunctionParserADBase<Output> fp;
544 fp.AddConstant(
"NaN", std::numeric_limits<Real>::quiet_NaN());
545 fp.AddConstant(
"pi", std::acos(
Real(-1)));
546 fp.AddConstant(
"e", std::exp(
Real(1)));
547 if (fp.Parse(_subexpressions.back(), variables) != -1)
549 (
"ERROR: FunctionParser is unable to parse expression: " 550 << _subexpressions.back() <<
'\n' << fp.ErrorMsg());
555 fp.SetADFlags(FunctionParserADBase<Output>::ADSilenceErrors |
556 FunctionParserADBase<Output>::ADAutoOptimize);
560 parsers.push_back(fp);
563 FunctionParserADBase<Output> dx_fp(fp);
564 if (dx_fp.AutoDiff(
"x") != -1)
565 _valid_derivatives =
false;
566 dx_parsers.push_back(dx_fp);
568 FunctionParserADBase<Output> dy_fp(fp);
569 if (dy_fp.AutoDiff(
"y") != -1)
570 _valid_derivatives =
false;
571 dy_parsers.push_back(dy_fp);
574 FunctionParserADBase<Output> dz_fp(fp);
575 if (dz_fp.AutoDiff(
"z") != -1)
576 _valid_derivatives =
false;
577 dz_parsers.push_back(dz_fp);
579 FunctionParserADBase<Output> dt_fp(fp);
580 if (dt_fp.AutoDiff(
"t") != -1)
581 _valid_derivatives =
false;
582 dt_parsers.push_back(dt_fp);
586 nextstart = (
end == std::string::npos) ?
587 std::string::npos :
end + 1;
592 template <
typename Output,
typename OutputGradient>
596 const std::string & expr)
const 598 const std::size_t namesize = varname.size();
599 std::size_t varname_i = expr.find(varname);
601 while ((varname_i != std::string::npos) &&
603 (std::isalnum(expr[varname_i-1]) ||
604 (expr[varname_i-1] ==
'_'))) ||
605 ((varname_i+namesize < expr.size()) &&
606 (std::isalnum(expr[varname_i+namesize]) ||
607 (expr[varname_i+namesize] ==
'_')))))
609 varname_i = expr.find(varname, varname_i+1);
614 template <
typename Output,
typename OutputGradient>
619 bool is_time_dependent =
false;
623 if (this->find_name(std::string(
"t"), expression) != std::string::npos)
624 is_time_dependent =
true;
626 return is_time_dependent;
630 template <
typename Output,
typename OutputGradient>
636 _spacetime[0] = p(0);
638 _spacetime[1] = p(1);
641 _spacetime[2] = p(2);
643 _spacetime[LIBMESH_DIM] = time;
650 template <
typename Output,
typename OutputGradient>
654 const std::string & libmesh_dbg_var(function_name),
655 unsigned int libmesh_dbg_var(component_idx))
const 658 Output result = parser.Eval(_spacetime.data());
659 int error_code = parser.EvalError();
662 libMesh::err <<
"ERROR: FunctionParser is unable to evaluate component " 664 <<
" of expression '" 666 <<
"' with arguments:\n";
667 for (
const auto & item : _spacetime)
672 std::string error_message =
"Reason: ";
677 error_message +=
"Division by zero";
680 error_message +=
"Square Root error (negative value)";
683 error_message +=
"Log error (negative value)";
686 error_message +=
"Trigonometric error (asin or acos of illegal value)";
689 error_message +=
"Maximum recursion level reached";
692 error_message +=
"Unknown";
695 libmesh_error_msg(error_message);
700 return parser.Eval(_spacetime.data());
707 #else // !LIBMESH_HAVE_FPARSER 713 template <
typename Output=Number>
714 class ParsedFunction :
public FunctionBase<Output>
718 const std::vector<std::string> * =
nullptr,
719 const std::vector<Output> * =
nullptr) :
_dummy(0)
721 libmesh_not_implemented();
745 virtual std::unique_ptr<FunctionBase<Output>>
clone()
const 747 return libmesh_make_unique<ParsedFunction<Output>>(
"");
758 #endif // LIBMESH_HAVE_FPARSER 760 #endif // LIBMESH_PARSED_FUNCTION_H virtual Output dot(const Point &p, const Real time=0)
std::vector< FunctionParserADBase< Output > > dt_parsers
virtual std::unique_ptr< FunctionBase< Output > > clone() const override
virtual Output & getVarAddress(const std::string &variable_name)
A Function defined by a std::string.
ParsedFunction(const std::string &, const std::vector< std::string > *=nullptr, const std::vector< Output > *=nullptr)
std::vector< Output > _spacetime
std::vector< std::string > _additional_vars
std::vector< FunctionParserADBase< Output > > parsers
void set_spacetime(const Point &p, const Real time=0)
std::vector< std::string > _subexpressions
virtual Output & getVarAddress(const std::string &)
std::vector< FunctionParserADBase< Output > > dz_parsers
std::vector< FunctionParserADBase< Output > > dx_parsers
std::vector< FunctionParserADBase< Output > > dy_parsers
void reparse(const std::string &expression)
void set_inline_value(const std::string &inline_var_name, Output newval)
Output eval(FunctionParserADBase< Output > &parser, const std::string &libmesh_dbg_var(function_name), unsigned int libmesh_dbg_var(component_idx)) const
virtual Output component(unsigned int i, const Point &p, Real time) override
OStreamProxy err(std::cerr)
virtual ~ParsedFunction()=default
bool expression_is_time_dependent(const std::string &expression) const
std::size_t find_name(const std::string &varname, const std::string &expr) const
virtual std::unique_ptr< FunctionBase< Output > > clone() const
virtual bool has_derivatives()
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
void partial_reparse(const std::string &expression)
Base class for functors that can be evaluated at a point and (optionally) time.
std::vector< Output > _initial_vals
virtual Output operator()(const Point &p, const Real time=0) override
ParsedFunction(const std::string &expression, const std::vector< std::string > *additional_vars=nullptr, const std::vector< Output > *initial_vals=nullptr)
A geometric point in (x,y,z) space.
Output get_inline_value(const std::string &inline_var_name) const
const std::string & expression()
virtual OutputGradient gradient(const Point &p, const Real time=0)
ParsedFunction & operator=(const ParsedFunction &)=delete