libMesh
Public Member Functions | Protected Member Functions | Private Attributes | List of all members
libMesh::ParsedFEMFunction< Output > Class Template Reference

ParsedFEMFunction provides support for FParser-based parsed functions in FEMSystem. More...

#include <parsed_fem_function.h>

Inheritance diagram for libMesh::ParsedFEMFunction< Output >:
[legend]

Public Member Functions

 ParsedFEMFunction (const System &sys, std::string expression, const std::vector< std::string > *additional_vars=nullptr, const std::vector< Output > *initial_vals=nullptr)
 Constructor. More...
 
ParsedFEMFunctionoperator= (const ParsedFEMFunction &)
 Constructors. More...
 
ParsedFEMFunctionoperator= (ParsedFEMFunction &&)=delete
 
 ParsedFEMFunction (const ParsedFEMFunction &)
 
 ParsedFEMFunction (ParsedFEMFunction &&)=default
 
virtual ~ParsedFEMFunction ()=default
 
void reparse (std::string expression)
 Re-parse with new expression. More...
 
virtual void init_context (const FEMContext &c) override
 Prepares a context object for use. More...
 
virtual std::unique_ptr< FEMFunctionBase< Output > > clone () const override
 
virtual Output operator() (const FEMContext &c, const Point &p, const Real time=0.) override
 
void operator() (const FEMContext &c, const Point &p, const Real time, DenseVector< Output > &output) override
 Evaluation function for time-dependent vector-valued functions. More...
 
virtual Output component (const FEMContext &c, unsigned int i, const Point &p, Real time=0.) override
 
const std::string & expression ()
 
Output get_inline_value (std::string_view inline_var_name) const
 
void set_inline_value (std::string_view inline_var_name, Output newval)
 Changes the value of an inline variable. More...
 
void operator() (const FEMContext &, const Point &p, DenseVector< Output > &output)
 Evaluation function for time-independent vector-valued functions. More...
 

Protected Member Functions

void partial_reparse (std::string expression)
 
std::size_t find_name (std::string_view varname, std::string_view expr) const
 
void eval_args (const FEMContext &c, const Point &p, const Real time)
 
Output eval (FunctionParserBase< Output > &parser, std::string_view libmesh_dbg_var(function_name), unsigned int libmesh_dbg_var(component_idx)) const
 
Output eval (char &libmesh_dbg_var(parser), std::string_view libmesh_dbg_var(function_name), unsigned int libmesh_dbg_var(component_idx)) const
 

Private Attributes

const System_sys
 
std::string _expression
 
std::vector< std::string > _subexpressions
 
unsigned int _n_vars
 
unsigned int _n_requested_vars
 
unsigned int _n_requested_grad_components
 
unsigned int _n_requested_hess_components
 
bool _requested_normals
 
std::vector< std::unique_ptr< FunctionParserBase< Output > > > parsers
 
std::vector< char * > parsers
 
std::vector< Output > _spacetime
 
std::vector< bool > _need_var
 
std::vector< bool > _need_var_grad
 
std::vector< bool > _need_var_hess
 
std::string variables
 
std::vector< std::string > _additional_vars
 
std::vector< Output > _initial_vals
 

Detailed Description

template<typename Output = Number>
class libMesh::ParsedFEMFunction< Output >

ParsedFEMFunction provides support for FParser-based parsed functions in FEMSystem.

All overridden virtual functions are documented in fem_function_base.h.

Author
Roy Stogner
Date
2014 Support for using parsed functions in FEMSystem.

Definition at line 57 of file parsed_fem_function.h.

Constructor & Destructor Documentation

◆ ParsedFEMFunction() [1/3]

template<typename Output>
libMesh::ParsedFEMFunction< Output >::ParsedFEMFunction ( const System sys,
std::string  expression,
const std::vector< std::string > *  additional_vars = nullptr,
const std::vector< Output > *  initial_vals = nullptr 
)
inlineexplicit

Constructor.

Definition at line 197 of file parsed_fem_function.h.

200  :
201  _sys(sys),
202  _expression (), // overridden by parse()
203  _n_vars(sys.n_vars()),
207  _requested_normals(false),
208  _need_var(_n_vars, false),
209  _need_var_grad(_n_vars*LIBMESH_DIM, false),
210 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
211  _need_var_hess(_n_vars*LIBMESH_DIM*LIBMESH_DIM, false),
212 #endif // LIBMESH_ENABLE_SECOND_DERIVATIVES
213  _additional_vars (additional_vars ? *additional_vars : std::vector<std::string>()),
214  _initial_vals (initial_vals ? *initial_vals : std::vector<Output>())
215 {
216  this->reparse(std::move(expression));
217 }
std::vector< bool > _need_var_grad
std::vector< Output > _initial_vals
std::vector< std::string > _additional_vars
void reparse(std::string expression)
Re-parse with new expression.
std::vector< bool > _need_var_hess
const std::string & expression()

