18 #ifndef LIBMESH_PARSED_FUNCTION_H    19 #define LIBMESH_PARSED_FUNCTION_H    21 #include "libmesh/libmesh_config.h"    22 #include "libmesh/function_base.h"    24 #ifdef LIBMESH_HAVE_FPARSER    27 #include "libmesh/dense_vector.h"    28 #include "libmesh/int_range.h"    29 #include "libmesh/vector_value.h"    30 #include "libmesh/point.h"    33 #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);
    86                              const Real time = 0) 
override;
   103   virtual Output 
component (
unsigned int i,
   112   virtual Output & 
getVarAddress(std::string_view variable_name);
   114   virtual std::unique_ptr<FunctionBase<Output>> 
clone() 
const override;
   148   std::size_t 
find_name (std::string_view varname,
   149                          std::string_view expr) 
const;
   161                      const Real time = 0);
   166   inline Output 
eval(FunctionParserADBase<Output> & parser,
   167                      std::string_view libmesh_dbg_var(function_name),
   168                      unsigned int libmesh_dbg_var(component_idx)) 
const;
   172   std::vector<std::unique_ptr<FunctionParserADBase<Output>>> 
parsers;
   176   std::vector<std::unique_ptr<FunctionParserADBase<Output>>> 
dx_parsers;
   178   std::vector<std::unique_ptr<FunctionParserADBase<Output>>> 
dy_parsers;
   181   std::vector<std::unique_ptr<FunctionParserADBase<Output>>> 
dz_parsers;
   183   std::vector<std::unique_ptr<FunctionParserADBase<Output>>> 
dt_parsers;
   195 template <
typename Output, 
typename OutputGradient>
   198                                                        const std::vector<std::string> * additional_vars,
   199                                                        const std::vector<Output> * initial_vals) :
   203   _spacetime (LIBMESH_DIM+1 + (additional_vars ? additional_vars->size() : 0)),
   204   _valid_derivatives (true),
   205   _additional_vars (additional_vars ? *additional_vars : 
std::vector<
std::string>()),
   206   _initial_vals (initial_vals ? *initial_vals : 
std::vector<Output>())
   209   this->reparse(std::move(expression));
   210   this->_initialized = 
true;
   214 template <
typename Output, 
typename OutputGradient>
   218   _expression(other._expression),
   219   _subexpressions(other._subexpressions),
   220   _spacetime(other._spacetime),
   221   _valid_derivatives(other._valid_derivatives),
   222   variables(other.variables),
   223   _additional_vars(other._additional_vars),
   224   _initial_vals(other._initial_vals)
   227   this->reparse(this->_expression);
   228   this->_initialized = 
true;
   233 template <
typename Output, 
typename OutputGradient>
   240   std::swap(tmp, *
this);
   245 template <
typename Output, 
typename OutputGradient>
   264       variables += 
"," + _additional_vars[i];
   267       _spacetime[LIBMESH_DIM+1 + i] =
   268         (i < _initial_vals.size()) ? _initial_vals[i] : 0;
   271   this->_is_time_dependent = this->expression_is_time_dependent(expression);
   273   this->partial_reparse(std::move(expression));
   276 template <
typename Output, 
typename OutputGradient>
   281   set_spacetime(p, time);
   282   return eval(*parsers[0], 
"f", 0);
   285 template <
typename Output, 
typename OutputGradient>
   290   set_spacetime(p, time);
   291   return eval(*dt_parsers[0], 
"df/dt", 0);
   294 template <
typename Output, 
typename OutputGradient>
   300   set_spacetime(p, time);
   302   grad(0) = eval(*dx_parsers[0], 
"df/dx", 0);
   304   grad(1) = eval(*dy_parsers[0], 
"df/dy", 0);
   307   grad(2) = eval(*dz_parsers[0], 
"df/dz", 0);
   313 template <
typename Output, 
typename OutputGradient>
   321   set_spacetime(p, time);
   323   unsigned int size = output.size();
   325   libmesh_assert_equal_to (size, parsers.size());
   329   for (
unsigned int i=0; i != size; ++i)
   330     output(i) = eval(*parsers[i], 
"f", i);
   337 template <
