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