◆ ParsedFEMFunction() [2/3]

template<typename Output>
libMesh::ParsedFEMFunction< Output >::ParsedFEMFunction ( const ParsedFEMFunction< Output > &  other)
inline

Definition at line 222 of file parsed_fem_function.h.

222  :
223  FEMFunctionBase<Output>(other),
224  _sys(other._sys),
225  _expression(other._expression),
226  _subexpressions(other._subexpressions),
227  _n_vars(other._n_vars),
228  _n_requested_vars(other._n_requested_vars),
229  _n_requested_grad_components(other._n_requested_grad_components),
230  _n_requested_hess_components(other._n_requested_hess_components),
231  _requested_normals(other._requested_normals),
232  _spacetime(other._spacetime),
233  _need_var(other._need_var),
234  _need_var_grad(other._need_var_grad),
235 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
236  _need_var_hess(other._need_var_hess),
237 #endif // LIBMESH_ENABLE_SECOND_DERIVATIVES
238  variables(other.variables),
239  _additional_vars(other._additional_vars),
240  _initial_vals(other._initial_vals)
241 {
242  this->reparse(_expression);
243 }
std::vector< bool > _need_var_grad
std::vector< Output > _initial_vals
std::vector< std::string > _additional_vars
std::vector< std::string > _subexpressions
std::vector< Output > _spacetime
void reparse(std::string expression)
Re-parse with new expression.
std::vector< bool > _need_var_hess

◆ ParsedFEMFunction() [3/3]

template<typename Output = Number>
libMesh::ParsedFEMFunction< Output >::ParsedFEMFunction ( ParsedFEMFunction< Output > &&  )
default

◆ ~ParsedFEMFunction()

template<typename Output = Number>
virtual libMesh::ParsedFEMFunction< Output >::~ParsedFEMFunction ( )
virtualdefault

Member Function Documentation

◆ clone()

template<typename Output >
std::unique_ptr< FEMFunctionBase< Output > > libMesh::ParsedFEMFunction< Output >::clone ( ) const
inlineoverridevirtual
Returns
A new copy of the function.

The new copy should be as "deep" as necessary to allow independent destruction and simultaneous evaluations of the copies in different threads.

Implements libMesh::FEMFunctionBase< Output >.

Definition at line 425 of file parsed_fem_function.h.

426 {
427  return std::make_unique<ParsedFEMFunction>
429 }
std::vector< Output > _initial_vals
std::vector< std::string > _additional_vars

◆ component()

template<typename Output >
Output libMesh::ParsedFEMFunction< Output >::component ( const FEMContext context,
unsigned int  i,
const Point p,
Real  time = 0. 
)
inlineoverridevirtual
Returns
The vector component i at coordinate p and time time.
Note
Subclasses aren't required to override this, since the default implementation is based on the full vector evaluation, which is often correct.
Subclasses are recommended to override this, since the default implementation is based on a vector evaluation, which is usually unnecessarily inefficient.

Reimplemented from libMesh::FEMFunctionBase< Output >.

Definition at line 467 of file parsed_fem_function.h.

471 {
472  eval_args(c, p, time);
473 
474  libmesh_assert_less (i, parsers.size());
475  return eval(*parsers[i], "f", i);
476 }
std::vector< std::unique_ptr< FunctionParserBase< Output > > > parsers
void eval_args(const FEMContext &c, const Point &p, const Real time)
Output eval(FunctionParserBase< Output > &parser, std::string_view libmesh_dbg_var(function_name), unsigned int libmesh_dbg_var(component_idx)) const

◆ eval() [1/2]

template<typename Output>
Output libMesh::ParsedFEMFunction< Output >::eval ( FunctionParserBase< Output > &  parser,
std::string_view   libmesh_dbg_varfunction_name,
unsigned int   libmesh_dbg_varcomponent_idx 
) const
inlineprotected

Definition at line 839 of file parsed_fem_function.h.

