LCOV - code coverage report
Current view: top level - src/functions - ParsedOptimizationFunction.C (source / functions) Hit Total Coverage
Test: idaholab/moose optimization: #31405 (292dce) with base fef103 Lines: 59 78 75.6 %
Date: 2025-09-04 07:54:57 Functions: 5 7 71.4 %
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 "ParsedOptimizationFunction.h"
      11             : 
      12             : // MOOSE includes
      13             : #include "MooseUtils.h"
      14             : 
      15             : registerMooseObject("OptimizationApp", ParsedOptimizationFunction);
      16             : 
      17             : InputParameters
      18         721 : ParsedOptimizationFunction::validParams()
      19             : {
      20         721 :   InputParameters params = OptimizationFunction::validParams();
      21         721 :   params.addClassDescription(
      22             :       "Function used for optimization that uses a parsed expression with parameter dependence.");
      23             : 
      24        1442 :   params.addRequiredCustomTypeParam<std::string>(
      25             :       "expression", "FunctionExpression", "The user defined function.");
      26        1442 :   params.addRequiredParam<std::vector<std::string>>(
      27             :       "param_symbol_names", "Names of parameters in 'expression' being optimized.");
      28        1442 :   params.addRequiredParam<ReporterName>(
      29             :       "param_vector_name", "Reporter or VectorPostprocessor vector containing parameter values.");
      30         721 :   params.addParam<std::vector<std::string>>(
      31             :       "constant_symbol_names",
      32         721 :       std::vector<std::string>(),
      33             :       "Variables (excluding t,x,y,z) that are bound to the values provided by the corresponding "
      34             :       "items in the symbol_values vector.");
      35         721 :   params.addParam<std::vector<Real>>(
      36         721 :       "constant_symbol_values", std::vector<Real>(), "Constant numeric values for vars.");
      37         721 :   return params;
      38           0 : }
      39             : 
      40         364 : ParsedOptimizationFunction::ParsedOptimizationFunction(const InputParameters & parameters)
      41             :   : OptimizationFunction(parameters),
      42             :     ReporterInterface(this),
      43         364 :     _expression(getParam<std::string>("expression")),
      44         728 :     _param_names(getParam<std::vector<std::string>>("param_symbol_names")),
      45         364 :     _params(getReporterValue<std::vector<Real>>("param_vector_name")),
      46         728 :     _symbol_names(getParam<std::vector<std::string>>("constant_symbol_names")),
      47        1092 :     _symbol_values(getParam<std::vector<Real>>("constant_symbol_values"))
      48             : {
      49         364 :   if (_symbol_names.size() != _symbol_values.size())
      50           0 :     paramError("symbol_names", "Number of vars must match the number of vals for a ", type(), "!");
      51             : 
      52             :   // Loop through the variables assigned by the user and give an error if x,y,z,t are used
      53             :   std::string msg = "The variables \"x, y, z, and t\" in the ParsedFunction are pre-declared for "
      54         364 :                     "use and must not be declared.";
      55        1005 :   for (const auto & var : _param_names)
      56         641 :     if (var.find_first_of("xyzt") != std::string::npos && var.size() == 1)
      57           0 :       paramError("param_names", msg);
      58         364 :   for (const auto & var : _symbol_names)
      59           0 :     if (var.find_first_of("xyzt") != std::string::npos && var.size() == 1)
      60           0 :       paramError("symbol_names", msg);
      61             : 
      62             :   // Create parser
      63         728 :   _parser = std::make_unique<FunctionParserADBase<Real>>();
      64             : 
      65             :   // Add basic and user-defined constants
      66         728 :   _parser->AddConstant("NaN", std::numeric_limits<Real>::quiet_NaN());
      67         728 :   _parser->AddConstant("pi", libMesh::pi);
      68         364 :   _parser->AddConstant("e", std::exp(1.0));
      69         364 :   for (const auto & i : index_range(_symbol_names))
      70           0 :     _parser->AddConstant(_symbol_names[i], _symbol_values[i]);
      71             : 
      72             :   // Join xyzt and parameters to give to FParser as variables
      73         364 :   std::vector<std::string> all_vars = {"x", "y", "z", "t"};
      74         364 :   all_vars.insert(all_vars.end(), _param_names.begin(), _param_names.end());
      75             : 
      76             :   // Parse expression and error if something goes wrong
      77         728 :   if (_parser->Parse(_expression, MooseUtils::join(all_vars, ",")) != -1)
      78           0 :     paramError("expression", "Unable to parse expression\n", _parser->ErrorMsg());
      79             :   _parser->SetADFlags(FunctionParserADBase<Real>::ADAutoOptimize);
      80         364 :   _parser->Optimize();
      81             : 
      82             :   // Add parsers for each derivative we are taking, including xyzt
      83         364 :   _derivative_parsers.resize(all_vars.size());
      84        2461 :   for (const auto & i : index_range(all_vars))
      85             :   {
      86        4194 :     _derivative_parsers[i] = std::make_unique<FunctionParserADBase<Real>>(*_parser);
      87        2097 :     if (_derivative_parsers[i]->AutoDiff(all_vars[i]) != -1)
      88           0 :       paramError("expression",
      89             :                  "Unable to take derivative with respect to ",
      90             :                  all_vars[i],
      91             :                  "\n",
      92             :                  _derivative_parsers[i]->ErrorMsg());
      93             :   }
      94         728 : }
      95             : 
      96             : Real
      97     5671728 : ParsedOptimizationFunction::value(Real t, const Point & p) const
      98             : {
      99    11343456 :   return evaluateExpression(*_parser, t, p);
     100             : }
     101             : 
     102             : RealGradient
     103           0 : ParsedOptimizationFunction::gradient(Real t, const Point & p) const
     104             : {
     105             :   RealGradient result;
     106           0 :   result(0) = evaluateExpression(*_derivative_parsers[0], t, p, "gradient");
     107           0 :   result(1) = evaluateExpression(*_derivative_parsers[1], t, p, "gradient");
     108           0 :   result(2) = evaluateExpression(*_derivative_parsers[2], t, p, "gradient");
     109           0 :   return result;
     110             : }
     111             : 
     112             : Real
     113           0 : ParsedOptimizationFunction::timeDerivative(Real t, const Point & p) const
     114             : {
     115           0 :   return evaluateExpression(*_derivative_parsers[3], t, p, "time derivative");
     116             : }
     117             : 
     118             : std::vector<Real>
     119      136426 : ParsedOptimizationFunction::parameterGradient(Real t, const Point & p) const
     120             : {
     121      136426 :   std::vector<Real> result(_param_names.size());
     122      292662 :   for (const auto & i : index_range(result))
     123      156236 :     result[i] =
     124      312474 :         evaluateExpression(*_derivative_parsers[4 + i], t, p, _param_names[i] + " derivative");
     125      136424 :   return result;
     126           0 : }
     127             : 
     128             : Real
     129     5827966 : ParsedOptimizationFunction::evaluateExpression(FunctionParserADBase<Real> & parser,
     130             :                                                Real t,
     131             :                                                const Point & p,
     132             :                                                std::string name) const
     133             : {
     134     5827966 :   if (_params.size() != _param_names.size())
     135           2 :     paramError("param_vector_name",
     136             :                "Size of vector (",
     137             :                _params.size(),
     138             :                ") does not match number of specified 'param_names' (",
     139             :                _param_names.size(),
     140             :                ").");
     141             : 
     142     5827964 :   std::vector<Real> parser_var_values(4 + _param_names.size());
     143     5827964 :   parser_var_values[0] = p(0);
     144     5827964 :   parser_var_values[1] = p(1);
     145     5827964 :   parser_var_values[2] = p(2);
     146     5827964 :   parser_var_values[3] = t;
     147    11867884 :   for (const auto & i : index_range(_param_names))
     148     6039920 :     parser_var_values[4 + i] = _params[i];
     149             : 
     150     5827964 :   Real result = parser.Eval(parser_var_values.data());
     151             : 
     152     5827964 :   auto err = parser.EvalError();
     153     5827964 :   if (err)
     154             :   {
     155           0 :     std::string msg = "Error evaluating function " + name + "\n";
     156           0 :     switch (err)
     157             :     {
     158             :       case 1:
     159             :         msg += "Division by zero";
     160             :         break;
     161             :       case 2:
     162             :         msg += "Square Root error (negative value)";
     163             :         break;
     164             :       case 3:
     165             :         msg += "Log error (negative value)";
     166             :         break;
     167             :       case 4:
     168             :         msg += "Trigonometric error (asin or acos of illegal value)";
     169             :         break;
     170             :       case 5:
     171             :         msg += "Maximum recursion level reached";
     172             :         break;
     173             :     }
     174             : 
     175           0 :     paramError("expression", msg);
     176             :   }
     177             : 
     178     5827964 :   return result;
     179     5827964 : }

Generated by: LCOV version 1.14