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)