20 #ifndef LIBMESH_PARSED_FEM_FUNCTION_H
21 #define LIBMESH_PARSED_FEM_FUNCTION_H
23 #include "libmesh/libmesh_config.h"
26 #include "libmesh/fem_function_base.h"
27 #include "libmesh/int_range.h"
28 #include "libmesh/point.h"
29 #include "libmesh/system.h"
31 #ifdef LIBMESH_HAVE_FPARSER
33 #include "libmesh/fparser.hh"
58 template <
typename Output=Number>
74 const std::vector<std::string> * additional_vars=
nullptr,
75 const std::vector<Output> * initial_vals=
nullptr);
102 void reparse (std::string expression);
109 virtual void init_context (
const FEMContext & c)
override;
116 virtual std::unique_ptr<FEMFunctionBase<Output>>
clone ()
const override;
127 virtual Output
operator() (
const FEMContext & c,
129 const Real time = 0.)
override;
155 virtual Output
component(
const FEMContext & c,
158 Real time=0.)
override;
209 std::size_t
find_name (std::string_view varname,
210 std::string_view expr)
const;
223 #ifdef LIBMESH_HAVE_FPARSER
233 inline Output
eval(FunctionParserBase<Output> & parser,
234 std::string_view libmesh_dbg_var(function_name),
235 unsigned int libmesh_dbg_var(component_idx))
const;
236 #else // LIBMESH_HAVE_FPARSER
246 inline Output
eval(
char & libmesh_dbg_var(parser),
247 std::string_view libmesh_dbg_var(function_name),
248 unsigned int libmesh_dbg_var(component_idx))
const;
260 #ifdef LIBMESH_HAVE_FPARSER
261 std::vector<std::unique_ptr<FunctionParserBase<Output>>>
parsers;
275 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
279 #endif // LIBMESH_ENABLE_SECOND_DERIVATIVES
290 template <
typename Output>
293 std::string expression,
294 const std::vector<std::string> * additional_vars,
295 const std::vector<Output> * initial_vals) :
298 _n_vars(sys.n_vars()),
299 _n_requested_vars(0),
300 _n_requested_grad_components(0),
301 _n_requested_hess_components(0),
302 _requested_normals(false),
303 _need_var(_n_vars, false),
304 _need_var_grad(_n_vars*LIBMESH_DIM, false),
305 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
306 _need_var_hess(_n_vars*LIBMESH_DIM*LIBMESH_DIM, false),
308 _additional_vars (additional_vars ? *additional_vars : std::vector<std::string>()),
309 _initial_vals (initial_vals ? *initial_vals : std::vector<Output>())
311 this->
reparse(std::move(expression));
315 template <
typename Output>
320 _expression(other._expression),
321 _subexpressions(other._subexpressions),
322 _n_vars(other._n_vars),
323 _n_requested_vars(other._n_requested_vars),
324 _n_requested_grad_components(other._n_requested_grad_components),
325 _n_requested_hess_components(other._n_requested_hess_components),
326 _requested_normals(other._requested_normals),
327 _spacetime(other._spacetime),
328 _need_var(other._need_var),
329 _need_var_grad(other._need_var_grad),
330 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
331 _need_var_hess(other._need_var_hess),
333 variables(other.variables),
334 _additional_vars(other._additional_vars),
335 _initial_vals(other._initial_vals)
341 template <
typename Output>
347 libmesh_assert(&_sys == &other.
_sys);
351 std::swap(tmp, *
this);
356 template <
typename Output>
370 for (
unsigned int v=0; v != _n_vars; ++v)
372 const std::string & varname = _sys.variable_name(v);
373 std::size_t varname_i = find_name(varname, expression);
377 if (varname_i == std::string::npos)
382 variables += varname;
386 for (
unsigned int v=0; v != _n_vars; ++v)
388 const std::string & varname = _sys.variable_name(v);
390 for (
unsigned int d=0; d != LIBMESH_DIM; ++d)
392 std::string gradname = std::string(
"grad_") +
393 "xyz"[d] +
'_' + varname;
394 std::size_t gradname_i = find_name(gradname, expression);
398 if (gradname_i == std::string::npos)
401 _need_var_grad[v*LIBMESH_DIM+d] =
true;
403 variables += gradname;
404 _n_requested_grad_components++;
408 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
409 for (
unsigned int v=0; v != _n_vars; ++v)
411 const std::string & varname = _sys.variable_name(v);
413 for (
unsigned int d1=0; d1 != LIBMESH_DIM; ++d1)
414 for (
unsigned int d2=0; d2 != LIBMESH_DIM; ++d2)
416 std::string hessname = std::string(
"hess_") +
417 "xyz"[d1] +
"xyz"[d2] +
'_' + varname;
418 std::size_t hessname_i = find_name(hessname, expression);
422 if (hessname_i == std::string::npos)
425 _need_var_hess[v*LIBMESH_DIM*LIBMESH_DIM+d1*LIBMESH_DIM+d2]
428 variables += hessname;
429 _n_requested_hess_components++;
432 #endif // LIBMESH_ENABLE_SECOND_DERIVATIVES
435 std::size_t nx_i = find_name(
"n_x", expression);
436 std::size_t ny_i = find_name(
"n_y", expression);
437 std::size_t nz_i = find_name(
"n_z", expression);
441 if (nx_i != std::string::npos ||
442 ny_i != std::string::npos ||
443 nz_i != std::string::npos)
445 _requested_normals =
true;
462 (LIBMESH_DIM + 1 + _n_requested_vars +
463 _n_requested_grad_components + _n_requested_hess_components +
464 (_requested_normals ? LIBMESH_DIM : 0) +
465 _additional_vars.size());
470 unsigned int offset = LIBMESH_DIM + 1 + _n_requested_vars +
471 _n_requested_grad_components + _n_requested_hess_components;
473 for (
auto i : index_range(_additional_vars))
475 variables +=
"," + _additional_vars[i];
478 _spacetime[offset + i] =
479 (i < _initial_vals.size()) ? _initial_vals[i] : 0;
482 this->partial_reparse(std::move(expression));
485 template <
typename Output>
490 for (
unsigned int v=0; v != _n_vars; ++v)
493 c.get_element_fe(v, elem_fe);
494 if (_n_requested_vars)
496 if (_n_requested_grad_components)
498 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
499 if (_n_requested_hess_components)
500 elem_fe->get_d2phi();
501 #endif // LIBMESH_ENABLE_SECOND_DERIVATIVES
504 if (_requested_normals)
507 c.get_side_fe(0, side_fe);
509 side_fe->get_normals();
517 template <
typename Output>
519 std::unique_ptr<FEMFunctionBase<Output>>
522 return std::make_unique<ParsedFEMFunction>
523 (_sys, _expression, &_additional_vars, &_initial_vals);
526 template <
typename Output>
533 eval_args(c, p, time);
535 return eval(*parsers[0],
"f", 0);
540 template <
typename Output>
548 eval_args(c, p, time);
550 unsigned int size = output.
size();
552 libmesh_assert_equal_to (size, parsers.size());
554 for (
unsigned int i=0; i != size; ++i)
555 output(i) = eval(*parsers[i],
"f", i);
559 template <
typename Output>
567 eval_args(c, p, time);
569 libmesh_assert_less (i, parsers.size());
570 return eval(*parsers[i],
"f", i);
573 template <
typename Output>
578 libmesh_assert_greater (_subexpressions.size(), 0);
581 bool found_var_name =
false;
583 Output old_var_value(0.);
585 for (
const std::string & subexpression : _subexpressions)
587 const std::size_t varname_i =
588 find_name(inline_var_name, subexpression);
589 if (varname_i == std::string::npos)
592 const std::size_t assignment_i =
593 subexpression.find(
":", varname_i+1);
595 libmesh_assert_not_equal_to(assignment_i, std::string::npos);
597 libmesh_assert_equal_to(subexpression[assignment_i+1],
'=');
598 for (std::size_t i = varname_i+1; i != assignment_i; ++i)
599 libmesh_assert_equal_to(subexpression[i],
' ');
601 std::size_t end_assignment_i =
602 subexpression.find(
";", assignment_i+1);
604 libmesh_assert_not_equal_to(end_assignment_i, std::string::npos);
606 std::string new_subexpression =
607 subexpression.substr(0, end_assignment_i+1).
608 append(inline_var_name);
610 #ifdef LIBMESH_HAVE_FPARSER
613 auto fp = std::make_unique<FunctionParserBase<Output>>();
614 fp->AddConstant(
"NaN", std::numeric_limits<Real>::quiet_NaN());
615 fp->AddConstant(
"pi", std::acos(
Real(-1)));
616 fp->AddConstant(
"e", std::exp(
Real(1)));
618 (fp->Parse(new_subexpression, variables) != -1,
619 "ERROR: FunctionParser is unable to parse modified expression: "
620 << new_subexpression <<
'\n' << fp->ErrorMsg());
622 Output new_var_value = this->eval(*fp, new_subexpression, 0);
624 return new_var_value;
628 libmesh_assert_equal_to(old_var_value, new_var_value);
632 old_var_value = new_var_value;
633 found_var_name =
true;
638 libmesh_error_msg(
"ERROR: This functionality requires fparser!");
642 libmesh_assert(found_var_name);
643 return old_var_value;
646 template <
typename Output>
652 libmesh_assert_greater (_subexpressions.size(), 0);
655 bool found_var_name =
false;
657 for (
auto s : index_range(_subexpressions))
659 const std::string & subexpression = _subexpressions[s];
660 const std::size_t varname_i =
661 find_name(inline_var_name, subexpression);
662 if (varname_i == std::string::npos)
666 found_var_name =
true;
669 const std::size_t assignment_i =
670 subexpression.find(
":", varname_i+1);
672 libmesh_assert_not_equal_to(assignment_i, std::string::npos);
674 libmesh_assert_equal_to(subexpression[assignment_i+1],
'=');
675 for (std::size_t i = varname_i+1; i != assignment_i; ++i)
676 libmesh_assert_equal_to(subexpression[i],
' ');
678 std::size_t end_assignment_i =
679 subexpression.find(
";", assignment_i+1);
681 libmesh_assert_not_equal_to(end_assignment_i, std::string::npos);
683 std::ostringstream new_subexpression;
684 new_subexpression << subexpression.substr(0, assignment_i+2)
685 << std::setprecision(std::numeric_limits<Output>::digits10+2)
686 #ifdef LIBMESH_USE_COMPLEX_NUMBERS
687 <<
'(' << newval.real() <<
'+'
688 << newval.imag() <<
'i' <<
')'
692 << subexpression.substr(end_assignment_i,
694 _subexpressions[s] = new_subexpression.str();
697 libmesh_assert(found_var_name);
699 std::string new_expression;
701 for (
const auto & subexpression : _subexpressions)
703 new_expression +=
'{';
704 new_expression += subexpression;
705 new_expression +=
'}';
708 this->partial_reparse(new_expression);
712 template <
typename Output>
717 _expression = std::move(expression);
718 _subexpressions.clear();
721 size_t nextstart = 0, end = 0;
723 while (end != std::string::npos)
727 if (nextstart >= _expression.size())
732 if (_expression[nextstart] ==
'{')
735 end = _expression.find(
'}', nextstart);
739 end = std::string::npos;
743 _subexpressions.push_back
744 (_expression.substr(nextstart, (end == std::string::npos) ?
745 std::string::npos : end - nextstart));
748 libmesh_error_msg_if(_subexpressions.back().empty(),
749 "ERROR: FunctionParser is unable to parse empty expression.\n");
752 #ifdef LIBMESH_HAVE_FPARSER
755 auto fp = std::make_unique<FunctionParserBase<Output>>();
756 fp->AddConstant(
"NaN", std::numeric_limits<Real>::quiet_NaN());
757 fp->AddConstant(
"pi", std::acos(
Real(-1)));
758 fp->AddConstant(
"e", std::exp(
Real(1)));
760 (fp->Parse(_subexpressions.back(), variables) != -1,
761 "ERROR: FunctionParser is unable to parse expression: "
762 << _subexpressions.back() <<
'\n' << fp->ErrorMsg());
764 parsers.push_back(std::move(fp));
766 libmesh_error_msg(
"ERROR: This functionality requires fparser!");
771 nextstart = (end == std::string::npos) ?
772 std::string::npos : end + 1;
776 template <
typename Output>
780 std::string_view expr)
const
782 const std::size_t namesize = varname.size();
783 std::size_t varname_i = expr.find(varname);
785 while ((varname_i != std::string::npos) &&
787 (std::isalnum(expr[varname_i-1]) ||
788 (expr[varname_i-1] ==
'_'))) ||
789 ((varname_i+namesize < expr.size()) &&
790 (std::isalnum(expr[varname_i+namesize]) ||
791 (expr[varname_i+namesize] ==
'_')))))
793 varname_i = expr.find(varname, varname_i+1);
802 template <
typename Output>
809 _spacetime[0] = p(0);
811 _spacetime[1] = p(1);
814 _spacetime[2] = p(2);
816 _spacetime[LIBMESH_DIM] = time;
818 unsigned int request_index = 0;
819 for (
unsigned int v=0; v != _n_vars; ++v)
824 c.point_value(v, p, _spacetime[LIBMESH_DIM+1+request_index]);
828 if (_n_requested_grad_components)
829 for (
unsigned int v=0; v != _n_vars; ++v)
831 if (!_need_var_grad[v*LIBMESH_DIM]
833 && !_need_var_grad[v*LIBMESH_DIM+1]
835 && !_need_var_grad[v*LIBMESH_DIM+2]
842 c.point_gradient(v, p, g);
844 for (
unsigned int d=0; d != LIBMESH_DIM; ++d)
846 if (!_need_var_grad[v*LIBMESH_DIM+d])
849 _spacetime[LIBMESH_DIM+1+request_index] = g(d);
854 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
855 if (_n_requested_hess_components)
856 for (
unsigned int v=0; v != _n_vars; ++v)
858 if (!_need_var_hess[v*LIBMESH_DIM*LIBMESH_DIM]
860 && !_need_var_hess[v*LIBMESH_DIM*LIBMESH_DIM+1]
861 && !_need_var_hess[v*LIBMESH_DIM*LIBMESH_DIM+2]
862 && !_need_var_hess[v*LIBMESH_DIM*LIBMESH_DIM+3]
864 && !_need_var_hess[v*LIBMESH_DIM*LIBMESH_DIM+4]
865 && !_need_var_hess[v*LIBMESH_DIM*LIBMESH_DIM+5]
866 && !_need_var_hess[v*LIBMESH_DIM*LIBMESH_DIM+6]
867 && !_need_var_hess[v*LIBMESH_DIM*LIBMESH_DIM+7]
868 && !_need_var_hess[v*LIBMESH_DIM*LIBMESH_DIM+8]
875 c.point_hessian(v, p, h);
877 for (
unsigned int d1=0; d1 != LIBMESH_DIM; ++d1)
878 for (
unsigned int d2=0; d2 != LIBMESH_DIM; ++d2)
880 if (!_need_var_hess[v*LIBMESH_DIM*LIBMESH_DIM+d1*LIBMESH_DIM+d2])
883 _spacetime[LIBMESH_DIM+1+request_index] = h(d1,d2);
887 #endif // LIBMESH_ENABLE_SECOND_DERIVATIVES
889 if (_requested_normals)
892 c.get_side_fe(0, side_fe);
894 const std::vector<Point> & normals = side_fe->get_normals();
896 const std::vector<Point> & xyz = side_fe->get_xyz();
898 libmesh_assert_equal_to(normals.size(), xyz.size());
902 bool at_quadrature_point =
false;
904 for (
auto qp : index_range(normals))
908 const Point & n = normals[qp];
909 for (
unsigned int d=0; d != LIBMESH_DIM; ++d)
911 _spacetime[LIBMESH_DIM+1+request_index] = n(d);
915 at_quadrature_point =
true;
921 libmesh_assert(at_quadrature_point);
930 #ifdef LIBMESH_HAVE_FPARSER
931 template <
typename Output>
935 std::string_view libmesh_dbg_var(function_name),
936 unsigned int libmesh_dbg_var(component_idx))
const
939 Output result = parser.Eval(_spacetime.data());
940 int error_code = parser.EvalError();
943 libMesh::err <<
"ERROR: FunctionParser is unable to evaluate component "
948 for (
auto i : index_range(parsers))
949 if (parsers[i].
get() == &parser)
951 << _subexpressions[i];
954 for (
const auto & st : _spacetime)
959 std::string error_message =
"Reason: ";
964 error_message +=
"Division by zero";
967 error_message +=
"Square Root error (negative value)";
970 error_message +=
"Log error (negative value)";
973 error_message +=
"Trigonometric error (asin or acos of illegal value)";
976 error_message +=
"Maximum recursion level reached";
979 error_message +=
"Unknown";
982 libmesh_error_msg(error_message);
987 return parser.Eval(_spacetime.data());
990 #else // LIBMESH_HAVE_FPARSER
991 template <
typename Output>
998 libmesh_error_msg(
"ERROR: This functionality requires fparser!");
1006 #endif // LIBMESH_PARSED_FEM_FUNCTION_H
Output get_inline_value(std::string_view inline_var_name) const
获取内联变量的值。
unsigned int _n_requested_vars
std::vector< bool > _need_var_grad
virtual void init_context(const FEMContext &c) override
初始化上下文。
std::vector< Output > _initial_vals
Output eval(FunctionParserBase< Output > &parser, std::string_view libmesh_dbg_var(function_name), unsigned int libmesh_dbg_var(component_idx)) const
评估第 i 个 FunctionParser 并检查结果。
std::vector< std::string > _additional_vars
此类定义了LIBMESH_DIM维的实数或复数空间中的向量。
std::vector< std::string > _subexpressions
void partial_reparse(std::string expression)
用于重新解析表达式的辅助函数。
std::vector< Output > _spacetime
virtual std::unique_ptr< FEMFunctionBase< Output > > clone() const override
克隆函数。
unsigned int _n_requested_grad_components
virtual Output operator()(const FEMContext &c, const Point &p, const Real time=0.) override
调用运算符,用于计算解析函数的值。
ParsedFEMFunction 提供对 FEMSystem 中基于 FParser 的解析函数的支持。
void reparse(std::string expression)
重新解析使用新表达式。
std::vector< std::unique_ptr< FunctionParserBase< Output > > > parsers
ParsedFEMFunction(const System &sys, std::string expression, const std::vector< std::string > *additional_vars=nullptr, const std::vector< Output > *initial_vals=nullptr)
构造函数。
ParsedFEMFunction & operator=(const ParsedFEMFunction &)
赋值运算符。
std::vector< bool > _need_var_hess
void set_inline_value(std::string_view inline_var_name, Output newval)
更改内联变量的值。
void eval_args(const FEMContext &c, const Point &p, const Real time)
用于计算函数参数的辅助函数。
unsigned int _n_requested_hess_components
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
std::vector< bool > _need_var
std::size_t find_name(std::string_view varname, std::string_view expr) const
用于解析变量名称的辅助函数。
virtual Output component(const FEMContext &c, unsigned int i, const Point &p, Real time=0.) override
计算解析函数的第 i 个分量的值。
std::vector< char * > parsers
FEMFunctionBase是一个基类,用户可以从中派生出“函数样式”的对象,以在FEMSystem中使用。
virtual unsigned int size() const overridefinal
const std::string & expression()
获取解析表达式。
此类定义了LIBMESH_DIM维度的实数或复数空间中的张量。typedef RealTensorValue总是定义为实数值的张量, 而NumberTensorValue则根据库的配置定义为实数或复数值...