typename Output, 
typename OutputGradient>
   344   set_spacetime(p, time);
   345   libmesh_assert_less (i, parsers.size());
   349   libmesh_assert_less(i, parsers.size());
   350   return eval(*parsers[i], 
"f", i);
   356 template <
typename Output, 
typename OutputGradient>
   361   const std::vector<std::string>::iterator it =
   362     std::find(_additional_vars.begin(), _additional_vars.end(), variable_name);
   364   libmesh_error_msg_if(it == _additional_vars.end(),
   365                        "ERROR: Requested variable not found in parsed function");
   368   return _spacetime[_spacetime.size() - (_additional_vars.end() - it)];
   372 template <
typename Output, 
typename OutputGradient>
   374 std::unique_ptr<FunctionBase<Output>>
   377   return std::make_unique<ParsedFunction>(_expression,
   382 template <
typename Output, 
typename OutputGradient>
   387   libmesh_assert_greater (_subexpressions.size(), 0);
   390   bool found_var_name = 
false;
   392   Output old_var_value(0.);
   394   for (
const auto & subexpression : _subexpressions)
   396       const std::size_t varname_i =
   397         find_name(inline_var_name, subexpression);
   398       if (varname_i == std::string::npos)
   401       const std::size_t assignment_i =
   402         subexpression.find(
":", varname_i+1);
   404       libmesh_assert_not_equal_to(assignment_i, std::string::npos);
   406       libmesh_assert_equal_to(subexpression[assignment_i+1], 
'=');
   407       for (std::size_t i = varname_i+1; i != assignment_i; ++i)
   408         libmesh_assert_equal_to(subexpression[i], 
' ');
   410       std::size_t end_assignment_i =
   411         subexpression.find(
";", assignment_i+1);
   413       libmesh_assert_not_equal_to(end_assignment_i, std::string::npos);
   415       std::string new_subexpression =
   416         subexpression.substr(0, end_assignment_i+1).append(inline_var_name);
   418 #ifdef LIBMESH_HAVE_FPARSER   421       FunctionParserADBase<Output> fp;
   422       fp.AddConstant(
"NaN", std::numeric_limits<Real>::quiet_NaN());
   423       fp.AddConstant(
"pi", std::acos(
Real(-1)));
   424       fp.AddConstant(
"e", std::exp(
Real(1)));
   426         (fp.Parse(new_subexpression, variables) != -1, 
   427          "ERROR: FunctionParser is unable to parse modified expression: "   428          << new_subexpression << 
'\n' << fp.ErrorMsg());
   430       Output new_var_value = this->eval(fp, new_subexpression, 0);
   432       return new_var_value;
   436           libmesh_assert_equal_to(old_var_value, new_var_value);
   440           old_var_value = new_var_value;
   441           found_var_name = 
true;
   446       libmesh_error_msg(
"ERROR: This functionality requires fparser!");
   451   return old_var_value;
   455 template <
typename Output, 
typename OutputGradient>
   461   libmesh_assert_greater (_subexpressions.size(), 0);
   464   bool found_var_name = 
false;
   466   for (
auto & subexpression : _subexpressions)
   468       const std::size_t varname_i =
   469         find_name(inline_var_name, subexpression);
   470       if (varname_i == std::string::npos)
   474       found_var_name = 
true;
   476       const std::size_t assignment_i =
   477         subexpression.find(
":", varname_i+1);
   479       libmesh_assert_not_equal_to(assignment_i, std::string::npos);
   481       libmesh_assert_equal_to(subexpression[assignment_i+1], 
'=');
   482       for (std::size_t i = varname_i+1; i != assignment_i; ++i)
   483         libmesh_assert_equal_to(subexpression[i], 
' ');
   485       std::size_t end_assignment_i =
   486         subexpression.find(
";", assignment_i+1);
   488       libmesh_assert_not_equal_to(end_assignment_i, std::string::npos);
   490       std::ostringstream new_subexpression;
   491       new_subexpression << subexpression.substr(0, assignment_i+2)
   492                         << std::setprecision(std::numeric_limits<Output>::digits10+2)
   493 #ifdef LIBMESH_USE_COMPLEX_NUMBERS   494                         << 
'(' << newval.real() << 
'+'   495                         << newval.imag() << 
'i' << 
')'   499                         << subexpression.substr(end_assignment_i,
   501       subexpression = new_subexpression.str();
   506   std::string new_expression;
   508   for (
const auto & subexpression : _subexpressions)
   510       new_expression += 
'{';
   511       new_expression += subexpression;
   512       new_expression += 
'}';
   515   this->partial_reparse(new_expression);
   519 template <
typename Output, 
typename OutputGradient>
   524   _expression = std::move(expression);
   525   _subexpressions.clear();
   528   size_t nextstart = 0, end = 0;
   530   while (end != std::string::npos)
   534       if (nextstart >= _expression.size())
   539       if (_expression[nextstart] == 
'{')
   542           end = _expression.find(
'}', nextstart);
   546         end = std::string::npos;
   550       _subexpressions.push_back
   551         (_expression.substr(nextstart, (end == std::string::npos) ?
   552                            std::string::npos : end - nextstart));
   555       libmesh_error_msg_if(_subexpressions.back().empty(),
   556                            "ERROR: FunctionParser is unable to parse empty expression.\n");
   560       auto fp = std::make_unique<FunctionParserADBase<Output>>();
   561       fp->AddConstant(
"NaN", std::numeric_limits<Real>::quiet_NaN());
   562       fp->AddConstant(
"pi", std::acos(
Real(-1)));
   563       fp->AddConstant(
"e", std::exp(
Real(1)));
   565         (fp->Parse(_subexpressions.back(), variables) != -1, 
   566          "ERROR: FunctionParser is unable to parse expression: "   567          << _subexpressions.back() << 
'\n' << fp->ErrorMsg());
   572       fp->SetADFlags(FunctionParserADBase<Output>::ADSilenceErrors |
   573                     FunctionParserADBase<Output>::ADAutoOptimize);
   579       auto dx_fp = std::make_unique<FunctionParserADBase<Output>>(*fp);
   580       if (dx_fp->AutoDiff(
"x") != -1) 
   581         _valid_derivatives = 
false;
   582       dx_parsers.push_back(std::move(dx_fp));
   584       auto dy_fp = std::make_unique<FunctionParserADBase<Output>>(*fp);
   585       if (dy_fp->AutoDiff(
"y") != -1) 
   586         _valid_derivatives = 
false;
   587       dy_parsers.push_back(std::move(dy_fp));
   590       auto dz_fp = std::make_unique<FunctionParserADBase<Output>>(*fp);
   591       if (dz_fp->AutoDiff(
"z") != -1) 
   592         _valid_derivatives = 
false;
   593       dz_parsers.push_back(std::move(dz_fp));
   595       auto dt_fp = std::make_unique<FunctionParserADBase<Output>>(*fp);
   596       if (dt_fp->AutoDiff(
"t") != -1) 
   597         _valid_derivatives = 
false;
   598       dt_parsers.push_back(std::move(dt_fp));
   602       nextstart = (end == std::string::npos) ?
   603         std::string::npos : end + 1;
   606       parsers.push_back(std::move(fp));
   611 template <
typename Output, 
typename OutputGradient>
   615                                                   std::string_view expr)
 const   617   const std::size_t namesize = varname.size();
   618   std::size_t varname_i = expr.find(varname);
   620   while ((varname_i != std::string::npos) &&
   622            (std::isalnum(expr[varname_i-1]) ||
   623             (expr[varname_i-1] == 
'_'))) ||
   624           ((varname_i+namesize < expr.size()) &&
   625            (std::isalnum(expr[varname_i+namesize]) ||
   626             (expr[varname_i+namesize] == 
'_')))))
   628       varname_i = expr.find(varname, varname_i+1);
   633 template <
