LCOV - code coverage report
Current view: top level - src/utils - FunctionMaterialPropertyDescriptor.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 2bf808 Lines: 116 151 76.8 %
Date: 2025-07-17 01:28:37 Functions: 18 24 75.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //* This file is part of the MOOSE framework
       2             : //* https://mooseframework.inl.gov
       3             : //*
       4             : //* All rights reserved, see COPYRIGHT for full restrictions
       5             : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
       6             : //*
       7             : //* Licensed under LGPL 2.1, please see LICENSE for details
       8             : //* https://www.gnu.org/licenses/lgpl-2.1.html
       9             : 
      10             : #include "FunctionMaterialPropertyDescriptor.h"
      11             : #include "DerivativeMaterialInterface.h"
      12             : #include "Material.h"
      13             : #include "Kernel.h"
      14             : #include <algorithm>
      15             : 
      16             : template <bool is_ad>
      17        3456 : FunctionMaterialPropertyDescriptor<is_ad>::FunctionMaterialPropertyDescriptor(
      18             :     const std::string & expression, MooseObject * parent, bool required)
      19        3456 :   : _state(PropertyState::CURRENT),
      20        3456 :     _dependent_symbols(),
      21        3456 :     _derivative_symbols(),
      22        3456 :     _value(nullptr),
      23        3456 :     _old_older_value(nullptr),
      24        3456 :     _parent(parent),
      25        6912 :     _required(required)
      26             : {
      27        3456 :   auto define = expression.find_last_of(":=");
      28             : 
      29             :   // expression contains a ':='
      30        3456 :   if (define != std::string::npos)
      31             :   {
      32             :     // section before ':=' is the name used in the function expression
      33        2748 :     _fparser_name = expression.substr(0, define - 1);
      34             : 
      35             :     // parse right hand side
      36        2748 :     parseDerivative(expression.substr(define + 1));
      37             :   }
      38             :   else
      39             :   {
      40             :     // parse entire expression and use natural material property base name
      41             :     // for D(x(t),t,t) this would simply be 'x'!
      42         708 :     parseDerivative(expression);
      43         708 :     _fparser_name = _base_name;
      44             :   }
      45             : 
      46        3456 :   updatePropertyName();
      47        3456 : }
      48             : 
      49             : template <bool is_ad>
      50        9792 : FunctionMaterialPropertyDescriptor<is_ad>::FunctionMaterialPropertyDescriptor(
      51             :     const FunctionMaterialPropertyDescriptor & rhs)
      52        9792 :   : _state(rhs._state),
      53        9792 :     _fparser_name(rhs._fparser_name),
      54        9792 :     _base_name(rhs._base_name),
      55        9792 :     _dependent_symbols(rhs._dependent_symbols),
      56        9792 :     _derivative_symbols(rhs._derivative_symbols),
      57        9792 :     _value(nullptr),
      58        9792 :     _old_older_value(nullptr),
      59        9792 :     _parent(rhs._parent),
      60        9792 :     _property_name(rhs._property_name),
      61        9792 :     _required(false)
      62             : {
      63        9792 : }
      64             : 
      65             : template <bool is_ad>
      66         162 : FunctionMaterialPropertyDescriptor<is_ad>::FunctionMaterialPropertyDescriptor(
      67             :     const FunctionMaterialPropertyDescriptor & rhs, MooseObject * parent)
      68         162 :   : _state(rhs._state),
      69         162 :     _fparser_name(rhs._fparser_name),
      70         162 :     _base_name(rhs._base_name),
      71         162 :     _dependent_symbols(rhs._dependent_symbols),
      72         162 :     _derivative_symbols(rhs._derivative_symbols),
      73         162 :     _value(nullptr),
      74         162 :     _old_older_value(nullptr),
      75         162 :     _parent(parent),
      76         162 :     _property_name(rhs._property_name),
      77         162 :     _required(false)
      78             : {
      79         162 : }
      80             : 
      81             : template <bool is_ad>
      82             : std::vector<FunctionMaterialPropertyDescriptor<is_ad>>
      83           0 : FunctionMaterialPropertyDescriptor<is_ad>::parseVector(
      84             :     const std::vector<std::string> & expression_list, MooseObject * parent)
      85             : {
      86           0 :   std::vector<FunctionMaterialPropertyDescriptor> fmpds;
      87           0 :   for (auto & ex : expression_list)
      88           0 :     fmpds.push_back(FunctionMaterialPropertyDescriptor(ex, parent));
      89           0 :   return fmpds;
      90           0 : }
      91             : 
      92             : template <bool is_ad>
      93             : void
      94        1656 : FunctionMaterialPropertyDescriptor<is_ad>::addDerivative(const SymbolName & var)
      95             : {
      96        1656 :   _derivative_symbols.push_back(var);
      97        1656 :   _value = nullptr;
      98        1656 :   updatePropertyName();
      99        1656 : }
     100             : 
     101             : template <bool is_ad>
     102             : bool
     103        2412 : FunctionMaterialPropertyDescriptor<is_ad>::dependsOn(const std::string & var) const
     104             : {
     105        2412 :   return std::find(_dependent_symbols.begin(), _dependent_symbols.end(), var) !=
     106        7020 :              _dependent_symbols.end() ||
     107        2196 :          std::find(_derivative_symbols.begin(), _derivative_symbols.end(), var) !=
     108        4608 :              _derivative_symbols.end();
     109             : }
     110             : 
     111             : template <bool is_ad>
     112             : std::vector<DerivativeMaterialPropertyNameInterface::SymbolName>
     113           0 : FunctionMaterialPropertyDescriptor<is_ad>::getDependentSymbols()
     114             : {
     115           0 :   std::set<SymbolName> all(_dependent_symbols.begin(), _dependent_symbols.end());
     116           0 :   all.insert(_derivative_symbols.begin(), _derivative_symbols.end());
     117             : 
     118           0 :   return std::vector<SymbolName>(all.begin(), all.end());
     119           0 : }
     120             : 
     121             : template <bool is_ad>
     122             : void
     123        3456 : FunctionMaterialPropertyDescriptor<is_ad>::parseDerivative(const std::string & expression)
     124             : {
     125        3456 :   auto open = expression.find_first_of("[");
     126        3456 :   auto close = expression.find_last_of("]");
     127             : 
     128        3456 :   if (open == std::string::npos && close == std::string::npos)
     129             :   {
     130             :     // no derivative requested
     131        2319 :     parseDependentSymbols(expression);
     132             : 
     133        2319 :     return;
     134             :   }
     135        1137 :   if (open != std::string::npos && close != std::string::npos)
     136             :   {
     137        1137 :     if (expression.substr(0, open) == "Old")
     138             :     {
     139          39 :       _base_name = expression.substr(open + 1, close - open - 1);
     140          39 :       _dependent_symbols.clear();
     141          39 :       _state = PropertyState::OLD;
     142          39 :       return;
     143             :     }
     144        1098 :     if (expression.substr(0, open) == "Older")
     145             :     {
     146          39 :       _base_name = expression.substr(open + 1, close - open - 1);
     147          39 :       _dependent_symbols.clear();
     148          39 :       _state = PropertyState::OLDER;
     149          39 :       return;
     150             :     }
     151        1059 :     else if (expression.substr(0, open) == "D")
     152             :     {
     153        1059 :       auto arguments = expression.substr(open + 1, close - open - 1);
     154        1059 :       auto close2 = arguments.find_last_of(")");
     155             : 
     156        1059 :       if (close2 == std::string::npos)
     157             :       {
     158             :         // rest of argument list 0 is the function and 1,.. are the variable to take the derivative
     159             :         // w.r.t.
     160        1059 :         MooseUtils::tokenize(arguments, _derivative_symbols, 0, ",");
     161             : 
     162             :         // check for empty [] brackets
     163        1059 :         if (_derivative_symbols.size() > 0)
     164             :         {
     165             :           // parse argument zero of D[] as the function material property
     166        1059 :           parseDependentSymbols(_derivative_symbols[0]);
     167             : 
     168             :           // remove function from the _derivative_symbols vector
     169        1059 :           _derivative_symbols.erase(_derivative_symbols.begin());
     170        1059 :           updatePropertyName();
     171             : 
     172        1059 :           return;
     173             :         }
     174             :       }
     175             :       else
     176             :       {
     177           0 :         parseDependentSymbols(arguments.substr(0, close2 + 1));
     178           0 :         MooseUtils::tokenize(arguments.substr(close2 + 2), _derivative_symbols, 0, ",");
     179           0 :         updatePropertyName();
     180           0 :         return;
     181             :       }
     182        1059 :     }
     183             :   }
     184             : 
     185           0 :   mooseError("Malformed material_properties expression '", expression, "'");
     186             : }
     187             : 
     188             : template <bool is_ad>
     189             : void
     190        3378 : FunctionMaterialPropertyDescriptor<is_ad>::parseDependentSymbols(const std::string & expression)
     191             : {
     192        3378 :   auto open = expression.find_first_of("(");
     193        3378 :   auto close = expression.find_last_of(")");
     194             : 
     195        3378 :   if (open == std::string::npos && close == std::string::npos)
     196             :   {
     197             :     // material property name without arguments
     198        3300 :     _base_name = expression;
     199             :   }
     200          78 :   else if (open != std::string::npos && close != std::string::npos)
     201             :   {
     202             :     // take material property name before bracket
     203          78 :     _base_name = expression.substr(0, open);
     204             : 
     205             :     // parse argument list
     206          78 :     MooseUtils::tokenize(expression.substr(open + 1, close - open - 1), _dependent_symbols, 0, ",");
     207             : 
     208             :     // remove duplicates from dependent variable list
     209          78 :     std::sort(_dependent_symbols.begin(), _dependent_symbols.end());
     210          78 :     _dependent_symbols.erase(std::unique(_dependent_symbols.begin(), _dependent_symbols.end()),
     211         156 :                              _dependent_symbols.end());
     212             :   }
     213             :   else
     214           0 :     mooseError("Malformed material_properties expression '", expression, "'");
     215        3378 : }
     216             : 
     217             : template <bool is_ad>
     218             : void
     219           0 : FunctionMaterialPropertyDescriptor<is_ad>::printDebug()
     220             : {
     221           0 :   Moose::out << "MPD: " << _fparser_name << ' ' << _base_name << " deriv = [";
     222           0 :   for (auto & dv : _derivative_symbols)
     223           0 :     Moose::out << dv << ' ';
     224           0 :   Moose::out << "] dep = [";
     225           0 :   for (auto & dv : _dependent_symbols)
     226           0 :     Moose::out << dv << ' ';
     227           0 :   Moose::out << "] " << getPropertyName() << '\n';
     228           0 : }
     229             : 
     230             : template <bool is_ad>
     231             : GenericReal<is_ad>
     232     3547797 : FunctionMaterialPropertyDescriptor<is_ad>::value(unsigned int qp) const
     233             : {
     234             :   // current property
     235     3547797 :   if (_state == PropertyState::CURRENT)
     236             :   {
     237     3547559 :     if (_value == nullptr)
     238             :     {
     239        5160 :       DerivativeMaterialInterface<Material> * _material_parent =
     240        5160 :           dynamic_cast<DerivativeMaterialInterface<Material> *>(_parent);
     241        5160 :       DerivativeMaterialInterface<Kernel> * _kernel_parent =
     242        5160 :           dynamic_cast<DerivativeMaterialInterface<Kernel> *>(_parent);
     243             : 
     244             :       // property name
     245        5160 :       auto name = derivativePropertyName(_base_name, _derivative_symbols);
     246             : 
     247             :       // get the material property reference
     248        5160 :       if (_material_parent)
     249        9183 :         _value = _required ? &(_material_parent->getGenericMaterialProperty<Real, is_ad>(name))
     250        4023 :                            : &(_material_parent->getGenericZeroMaterialProperty<Real, is_ad>(name));
     251           0 :       else if (_kernel_parent)
     252           0 :         _value = _required ? &(_kernel_parent->getGenericMaterialProperty<Real, is_ad>(name))
     253           0 :                            : &(_kernel_parent->getGenericZeroMaterialProperty<Real, is_ad>(name));
     254             :       else
     255           0 :         mooseError("A FunctionMaterialPropertyDescriptor must be owned by either a Material or a "
     256             :                    "Kernel object.");
     257        5160 :     }
     258             : 
     259     3547559 :     return qp != libMesh::invalid_uint ? (*_value)[qp] : 0.0;
     260             :   }
     261             : 
     262             :   // old or older property
     263         238 :   if (_old_older_value == nullptr)
     264             :   {
     265             :     mooseAssert(_derivative_symbols.empty(), "Don't take derivatives of old/older properties.");
     266             : 
     267          78 :     DerivativeMaterialInterface<Material> * _material_parent =
     268          78 :         dynamic_cast<DerivativeMaterialInterface<Material> *>(_parent);
     269          78 :     DerivativeMaterialInterface<Kernel> * _kernel_parent =
     270          78 :         dynamic_cast<DerivativeMaterialInterface<Kernel> *>(_parent);
     271             : 
     272             :     // get the material property reference
     273          78 :     if (_material_parent)
     274          78 :       _old_older_value = (_state == PropertyState::OLD)
     275          78 :                              ? &(_material_parent->getMaterialPropertyOld<Real>(_base_name))
     276          39 :                              : &(_material_parent->getMaterialPropertyOlder<Real>(_base_name));
     277           0 :     else if (_kernel_parent)
     278           0 :       _old_older_value = (_state == PropertyState::OLD)
     279           0 :                              ? &(_kernel_parent->getMaterialPropertyOld<Real>(_base_name))
     280           0 :                              : &(_kernel_parent->getMaterialPropertyOlder<Real>(_base_name));
     281             :     else
     282           0 :       mooseError("A FunctionMaterialPropertyDescriptor must be owned by either a Material or a "
     283             :                  "Kernel object.");
     284             :   }
     285             : 
     286         238 :   return qp != libMesh::invalid_uint ? (*_old_older_value)[qp] : 0.0;
     287             : }
     288             : 
     289             : template <bool is_ad>
     290             : void
     291        6171 : FunctionMaterialPropertyDescriptor<is_ad>::updatePropertyName()
     292             : {
     293        6171 :   _property_name = derivativePropertyName(_base_name, _derivative_symbols);
     294        6171 : }
     295             : 
     296             : // explicit instantiation
     297             : template class FunctionMaterialPropertyDescriptor<false>;
     298             : template class FunctionMaterialPropertyDescriptor<true>;

Generated by: LCOV version 1.14