842 {
843 #ifndef NDEBUG
844  Output result = parser.Eval(_spacetime.data());
845  int error_code = parser.EvalError();
846  if (error_code)
847  {
848  libMesh::err << "ERROR: FunctionParser is unable to evaluate component "
849  << component_idx
850  << " for '"
851  << function_name;
852 
853  for (auto i : index_range(parsers))
854  if (parsers[i].get() == &parser)
855  libMesh::err << "' of expression '"
856  << _subexpressions[i];
857 
858  libMesh::err << "' with arguments:\n";
859  for (const auto & st : _spacetime)
860  libMesh::err << '\t' << st << '\n';
861  libMesh::err << '\n';
862 
863  // Currently no API to report error messages, we'll do it manually
864  std::string error_message = "Reason: ";
865 
866  switch (error_code)
867  {
868  case 1:
869  error_message += "Division by zero";
870  break;
871  case 2:
872  error_message += "Square Root error (negative value)";
873  break;
874  case 3:
875  error_message += "Log error (negative value)";
876  break;
877  case 4:
878  error_message += "Trigonometric error (asin or acos of illegal value)";
879  break;
880  case 5:
881  error_message += "Maximum recursion level reached";
882  break;
883  default:
884  error_message += "Unknown";
885  break;
886  }
887  libmesh_error_msg(error_message);
888  }
889 
890  return result;
891 #else
892  return parser.Eval(_spacetime.data());
893 #endif
894 }
OStreamProxy err
std::vector< std::string > _subexpressions
std::vector< Output > _spacetime
std::vector< std::unique_ptr< FunctionParserBase< Output > > > parsers
auto index_range(const T &sizable)
Helper function that returns an IntRange<std::size_t> representing all the indices of the passed-in v...
Definition: int_range.h:111

◆ eval() [2/2]

template<typename Output = Number>
Output libMesh::ParsedFEMFunction< Output >::eval ( char &  libmesh_dbg_varparser,
std::string_view   libmesh_dbg_varfunction_name,
unsigned int   libmesh_dbg_varcomponent_idx 
) const
inlineprotected

◆ eval_args()

template<typename Output >
void libMesh::ParsedFEMFunction< Output >::eval_args ( const FEMContext c,
const Point p,
const Real  time 
)
inlineprotected

Definition at line 710 of file parsed_fem_function.h.

713 {
714  _spacetime[0] = p(0);
715 #if LIBMESH_DIM > 1
716  _spacetime[1] = p(1);
717 #endif
718 #if LIBMESH_DIM > 2
719  _spacetime[2] = p(2);
720 #endif
721  _spacetime[LIBMESH_DIM] = time;
722 
723  unsigned int request_index = 0;
724  for (unsigned int v=0; v != _n_vars; ++v)
725  {
726  if (!_need_var[v])
727  continue;
728 
729  c.point_value(v, p, _spacetime[LIBMESH_DIM+1+request_index]);
730  request_index++;
731  }
732 
734  for (unsigned int v=0; v != _n_vars; ++v)
735  {
736  if (!_need_var_grad[v*LIBMESH_DIM]
737 #if LIBMESH_DIM > 1
738  && !_need_var_grad[v*LIBMESH_DIM+1]
739 #if LIBMESH_DIM > 2
740  && !_need_var_grad[v*LIBMESH_DIM+2]
741 #endif
742 #endif
743  )
744  continue;
745 
746  Gradient g;
747  c.point_gradient(v, p, g);
748 
749  for (unsigned int d=0; d != LIBMESH_DIM; ++d)
750  {
751  if (!_need_var_grad[v*LIBMESH_DIM+d])
752  continue;
753 
754  _spacetime[LIBMESH_DIM+1+request_index] = g(d);
755  request_index++;
756  }
757  }
758 
759 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
761  for (unsigned int v=0; v != _n_vars; ++v)
762  {
763  if (!_need_var_hess[v*LIBMESH_DIM*LIBMESH_DIM]
764 #if LIBMESH_DIM > 1
765  && !_need_var_hess[v*LIBMESH_DIM*LIBMESH_DIM+1]
766  && !_need_var_hess[v*LIBMESH_DIM*LIBMESH_DIM+2]
767  && !_need_var_hess[v*LIBMESH_DIM*LIBMESH_DIM+3]
768 #if LIBMESH_DIM > 2
769  && !_need_var_hess[v*LIBMESH_DIM*LIBMESH_DIM+4]
770  && !_need_var_hess[v*LIBMESH_DIM*LIBMESH_DIM+5]
771  && !_need_var_hess[v*LIBMESH_DIM*LIBMESH_DIM+6]
772  && !_need_var_hess[v*LIBMESH_DIM*LIBMESH_DIM+7]
773  && !_need_var_hess[v*LIBMESH_DIM*LIBMESH_DIM+8]
774 #endif
775 #endif
776  )
777  continue;
778 
779  Tensor h;
780  c.point_hessian(v, p, h);
781 
782  for (unsigned int d1=0; d1 != LIBMESH_DIM; ++d1)
783  for (unsigned int d2=0; d2 != LIBMESH_DIM; ++d2)
784  {
785  if (!_need_var_hess[v*LIBMESH_DIM*LIBMESH_DIM+d1*LIBMESH_DIM+d2])
786  continue;
787 
788  _spacetime[LIBMESH_DIM+1+request_index] = h(d1,d2);
789  request_index++;
790  }
791  }
792 #endif // LIBMESH_ENABLE_SECOND_DERIVATIVES
793 
794  if (_requested_normals)
795  {
796  FEBase * side_fe;
797  c.get_side_fe(0, side_fe);
798 
799  const std::vector<Point> & normals = side_fe->get_normals();
800 
801  const std::vector<Point> & xyz = side_fe->get_xyz();
802 
803  libmesh_assert_equal_to(normals.size(), xyz.size());
804 
805  // We currently only support normals at quadrature points!
806 #ifndef NDEBUG
807  bool at_quadrature_point = false;
808 #endif
809  for (auto qp : index_range(normals))
810  {
811  if (p == xyz[qp])
812  {
813  const Point & n = normals[qp];
814  for (unsigned int d=0; d != LIBMESH_DIM; ++d)
815  {
816  _spacetime[LIBMESH_DIM+1+request_index] = n(d);
817  request_index++;
818  }
819 #ifndef NDEBUG
820  at_quadrature_point = true;
821 #endif
822  break;
823  }
824  }
825 
826  libmesh_assert(at_quadrature_point);
827  }
828 
829  // The remaining locations in _spacetime are currently set at construction
830  // but could potentially be made dynamic
831 }
std::vector< bool > _need_var_grad
std::vector< Output > _spacetime
NumberVectorValue Gradient
libmesh_assert(ctx)
FEGenericBase< Real > FEBase
std::vector< bool > _need_var_hess
NumberTensorValue Tensor
auto index_range(const T &sizable)
Helper function that returns an IntRange<std::size_t> representing all the indices of the passed-in v...
Definition: int_range.h:111

