LCOV - code coverage report
Current view: top level - src/utils - ExpressionBuilder.C (source / functions) Hit Total Coverage
Test: idaholab/moose phase_field: #31405 (292dce) with base fef103 Lines: 174 214 81.3 %
Date: 2025-09-04 07:55:36 Functions: 32 47 68.1 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //* This file is part of the MOOSE framework
       2             : //* https://mooseframework.inl.gov
       3             : //*
       4             : //* All rights reserved, see COPYRIGHT for full restrictions
       5             : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
       6             : //*
       7             : //* Licensed under LGPL 2.1, please see LICENSE for details
       8             : //* https://www.gnu.org/licenses/lgpl-2.1.html
       9             : 
      10             : #include "ExpressionBuilder.h"
      11             : 
      12             : ExpressionBuilder::EBTermList
      13         447 : operator, (const ExpressionBuilder::EBTerm & larg, const ExpressionBuilder::EBTerm & rarg)
      14             : {
      15        1341 :   return {larg, rarg};
      16           0 : }
      17             : 
      18             : ExpressionBuilder::EBTermList
      19           0 : operator, (const ExpressionBuilder::EBTerm & larg, const ExpressionBuilder::EBTermList & rargs)
      20             : {
      21           0 :   ExpressionBuilder::EBTermList list = {larg};
      22           0 :   list.insert(list.end(), rargs.begin(), rargs.end());
      23           0 :   return list;
      24           0 : }
      25             : 
      26             : ExpressionBuilder::EBTermList
      27         386 : operator, (const ExpressionBuilder::EBTermList & largs, const ExpressionBuilder::EBTerm & rarg)
      28             : {
      29         386 :   ExpressionBuilder::EBTermList list = largs;
      30         386 :   list.push_back(rarg);
      31         386 :   return list;
      32           0 : }
      33             : 
      34             : std::ostream &
      35        1449 : operator<<(std::ostream & os, const ExpressionBuilder::EBTerm & term)
      36             : {
      37        1449 :   if (term._root != NULL)
      38        1449 :     return os << *term._root;
      39             :   else
      40           0 :     return os << "[NULL]";
      41             : }
      42             : 
      43             : std::string
      44       36599 : ExpressionBuilder::EBSymbolNode::stringify() const
      45             : {
      46       36599 :   return _symbol;
      47             : }
      48             : 
      49             : std::string
      50           2 : ExpressionBuilder::EBTempIDNode::stringify() const
      51             : {
      52           2 :   std::ostringstream s;
      53           2 :   s << '[' << _id << ']';
      54           2 :   return s.str();
      55           2 : }
      56             : 
      57             : std::string
      58         864 : ExpressionBuilder::EBUnaryFuncTermNode::stringify() const
      59             : {
      60         864 :   const char * name[] = {
      61             :       "sin", "cos", "tan", "abs", "log", "log2", "log10", "exp", "sinh", "cosh", "tanh"};
      62         864 :   std::ostringstream s;
      63         864 :   s << name[_type] << '(' << *_subnode << ')';
      64         864 :   return s.str();
      65         864 : }
      66             : 
      67             : std::string
      68          74 : ExpressionBuilder::EBUnaryOpTermNode::stringify() const
      69             : {
      70          74 :   const char * name[] = {"-", "!"};
      71          74 :   std::ostringstream s;
      72             : 
      73          74 :   s << name[_type];
      74             : 
      75          74 :   if (_subnode->precedence() > precedence())
      76          73 :     s << '(' << *_subnode << ')';
      77             :   else
      78           1 :     s << *_subnode;
      79             : 
      80          74 :   return s.str();
      81          74 : }
      82             : 
      83             : std::string
      84         110 : ExpressionBuilder::EBBinaryFuncTermNode::stringify() const
      85             : {
      86         110 :   const char * name[] = {"min", "max", "atan2", "hypot", "plog"};
      87         110 :   std::ostringstream s;
      88         110 :   s << name[_type] << '(' << *_left << ',' << *_right << ')';
      89         110 :   return s.str();
      90         110 : }
      91             : 
      92             : std::string
      93       27096 : ExpressionBuilder::EBBinaryOpTermNode::stringify() const
      94             : {
      95       27096 :   const char * name[] = {"+", "-", "*", "/", "%", "^", "<", ">", "<=", ">=", "=", "!="};
      96       27096 :   std::ostringstream s;
      97             : 
      98       27096 :   if (_left->precedence() > precedence())
      99        2343 :     s << '(' << *_left << ')';
     100             :   else
     101       24753 :     s << *_left;
     102             : 
     103       27096 :   s << name[_type];
     104             : 
     105             :   // these operators are left associative at equal precedence
     106             :   // (this matters for -,/,&,^ but not for + and *)
     107       50301 :   if (_right->precedence() > precedence() ||
     108       23205 :       (_right->precedence() == precedence() &&
     109         110 :        (_type == SUB || _type == DIV || _type == MOD || _type == POW)))
     110        3964 :     s << '(' << *_right << ')';
     111             :   else
     112       23132 :     s << *_right;
     113             : 
     114       27096 :   return s.str();
     115       27096 : }
     116             : 
     117             : int
     118      108904 : ExpressionBuilder::EBBinaryOpTermNode::precedence() const
     119             : {
     120      108904 :   switch (_type)
     121             :   {
     122             :     case ADD:
     123             :     case SUB:
     124             :       return 6;
     125             :     case MUL:
     126             :     case DIV:
     127             :     case MOD:
     128             :       return 5;
     129             :     case POW:
     130             :       return 2;
     131             :     case LESS:
     132             :     case GREATER:
     133             :     case LESSEQ:
     134             :     case GREATEREQ:
     135             :       return 8;
     136             :     case EQ:
     137             :     case NOTEQ:
     138             :       return 9;
     139             :   }
     140             : 
     141           0 :   mooseError("Unknown type.");
     142             : }
     143             : 
     144             : std::string
     145           3 : ExpressionBuilder::EBTernaryFuncTermNode::stringify() const
     146             : {
     147             :   const char * name[] = {"if"};
     148           3 :   std::ostringstream s;
     149           3 :   s << name[_type] << '(' << *_left << ',' << *_middle << ',' << *_right << ')';
     150           3 :   return s.str();
     151           3 : }
     152             : 
     153             : ExpressionBuilder::EBFunction &
     154        1009 : ExpressionBuilder::EBFunction::operator()(const ExpressionBuilder::EBTerm & arg)
     155             : {
     156        3027 :   this->_eval_arguments = {arg};
     157        1009 :   return *this;
     158             : }
     159             : 
     160             : ExpressionBuilder::EBFunction &
     161         447 : ExpressionBuilder::EBFunction::operator()(const ExpressionBuilder::EBTermList & args)
     162             : {
     163         447 :   this->_eval_arguments = EBTermList(args);
     164         447 :   return *this;
     165             : }
     166             : 
     167             : ExpressionBuilder::EBFunction &
     168        1447 : ExpressionBuilder::EBFunction::operator=(const ExpressionBuilder::EBTerm & term)
     169             : {
     170        1447 :   this->_arguments = this->_eval_arguments;
     171        1447 :   this->_term = term;
     172        1447 :   return *this;
     173             : }
     174             : 
     175             : ExpressionBuilder::EBFunction &
     176           0 : ExpressionBuilder::EBFunction::operator=(const ExpressionBuilder::EBFunction & func)
     177             : {
     178           0 :   this->_arguments = this->_eval_arguments;
     179           0 :   this->_term = EBTerm(func);
     180           0 :   return *this;
     181             : }
     182             : 
     183        1451 : ExpressionBuilder::EBFunction::operator ExpressionBuilder::EBTerm() const
     184             : {
     185        1451 :   unsigned int narg = _arguments.size();
     186        1451 :   if (narg != _eval_arguments.size())
     187           0 :     mooseError("EBFunction is used wth a different number of arguments than it was defined with.");
     188             : 
     189             :   // prepare a copy of the function term to perform the substitution on
     190        1451 :   EBTerm result(_term);
     191             : 
     192             :   // prepare a rule list for the substitutions
     193             :   EBSubstitutionRuleList rules;
     194        3720 :   for (unsigned i = 0; i < narg; ++i)
     195        2269 :     rules.push_back(new EBTermSubstitution(_arguments[i], _eval_arguments[i]));
     196             : 
     197             :   // perform substitution
     198        1451 :   result.substitute(rules);
     199             : 
     200             :   // discard rule set
     201        3720 :   for (unsigned i = 0; i < narg; ++i)
     202        2269 :     delete rules[i];
     203             : 
     204        1451 :   return result;
     205        1451 : }
     206             : 
     207        1447 : ExpressionBuilder::EBFunction::operator std::string() const
     208             : {
     209        1447 :   EBTerm eval;
     210        1447 :   eval = *this; // typecast EBFunction -> EBTerm performs a parameter substitution
     211        1447 :   std::ostringstream s;
     212        1447 :   s << eval;
     213        1447 :   return s.str();
     214        1447 : }
     215             : 
     216             : std::string
     217           1 : ExpressionBuilder::EBFunction::args()
     218             : {
     219           1 :   unsigned int narg = _arguments.size();
     220           1 :   if (narg < 1)
     221           0 :     return "";
     222             : 
     223           1 :   std::ostringstream s;
     224           1 :   s << _arguments[0];
     225           2 :   for (unsigned int i = 1; i < narg; ++i)
     226           1 :     s << ',' << _arguments[i];
     227             : 
     228             :   return s.str();
     229           1 : }
     230             : 
     231             : unsigned int
     232          36 : ExpressionBuilder::EBFunction::substitute(const EBSubstitutionRule & rule)
     233             : {
     234          36 :   return _term.substitute(rule);
     235             : }
     236             : 
     237             : unsigned int
     238           0 : ExpressionBuilder::EBFunction::substitute(const EBSubstitutionRuleList & rules)
     239             : {
     240           0 :   return _term.substitute(rules);
     241             : }
     242             : 
     243             : #define UNARY_FUNC_IMPLEMENT(op, OP)                                                               \
     244             :   ExpressionBuilder::EBTerm op(const ExpressionBuilder::EBTerm & term)                             \
     245             :   {                                                                                                \
     246             :     mooseAssert(term._root != NULL, "Empty term provided as argument of function " #op "()");      \
     247             :     return ExpressionBuilder::EBTerm(new ExpressionBuilder::EBUnaryFuncTermNode(                   \
     248             :         term.cloneRoot(), ExpressionBuilder::EBUnaryFuncTermNode::OP));                            \
     249             :   }
     250           0 : UNARY_FUNC_IMPLEMENT(sin, SIN)
     251           0 : UNARY_FUNC_IMPLEMENT(cos, COS)
     252           0 : UNARY_FUNC_IMPLEMENT(tan, TAN)
     253           0 : UNARY_FUNC_IMPLEMENT(abs, ABS)
     254         325 : UNARY_FUNC_IMPLEMENT(log, LOG)
     255           0 : UNARY_FUNC_IMPLEMENT(log2, LOG2)
     256           0 : UNARY_FUNC_IMPLEMENT(log10, LOG10)
     257           0 : UNARY_FUNC_IMPLEMENT(exp, EXP)
     258           0 : UNARY_FUNC_IMPLEMENT(sinh, SINH)
     259           0 : UNARY_FUNC_IMPLEMENT(cosh, COSH)
     260         612 : UNARY_FUNC_IMPLEMENT(tanh, TANH)
     261             : 
     262             : #define BINARY_FUNC_IMPLEMENT(op, OP)                                                              \
     263             :   ExpressionBuilder::EBTerm op(const ExpressionBuilder::EBTerm & left,                             \
     264             :                                const ExpressionBuilder::EBTerm & right)                            \
     265             :   {                                                                                                \
     266             :     mooseAssert(left._root != NULL,                                                                \
     267             :                 "Empty term provided as first argument of function " #op "()");                    \
     268             :     mooseAssert(right._root != NULL,                                                               \
     269             :                 "Empty term provided as second argument of function " #op "()");                   \
     270             :     return ExpressionBuilder::EBTerm(new ExpressionBuilder::EBBinaryFuncTermNode(                  \
     271             :         left.cloneRoot(), right.cloneRoot(), ExpressionBuilder::EBBinaryFuncTermNode::OP));        \
     272             :   }
     273           0 : BINARY_FUNC_IMPLEMENT(min, MIN)
     274           0 : BINARY_FUNC_IMPLEMENT(max, MAX)
     275           1 : BINARY_FUNC_IMPLEMENT(atan2, ATAN2)
     276           0 : BINARY_FUNC_IMPLEMENT(hypot, HYPOT)
     277          36 : BINARY_FUNC_IMPLEMENT(plog, PLOG)
     278             : 
     279             : // this is a function in ExpressionBuilder (pow) but an operator in FParser (^)
     280             : ExpressionBuilder::EBTerm
     281           2 : pow(const ExpressionBuilder::EBTerm & left, const ExpressionBuilder::EBTerm & right)
     282             : {
     283             :   mooseAssert(left._root != NULL, "Empty term for base of pow()");
     284             :   mooseAssert(right._root != NULL, "Empty term for exponent of pow()");
     285             :   return ExpressionBuilder::EBTerm(new ExpressionBuilder::EBBinaryOpTermNode(
     286           2 :       left.cloneRoot(), right.cloneRoot(), ExpressionBuilder::EBBinaryOpTermNode::POW));
     287             : }
     288             : 
     289             : #define TERNARY_FUNC_IMPLEMENT(op, OP)                                                             \
     290             :   ExpressionBuilder::EBTerm op(const ExpressionBuilder::EBTerm & left,                             \
     291             :                                const ExpressionBuilder::EBTerm & middle,                           \
     292             :                                const ExpressionBuilder::EBTerm & right)                            \
     293             :   {                                                                                                \
     294             :     mooseAssert(left._root != NULL,                                                                \
     295             :                 "Empty term provided as first argument of the ternary function " #op "()");        \
     296             :     mooseAssert(middle._root != NULL,                                                              \
     297             :                 "Empty term provided as second argument of the ternary function " #op "()");       \
     298             :     mooseAssert(right._root != NULL,                                                               \
     299             :                 "Empty term provided as third argument of the ternary function " #op "()");        \
     300             :     return ExpressionBuilder::EBTerm(new ExpressionBuilder::EBTernaryFuncTermNode(                 \
     301             :         left.cloneRoot(),                                                                          \
     302             :         middle.cloneRoot(),                                                                        \
     303             :         right.cloneRoot(),                                                                         \
     304             :         ExpressionBuilder::EBTernaryFuncTermNode::OP));                                            \
     305             :   }
     306           3 : TERNARY_FUNC_IMPLEMENT(conditional, CONDITIONAL)
     307             : 
     308             : unsigned int
     309         939 : ExpressionBuilder::EBUnaryTermNode::substitute(const EBSubstitutionRuleList & rules)
     310             : {
     311         939 :   unsigned int nrule = rules.size();
     312             : 
     313        1879 :   for (unsigned int i = 0; i < nrule; ++i)
     314             :   {
     315        1048 :     EBTermNode * replace = rules[i]->apply(_subnode);
     316        1048 :     if (replace != NULL)
     317             :     {
     318         108 :       delete _subnode;
     319         108 :       _subnode = replace;
     320         108 :       return 1;
     321             :     }
     322             :   }
     323             : 
     324         831 :   return _subnode->substitute(rules);
     325             : }
     326             : 
     327             : unsigned int
     328       21609 : ExpressionBuilder::EBBinaryTermNode::substitute(const EBSubstitutionRuleList & rules)
     329             : {
     330       21609 :   unsigned int nrule = rules.size();
     331             :   unsigned int success = 0;
     332             : 
     333       66599 :   for (unsigned int i = 0; i < nrule; ++i)
     334             :   {
     335       47961 :     EBTermNode * replace = rules[i]->apply(_left);
     336       47961 :     if (replace != NULL)
     337             :     {
     338        2971 :       delete _left;
     339        2971 :       _left = replace;
     340             :       success = 1;
     341             :       break;
     342             :     }
     343             :   }
     344             : 
     345             :   if (success == 0)
     346       18638 :     success += _left->substitute(rules);
     347             : 
     348       65145 :   for (unsigned int i = 0; i < nrule; ++i)
     349             :   {
     350       50980 :     EBTermNode * replace = rules[i]->apply(_right);
     351       50980 :     if (replace != NULL)
     352             :     {
     353        7444 :       delete _right;
     354        7444 :       _right = replace;
     355        7444 :       return success + 1;
     356             :     }
     357             :   }
     358             : 
     359       14165 :   return success + _right->substitute(rules);
     360             : }
     361             : 
     362             : unsigned int
     363           2 : ExpressionBuilder::EBTernaryTermNode::substitute(const EBSubstitutionRuleList & rules)
     364             : {
     365           2 :   unsigned int nrule = rules.size();
     366             :   bool left_success = false, middle_success = false, right_success = false;
     367             :   EBTermNode * replace;
     368             : 
     369           5 :   for (unsigned int i = 0; i < nrule; ++i)
     370             :   {
     371           3 :     replace = rules[i]->apply(_left);
     372           3 :     if (replace)
     373             :     {
     374           0 :       delete _left;
     375           0 :       _left = replace;
     376             :       left_success = true;
     377           0 :       break;
     378             :     }
     379             :   }
     380             : 
     381           5 :   for (unsigned int i = 0; i < nrule; ++i)
     382             :   {
     383           3 :     replace = rules[i]->apply(_middle);
     384           3 :     if (replace)
     385             :     {
     386           0 :       delete _middle;
     387           0 :       _middle = replace;
     388             :       middle_success = true;
     389           0 :       break;
     390             :     }
     391             :   }
     392             : 
     393           5 :   for (unsigned int i = 0; i < nrule; ++i)
     394             :   {
     395           3 :     replace = rules[i]->apply(_right);
     396           3 :     if (replace)
     397             :     {
     398           0 :       delete _right;
     399           0 :       _right = replace;
     400             :       right_success = true;
     401           0 :       break;
     402             :     }
     403             :   }
     404             : 
     405           2 :   if (!left_success)
     406           2 :     left_success = _left->substitute(rules);
     407           2 :   if (!middle_success)
     408           2 :     middle_success = _middle->substitute(rules);
     409           2 :   if (!right_success)
     410           2 :     right_success = _right->substitute(rules);
     411             : 
     412           2 :   return left_success + middle_success + right_success;
     413             : }
     414             : 
     415             : unsigned int
     416          38 : ExpressionBuilder::EBTerm::substitute(const EBSubstitutionRule & rule)
     417             : {
     418          38 :   EBSubstitutionRuleList rules(1);
     419          38 :   rules[0] = &rule;
     420          76 :   return substitute(rules);
     421          38 : }
     422             : 
     423             : unsigned int
     424        1490 : ExpressionBuilder::EBTerm::substitute(const EBSubstitutionRuleList & rules)
     425             : {
     426        1490 :   unsigned int nrule = rules.size();
     427             : 
     428        1490 :   if (_root == NULL)
     429             :     return 0;
     430             : 
     431        3798 :   for (unsigned int i = 0; i < nrule; ++i)
     432             :   {
     433        2309 :     EBTermNode * replace = rules[i]->apply(_root);
     434        2309 :     if (replace != NULL)
     435             :     {
     436           1 :       delete _root;
     437           1 :       _root = replace;
     438           1 :       return 1;
     439             :     }
     440             :   }
     441             : 
     442        1489 :   return _root->substitute(rules);
     443             : }
     444             : 
     445        2272 : ExpressionBuilder::EBTermSubstitution::EBTermSubstitution(const EBTerm & find,
     446        2272 :                                                           const EBTerm & replace)
     447             : {
     448             :   // the expression we want to substitute (has to be a symbol node)
     449        2272 :   const EBSymbolNode * find_root = dynamic_cast<const EBSymbolNode *>(find.getRoot());
     450        2272 :   if (find_root == NULL)
     451           0 :     mooseError("Function arguments must be pure symbols.");
     452        4544 :   _find = find_root->stringify();
     453             : 
     454             :   // the term we want to substitute with
     455        2272 :   if (replace.getRoot() != NULL)
     456        2272 :     _replace = replace.cloneRoot();
     457             :   else
     458           0 :     mooseError("Trying to substitute in an empty term for ", _find);
     459        2272 : }
     460             : 
     461             : ExpressionBuilder::EBTermNode *
     462       20956 : ExpressionBuilder::EBTermSubstitution::substitute(const EBSymbolNode & node) const
     463             : {
     464       20956 :   if (node.stringify() == _find)
     465       10451 :     return _replace->clone();
     466             :   else
     467             :     return NULL;
     468             : }
     469             : 
     470             : ExpressionBuilder::EBTermNode *
     471          73 : ExpressionBuilder::EBLogPlogSubstitution::substitute(const EBUnaryFuncTermNode & node) const
     472             : {
     473          73 :   if (node._type == EBUnaryFuncTermNode::LOG)
     474             :     return new EBBinaryFuncTermNode(
     475          73 :         node.getSubnode()->clone(), _epsilon->clone(), EBBinaryFuncTermNode::PLOG);
     476             :   else
     477             :     return NULL;
     478             : }

Generated by: LCOV version 1.14