LCOV - code coverage report
Current view: top level - src/scalarkernels - ParsedODEKernel.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #31706 (f8ed4a) with base bb0a08 Lines: 75 82 91.5 %
Date: 2025-11-03 17:23:24 Functions: 6 6 100.0 %
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 "ParsedODEKernel.h"
      11             : 
      12             : // MOOSE includes
      13             : #include "MooseVariableScalar.h"
      14             : #include "SystemBase.h"
      15             : #include "MooseApp.h"
      16             : 
      17             : #include "libmesh/fparser_ad.hh"
      18             : 
      19             : registerMooseObject("MooseApp", ParsedODEKernel);
      20             : 
      21             : InputParameters
      22       16051 : ParsedODEKernel::validParams()
      23             : {
      24       16051 :   InputParameters params = ODEKernel::validParams();
      25       16051 :   params += FunctionParserUtils<false>::validParams();
      26       32102 :   params.addClassDescription("Parsed expression ODE kernel.");
      27             : 
      28       96306 :   params.addRequiredCustomTypeParam<std::string>(
      29             :       "expression", "FunctionExpression", "function expression");
      30       64204 :   params.addCoupledVar("coupled_variables", "Scalar variables coupled in the parsed expression.");
      31       64204 :   params.addParam<std::vector<std::string>>(
      32             :       "constant_names", {}, "Vector of constants used in the parsed expression");
      33       64204 :   params.addParam<std::vector<std::string>>(
      34             :       "constant_expressions",
      35             :       {},
      36             :       "Vector of values for the constants in constant_names (can be an FParser expression)");
      37       48153 :   params.addParam<std::vector<PostprocessorName>>(
      38             :       "postprocessors", {}, "Vector of postprocessor names used in the function expression");
      39             : 
      40       16051 :   return params;
      41           0 : }
      42             : 
      43         588 : ParsedODEKernel::ParsedODEKernel(const InputParameters & parameters)
      44             :   : ODEKernel(parameters),
      45             :     FunctionParserUtils(parameters),
      46         588 :     _function(getParam<std::string>("expression")),
      47        1530 :     _nargs(isCoupledScalar("coupled_variables") ? coupledScalarComponents("coupled_variables") : 0),
      48        1176 :     _args(_nargs),
      49        1176 :     _arg_names(_nargs),
      50        1176 :     _func_dFdarg(_nargs),
      51         588 :     _number_of_nl_variables(_sys.nVariables()),
      52        2352 :     _arg_index(_number_of_nl_variables, -1)
      53             : {
      54             :   // build variables argument (start with variable the kernel is operating on)
      55         588 :   std::string variables = _var.name();
      56             : 
      57             :   // add additional coupled variables
      58         836 :   for (unsigned int i = 0; i < _nargs; ++i)
      59             :   {
      60         496 :     _arg_names[i] = getScalarVar("coupled_variables", i)->name();
      61         248 :     variables += "," + _arg_names[i];
      62         496 :     _args[i] = &coupledScalarValue("coupled_variables", i);
      63             : 
      64             :     // populate number -> arg index lookup table skipping aux variables
      65         496 :     unsigned int number = coupledScalar("coupled_variables", i);
      66         248 :     if (number < _number_of_nl_variables)
      67         248 :       _arg_index[number] = i;
      68             :   }
      69             : 
      70             :   // add postprocessors
      71        1176 :   auto pp_names = getParam<std::vector<PostprocessorName>>("postprocessors");
      72         588 :   _pp.resize(pp_names.size());
      73         601 :   for (unsigned int i = 0; i < pp_names.size(); ++i)
      74             :   {
      75          13 :     variables += "," + pp_names[i];
      76          13 :     _pp[i] = &getPostprocessorValueByName(pp_names[i]);
      77             :   }
      78             : 
      79             :   // Note: we do not use the FunctionParsedUtils::parsedFunctionSetup because we are building
      80             :   // multiple expressions, and we can share the MPI barriers by keeping the code here.
      81             :   // base function object
      82         588 :   _func_F = std::make_shared<SymFunction>();
      83             : 
      84             :   // set FParser interneal feature flags
      85         588 :   setParserFeatureFlags(_func_F);
      86             : 
      87             :   // add the constant expressions
      88        2940 :   addFParserConstants(_func_F,
      89             :                       getParam<std::vector<std::string>>("constant_names"),
      90             :                       getParam<std::vector<std::string>>("constant_expressions"));
      91             : 
      92             :   // parse function
      93         588 :   if (_func_F->Parse(_function, variables) >= 0)
      94           0 :     mooseError("Invalid function\n",
      95           0 :                _function,
      96             :                "\nin ParsedODEKernel ",
      97           0 :                name(),
      98             :                ".\n",
      99           0 :                _func_F->ErrorMsg());
     100             : 
     101             :   // on-diagonal derivative
     102         588 :   _func_dFdu = std::make_shared<SymFunction>(*_func_F);
     103             : 
     104             :   // let rank 0 do the work first (diff and JIT) to populate caches
     105         588 :   if (_communicator.rank() != 0)
     106         165 :     _communicator.barrier();
     107             : 
     108         588 :   if (_func_dFdu->AutoDiff(_var.name()) != -1)
     109           0 :     mooseError("Failed to take first derivative w.r.t. ", _var.name());
     110             : 
     111             :   // off-diagonal derivatives
     112         836 :   for (unsigned int i = 0; i < _nargs; ++i)
     113             :   {
     114         248 :     _func_dFdarg[i] = std::make_shared<SymFunction>(*_func_F);
     115             : 
     116         248 :     if (_func_dFdarg[i]->AutoDiff(_arg_names[i]) != -1)
     117           0 :       mooseError("Failed to take first derivative w.r.t. ", _arg_names[i]);
     118             :   }
     119             : 
     120             :   // optimize
     121         588 :   if (!_disable_fpoptimizer)
     122             :   {
     123         588 :     _func_F->Optimize();
     124         588 :     _func_dFdu->Optimize();
     125         836 :     for (unsigned int i = 0; i < _nargs; ++i)
     126         248 :       _func_dFdarg[i]->Optimize();
     127             :   }
     128             : 
     129             :   // just-in-time compile
     130         588 :   if (_enable_jit)
     131             :   {
     132         588 :     _func_F->JITCompile();
     133         588 :     _func_dFdu->JITCompile();
     134         836 :     for (unsigned int i = 0; i < _nargs; ++i)
     135         248 :       _func_dFdarg[i]->JITCompile();
     136             :   }
     137             : 
     138             :   // wait for ranks > 0 to catch up
     139         588 :   if (_communicator.rank() == 0)
     140         423 :     _communicator.barrier();
     141             : 
     142             :   // reserve storage for parameter passing buffer
     143         588 :   _func_params.resize(1 + _nargs + _pp.size());
     144         588 : }
     145             : 
     146             : void
     147       84006 : ParsedODEKernel::updateParams()
     148             : {
     149       84006 :   _func_params[0] = _u[_i];
     150             : 
     151      111822 :   for (unsigned int j = 0; j < _nargs; ++j)
     152       27816 :     _func_params[j + 1] = (*_args[j])[_i];
     153       84279 :   for (unsigned int j = 0; j < _pp.size(); ++j)
     154         273 :     _func_params[j + 1 + _nargs] = *_pp[j];
     155       84006 : }
     156             : 
     157             : Real
     158       64013 : ParsedODEKernel::computeQpResidual()
     159             : {
     160       64013 :   updateParams();
     161      192039 :   return evaluate(_func_F);
     162             : }
     163             : 
     164             : Real
     165       15818 : ParsedODEKernel::computeQpJacobian()
     166             : {
     167       15818 :   updateParams();
     168       47454 :   return evaluate(_func_dFdu);
     169             : }
     170             : 
     171             : Real
     172        5281 : ParsedODEKernel::computeQpOffDiagJacobianScalar(unsigned int jvar)
     173             : {
     174        5281 :   int i = _arg_index[jvar];
     175        5281 :   if (i < 0)
     176        1106 :     return 0.0;
     177             : 
     178        4175 :   updateParams();
     179       12525 :   return evaluate(_func_dFdarg[i]);
     180             : }

Generated by: LCOV version 1.14