◆ expression()

template<typename Output = Number>
const std::string& libMesh::ParsedFEMFunction< Output >::expression ( )
inline

Definition at line 107 of file parsed_fem_function.h.

107 { return _expression; }

◆ find_name()

template<typename Output >
std::size_t libMesh::ParsedFEMFunction< Output >::find_name ( std::string_view  varname,
std::string_view  expr 
) const
inlineprotected

Definition at line 684 of file parsed_fem_function.h.

686 {
687  const std::size_t namesize = varname.size();
688  std::size_t varname_i = expr.find(varname);
689 
690  while ((varname_i != std::string::npos) &&
691  (((varname_i > 0) &&
692  (std::isalnum(expr[varname_i-1]) ||
693  (expr[varname_i-1] == '_'))) ||
694  ((varname_i+namesize < expr.size()) &&
695  (std::isalnum(expr[varname_i+namesize]) ||
696  (expr[varname_i+namesize] == '_')))))
697  {
698  varname_i = expr.find(varname, varname_i+1);
699  }
700 
701  return varname_i;
702 }

◆ get_inline_value()

template<typename Output >
Output libMesh::ParsedFEMFunction< Output >::get_inline_value ( std::string_view  inline_var_name) const
inline
Returns
The value of an inline variable.
Note
Will only be correct if the inline variable value is independent of input variables, if the inline variable is not redefined within any subexpression, and if the inline variable takes the same value within any subexpressions where it appears.

Definition at line 481 of file parsed_fem_function.h.

Referenced by libMesh::ParsedFEMFunctionParameter< T >::get(), ParsedFEMFunctionTest::testInlineGetter(), and ParsedFEMFunctionTest::testInlineSetter().

482 {
483  libmesh_assert_greater (_subexpressions.size(), 0);
484 
485 #ifndef NDEBUG
486  bool found_var_name = false;
487 #endif
488  Output old_var_value(0.);
489 
490  for (const std::string & subexpression : _subexpressions)
491  {
492  const std::size_t varname_i =
493  find_name(inline_var_name, subexpression);
494  if (varname_i == std::string::npos)
495  continue;
496 
497  const std::size_t assignment_i =
498  subexpression.find(":", varname_i+1);
499 
500  libmesh_assert_not_equal_to(assignment_i, std::string::npos);
501 
502  libmesh_assert_equal_to(subexpression[assignment_i+1], '=');
503  for (std::size_t i = varname_i+1; i != assignment_i; ++i)
504  libmesh_assert_equal_to(subexpression[i], ' ');
505 
506  std::size_t end_assignment_i =
507  subexpression.find(";", assignment_i+1);
508 
509  libmesh_assert_not_equal_to(end_assignment_i, std::string::npos);
510 
511  std::string new_subexpression =
512  subexpression.substr(0, end_assignment_i+1).
513  append(inline_var_name);
514 
515 #ifdef LIBMESH_HAVE_FPARSER
516  // Parse and evaluate the new subexpression.
517  // Add the same constants as we used originally.
518  auto fp = std::make_unique<FunctionParserBase<Output>>();
519  fp->AddConstant("NaN", std::numeric_limits<Real>::quiet_NaN());
520  fp->AddConstant("pi", std::acos(Real(-1)));
521  fp->AddConstant("e", std::exp(Real(1)));
522  libmesh_error_msg_if
523  (fp->Parse(new_subexpression, variables) != -1, // -1 for success
524  "ERROR: FunctionParser is unable to parse modified expression: "
525  << new_subexpression << '\n' << fp->ErrorMsg());
526 
527  Output new_var_value = this->eval(*fp, new_subexpression, 0);
528 #ifdef NDEBUG
529  return new_var_value;
530 #else
531  if (found_var_name)
532  {
533  libmesh_assert_equal_to(old_var_value, new_var_value);
534  }
535  else
536  {
537  old_var_value = new_var_value;
538  found_var_name = true;
539  }
540 #endif
541 
542 #else
543  libmesh_error_msg("ERROR: This functionality requires fparser!");
544 #endif
545  }
546 
547  libmesh_assert(found_var_name);
548  return old_var_value;
549 }
std::size_t find_name(std::string_view varname, std::string_view expr) const
std::vector< std::string > _subexpressions
libmesh_assert(ctx)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
Output eval(FunctionParserBase< Output > &parser, std::string_view libmesh_dbg_var(function_name), unsigned int libmesh_dbg_var(component_idx)) const

