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"
57 template <
typename Output=Number,
typename OutputGradient=Gradient>
70 const std::vector<std::string> * additional_vars=
nullptr,
71 const std::vector<Output> * initial_vals=
nullptr);
86 void reparse (std::string expression);
96 const Real time = 0)
override;
112 virtual Output
dot(
const Point & p,
113 const Real time = 0);
122 virtual OutputGradient
gradient(
const Point & p,
123 const Real time = 0);
144 virtual Output
component (
unsigned int i,
161 virtual Output &
getVarAddress(std::string_view variable_name);
168 virtual std::unique_ptr<FunctionBase<Output>>
clone()
const override;
214 std::size_t
find_name (std::string_view varname,
215 std::string_view expr)
const;
233 const Real time = 0);
243 inline Output
eval(FunctionParserADBase<Output> & parser,
244 std::string_view libmesh_dbg_var(function_name),
245 unsigned int libmesh_dbg_var(component_idx))
const;
260 std::vector<std::unique_ptr<FunctionParserADBase<Output>>>
parsers;
270 std::vector<std::unique_ptr<FunctionParserADBase<Output>>>
dx_parsers;
276 std::vector<std::unique_ptr<FunctionParserADBase<Output>>>
dy_parsers;
283 std::vector<std::unique_ptr<FunctionParserADBase<Output>>>
dz_parsers;
289 std::vector<std::unique_ptr<FunctionParserADBase<Output>>>
dt_parsers;
315 template <
typename Output,
typename OutputGradient>
318 const std::vector<std::string> * additional_vars,
319 const std::vector<Output> * initial_vals) :
322 _spacetime (LIBMESH_DIM+1 + (additional_vars ? additional_vars->size() : 0)),
323 _valid_derivatives (true),
324 _additional_vars (additional_vars ? *additional_vars : std::vector<std::string>()),
325 _initial_vals (initial_vals ? *initial_vals : std::vector<Output>())
328 this->
reparse(std::move(expression));
333 template <
typename Output,
typename OutputGradient>
337 _expression(other._expression),
338 _subexpressions(other._subexpressions),
339 _spacetime(other._spacetime),
340 _valid_derivatives(other._valid_derivatives),
341 variables(other.variables),
342 _additional_vars(other._additional_vars),
343 _initial_vals(other._initial_vals)
352 template <
typename Output,
typename OutputGradient>
359 std::swap(tmp, *
this);
364 template <
typename Output,
typename OutputGradient>
379 for (
auto i : index_range(_additional_vars))
381 variables +=
"," + _additional_vars[i];
383 _spacetime[LIBMESH_DIM+1 + i] =
384 (i < _initial_vals.size()) ? _initial_vals[i] : 0;
387 this->_is_time_dependent = this->expression_is_time_dependent(expression);
389 this->partial_reparse(std::move(expression));
392 template <
typename Output,
typename OutputGradient>
397 set_spacetime(p, time);
398 return eval(*parsers[0],
"f", 0);
401 template <
typename Output,
typename OutputGradient>
406 set_spacetime(p, time);
407 return eval(*dt_parsers[0],
"df/dt", 0);
410 template <
typename Output,
typename OutputGradient>
416 set_spacetime(p, time);
418 grad(0) = eval(*dx_parsers[0],
"df/dx", 0);
420 grad(1) = eval(*dy_parsers[0],
"df/dy", 0);
423 grad(2) = eval(*dz_parsers[0],
"df/dz", 0);
429 template <
typename Output,
typename OutputGradient>
437 set_spacetime(p, time);
439 unsigned int size = output.size();
441 libmesh_assert_equal_to (size, parsers.size());
444 for (
unsigned int i=0; i != size; ++i)
445 output(i) = eval(*parsers[i],
"f", i);
452 template <
typename Output,
typename OutputGradient>
459 set_spacetime(p, time);
460 libmesh_assert_less (i, parsers.size());
463 libmesh_assert_less(i, parsers.size());
464 return eval(*parsers[i],
"f", i);
470 template <
typename Output,
typename OutputGradient>
475 const std::vector<std::string>::iterator it =
476 std::find(_additional_vars.begin(), _additional_vars.end(), variable_name);
478 libmesh_error_msg_if(it == _additional_vars.end(),
479 "ERROR: Requested variable not found in parsed function");
482 return _spacetime[_spacetime.size() - (_additional_vars.end() - it)];
486 template <
typename Output,
typename OutputGradient>
488 std::unique_ptr<FunctionBase<Output>>
491 return std::make_unique<ParsedFunction>(_expression,
496 template <
typename Output,
typename OutputGradient>
501 libmesh_assert_greater (_subexpressions.size(), 0);
504 bool found_var_name =
false;
506 Output old_var_value(0.);
508 for (
const auto & subexpression : _subexpressions)
510 const std::size_t varname_i =
511 find_name(inline_var_name, subexpression);
512 if (varname_i == std::string::npos)
515 const std::size_t assignment_i =
516 subexpression.find(
":", varname_i+1);
518 libmesh_assert_not_equal_to(assignment_i, std::string::npos);
520 libmesh_assert_equal_to(subexpression[assignment_i+1],
'=');
521 for (std::size_t i = varname_i+1; i != assignment_i; ++i)
522 libmesh_assert_equal_to(subexpression[i],
' ');
524 std::size_t end_assignment_i =
525 subexpression.find(
";", assignment_i+1);
527 libmesh_assert_not_equal_to(end_assignment_i, std::string::npos);
529 std::string new_subexpression =
530 subexpression.substr(0, end_assignment_i+1).append(inline_var_name);
532 #ifdef LIBMESH_HAVE_FPARSER
535 FunctionParserADBase<Output> fp;
536 fp.AddConstant(
"NaN", std::numeric_limits<Real>::quiet_NaN());
537 fp.AddConstant(
"pi", std::acos(
Real(-1)));
538 fp.AddConstant(
"e", std::exp(
Real(1)));
540 (fp.Parse(new_subexpression, variables) != -1,
541 "ERROR: FunctionParser is unable to parse modified expression: "
542 << new_subexpression <<
'\n' << fp.ErrorMsg());
544 Output new_var_value = this->eval(fp, new_subexpression, 0);
546 return new_var_value;
550 libmesh_assert_equal_to(old_var_value, new_var_value);
554 old_var_value = new_var_value;
555 found_var_name =
true;
560 libmesh_error_msg(
"ERROR: This functionality requires fparser!");
564 libmesh_assert(found_var_name);
565 return old_var_value;
569 template <
typename Output,
typename OutputGradient>
575 libmesh_assert_greater (_subexpressions.size(), 0);
578 bool found_var_name =
false;
580 for (
auto & subexpression : _subexpressions)
582 const std::size_t varname_i =
583 find_name(inline_var_name, subexpression);
584 if (varname_i == std::string::npos)
588 found_var_name =
true;
590 const std::size_t assignment_i =
591 subexpression.find(
":", varname_i+1);
593 libmesh_assert_not_equal_to(assignment_i, std::string::npos);
595 libmesh_assert_equal_to(subexpression[assignment_i+1],
'=');
596 for (std::size_t i = varname_i+1; i != assignment_i; ++i)
597 libmesh_assert_equal_to(subexpression[i],
' ');
599 std::size_t end_assignment_i =
600 subexpression.find(
";", assignment_i+1);
602 libmesh_assert_not_equal_to(end_assignment_i, std::string::npos);
604 std::ostringstream new_subexpression;
605 new_subexpression << subexpression.substr(0, assignment_i+2)
606 << std::setprecision(std::numeric_limits<Output>::digits10+2)
607 #ifdef LIBMESH_USE_COMPLEX_NUMBERS
608 <<
'(' << newval.real() <<
'+'
609 << newval.imag() <<
'i' <<
')'
613 << subexpression.substr(end_assignment_i,
615 subexpression = new_subexpression.str();
618 libmesh_assert(found_var_name);
620 std::string new_expression;
622 for (
const auto & subexpression : _subexpressions)
624 new_expression +=
'{';
625 new_expression += subexpression;
626 new_expression +=
'}';
629 this->partial_reparse(new_expression);
633 template <
typename Output,
typename OutputGradient>
638 _expression = std::move(expression);
639 _subexpressions.clear();
642 size_t nextstart = 0, end = 0;
644 while (end != std::string::npos)
647 if (nextstart >= _expression.size())
651 if (_expression[nextstart] ==
'{')
654 end = _expression.find(
'}', nextstart);
658 end = std::string::npos;
661 _subexpressions.push_back
662 (_expression.substr(nextstart, (end == std::string::npos) ?
663 std::string::npos : end - nextstart));
666 libmesh_error_msg_if(_subexpressions.back().empty(),
667 "ERROR: FunctionParser is unable to parse empty expression.\n");
670 auto fp = std::make_unique<FunctionParserADBase<Output>>();
671 fp->AddConstant(
"NaN", std::numeric_limits<Real>::quiet_NaN());
672 fp->AddConstant(
"pi", std::acos(
Real(-1)));
673 fp->AddConstant(
"e", std::exp(
Real(1)));
675 (fp->Parse(_subexpressions.back(), variables) != -1,
676 "ERROR: FunctionParser is unable to parse expression: "
677 << _subexpressions.back() <<
'\n' << fp->ErrorMsg());
682 fp->SetADFlags(FunctionParserADBase<Output>::ADSilenceErrors |
683 FunctionParserADBase<Output>::ADAutoOptimize);
689 auto dx_fp = std::make_unique<FunctionParserADBase<Output>>(*fp);
690 if (dx_fp->AutoDiff(
"x") != -1)
691 _valid_derivatives =
false;
692 dx_parsers.push_back(std::move(dx_fp));
694 auto dy_fp = std::make_unique<FunctionParserADBase<Output>>(*fp);
695 if (dy_fp->AutoDiff(
"y") != -1)
696 _valid_derivatives =
false;
697 dy_parsers.push_back(std::move(dy_fp));
700 auto dz_fp = std::make_unique<FunctionParserADBase<Output>>(*fp);
701 if (dz_fp->AutoDiff(
"z") != -1)
702 _valid_derivatives =
false;
703 dz_parsers.push_back(std::move(dz_fp));
705 auto dt_fp = std::make_unique<FunctionParserADBase<Output>>(*fp);
706 if (dt_fp->AutoDiff(
"t") != -1)
707 _valid_derivatives =
false;
708 dt_parsers.push_back(std::move(dt_fp));
711 nextstart = (end == std::string::npos) ?
712 std::string::npos : end + 1;
715 parsers.push_back(std::move(fp));
720 template <
typename Output,
typename OutputGradient>
724 std::string_view expr)
const
726 const std::size_t namesize = varname.size();
727 std::size_t varname_i = expr.find(varname);
729 while ((varname_i != std::string::npos) &&
731 (std::isalnum(expr[varname_i-1]) ||
732 (expr[varname_i-1] ==
'_'))) ||
733 ((varname_i+namesize < expr.size()) &&
734 (std::isalnum(expr[varname_i+namesize]) ||
735 (expr[varname_i+namesize] ==
'_')))))
737 varname_i = expr.find(varname, varname_i+1);
742 template <
typename Output,
typename OutputGradient>
747 bool is_time_dependent =
false;
750 if (this->find_name(std::string(
"t"), expression) != std::string::npos)
751 is_time_dependent =
true;
753 return is_time_dependent;
757 template <
typename Output,
typename OutputGradient>
763 _spacetime[0] = p(0);
765 _spacetime[1] = p(1);
768 _spacetime[2] = p(2);
770 _spacetime[LIBMESH_DIM] = time;
776 template <
typename Output,
typename OutputGradient>
780 std::string_view function_name,
781 unsigned int component_idx)
const
783 Output result = parser.Eval(_spacetime.data());
784 int error_code = parser.EvalError();
787 libMesh::err <<
"ERROR: FunctionParser is unable to evaluate component "
792 for (
auto i : index_range(parsers))
793 if (parsers[i].
get() == &parser)
795 << _subexpressions[i];
798 for (
const auto & item : _spacetime)
803 std::string error_message =
"Reason: ";
808 error_message +=
"Division by zero";
811 error_message +=
"Square Root error (negative value)";
814 error_message +=
"Log error (negative value)";
817 error_message +=
"Trigonometric error (asin or acos of illegal value)";
820 error_message +=
"Maximum recursion level reached";
823 error_message +=
"Unknown";
826 libmesh_error_msg(error_message);
835 #else // !LIBMESH_HAVE_FPARSER
841 template <
typename Output=Number>
842 class ParsedFunction :
public FunctionBase<Output>
846 const std::vector<std::string> * =
nullptr,
847 const std::vector<Output> * =
nullptr) :
_dummy(0)
849 libmesh_not_implemented();
873 virtual std::unique_ptr<FunctionBase<Output>>
clone()
const
875 return std::make_unique<ParsedFunction<Output>>(
"");
886 #endif // LIBMESH_HAVE_FPARSER
888 #endif // LIBMESH_PARSED_FUNCTION_H
virtual Output dot(const Point &p, const Real time=0)
计算 ParsedFunction 在给定点上的点乘结果。
virtual std::unique_ptr< FunctionBase< Output > > clone() const
void set_inline_value(std::string_view inline_var_name, Output newval)
Changes the value of an inline variable.
Output eval(FunctionParserADBase< Output > &parser, std::string_view libmesh_dbg_var(function_name), unsigned int libmesh_dbg_var(component_idx)) const
评估第 i 个 FunctionParser 并检查结果。
virtual std::unique_ptr< FunctionBase< Output > > clone() const override
克隆 ParsedFunction 对象。
virtual void clear()
清除函数。
void partial_reparse(std::string expression)
重新解析数学表达式,仅对表达式进行轻微更改。
Output get_inline_value(std::string_view inline_var_name) const
获取内联变量的值。
通过解析数学表达式生成(通过 FParser)的函数。所有重写的虚拟函数在 function_base.h 中都有文档说明。
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)
设置 _spacetime 参数向量。
bool _initialized
当 init() 被调用以确保一切都准备好后,可以调用 operator() (...) 时为 true。
std::vector< std::string > _subexpressions
存储在数学表达式中找到的子表达式的字符串表示。
std::string _expression
存储数学表达式的字符串表示。
std::vector< std::unique_ptr< FunctionParserADBase< Output > > > dy_parsers
存储用于计算二维场景中 y 方向导数的解析器的集合。
std::vector< std::unique_ptr< FunctionParserADBase< Output > > > dt_parsers
存储用于计算时间导数的解析器的集合。
bool _valid_derivatives
用于跟踪导数是否有效的标志。
virtual Output & getVarAddress(std::string_view variable_name)
获取一个解析变量的地址,以便提供参数化的值。
std::size_t find_name(std::string_view varname, std::string_view expr) const
解析出变量名的辅助函数。
virtual Output component(unsigned int i, const Point &p, Real time) override
计算 ParsedFunction 的特定分量在给定点上的值。
ParsedFunction(std::string expression, const std::vector< std::string > *additional_vars=nullptr, const std::vector< Output > *initial_vals=nullptr)
构造函数。使用给定的数学表达式创建一个 ParsedFunction。
virtual ~ParsedFunction()=default
std::vector< std::unique_ptr< FunctionParserADBase< Output > > > dx_parsers
存储用于计算导数的解析器的集合。
virtual bool has_derivatives()
查询是否成功生成了自动导数。
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)
bool expression_is_time_dependent(std::string_view expression) const
检查表达式是否与时间有关。
std::vector< std::unique_ptr< FunctionParserADBase< Output > > > dz_parsers
存储用于计算三维场景中 z 方向导数的解析器的集合。
void reparse(std::string expression)
重新解析 ParsedFunction 的数学表达式。
FunctionBase是一个函数对象的基类,可以在某一点(可选地包括时间)进行评估。
std::vector< Output > _initial_vals
存储函数中变量的初始值。
virtual Output operator()(const Point &p, const Real time=0) override
计算 ParsedFunction 在给定点上的值。
const std::string & expression()
获取 ParsedFunction 的数学表达式。
std::string variables
存储函数中可以解析和处理的变量名称和值。
virtual void init()
实际的初始化过程。
virtual OutputGradient gradient(const Point &p, const Real time=0)
计算 ParsedFunction 在给定点上的梯度。