18 #ifndef LIBMESH_PARSED_FUNCTION_H
19 #define LIBMESH_PARSED_FUNCTION_H
21 #include "libmesh/libmesh_config.h"
22 #include "libmesh/function_base.h"
23 #include "libmesh/auto_ptr.h"
25 #ifdef LIBMESH_HAVE_FPARSER
28 #include "libmesh/dense_vector.h"
29 #include "libmesh/int_range.h"
30 #include "libmesh/vector_value.h"
31 #include "libmesh/point.h"
34 #include "libmesh/fparser_ad.hh"
59 template <
typename Output=Number,
typename OutputGradient=Gradient>
65 const std::vector<std::string> * additional_vars=
nullptr,
66 const std::vector<Output> * initial_vals=
nullptr);
100 const Real time = 0)
override;
108 const Real time = 0);
111 const Real time = 0);
117 virtual Output
component (
unsigned int i,
126 virtual Output &
getVarAddress(
const std::string & variable_name);
128 virtual std::unique_ptr<FunctionBase<Output>>
clone()
const override;
162 std::size_t
find_name (
const std::string & varname,
163 const std::string & expr)
const;
175 const Real time = 0);
180 inline Output
eval(FunctionParserADBase<Output> & parser,
181 const std::string & libmesh_dbg_var(function_name),
182 unsigned int libmesh_dbg_var(component_idx))
const;
186 std::vector<FunctionParserADBase<Output>>
parsers;
209 template <
typename Output,
typename OutputGradient>
212 const std::vector<std::string> * additional_vars,
213 const std::vector<Output> * initial_vals) :
217 _spacetime (LIBMESH_DIM+1 + (additional_vars ? additional_vars->size() : 0)),
218 _valid_derivatives (true),
219 _additional_vars (additional_vars ? *additional_vars :
std::vector<
std::string>()),
220 _initial_vals (initial_vals ? *initial_vals :
std::vector<Output>())
223 this->reparse(expression);
224 this->_initialized =
true;
228 template <
typename Output,
typename OutputGradient>
247 variables +=
"," + _additional_vars[i];
250 _spacetime[LIBMESH_DIM+1 + i] =
251 (i < _initial_vals.size()) ? _initial_vals[i] : 0;
254 this->partial_reparse(expression);
256 this->_is_time_dependent = this->expression_is_time_dependent(expression);
259 template <
typename Output,
typename OutputGradient>
264 set_spacetime(p, time);
265 return eval(parsers[0],
"f", 0);
268 template <
typename Output,
typename OutputGradient>
273 set_spacetime(p, time);
274 return eval(dt_parsers[0],
"df/dt", 0);
277 template <
typename Output,
typename OutputGradient>
283 set_spacetime(p, time);
285 grad(0) = eval(dx_parsers[0],
"df/dx", 0);
287 grad(1) = eval(dy_parsers[0],
"df/dy", 0);
290 grad(2) = eval(dz_parsers[0],
"df/dz", 0);
296 template <
typename Output,
typename OutputGradient>
304 set_spacetime(p, time);
306 unsigned int size = output.size();
308 libmesh_assert_equal_to (size, parsers.size());
312 for (
unsigned int i=0; i != size; ++i)
313 output(i) = eval(parsers[i],
"f", i);
320 template <
typename Output,
typename OutputGradient>
327 set_spacetime(p, time);
328 libmesh_assert_less (i, parsers.size());
332 libmesh_assert_less(i, parsers.size());
333 return eval(parsers[i],
"f", i);
339 template <
typename Output,
typename OutputGradient>
344 const std::vector<std::string>::iterator it =
345 std::find(_additional_vars.begin(), _additional_vars.end(), variable_name);
347 if (it == _additional_vars.end())
348 libmesh_error_msg(
"ERROR: Requested variable not found in parsed function");
351 return _spacetime[_spacetime.size() - (_additional_vars.end() - it)];
355 template <
typename Output,
typename OutputGradient>
357 std::unique_ptr<FunctionBase<Output>>
360 return libmesh_make_unique<ParsedFunction>(_expression,
365 template <
typename Output,
typename OutputGradient>
370 libmesh_assert_greater (_subexpressions.size(), 0);
373 bool found_var_name =
false;
375 Output old_var_value(0.);
377 for (
const auto & subexpression : _subexpressions)
379 const std::size_t varname_i =
380 find_name(inline_var_name, subexpression);
381 if (varname_i == std::string::npos)
384 const std::size_t assignment_i =
385 subexpression.find(
":", varname_i+1);
387 libmesh_assert_not_equal_to(assignment_i, std::string::npos);
389 libmesh_assert_equal_to(subexpression[assignment_i+1],
'=');
390 for (std::size_t i = varname_i+1; i != assignment_i; ++i)
391 libmesh_assert_equal_to(subexpression[i],
' ');
393 std::size_t end_assignment_i =
394 subexpression.find(
";", assignment_i+1);
396 libmesh_assert_not_equal_to(end_assignment_i, std::string::npos);
398 std::string new_subexpression =
399 subexpression.substr(0, end_assignment_i+1) +
402 #ifdef LIBMESH_HAVE_FPARSER
405 FunctionParserADBase<Output> fp;
406 fp.AddConstant(
"NaN", std::numeric_limits<Real>::quiet_NaN());
407 fp.AddConstant(
"pi", std::acos(
Real(-1)));
408 fp.AddConstant(
"e", std::exp(
Real(1)));
409 if (fp.Parse(new_subexpression, variables) != -1)
411 (
"ERROR: FunctionParser is unable to parse modified expression: "
412 << new_subexpression <<
'\n' << fp.ErrorMsg());
414 Output new_var_value = this->eval(fp, new_subexpression, 0);
416 return new_var_value;
420 libmesh_assert_equal_to(old_var_value, new_var_value);
424 old_var_value = new_var_value;
425 found_var_name =
true;
430 libmesh_error_msg(
"ERROR: This functionality requires fparser!");
435 return old_var_value;
439 template <
typename Output,
typename OutputGradient>
445 libmesh_assert_greater (_subexpressions.size(), 0);
448 bool found_var_name =
false;
450 for (
auto & subexpression : _subexpressions)
452 const std::size_t varname_i =
453 find_name(inline_var_name, subexpression);
454 if (varname_i == std::string::npos)
458 found_var_name =
true;
460 const std::size_t assignment_i =
461 subexpression.find(
":", varname_i+1);
463 libmesh_assert_not_equal_to(assignment_i, std::string::npos);
465 libmesh_assert_equal_to(subexpression[assignment_i+1],
'=');
466 for (std::size_t i = varname_i+1; i != assignment_i; ++i)
467 libmesh_assert_equal_to(subexpression[i],
' ');
469 std::size_t end_assignment_i =
470 subexpression.find(
";", assignment_i+1);
472 libmesh_assert_not_equal_to(end_assignment_i, std::string::npos);
474 std::ostringstream new_subexpression;
475 new_subexpression << subexpression.substr(0, assignment_i+2)
476 << std::setprecision(std::numeric_limits<Output>::digits10+2)
477 #ifdef LIBMESH_USE_COMPLEX_NUMBERS
478 <<
'(' << newval.real() <<
'+'
479 << newval.imag() <<
'i' <<
')'
483 << subexpression.substr(end_assignment_i,
485 subexpression = new_subexpression.str();
490 std::string new_expression;
492 for (
const auto & subexpression : _subexpressions)
494 new_expression +=
'{';
495 new_expression += subexpression;
496 new_expression +=
'}';
499 this->partial_reparse(new_expression);
503 template <
typename Output,
typename OutputGradient>
508 _expression = expression;
509 _subexpressions.
clear();
512 size_t nextstart = 0,
end = 0;
514 while (
end != std::string::npos)
518 if (nextstart >= expression.size())
523 if (expression[nextstart] ==
'{')
526 end = expression.find(
'}', nextstart);
530 end = std::string::npos;
534 _subexpressions.push_back
535 (expression.substr(nextstart, (
end == std::string::npos) ?
536 std::string::npos :
end - nextstart));
539 if (_subexpressions.back().empty())
540 libmesh_error_msg(
"ERROR: FunctionParser is unable to parse empty expression.\n");
544 FunctionParserADBase<Output> fp;
545 fp.AddConstant(
"NaN", std::numeric_limits<Real>::quiet_NaN());
546 fp.AddConstant(
"pi", std::acos(
Real(-1)));
547 fp.AddConstant(
"e", std::exp(
Real(1)));
548 if (fp.Parse(_subexpressions.back(), variables) != -1)
550 (
"ERROR: FunctionParser is unable to parse expression: "
551 << _subexpressions.back() <<
'\n' << fp.ErrorMsg());
556 fp.SetADFlags(FunctionParserADBase<Output>::ADSilenceErrors |
557 FunctionParserADBase<Output>::ADAutoOptimize);
561 parsers.push_back(fp);
564 FunctionParserADBase<Output> dx_fp(fp);
565 if (dx_fp.AutoDiff(
"x") != -1)
566 _valid_derivatives =
false;
567 dx_parsers.push_back(dx_fp);
569 FunctionParserADBase<Output> dy_fp(fp);
570 if (dy_fp.AutoDiff(
"y") != -1)
571 _valid_derivatives =
false;
572 dy_parsers.push_back(dy_fp);
575 FunctionParserADBase<Output> dz_fp(fp);
576 if (dz_fp.AutoDiff(
"z") != -1)
577 _valid_derivatives =
false;
578 dz_parsers.push_back(dz_fp);
580 FunctionParserADBase<Output> dt_fp(fp);
581 if (dt_fp.AutoDiff(
"t") != -1)
582 _valid_derivatives =
false;
583 dt_parsers.push_back(dt_fp);
587 nextstart = (
end == std::string::npos) ?
588 std::string::npos :
end + 1;
593 template <
typename Output,
typename OutputGradient>
597 const std::string & expr)
const
599 const std::size_t namesize = varname.size();
600 std::size_t varname_i = expr.find(varname);
602 while ((varname_i != std::string::npos) &&
604 (std::isalnum(expr[varname_i-1]) ||
605 (expr[varname_i-1] ==
'_'))) ||
606 ((varname_i+namesize < expr.size()) &&
607 (std::isalnum(expr[varname_i+namesize]) ||
608 (expr[varname_i+namesize] ==
'_')))))
610 varname_i = expr.find(varname, varname_i+1);
615 template <
typename Output,
typename OutputGradient>
620 bool is_time_dependent =
false;
624 if (this->find_name(std::string(
"t"), expression) != std::string::npos)
625 is_time_dependent =
true;
627 return is_time_dependent;
631 template <
typename Output,
typename OutputGradient>
637 _spacetime[0] = p(0);
639 _spacetime[1] = p(1);
642 _spacetime[2] = p(2);
644 _spacetime[LIBMESH_DIM] = time;
651 template <
typename Output,
typename OutputGradient>
655 const std::string & libmesh_dbg_var(function_name),
656 unsigned int libmesh_dbg_var(component_idx))
const
659 Output result = parser.Eval(_spacetime.data());
660 int error_code = parser.EvalError();
663 libMesh::err <<
"ERROR: FunctionParser is unable to evaluate component "
665 <<
" of expression '"
667 <<
"' with arguments:\n";
668 for (
const auto & item : _spacetime)
673 std::string error_message =
"Reason: ";
678 error_message +=
"Division by zero";
681 error_message +=
"Square Root error (negative value)";
684 error_message +=
"Log error (negative value)";
687 error_message +=
"Trigonometric error (asin or acos of illegal value)";
690 error_message +=
"Maximum recursion level reached";
693 error_message +=
"Unknown";
696 libmesh_error_msg(error_message);
701 return parser.Eval(_spacetime.data());
708 #else // !LIBMESH_HAVE_FPARSER
714 template <
typename Output=Number>
715 class ParsedFunction :
public FunctionBase<Output>
719 const std::vector<std::string> * =
nullptr,
720 const std::vector<Output> * =
nullptr) :
_dummy(0)
722 libmesh_not_implemented();
746 virtual std::unique_ptr<FunctionBase<Output>>
clone()
const
748 return libmesh_make_unique<ParsedFunction<Output>>(
"");
759 #endif // LIBMESH_HAVE_FPARSER
761 #endif // LIBMESH_PARSED_FUNCTION_H