◆ init_context()

template<typename Output >
void libMesh::ParsedFEMFunction< Output >::init_context ( const FEMContext )
inlineoverridevirtual

Prepares a context object for use.

Most problems will want to reimplement this for efficiency, in order to call FE::get_*() as their particular function requires.

Reimplemented from libMesh::FEMFunctionBase< Output >.

Definition at line 393 of file parsed_fem_function.h.

394 {
395  for (unsigned int v=0; v != _n_vars; ++v)
396  {
397  FEBase * elem_fe;
398  c.get_element_fe(v, elem_fe);
399  if (_n_requested_vars)
400  elem_fe->get_phi();
402  elem_fe->get_dphi();
403 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
405  elem_fe->get_d2phi();
406 #endif // LIBMESH_ENABLE_SECOND_DERIVATIVES
407  }
408 
409  if (_requested_normals)
410  {
411  FEBase * side_fe;
412  c.get_side_fe(0, side_fe);
413 
414  side_fe->get_normals();
415 
416  // FIXME: this is a hack to support normals at quadrature
417  // points; we don't support normals elsewhere.
418  side_fe->get_xyz();
419  }
420 }
FEGenericBase< Real > FEBase

◆ operator()() [1/3]

template<typename Output >
Output libMesh::ParsedFEMFunction< Output >::operator() ( const FEMContext ,
const Point p,
const Real  time = 0. 
)
inlineoverridevirtual
Returns
The scalar function value at coordinate p and time time, which defaults to zero.

Pure virtual, so you have to override it.

Implements libMesh::FEMFunctionBase< Output >.

Definition at line 434 of file parsed_fem_function.h.

437 {
438  eval_args(c, p, time);
439 
440  return eval(*parsers[0], "f", 0);
441 }
std::vector< std::unique_ptr< FunctionParserBase< Output > > > parsers
void eval_args(const FEMContext &c, const Point &p, const Real time)
Output eval(FunctionParserBase< Output > &parser, std::string_view libmesh_dbg_var(function_name), unsigned int libmesh_dbg_var(component_idx)) const

◆ operator()() [2/3]

template<typename Output >
void libMesh::FEMFunctionBase< Output >::operator() ( const FEMContext context,
const Point p,
DenseVector< Output > &  output 
)
inlineinherited

Evaluation function for time-independent vector-valued functions.

Sets output values in the passed-in output DenseVector.

Definition at line 144 of file fem_function_base.h.

147 {
148  // Call the time-dependent function with t=0.
149  this->operator()(context, p, 0., output);
150 }
virtual Output operator()(const FEMContext &, const Point &p, const Real time=0.)=0

◆ operator()() [3/3]

template<typename Output>
void libMesh::ParsedFEMFunction< Output >::operator() ( const FEMContext ,
const Point p,
const Real  time,
DenseVector< Output > &  output 
)
inlineoverridevirtual

Evaluation function for time-dependent vector-valued functions.

Sets output values in the passed-in output DenseVector.

Pure virtual, so you have to override it.

Implements libMesh::FEMFunctionBase< Output >.

Definition at line 448 of file parsed_fem_function.h.

452 {
453  eval_args(c, p, time);
454 
455  unsigned int size = output.size();
456 
457  libmesh_assert_equal_to (size, parsers.size());
458 
459  for (unsigned int i=0; i != size; ++i)
460  output(i) = eval(*parsers[i], "f", i);
461 }
std::vector< std::unique_ptr< FunctionParserBase< Output > > > parsers
void eval_args(const FEMContext &c, const Point &p, const Real time)
virtual unsigned int size() const override final
Definition: dense_vector.h:104
Output eval(FunctionParserBase< Output > &parser, std::string_view libmesh_dbg_var(function_name), unsigned int libmesh_dbg_var(component_idx)) const

◆ operator=() [1/2]

template<typename Output >
ParsedFEMFunction< Output > & libMesh::ParsedFEMFunction< Output >::operator= ( const ParsedFEMFunction< Output > &  other)
inline