typename Output, 
typename OutputGradient>
   638   bool is_time_dependent = 
false;
   642   if (this->find_name(std::string(
"t"), expression) != std::string::npos)
   643     is_time_dependent = 
true;
   645   return is_time_dependent;
   649 template <
typename Output, 
typename OutputGradient>
   655   _spacetime[0] = p(0);
   657   _spacetime[1] = p(1);
   660   _spacetime[2] = p(2);
   662   _spacetime[LIBMESH_DIM] = time;
   669 template <
typename Output, 
typename OutputGradient>
   673                                              std::string_view function_name,
   674                                              unsigned int component_idx)
 const   676   Output result = parser.Eval(_spacetime.data());
   677   int error_code = parser.EvalError();
   680       libMesh::err << 
"ERROR: FunctionParser is unable to evaluate component "   686         if (parsers[i].
get() == &parser)
   688                        << _subexpressions[i];
   691       for (
const auto & item : _spacetime)
   696       std::string error_message = 
"Reason: ";
   701           error_message += 
"Division by zero";
   704           error_message += 
"Square Root error (negative value)";
   707           error_message += 
"Log error (negative value)";
   710           error_message += 
"Trigonometric error (asin or acos of illegal value)";
   713           error_message += 
"Maximum recursion level reached";
   716           error_message += 
