LCOV - code coverage report
Current view: top level - src/utils - FunctionMaterialPropertyDescriptor.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 419b9d Lines: 116 151 76.8 %
Date: 2025-08-08 20:01:16 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        3702 : FunctionMaterialPropertyDescriptor<is_ad>::FunctionMaterialPropertyDescriptor(
      18             :     const std::string & expression, MooseObject * parent, bool required)
      19        3702 :   : _state(PropertyState::CURRENT),
      20        3702 :     _dependent_symbols(),
      21        3702 :     _derivative_symbols(),
      22        3702 :     _value(nullptr),
      23        3702 :     _old_older_value(nullptr),
      24        3702 :     _parent(parent),
      25        7404 :     _required(required)
      26             : {
      27        3702 :   auto define = expression.find_last_of(":=");
      28             : 
      29             :   // expression contains a ':='
      30        3702 :   if (define != std::string::npos)
      31             :   {
      32             :     // section before ':=' is the name used in the function expression
      33        2961 :     _fparser_name = expression.substr(0, define - 1);
      34             : 
      35             :     // parse right hand side
      36        2961 :     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         741 :     parseDerivative(expression);
      43         741 :     _fparser_name = _base_name;
      44             :   }
      45             : 
      46        3702 :   updatePropertyName();
      47        3702 : }
      48             : 
      49             : template <bool is_ad>
      50       10656 : FunctionMaterialPropertyDescriptor<is_ad>::FunctionMaterialPropertyDescriptor(
      51             :     const FunctionMaterialPropertyDescriptor & rhs)
      52       10656 :   : _state(rhs._state),
      53       10656 :     _fparser_name(rhs._fparser_name),
      54       10656 :     _base_name(rhs._base_name),
      55       10656 :     _dependent_symbols(rhs._dependent_symbols),
      56       10656 :     _derivative_symbols(rhs._derivative_symbols),
      57       10656 :     _value(nullptr),
      58       10656 :     _old_older_value(nullptr),
      59       10656 :     _parent(rhs._parent),
      60       10656 :     _property_name(rhs._property_name),
      61       10656 :     _required(false)
      62             : {
      63       10656 : }
      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        1818 : FunctionMaterialPropertyDescriptor<is_ad>::addDerivative(const SymbolName & var)
      95             : {
      96        1818 :   _derivative_symbols.push_back(var);
      97        1818 :   _value = nullptr;
      98        1818 :   updatePropertyName();
      99        1818 : }
     100             : 
     101             : template <bool is_ad>
     102             : bool
     103        2637 : FunctionMaterialPropertyDescriptor<is_ad>::dependsOn(const std::string & var) const
     104             : {
     105        2637 :   return std::find(_dependent_symbols.begin(), _dependent_symbols.end(), var) !=
     106        7677 :              _dependent_symbols.end() ||
     107        2403 :          std::find(_derivative_symbols.begin(), _derivative_symbols.end(), var) !=
     108        5040 :              _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        3702 : FunctionMaterialPropertyDescriptor<is_ad>::parseDerivative(const std::string & expression)
     124             : {
     125        3702 :   auto open = expression.find_first_of("[");
     126        3702 :   auto close = expression.find_last_of("]");
     127             : 
     128        3702 :   if (open == std::string::npos && close == std::string::npos)
     129             :   {
     130             :     // no derivative requested
     131        2475 :     parseDependentSymbols(expression);
     132             : 
     133        2475 :     return;
     134             :   }
     135        1227 :   if (open != std::string::npos && close != std::string::npos)
     136             :   {
     137        1227 :     if (expression.substr(0, open) == "Old")
     138             :     {
     139          42 :       _base_name = expression.substr(open + 1, close - open - 1);
     140          42 :       _dependent_symbols.clear();
     141          42 :       _state = PropertyState::OLD;
     142          42 :       return;
     143             :     }
     144        1185 :     if (expression.substr(0, open) == "Older")
     145             :     {
     146          42 :       _base_name = expression.substr(open + 1, close - open - 1);
     147          42 :       _dependent_symbols.clear();
     148          42 :       _state = PropertyState::OLDER;
     149          42 :       return;
     150             :     }
     151        1143 :     else if (expression.substr(0, open) == "D")
     152             :     {
     153        1143 :       auto arguments = expression.substr(open + 1, close - open - 1);
     154        1143 :       auto close2 = arguments.find_last_of(")");
     155             : 
     156        1143 :       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        1143 :         MooseUtils::tokenize(arguments, _derivative_symbols, 0, ",");
     161             : 
     162             :         // check for empty [] brackets
     163        1143 :         if (_derivative_symbols.size() > 0)
     164             :         {
     165             :           // parse argument zero of D[] as the function material property
     166        1143 :           parseDependentSymbols(_derivative_symbols[0]);
     167             : 
     168             :           // remove function from the _derivative_symbols vector
     169        1143 :           _derivative_symbols.erase(_derivative_symbols.begin());
     170        1143 :           updatePropertyName();
     171             : 
     172        1143 :           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        1143 :     }
     183             :   }
     184             : 
     185           0 :   mooseError("Malformed material_properties expression '", expression, "'");
     186             : }
     187             : 
     188             : template <bool is_ad>
     189             : void
     190        3618 : FunctionMaterialPropertyDescriptor<is_ad>::parseDependentSymbols(const std::string & expression)
     191             : {
     192        3618 :   auto open = expression.find_first_of("(");
     193        3618 :   auto close = expression.find_last_of(")");
     194             : 
     195        3618 :   if (open == std::string::npos && close == std::string::npos)
     196             :   {
     197             :     // material property name without arguments
     198        3534 :     _base_name = expression;
     199             :   }
     200          84 :   else if (open != std::string::npos && close != std::string::npos)
     201             :   {
     202             :     // take material property name before bracket
     203          84 :     _base_name = expression.substr(0, open);
     204             : 
     205             :     // parse argument list
     206          84 :     MooseUtils::tokenize(expression.substr(open + 1, close - open - 1), _dependent_symbols, 0, ",");
     207             : 
     208             :     // remove duplicates from dependent variable list
     209          84 :     std::sort(_dependent_symbols.begin(), _dependent_symbols.end());
     210          84 :     _dependent_symbols.erase(std::unique(_dependent_symbols.begin(), _dependent_symbols.end()),
     211         168 :                              _dependent_symbols.end());
     212             :   }
     213             :   else
     214           0 :     mooseError("Malformed material_properties expression '", expression, "'");
     215        3618 : }
     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     4362059 : FunctionMaterialPropertyDescriptor<is_ad>::value(unsigned int qp) const
     233             : {
     234             :   // current property
     235     4362059 :   if (_state == PropertyState::CURRENT)
     236             :   {
     237     4361795 :     if (_value == nullptr)
     238             :     {
     239        5562 :       DerivativeMaterialInterface<Material> * _material_parent =
     240        5562 :           dynamic_cast<DerivativeMaterialInterface<Material> *>(_parent);
     241        5562 :       DerivativeMaterialInterface<Kernel> * _kernel_parent =
     242        5562 :           dynamic_cast<DerivativeMaterialInterface<Kernel> *>(_parent);
     243             : 
     244             :       // property name
     245        5562 :       auto name = derivativePropertyName(_base_name, _derivative_symbols);
     246             : 
     247             :       // get the material property reference
     248        5562 :       if (_material_parent)
     249        9924 :         _value = _required ? &(_material_parent->getGenericMaterialProperty<Real, is_ad>(name))
     250        4362 :                            : &(_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        5562 :     }
     258             : 
     259     4361795 :     return qp != libMesh::invalid_uint ? (*_value)[qp] : 0.0;
     260             :   }
     261             : 
     262             :   // old or older property
     263         264 :   if (_old_older_value == nullptr)
     264             :   {
     265             :     mooseAssert(_derivative_symbols.empty(), "Don't take derivatives of old/older properties.");
     266             : 
     267          84 :     DerivativeMaterialInterface<Material> * _material_parent =
     268          84 :         dynamic_cast<DerivativeMaterialInterface<Material> *>(_parent);
     269          84 :     DerivativeMaterialInterface<Kernel> * _kernel_parent =
     270          84 :         dynamic_cast<DerivativeMaterialInterface<Kernel> *>(_parent);
     271             : 
     272             :     // get the material property reference
     273          84 :     if (_material_parent)
     274          84 :       _old_older_value = (_state == PropertyState::OLD)
     275          84 :                              ? &(_material_parent->getMaterialPropertyOld<Real>(_base_name))
     276          42 :                              : &(_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         264 :   return qp != libMesh::invalid_uint ? (*_old_older_value)[qp] : 0.0;
     287             : }
     288             : 
     289             : template <bool is_ad>
     290             : void
     291        6663 : FunctionMaterialPropertyDescriptor<is_ad>::updatePropertyName()
     292             : {
     293        6663 :   _property_name = derivativePropertyName(_base_name, _derivative_symbols);
     294        6663 : }
     295             : 
     296             : // explicit instantiation
     297             : template class FunctionMaterialPropertyDescriptor<false>;
     298             : template class FunctionMaterialPropertyDescriptor<true>;

Generated by: LCOV version 1.14