Constructors.

  • This class contains a const reference so it can't be default copy or move-assigned. We manually implement the former
  • This class contains unique_ptrs so it can't be default copy constructed or assigned.
  • It can still be default moved and deleted.

Definition at line 249 of file parsed_fem_function.h.

250 {
251  // We can only be assigned another ParsedFEMFunction defined on the same System
252  libmesh_assert(&_sys == &other._sys);
253 
254  // Use copy-and-swap idiom
255  ParsedFEMFunction<Output> tmp(other);
256  std::swap(tmp, *this);
257  return *this;
258 }
libmesh_assert(ctx)

◆ operator=() [2/2]

template<typename Output = Number>
ParsedFEMFunction& libMesh::ParsedFEMFunction< Output >::operator= ( ParsedFEMFunction< Output > &&  )
delete

◆ partial_reparse()

template<typename Output >
void libMesh::ParsedFEMFunction< Output >::partial_reparse ( std::string  expression)
inlineprotected

Definition at line 620 of file parsed_fem_function.h.

621 {
622  _expression = std::move(expression);
623  _subexpressions.clear();
624  parsers.clear();
625 
626  size_t nextstart = 0, end = 0;
627 
628  while (end != std::string::npos)
629  {
630  // If we're past the end of the string, we can't make any more
631  // subparsers
632  if (nextstart >= _expression.size())
633  break;
634 
635  // If we're at the start of a brace delimited section, then we
636  // parse just that section:
637  if (_expression[nextstart] == '{')
638  {
639  nextstart++;
640  end = _expression.find('}', nextstart);
641  }
642  // otherwise we parse the whole thing
643  else
644  end = std::string::npos;
645 
646  // We either want the whole end of the string (end == npos) or
647  // a substring in the middle.
648  _subexpressions.push_back
649  (_expression.substr(nextstart, (end == std::string::npos) ?
650  std::string::npos : end - nextstart));
651 
652  // fparser can crash on empty expressions
653  libmesh_error_msg_if(_subexpressions.back().empty(),
654  "ERROR: FunctionParser is unable to parse empty expression.\n");
655 
656 
657 #ifdef LIBMESH_HAVE_FPARSER
658  // Parse (and optimize if possible) the subexpression.
659  // Add some basic constants, to Real precision.
660  auto fp = std::make_unique<FunctionParserBase<Output>>();
661  fp->AddConstant("NaN", std::numeric_limits<Real>::quiet_NaN());
662  fp->AddConstant("pi", std::acos(Real(-1)));
663  fp->AddConstant("e", std::exp(Real(1)));
664  libmesh_error_msg_if
665  (fp->Parse(_subexpressions.back(), variables) != -1, // -1 for success
666  "ERROR: FunctionParser is unable to parse expression: "
667  << _subexpressions.back() << '\n' << fp->ErrorMsg());
668  fp->Optimize();
669  parsers.push_back(std::move(fp));
670 #else
671  libmesh_error_msg("ERROR: This functionality requires fparser!");
672 #endif
673 
674  // If at end, use nextstart=maxSize. Else start at next
675  // character.
676  nextstart = (end == std::string::npos) ?
677  std::string::npos : end + 1;
678  }
679 }
std::vector< std::string > _subexpressions
std::vector< std::unique_ptr< FunctionParserBase< Output > > > parsers
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
const std::string & expression()

◆ reparse()

template<typename Output >
void libMesh::ParsedFEMFunction< Output >::reparse ( std::string  expression)
inline

Re-parse with new expression.

Definition at line 264 of file parsed_fem_function.h.