"Unknown";
   719       libmesh_error_msg(error_message);
   728 #else // !LIBMESH_HAVE_FPARSER   734 template <
typename Output=Number>
   735 class ParsedFunction : 
public FunctionBase<Output>
   739                   const std::vector<std::string> * = 
nullptr,
   740                   const std::vector<Output> * = 
nullptr) : 
_dummy(0)
   742     libmesh_not_implemented();
   766   virtual std::unique_ptr<FunctionBase<Output>> 
clone()
 const   768     return std::make_unique<ParsedFunction<Output>>(
"");
   779 #endif // LIBMESH_HAVE_FPARSER   781 #endif // LIBMESH_PARSED_FUNCTION_H virtual Output dot(const Point &p, const Real time=0)
void set_inline_value(std::string_view inline_var_name, Output newval)
Changes the value of an inline variable. 
virtual std::unique_ptr< FunctionBase< Output > > clone() const override
Output get_inline_value(std::string_view inline_var_name) const
virtual void clear()
Clears the function. 
void partial_reparse(std::string expression)
Re-parse with minor changes to expression. 
Output eval(FunctionParserADBase< Output > &parser, std::string_view libmesh_dbg_var(function_name), unsigned int libmesh_dbg_var(component_idx)) const
Evaluate the ith FunctionParser and check the result. 
A Function generated (via FParser) by parsing a mathematical expression. 
ParsedFunction & operator=(const ParsedFunction &)
std::vector< Output > _spacetime
std::vector< std::unique_ptr< FunctionParserADBase< Output > > > parsers
std::vector< std::string > _additional_vars
void set_spacetime(const Point &p, const Real time=0)
Set the _spacetime argument vector. 
std::vector< std::string > _subexpressions
The libMesh namespace provides an interface to certain functionality in the library. 
std::vector< std::unique_ptr< FunctionParserADBase< Output > > > dy_parsers
std::vector< std::unique_ptr< FunctionParserADBase< Output > > > dt_parsers
bool expression_is_time_dependent(std::string_view expression) const
std::size_t find_name(std::string_view varname, std::string_view expr) const
Helper function for parsing out variable names. 
virtual Output & getVarAddress(std::string_view variable_name)
virtual Output component(unsigned int i, const Point &p, Real time) override
ParsedFunction(std::string expression, const std::vector< std::string > *additional_vars=nullptr, const std::vector< Output > *initial_vals=nullptr)
virtual ~ParsedFunction()=default
std::vector< std::unique_ptr< FunctionParserADBase< Output > > > dx_parsers
virtual std::unique_ptr< FunctionBase< Output > > clone() const
virtual bool has_derivatives()
Query if the automatic derivative generation was successful. 
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
virtual Output & getVarAddress(std::string_view)
ParsedFunction(std::string, const std::vector< std::string > *=nullptr, const std::vector< Output > *=nullptr)
std::vector< std::unique_ptr< FunctionParserADBase< Output > > > dz_parsers
void reparse(std::string expression)
Re-parse with new 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
A Point defines a location in LIBMESH_DIM dimensional Real space. 
auto index_range(const T &sizable)
Helper function that returns an IntRange<std::size_t> representing all the indices of the passed-in v...
const std::string & expression()
virtual void init()
The actual initialization process. 
virtual OutputGradient gradient(const Point &p, const Real time=0)