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

Generated by: LCOV version 1.14