265 {
266  variables = "x";
267 #if LIBMESH_DIM > 1
268  variables += ",y";
269 #endif
270 #if LIBMESH_DIM > 2
271  variables += ",z";
272 #endif
273  variables += ",t";
274 
275  for (unsigned int v=0; v != _n_vars; ++v)
276  {
277  const std::string & varname = _sys.variable_name(v);
278  std::size_t varname_i = find_name(varname, expression);
279 
280  // If we didn't find our variable name then let's go to the
281  // next.
282  if (varname_i == std::string::npos)
283  continue;
284 
285  _need_var[v] = true;
286  variables += ',';
287  variables += varname;
289  }
290 
291  for (unsigned int v=0; v != _n_vars; ++v)
292  {
293  const std::string & varname = _sys.variable_name(v);
294 
295  for (unsigned int d=0; d != LIBMESH_DIM; ++d)
296  {
297  std::string gradname = std::string("grad_") +
298  "xyz"[d] + '_' + varname;
299  std::size_t gradname_i = find_name(gradname, expression);
300 
301  // If we didn't find that gradient component of our
302  // variable name then let's go to the next.
303  if (gradname_i == std::string::npos)
304  continue;
305 
306  _need_var_grad[v*LIBMESH_DIM+d] = true;
307  variables += ',';
308  variables += gradname;
310  }
311  }
312 
313 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
314  for (unsigned int v=0; v != _n_vars; ++v)
315  {
316  const std::string & varname = _sys.variable_name(v);
317 
318  for (unsigned int d1=0; d1 != LIBMESH_DIM; ++d1)
319  for (unsigned int d2=0; d2 != LIBMESH_DIM; ++d2)
320  {
321  std::string hessname = std::string("hess_") +
322  "xyz"[d1] + "xyz"[d2] + '_' + varname;
323  std::size_t hessname_i = find_name(hessname, expression);
324 
325  // If we didn't find that hessian component of our
326  // variable name then let's go to the next.
327  if (hessname_i == std::string::npos)
328  continue;
329 
330  _need_var_hess[v*LIBMESH_DIM*LIBMESH_DIM+d1*LIBMESH_DIM+d2]
331  = true;
332  variables += ',';
333  variables += hessname;
335  }
336  }
337 #endif // LIBMESH_ENABLE_SECOND_DERIVATIVES
338 
339  {
340  std::size_t nx_i = find_name("n_x", expression);
341  std::size_t ny_i = find_name("n_y", expression);
342  std::size_t nz_i = find_name("n_z", expression);
343 
344  // If we found any requests for normal components then we'll
345  // compute normals
346  if (nx_i != std::string::npos ||
347  ny_i != std::string::npos ||
348  nz_i != std::string::npos)
349  {
350  _requested_normals = true;
351  variables += ',';
352  variables += "n_x";
353  if (LIBMESH_DIM > 1)
354  {
355  variables += ',';
356  variables += "n_y";
357  }
358  if (LIBMESH_DIM > 2)
359  {
360  variables += ',';
361  variables += "n_z";
362  }
363  }
364  }
365 
366  _spacetime.resize
367  (LIBMESH_DIM + 1 + _n_requested_vars +
369  (_requested_normals ? LIBMESH_DIM : 0) +
370  _additional_vars.size());
371 
372  // If additional vars were passed, append them to the string
373  // that we send to the function parser. Also add them to the
374  // end of our spacetime vector
375  unsigned int offset = LIBMESH_DIM + 1 + _n_requested_vars +
377 
378  for (auto i : index_range(_additional_vars))
379  {
380  variables += "," + _additional_vars[i];
381  // Initialize extra variables to the vector passed in or zero
382  // Note: The initial_vals vector can be shorter than the additional_vars vector
383  _spacetime[offset + i] =
384  (i < _initial_vals.size()) ? _initial_vals[i] : 0;
385  }
386 
387  this->partial_reparse(std::move(expression));
388 }
std::vector< bool > _need_var_grad
std::vector< Output > _initial_vals
std::vector< std::string > _additional_vars
std::size_t find_name(std::string_view varname, std::string_view expr) const
void partial_reparse(std::string expression)
std::vector< Output > _spacetime
const std::string & variable_name(const unsigned int i) const
Definition: system.h:2397
std::vector< bool > _need_var_hess
auto index_range(const T &sizable)
Helper function that returns an IntRange<std::size_t> representing all the indices of the passed-in v...
Definition: int_range.h:111
const std::string & expression()

◆ set_inline_value()

template<typename Output>
void libMesh::ParsedFEMFunction< Output >::set_inline_value ( std::string_view  inline_var_name,
Output  newval 
)
inline

Changes the value of an inline variable.

Note
Forever after, the variable value will take the given constant, independent of input variables, in every subexpression where it is already defined.
Currently only works if the inline variable is not redefined within any one subexpression.

Definition at line 554 of file parsed_fem_function.h.

Referenced by libMesh::ParsedFEMFunctionParameter< T >::set(), and ParsedFEMFunctionTest::testInlineSetter().

