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

Generated by: LCOV version 1.14