LCOV - code coverage report
Current view: top level - src/materials - ParsedMaterialHelper.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #32971 (54bef8) with base c6cf66 Lines: 133 203 65.5 %
Date: 2026-05-29 20:35:17 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       17753 : ParsedMaterialHelper<is_ad>::validParams()
      18             : {
      19       17753 :   InputParameters params = FunctionMaterialBase<is_ad>::validParams();
      20       17753 :   params += FunctionParserUtils<is_ad>::validParams();
      21       35506 :   params.addClassDescription("Parsed Function Material.");
      22       53259 :   params.addParam<bool>("error_on_missing_material_properties",
      23       35506 :                         true,
      24             :                         "Throw an error if any explicitly requested material property does not "
      25             :                         "exist. Otherwise assume it to be zero.");
      26       53259 :   params.addParam<MultiMooseEnum>(
      27             :       "extra_symbols",
      28       35506 :       MultiMooseEnum(getExtraSymbolsOptions()),
      29             :       "Special symbols, like point coordinates, time, and timestep size.");
      30       35506 :   params.addParam<std::vector<MaterialName>>(
      31             :       "upstream_materials",
      32       35506 :       std::vector<MaterialName>(),
      33             :       "List of upstream material properties that must be evaluated when compute=false");
      34       17753 :   return params;
      35           0 : }
      36             : 
      37             : template <bool is_ad>
      38        4227 : 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        8454 :     _symbol_names(_nargs),
      45        8454 :     _extra_symbols(this->template getParam<MultiMooseEnum>("extra_symbols")
      46             :                        .template getSetValueIDs<ExtraSymbols>()),
      47        8454 :     _tol(0),
      48        4227 :     _map_mode(map_mode),
      49        4227 :     _function_param_name(function_param_name),
      50        8454 :     _upstream_mat_names(this->template getParam<std::vector<MaterialName>>("upstream_materials")),
      51        4227 :     _error_on_missing_material_properties(
      52        8454 :         this->template getParam<bool>("error_on_missing_material_properties")),
      53       16908 :     _params(parameters)
      54             : {
      55        4227 :   if (_function_param_name)
      56             :     mooseAssert(_params.have_parameter<std::string>(*_function_param_name),
      57             :                 "Does not have parameter");
      58        4227 : }
      59             : 
      60             : template <bool is_ad>
      61             : void
      62        1638 : ParsedMaterialHelper<is_ad>::insertReservedNames(std::set<std::string> & reserved_names)
      63             : {
      64        1638 :   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        1638 : }
      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        4227 : 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        4227 :   _func_F = std::make_shared<SymFunction>();
     167             : 
     168             :   // set FParser internal feature flags
     169        4227 :   setParserFeatureFlags(_func_F);
     170             : 
     171             :   // initialize constants
     172        4227 :   addFParserConstants(_func_F, constant_names, constant_expressions);
     173             : 
     174             :   // add further constants coming from default value coupling
     175        4227 :   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        4227 :   switch (_map_mode)
     182             :   {
     183        4227 :     case VariableNameMappingMode::USE_MOOSE_NAMES:
     184        7560 :       for (unsigned int i = 0; i < _nargs; ++i)
     185        3333 :         _symbol_names[i] = _arg_names[i];
     186        4227 :       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        4227 :   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        4227 :   _tol.resize(_nargs);
     208        7560 :   for (const auto i : make_range(_nargs))
     209             :   {
     210        3333 :     _tol[i] = -1.0;
     211             : 
     212             :     // for every argument look through the entire tolerance vector to find a match
     213        3333 :     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        4227 :   unsigned int nmat_props = mat_prop_expressions.size();
     223        7632 :   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        4383 :   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        4635 :   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        4227 :   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        4227 :   _functors.resize(functor_names.size());
     267        4266 :   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       12681 :   std::string variables = Moose::stringify(_symbol_names);
     286             : 
     287             :   // build the base function
     288        4227 :   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        8454 :   _func_params.resize(_nargs + nmat_props + _postprocessor_values.size() + _extra_symbols.size() +
     294        4227 :                       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        4227 :   if (_communicator.rank() != 0)
     300         933 :     _communicator.barrier();
     301             : 
     302        4227 :   functionsPostParse();
     303             : 
     304             :   // wait for ranks > 0 to catch up
     305        4218 :   if (_communicator.rank() == 0)
     306        3285 :     _communicator.barrier();
     307        4218 : }
     308             : 
     309             : template <bool is_ad>
     310             : void
     311        1638 : ParsedMaterialHelper<is_ad>::functionsPostParse()
     312             : {
     313        1638 :   functionsOptimize(_func_F);
     314             : 
     315             :   // force a value update to get the property at least once and register it for the dependencies
     316        3966 :   for (auto & mpd : _mat_prop_descriptors)
     317        2328 :     mpd.value();
     318        1638 : }
     319             : 
     320             : template <bool is_ad>
     321             : void
     322        4122 : ParsedMaterialHelper<is_ad>::initialSetup()
     323             : {
     324        4122 :   _upstream_mat.resize(_upstream_mat_names.size());
     325        4122 :   for (const auto i : make_range(_upstream_mat_names.size()))
     326           0 :     _upstream_mat[i] = &this->getMaterialByName(_upstream_mat_names[i]);
     327        4122 : }
     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     6265125 : ParsedMaterialHelper<is_ad>::computeQpProperties()
     339             : {
     340     6265125 :   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    11881697 :   for (const auto i : make_range(_nargs))
     348             :   {
     349     5616572 :     if (_tol[i] < 0.0)
     350     5616572 :       _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     6265125 :   auto offset = _nargs;
     358             : 
     359             :   // insert material property values
     360    10191478 :   for (const auto i : index_range(_mat_prop_descriptors))
     361     3926353 :     _func_params[i + offset] = _mat_prop_descriptors[i].value(_qp);
     362     6265125 :   offset += _mat_prop_descriptors.size();
     363             : 
     364             :   // insert postprocessor values
     365     6265125 :   auto npps = _postprocessor_values.size();
     366     6265253 :   for (MooseIndex(_postprocessor_values) i = 0; i < npps; ++i)
     367         128 :     _func_params[i + offset] = *_postprocessor_values[i];
     368     6265125 :   offset += _postprocessor_values.size();
     369             : 
     370             :   // insert extra symbol values
     371     6750757 :   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     6265125 :   offset += _extra_symbols.size();
     394             : 
     395             :   // insert functor values
     396     6265125 :   const auto & state = TransientInterface::determineState();
     397     6265125 :   const Moose::ElemQpArg qp_arg = {_current_elem, _qp, _qrule, _q_point[_qp]};
     398     6897125 :   for (const auto i : index_range(_functors))
     399      632000 :     _func_params[offset + i] = (*_functors[i])(qp_arg, state);
     400             : 
     401             :   // set function value
     402     6265125 :   if (_prop_F)
     403     6265125 :     (*_prop_F)[_qp] = evaluate(_func_F, _name);
     404     6265098 : }
     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