556 {
557  libmesh_assert_greater (_subexpressions.size(), 0);
558 
559 #ifndef NDEBUG
560  bool found_var_name = false;
561 #endif
562  for (auto s : index_range(_subexpressions))
563  {
564  const std::string & subexpression = _subexpressions[s];
565  const std::size_t varname_i =
566  find_name(inline_var_name, subexpression);
567  if (varname_i == std::string::npos)
568  continue;
569 
570 #ifndef NDEBUG
571  found_var_name = true;
572 #endif
573 
574  const std::size_t assignment_i =
575  subexpression.find(":", varname_i+1);
576 
577  libmesh_assert_not_equal_to(assignment_i, std::string::npos);
578 
579  libmesh_assert_equal_to(subexpression[assignment_i+1], '=');
580  for (std::size_t i = varname_i+1; i != assignment_i; ++i)
581  libmesh_assert_equal_to(subexpression[i], ' ');
582 
583  std::size_t end_assignment_i =
584  subexpression.find(";", assignment_i+1);
585 
586  libmesh_assert_not_equal_to(end_assignment_i, std::string::npos);
587 
588  std::ostringstream new_subexpression;
589  new_subexpression << subexpression.substr(0, assignment_i+2)
590  << std::setprecision(std::numeric_limits<Output>::digits10+2)
591 #ifdef LIBMESH_USE_COMPLEX_NUMBERS
592  << '(' << newval.real() << '+'
593  << newval.imag() << 'i' << ')'
594 #else
595  << newval
596 #endif
597  << subexpression.substr(end_assignment_i,
598  std::string::npos);
599  _subexpressions[s] = new_subexpression.str();
600  }
601 
602  libmesh_assert(found_var_name);
603 
604  std::string new_expression;
605 
606  for (const auto & subexpression : _subexpressions)
607  {
608  new_expression += '{';
609  new_expression += subexpression;
610  new_expression += '}';
611  }
612 
613  this->partial_reparse(new_expression);
614 }
std::size_t find_name(std::string_view varname, std::string_view expr) const
std::vector< std::string > _subexpressions
void partial_reparse(std::string expression)
libmesh_assert(ctx)
auto index_range(const T &sizable)
Helper function that returns an IntRange<std::size_t> representing all the indices of the passed-in v...
Definition: int_range.h:111

Member Data Documentation

◆ _additional_vars

template<typename Output = Number>
std::vector<std::string> libMesh::ParsedFEMFunction< Output >::_additional_vars
private

Definition at line 188 of file parsed_fem_function.h.

◆ _expression

template<typename Output = Number>
std::string libMesh::ParsedFEMFunction< Output >::_expression
private

Definition at line 158 of file parsed_fem_function.h.

Referenced by libMesh::ParsedFEMFunction< T >::expression().

◆ _initial_vals

template<typename Output = Number>
std::vector<Output> libMesh::ParsedFEMFunction< Output >::_initial_vals
private

Definition at line 189 of file parsed_fem_function.h.

◆ _n_requested_grad_components

template<typename Output = Number>
unsigned int libMesh::ParsedFEMFunction< Output >::_n_requested_grad_components
private

Definition at line 160 of file parsed_fem_function.h.

◆ _n_requested_hess_components

template<typename Output = Number>
unsigned int libMesh::ParsedFEMFunction< Output >::_n_requested_hess_components
private

Definition at line 160 of file parsed_fem_function.h.

◆ _n_requested_vars

template<typename Output = Number>
unsigned int libMesh::ParsedFEMFunction< Output >::_n_requested_vars
private

Definition at line 160 of file parsed_fem_function.h.

◆ _n_vars

template<typename Output = Number>
unsigned int libMesh::ParsedFEMFunction< Output >::_n_vars
private

Definition at line 160 of file parsed_fem_function.h.

◆ _need_var

template<typename Output = Number>
std::vector<bool> libMesh::ParsedFEMFunction< Output >::_need_var
private

Definition at line 175 of file parsed_fem_function.h.

◆ _need_var_grad

template<typename Output = Number>
std::vector<bool> libMesh::ParsedFEMFunction< Output >::_need_var_grad
private

Definition at line 178 of file parsed_fem_function.h.

◆ _need_var_hess

template<typename Output = Number>
std::vector<bool> libMesh::ParsedFEMFunction< Output >::_need_var_hess
private

Definition at line 183 of file parsed_fem_function.h.

◆ _requested_normals

template<typename Output = Number>
bool libMesh::ParsedFEMFunction< Output >::_requested_normals
private

Definition at line 164 of file parsed_fem_function.h.

◆ _spacetime

template<typename Output = Number>
std::vector<Output> libMesh::ParsedFEMFunction< Output >::_spacetime
private

Definition at line 170 of file parsed_fem_function.h.

◆ _subexpressions

template<typename Output = Number>
std::vector<std::string> libMesh::ParsedFEMFunction< Output >::_subexpressions
private

Definition at line 159 of file parsed_fem_function.h.

◆ _sys

template<typename Output = Number>
const System& libMesh::ParsedFEMFunction< Output >::_sys
private

Definition at line 157 of file parsed_fem_function.h.

Referenced by libMesh::ParsedFEMFunction< T >::operator=().

◆ parsers [1/2]

template<typename Output = Number>
std::vector<std::unique_ptr<FunctionParserBase<Output> > > libMesh::ParsedFEMFunction< Output >::parsers
private

Definition at line 166 of file parsed_fem_function.h.

◆ parsers [2/2]

template<typename Output = Number>
std::vector<char*> libMesh::ParsedFEMFunction< Output >::parsers
private

Definition at line 168 of file parsed_fem_function.h.

◆ variables

template<typename Output = Number>
std::string libMesh::ParsedFEMFunction< Output >::variables
private

Definition at line 187 of file parsed_fem_function.h.


The documentation for this class was generated from the following file: