LCOV - code coverage report
Current view: top level - src/materials - ParsedMaterialHelper.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #33416 (b10b36) with base 9fbd27 Lines: 133 203 65.5 %
Date: 2026-07-23 16:15:30 Functions: 14 26 53.8 %
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 "ParsedMaterialHelper.h"
      11             : 
      12             : #include "libmesh/quadrature.h"
      13             : #include "Conversion.h"
      14             : 
      15             : template <bool is_ad>
      16             : InputParameters
      17       18177 : ParsedMaterialHelper<is_ad>::validParams()
      18             : {
      19       18177 :   InputParameters params = FunctionMaterialBase<is_ad>::validParams();
      20       18177 :   params += FunctionParserUtils<is_ad>::validParams();
      21       36354 :   params.addClassDescription("Parsed Function Material.");
      22       54531 :   params.addParam<bool>("error_on_missing_material_properties",
      23       36354 :                         true,
      24             :                         "Throw an error if any explicitly requested material property does not "
      25             :                         "exist. Otherwise assume it to be zero.");
      26       54531 :   params.addParam<MultiMooseEnum>(
      27             :       "extra_symbols",
      28       36354 :       MultiMooseEnum(getExtraSymbolsOptions()),
      29             :       "Special symbols, like point coordinates, time, and timestep size.");
      30       36354 :   params.addParam<std::vector<MaterialName>>(
      31             :       "upstream_materials",
      32       36354 :       std::vector<MaterialName>(),
      33             :       "List of upstream material properties that must be evaluated when compute=false");
      34       18177 :   return params;
      35           0 : }
      36             : 
      37             : template <bool is_ad>
      38        4467 : ParsedMaterialHelper<is_ad>::ParsedMaterialHelper(
      39             :     const InputParameters & parameters,
      40             :     const VariableNameMappingMode map_mode,
      41             :     const std::optional<std::string> & function_param_name /* = {} */)
      42             :   : FunctionMaterialBase<is_ad>(parameters),
      43             :     FunctionParserUtils<is_ad>(parameters),
      44        8934 :     _symbol_names(_nargs),
      45        8934 :     _extra_symbols(this->template getParam<MultiMooseEnum>("extra_symbols")
      46             :                        .template getSetValueIDs<ExtraSymbols>()),
      47        8934 :     _tol(0),
      48        4467 :     _map_mode(map_mode),
      49        4467 :     _function_param_name(function_param_name),
      50        8934 :     _upstream_mat_names(this->template getParam<std::vector<MaterialName>>("upstream_materials")),
      51        4467 :     _error_on_missing_material_properties(
      52        8934 :         this->template getParam<bool>("error_on_missing_material_properties")),
      53       17868 :     _params(parameters)
      54             : {
      55        4467 :   if (_function_param_name)
      56             :     mooseAssert(_params.have_parameter<std::string>(*_function_param_name),
      57             :                 "Does not have parameter");
      58        4467 : }
      59             : 
      60             : template <bool is_ad>
      61             : void
      62        1878 : ParsedMaterialHelper<is_ad>::insertReservedNames(std::set<std::string> & reserved_names)
      63             : {
      64        1878 :   for (const auto symbol : _extra_symbols)
      65           0 :     switch (symbol)
      66             :     {
      67           0 :       case ExtraSymbols::x:
      68           0 :         reserved_names.insert("x");
      69           0 :         break;
      70           0 :       case ExtraSymbols::y:
      71           0 :         reserved_names.insert("y");
      72           0 :         break;
      73           0 :       case ExtraSymbols::z:
      74           0 :         reserved_names.insert("z");
      75           0 :         break;
      76           0 :       case ExtraSymbols::t:
      77           0 :         reserved_names.insert("t");
      78           0 :         break;
      79           0 :       case ExtraSymbols::dt:
      80           0 :         reserved_names.insert("dt");
      81           0 :         break;
      82             :     };
      83        1878 : }
      84             : 
      85             : template <bool is_ad>
      86             : void
      87           0 : ParsedMaterialHelper<is_ad>::functionParse(const std::string & function_expression)
      88             : {
      89           0 :   const std::vector<std::string> empty_string_vector;
      90           0 :   functionParse(function_expression, empty_string_vector, empty_string_vector);
      91           0 : }
      92             : 
      93             : template <bool is_ad>
      94             : void
      95           0 : ParsedMaterialHelper<is_ad>::functionParse(const std::string & function_expression,
      96             :                                            const std::vector<std::string> & constant_names,
      97             :                                            const std::vector<std::string> & constant_expressions)
      98             : {
      99           0 :   const std::vector<std::string> empty_string_vector;
     100           0 :   const std::vector<Real> empty_real_vector;
     101           0 :   functionParse(function_expression,
     102             :                 constant_names,
     103             :                 constant_expressions,
     104             :                 empty_string_vector,
     105             :                 empty_string_vector,
     106             :                 empty_real_vector);
     107           0 : }
     108             : 
     109             : template <bool is_ad>
     110             : void
     111           0 : ParsedMaterialHelper<is_ad>::functionParse(const std::string & function_expression,
     112             :                                            const std::vector<std::string> & constant_names,
     113             :                                            const std::vector<std::string> & constant_expressions,
     114             :                                            const std::vector<std::string> & mat_prop_expressions,
     115             :                                            const std::vector<std::string> & tol_names,
     116             :                                            const std::vector<Real> & tol_values)
     117             : {
     118           0 :   const std::vector<PostprocessorName> empty_pp_name_vector;
     119           0 :   functionParse(function_expression,
     120             :                 constant_names,
     121             :                 constant_expressions,
     122             :                 mat_prop_expressions,
     123             :                 empty_pp_name_vector,
     124             :                 tol_names,
     125             :                 tol_values);
     126           0 : }
     127             : 
     128             : template <bool is_ad>
     129             : void
     130           0 : ParsedMaterialHelper<is_ad>::functionParse(
     131             :     const std::string & function_expression,
     132             :     const std::vector<std::string> & constant_names,
     133             :     const std::vector<std::string> & constant_expressions,
     134             :     const std::vector<std::string> & mat_prop_expressions,
     135             :     const std::vector<PostprocessorName> & postprocessor_names,
     136             :     const std::vector<std::string> & tol_names,
     137             :     const std::vector<Real> & tol_values)
     138             : {
     139           0 :   const std::vector<MooseFunctorName> empty_functor_vector;
     140           0 :   const std::vector<std::string> empty_string_vector;
     141           0 :   functionParse(function_expression,
     142             :                 constant_names,
     143             :                 constant_expressions,
     144             :                 mat_prop_expressions,
     145             :                 postprocessor_names,
     146             :                 tol_names,
     147             :                 tol_values,
     148             :                 empty_functor_vector,
     149             :                 empty_string_vector);
     150           0 : }
     151             : 
     152             : template <bool is_ad>
     153             : void
     154        4467 : ParsedMaterialHelper<is_ad>::functionParse(
     155             :     const std::string & function_expression,
     156             :     const std::vector<std::string> & constant_names,
     157             :     const std::vector<std::string> & constant_expressions,
     158             :     const std::vector<std::string> & mat_prop_expressions,
     159             :     const std::vector<PostprocessorName> & postprocessor_names,
     160             :     const std::vector<std::string> & tol_names,
     161             :     const std::vector<Real> & tol_values,
     162             :     const std::vector<MooseFunctorName> & functor_names,
     163             :     const std::vector<std::string> & functor_symbols)
     164             : {
     165             :   // build base function object
     166        4467 :   _func_F = std::make_shared<SymFunction>();
     167             : 
     168             :   // set FParser internal feature flags
     169        4467 :   setParserFeatureFlags(_func_F);
     170             : 
     171             :   // initialize constants
     172        4467 :   addFParserConstants(_func_F, constant_names, constant_expressions);
     173             : 
     174             :   // add further constants coming from default value coupling
     175        4467 :   if (_map_mode == VariableNameMappingMode::USE_PARAM_NAMES)
     176           0 :     for (const auto & acd : _arg_constant_defaults)
     177           0 :       if (!_func_F->AddConstant(acd, this->_pars.defaultCoupledValue(acd)))
     178           0 :         _params.mooseError("Invalid constant name in parsed function object");
     179             : 
     180             :   // set variable names based on map_mode
     181        4467 :   switch (_map_mode)
     182             :   {
     183        4467 :     case VariableNameMappingMode::USE_MOOSE_NAMES:
     184        8040 :       for (unsigned int i = 0; i < _nargs; ++i)
     185        3573 :         _symbol_names[i] = _arg_names[i];
     186        4467 :       break;
     187             : 
     188           0 :     case VariableNameMappingMode::USE_PARAM_NAMES:
     189           0 :       for (unsigned i = 0; i < _nargs; ++i)
     190             :       {
     191           0 :         if (_arg_param_numbers[i] < 0)
     192           0 :           _symbol_names[i] = _arg_param_names[i];
     193             :         else
     194           0 :           _symbol_names[i] = _arg_param_names[i] + std::to_string(_arg_param_numbers[i]);
     195             :       }
     196           0 :       break;
     197             : 
     198           0 :     default:
     199           0 :       _params.mooseError("Unknown variable mapping mode.");
     200             :   }
     201             : 
     202             :   // tolerance vectors
     203        4467 :   if (tol_names.size() != tol_values.size())
     204           0 :     _params.mooseError("The parameter vectors tol_names and tol_values must have equal length.");
     205             : 
     206             :   // set tolerances
     207        4467 :   _tol.resize(_nargs);
     208        8040 :   for (const auto i : make_range(_nargs))
     209             :   {
     210        3573 :     _tol[i] = -1.0;
     211             : 
     212             :     // for every argument look through the entire tolerance vector to find a match
     213        3573 :     for (const auto j : index_range(tol_names))
     214           0 :       if (_symbol_names[i] == tol_names[j])
     215             :       {
     216           0 :         _tol[i] = tol_values[j];
     217           0 :         break;
     218             :       }
     219             :   }
     220             : 
     221             :   // get all material properties
     222        4467 :   unsigned int nmat_props = mat_prop_expressions.size();
     223        7872 :   for (const auto i : make_range(nmat_props))
     224             :   {
     225             :     // parse the material property parameter entry into a FunctionMaterialPropertyDescriptor
     226        3405 :     _mat_prop_descriptors.emplace_back(
     227        3405 :         mat_prop_expressions[i], this, _error_on_missing_material_properties);
     228             : 
     229             :     // get the fparser symbol name for the new material property
     230        3405 :     _symbol_names.push_back(_mat_prop_descriptors.back().getSymbolName());
     231             :   }
     232             : 
     233             :   // get all coupled postprocessors
     234        4623 :   for (const auto & pp : postprocessor_names)
     235             :   {
     236         156 :     _postprocessor_values.push_back(&this->getPostprocessorValueByName(pp));
     237         156 :     _symbol_names.push_back(pp);
     238             :   }
     239             : 
     240             :   // get all extra symbols
     241        4875 :   for (const auto symbol : _extra_symbols)
     242         408 :     switch (symbol)
     243             :     {
     244         144 :       case ExtraSymbols::x:
     245         288 :         _symbol_names.push_back("x");
     246         144 :         break;
     247          66 :       case ExtraSymbols::y:
     248         132 :         _symbol_names.push_back("y");
     249          66 :         break;
     250          66 :       case ExtraSymbols::z:
     251         132 :         _symbol_names.push_back("z");
     252          66 :         break;
     253          66 :       case ExtraSymbols::t:
     254         132 :         _symbol_names.push_back("t");
     255          66 :         break;
     256          66 :       case ExtraSymbols::dt:
     257         132 :         _symbol_names.push_back("dt");
     258          66 :         break;
     259             :     }
     260             : 
     261             :   // get all functors
     262        4467 :   if (!functor_symbols.empty() && functor_symbols.size() != functor_names.size())
     263           0 :     _params.mooseError(
     264             :         "The parameter vector functor_symbols must be of same length as functor_names, if "
     265             :         "not empty.");
     266        4467 :   _functors.resize(functor_names.size());
     267        4506 :   for (const auto i : index_range(functor_names))
     268             :   {
     269          39 :     if (functor_symbols.empty())
     270             :     {
     271           0 :       auto functor_name = functor_names[i];
     272           0 :       _symbol_names.push_back(functor_name);
     273           0 :       _functors[i] = &FunctorInterface::getFunctor<Real>(functor_name);
     274           0 :     }
     275             :     else
     276             :     {
     277          39 :       auto functor_name = functor_names[i];
     278          39 :       auto symbol_name = functor_symbols[i];
     279          39 :       _symbol_names.push_back(symbol_name);
     280          39 :       _functors[i] = &FunctorInterface::getFunctor<Real>(functor_name);
     281          39 :     }
     282             :   }
     283             : 
     284             :   // build 'variables' argument for fparser
     285       13401 :   std::string variables = Moose::stringify(_symbol_names);
     286             : 
     287             :   // build the base function
     288        4467 :   if (_func_F->Parse(function_expression, variables) >= 0)
     289           0 :     parseError("Invalid parsed material function \"" + function_expression +
     290           0 :                "\" with variables \"" + variables + "\"; " + _func_F->ErrorMsg());
     291             : 
     292             :   // create parameter passing buffer
     293        8934 :   _func_params.resize(_nargs + nmat_props + _postprocessor_values.size() + _extra_symbols.size() +
     294        4467 :                       functor_names.size());
     295             : 
     296             :   // perform next steps (either optimize or take derivatives and then optimize)
     297             : 
     298             :   // let rank 0 do the work first to populate caches
     299        4467 :   if (_communicator.rank() != 0)
     300        1143 :     _communicator.barrier();
     301             : 
     302        4467 :   functionsPostParse();
     303             : 
     304             :   // wait for ranks > 0 to catch up
     305        4458 :   if (_communicator.rank() == 0)
     306        3315 :     _communicator.barrier();
     307        4458 : }
     308             : 
     309             : template <bool is_ad>
     310             : void
     311        1878 : ParsedMaterialHelper<is_ad>::functionsPostParse()
     312             : {
     313        1878 :   functionsOptimize(_func_F);
     314             : 
     315             :   // force a value update to get the property at least once and register it for the dependencies
     316        4206 :   for (auto & mpd : _mat_prop_descriptors)
     317        2328 :     mpd.value();
     318        1878 : }
     319             : 
     320             : template <bool is_ad>
     321             : void
     322        4362 : ParsedMaterialHelper<is_ad>::initialSetup()
     323             : {
     324        4362 :   _upstream_mat.resize(_upstream_mat_names.size());
     325        4362 :   for (const auto i : make_range(_upstream_mat_names.size()))
     326           0 :     _upstream_mat[i] = &this->getMaterialByName(_upstream_mat_names[i]);
     327        4362 : }
     328             : 
     329             : template <bool is_ad>
     330             : void
     331           0 : ParsedMaterialHelper<is_ad>::initQpStatefulProperties()
     332             : {
     333           0 :   computeQpProperties();
     334           0 : }
     335             : 
     336             : template <bool is_ad>
     337             : void
     338     6433061 : ParsedMaterialHelper<is_ad>::computeQpProperties()
     339             : {
     340     6433061 :   if (!(this->_compute))
     341             :   {
     342           0 :     for (const auto i : make_range(_upstream_mat_names.size()))
     343           0 :       _upstream_mat[i]->computePropertiesAtQp(_qp);
     344             :   }
     345             : 
     346             :   // fill the parameter vector, apply tolerances
     347    12217569 :   for (const auto i : make_range(_nargs))
     348             :   {
     349     5784508 :     if (_tol[i] < 0.0)
     350     5784508 :       _func_params[i] = (*_args[i])[_qp];
     351             :     else
     352             :     {
     353           0 :       auto a = (*_args[i])[_qp];
     354           0 :       _func_params[i] = a < _tol[i] ? _tol[i] : (a > 1.0 - _tol[i] ? 1.0 - _tol[i] : a);
     355           0 :     }
     356             :   }
     357     6433061 :   auto offset = _nargs;
     358             : 
     359             :   // insert material property values
     360    10359414 :   for (const auto i : index_range(_mat_prop_descriptors))
     361     3926353 :     _func_params[i + offset] = _mat_prop_descriptors[i].value(_qp);
     362     6433061 :   offset += _mat_prop_descriptors.size();
     363             : 
     364             :   // insert postprocessor values
     365     6433061 :   auto npps = _postprocessor_values.size();
     366     6433189 :   for (MooseIndex(_postprocessor_values) i = 0; i < npps; ++i)
     367         128 :     _func_params[i + offset] = *_postprocessor_values[i];
     368     6433061 :   offset += _postprocessor_values.size();
     369             : 
     370             :   // insert extra symbol values
     371     6918693 :   for (const auto i : index_range(_extra_symbols))
     372             :   {
     373      485632 :     const auto j = offset + i;
     374      485632 :     switch (_extra_symbols[i])
     375             :     {
     376      464128 :       case ExtraSymbols::x:
     377      464128 :         _func_params[j] = _q_point[_qp](0);
     378      464128 :         break;
     379        5376 :       case ExtraSymbols::y:
     380        5376 :         _func_params[j] = _q_point[_qp](1);
     381        5376 :         break;
     382        5376 :       case ExtraSymbols::z:
     383        5376 :         _func_params[j] = _q_point[_qp](2);
     384        5376 :         break;
     385        5376 :       case ExtraSymbols::t:
     386        5376 :         _func_params[j] = _t;
     387        5376 :         break;
     388        5376 :       case ExtraSymbols::dt:
     389        5376 :         _func_params[j] = _dt;
     390        5376 :         break;
     391             :     }
     392             :   }
     393     6433061 :   offset += _extra_symbols.size();
     394             : 
     395             :   // insert functor values
     396     6433061 :   const auto & state = TransientInterface::determineState();
     397     6433061 :   const Moose::ElemQpArg qp_arg = {_current_elem, _qp, _qrule, _q_point[_qp]};
     398     7065061 :   for (const auto i : index_range(_functors))
     399      632000 :     _func_params[offset + i] = (*_functors[i])(qp_arg, state);
     400             : 
     401             :   // set function value
     402     6433061 :   if (_prop_F)
     403     6433061 :     (*_prop_F)[_qp] = evaluate(_func_F, _name);
     404     6433034 : }
     405             : 
     406             : template <bool is_ad>
     407             : void
     408           0 : ParsedMaterialHelper<is_ad>::parseError(const std::string & message) const
     409             : {
     410           0 :   if (_function_param_name)
     411           0 :     _params.paramError(*_function_param_name, message);
     412             :   else
     413           0 :     _params.mooseError(message);
     414             : }
     415             : 
     416             : // explicit instantiation
     417             : template class ParsedMaterialHelper<false>;
     418             : template class ParsedMaterialHelper<true>;

Generated by: LCOV version 1.14