LCOV - code coverage report
Current view: top level - include/utils - FactorizedRankTwoTensor.h (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 8601ad Lines: 43 44 97.7 %
Date: 2025-07-18 13:27:08 Functions: 22 67 32.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             : #pragma once
      11             : 
      12             : #include "RankTwoTensor.h"
      13             : #include "SymmetricRankTwoTensor.h"
      14             : 
      15             : // forward declarations
      16             : template <typename>
      17             : class FactorizedRankTwoTensorTempl;
      18             : 
      19             : /**
      20             :  * FactorizedRankTwoTensorTempl is designed to perform the spectral decomposition of an
      21             :  * underlying symmetric second order tensor and reuse its bases for future operations if possible.
      22             :  *
      23             :  * FactorizedRankTwoTensorTempl templates on the underlying second order tensor.
      24             :  * IMPORTANT: the underlying second order tensor must be symmetric. A check is only performed in
      25             :  * debug mode.
      26             :  *
      27             :  * Only operations that reuses the known factorization are provided. Otherwise, you will need to
      28             :  * first retrieve the underlying RankTwoTensorTempl to perform the operation.
      29             :  *
      30             :  * TODO? Although I am calling it factorization, it only really refers to eigenvalue decompositon at
      31             :  * this point. I am not sure if in the future we need to add other types of similarity
      32             :  * transformation.
      33             :  */
      34             : template <typename T>
      35             : class FactorizedRankTwoTensorTempl
      36             : {
      37             : public:
      38             :   /// For generic programming
      39             :   typedef typename T::value_type value_type;
      40             : 
      41             :   /// No default constructor
      42             :   FactorizedRankTwoTensorTempl() = delete;
      43             : 
      44             :   /// Copy constructor
      45           6 :   FactorizedRankTwoTensorTempl(const FactorizedRankTwoTensorTempl<T> & A) = default;
      46             : 
      47             :   /// Constructor if the factorization isn't known a priori
      48          23 :   FactorizedRankTwoTensorTempl(const T & A)
      49          23 :   {
      50          23 :     if (!A.isSymmetric())
      51           0 :       mooseError("The tensor is not symmetric.");
      52          23 :     A.symmetricEigenvaluesEigenvectors(_eigvals, _eigvecs);
      53          23 :   }
      54             : 
      55             :   // Construct from the factorization
      56             :   // Assume that regardless of the type of T, the eigenvectors are always stored as as a full second
      57             :   // order tensor, e.g. the eigenvector matrix of a symmetric second order tensor isn't symmetric in
      58             :   // general. Hence we don't take advantage of orthonormal and/or unitary second order tensors.
      59           8 :   FactorizedRankTwoTensorTempl(const std::vector<typename T::value_type> & eigvals,
      60             :                                const RankTwoTensorTempl<typename T::value_type> & eigvecs)
      61           8 :     : _eigvals(eigvals), _eigvecs(eigvecs)
      62             :   {
      63           8 :   }
      64             : 
      65             :   // @{ getters
      66             :   template <typename T2 = T>
      67           4 :   T2 get() const
      68             :   {
      69           4 :     return static_cast<T2>(assemble());
      70             :   }
      71             :   template <typename T2 = T>
      72         180 :   T2 get()
      73             :   {
      74         180 :     return static_cast<T2>(assemble());
      75             :   }
      76          70 :   const std::vector<typename T::value_type> & eigvals() const { return _eigvals; }
      77          36 :   std::vector<typename T::value_type> eigvals() { return _eigvals; }
      78          50 :   const RankTwoTensorTempl<typename T::value_type> & eigvecs() const { return _eigvecs; }
      79          63 :   RankTwoTensorTempl<typename T::value_type> eigvecs() { return _eigvecs; }
      80             :   // @}
      81             : 
      82             :   void print(std::ostream & stm = Moose::out) const;
      83             : 
      84             :   // Returns _A rotated by R.
      85             :   FactorizedRankTwoTensorTempl<T>
      86             :   rotated(const RankTwoTensorTempl<typename T::value_type> & R) const;
      87             : 
      88             :   /// Returns the transpose of _A.
      89             :   FactorizedRankTwoTensorTempl<T> transpose() const;
      90             : 
      91             :   // @{ Assignment operators
      92             :   FactorizedRankTwoTensorTempl<T> & operator=(const FactorizedRankTwoTensorTempl<T> & A);
      93             :   FactorizedRankTwoTensorTempl<T> & operator=(const T & A);
      94             :   // @}
      95             : 
      96             :   /// performs _A *= a in place, also updates eigen values
      97             :   FactorizedRankTwoTensorTempl<T> & operator*=(const typename T::value_type & a);
      98             : 
      99             :   /// returns _A * a, also updates eigen values
     100             :   template <typename T2>
     101             :   FactorizedRankTwoTensorTempl<T> operator*(const T2 & a) const;
     102             : 
     103             :   /// performs _A /= a in place, also updates eigen values
     104             :   FactorizedRankTwoTensorTempl<T> & operator/=(const typename T::value_type & a);
     105             : 
     106             :   /// returns _A / a, also updates eigen values
     107             :   template <typename T2>
     108             :   FactorizedRankTwoTensorTempl<T> operator/(const T2 & a) const;
     109             : 
     110             :   /// Defines logical equality with another second order tensor
     111             :   bool operator==(const T & A) const;
     112             : 
     113             :   /// Defines logical equality with another FactorizedRankTwoTensorTempl<T>
     114             :   bool operator==(const FactorizedRankTwoTensorTempl<T> & A) const;
     115             : 
     116             :   /// inverse of _A
     117             :   FactorizedRankTwoTensorTempl<T> inverse() const;
     118             : 
     119             :   /// add identity times a to _A
     120             :   void addIa(const typename T::value_type & a);
     121             : 
     122             :   /// trace of _A
     123             :   typename T::value_type trace() const;
     124             : 
     125             :   /// determinant of _A
     126             :   typename T::value_type det() const;
     127             : 
     128             : private:
     129             :   // Assemble the tensor from the factorization
     130         184 :   RankTwoTensorTempl<typename T::value_type> assemble() const
     131             :   {
     132             :     typedef RankTwoTensorTempl<typename T::value_type> R2T;
     133         368 :     return _eigvals[0] * R2T::selfOuterProduct(_eigvecs.column(0)) +
     134         368 :            _eigvals[1] * R2T::selfOuterProduct(_eigvecs.column(1)) +
     135         920 :            _eigvals[2] * R2T::selfOuterProduct(_eigvecs.column(2));
     136             :   }
     137             : 
     138             :   // The eigen values of _A;
     139             :   std::vector<typename T::value_type> _eigvals;
     140             : 
     141             :   // The eigen vectors of _A;
     142             :   RankTwoTensorTempl<typename T::value_type> _eigvecs;
     143             : };
     144             : 
     145             : namespace MathUtils
     146             : {
     147             : #define FactorizedRankTwoTensorOperatorMapBody(operator)                                           \
     148             :   {                                                                                                \
     149             :     std::vector<typename T::value_type> op_eigvals;                                                \
     150             :     for (const auto & eigval : A.eigvals())                                                        \
     151             :       op_eigvals.push_back(operator);                                                              \
     152             :     return FactorizedRankTwoTensorTempl<T>(op_eigvals, A.eigvecs());                               \
     153             :   }
     154             : 
     155             : #define FactorizedRankTwoTensorOperatorMapUnary(operatorname, operator)                            \
     156             :   template <typename T>                                                                            \
     157             :   FactorizedRankTwoTensorTempl<T> operatorname(const FactorizedRankTwoTensorTempl<T> & A)          \
     158             :   {                                                                                                \
     159             :     FactorizedRankTwoTensorOperatorMapBody(operator)                                               \
     160             :   }                                                                                                \
     161             :   static_assert(true, "")
     162             : 
     163             : #define FactorizedRankTwoTensorOperatorMapBinary(operatorname, operator)                           \
     164             :   template <typename T, typename T2>                                                               \
     165             :   FactorizedRankTwoTensorTempl<T> operatorname(const FactorizedRankTwoTensorTempl<T> & A,          \
     166             :                                                const T2 & arg)                                     \
     167             :   {                                                                                                \
     168             :     if constexpr (libMesh::ScalarTraits<T2>::value)                                                \
     169             :     {                                                                                              \
     170             :       FactorizedRankTwoTensorOperatorMapBody(operator)                                             \
     171             :     }                                                                                              \
     172             :   }                                                                                                \
     173             :   static_assert(true, "")
     174             : 
     175             : #define FactorizedRankTwoTensorOperatorMapDerivativeBody(operator, derivative)                     \
     176             :   {                                                                                                \
     177             :     std::vector<typename T::value_type> op_eigvals, op_derivs;                                     \
     178             :     for (const auto & eigval : A.eigvals())                                                        \
     179             :     {                                                                                              \
     180             :       op_eigvals.push_back(operator);                                                              \
     181             :       op_derivs.push_back(derivative);                                                             \
     182             :     }                                                                                              \
     183             :                                                                                                    \
     184             :     RankFourTensorTempl<typename T::value_type> P, Gab, Gba;                                       \
     185             :     typedef RankTwoTensorTempl<typename T::value_type> R2T;                                        \
     186             :                                                                                                    \
     187             :     for (auto a : make_range(3))                                                                   \
     188             :     {                                                                                              \
     189             :       const auto Ma = R2T::selfOuterProduct(A.eigvecs().column(a));                                \
     190             :       P += op_derivs[a] * Ma.outerProduct(Ma);                                                     \
     191             :     }                                                                                              \
     192             :                                                                                                    \
     193             :     for (auto a : make_range(3))                                                                   \
     194             :       for (auto b : make_range(a))                                                                 \
     195             :       {                                                                                            \
     196             :         const auto Ma = R2T::selfOuterProduct(A.eigvecs().column(a));                              \
     197             :         const auto Mb = R2T::selfOuterProduct(A.eigvecs().column(b));                              \
     198             :                                                                                                    \
     199             :         usingTensorIndices(i_, j_, k_, l_);                                                        \
     200             :         Gab = Ma.template times<i_, k_, j_, l_>(Mb) + Ma.template times<i_, l_, j_, k_>(Mb);       \
     201             :         Gba = Mb.template times<i_, k_, j_, l_>(Ma) + Mb.template times<i_, l_, j_, k_>(Ma);       \
     202             :                                                                                                    \
     203             :         Real theta_ab;                                                                             \
     204             :         if (!MooseUtils::absoluteFuzzyEqual(A.eigvals()[a], A.eigvals()[b]))                       \
     205             :           theta_ab = 0.5 * (op_eigvals[a] - op_eigvals[b]) / (A.eigvals()[a] - A.eigvals()[b]);    \
     206             :         else                                                                                       \
     207             :           theta_ab = 0.25 * (op_derivs[a] + op_derivs[b]);                                         \
     208             :                                                                                                    \
     209             :         P += theta_ab * (Gab + Gba);                                                               \
     210             :       }                                                                                            \
     211             :     return P;                                                                                      \
     212             :   }
     213             : 
     214             : #define FactorizedRankTwoTensorOperatorMapDerivativeUnary(derivativename, operator, derivative)    \
     215             :   template <typename T>                                                                            \
     216             :   RankFourTensorTempl<typename T::value_type> derivativename(                                      \
     217             :       const FactorizedRankTwoTensorTempl<T> & A)                                                   \
     218             :   {                                                                                                \
     219             :     FactorizedRankTwoTensorOperatorMapDerivativeBody(operator, derivative)                         \
     220             :   }                                                                                                \
     221             :   static_assert(true, "")
     222             : 
     223             : #define FactorizedRankTwoTensorOperatorMapDerivativeBinary(derivativename, operator, derivative)   \
     224             :   template <typename T, typename T2>                                                               \
     225             :   RankFourTensorTempl<typename T::value_type> derivativename(                                      \
     226             :       const FactorizedRankTwoTensorTempl<T> & A, const T2 & arg)                                   \
     227             :   {                                                                                                \
     228             :     if constexpr (libMesh::ScalarTraits<T2>::value)                                                \
     229             :     {                                                                                              \
     230             :       FactorizedRankTwoTensorOperatorMapDerivativeBody(operator, derivative)                       \
     231             :     }                                                                                              \
     232             :   }                                                                                                \
     233             :   static_assert(true, "")
     234             : 
     235             : // TODO: While the macros are here, in the future we could instantiate other operator maps like
     236             : // trignometry functions.
     237             : // @{
     238           6 : FactorizedRankTwoTensorOperatorMapUnary(log, std::log(eigval));
     239          14 : FactorizedRankTwoTensorOperatorMapDerivativeUnary(dlog, std::log(eigval), 1 / eigval);
     240             : 
     241           6 : FactorizedRankTwoTensorOperatorMapUnary(exp, std::exp(eigval));
     242          14 : FactorizedRankTwoTensorOperatorMapDerivativeUnary(dexp, std::exp(eigval), std::exp(eigval));
     243             : 
     244           6 : FactorizedRankTwoTensorOperatorMapUnary(sqrt, std::sqrt(eigval));
     245          14 : FactorizedRankTwoTensorOperatorMapDerivativeUnary(dsqrt,
     246             :                                                   std::sqrt(eigval),
     247             :                                                   std::pow(eigval, -1. / 2.) / 2.);
     248             : 
     249           6 : FactorizedRankTwoTensorOperatorMapUnary(cbrt, std::cbrt(eigval));
     250          14 : FactorizedRankTwoTensorOperatorMapDerivativeUnary(dcbrt,
     251             :                                                   std::cbrt(eigval),
     252             :                                                   std::pow(eigval, -2. / 3.) / 3.);
     253             : 
     254           6 : FactorizedRankTwoTensorOperatorMapBinary(pow, std::pow(eigval, arg));
     255          14 : FactorizedRankTwoTensorOperatorMapDerivativeBinary(dpow,
     256             :                                                    std::pow(eigval, arg),
     257             :                                                    arg * std::pow(eigval, arg - 1));
     258             : // @}
     259             : } // end namespace MathUtils
     260             : 
     261             : template <typename T>
     262             : template <typename T2>
     263             : FactorizedRankTwoTensorTempl<T>
     264           1 : FactorizedRankTwoTensorTempl<T>::operator*(const T2 & a) const
     265             : {
     266             :   if constexpr (libMesh::ScalarTraits<T2>::value)
     267             :   {
     268           1 :     FactorizedRankTwoTensorTempl<T> A = *this;
     269           4 :     for (auto & eigval : A._eigvals)
     270           3 :       eigval *= a;
     271           2 :     return A;
     272           1 :   }
     273             : }
     274             : 
     275             : template <typename T>
     276             : template <typename T2>
     277             : FactorizedRankTwoTensorTempl<T>
     278           1 : FactorizedRankTwoTensorTempl<T>::operator/(const T2 & a) const
     279             : {
     280             :   if constexpr (libMesh::ScalarTraits<T2>::value)
     281             :   {
     282           1 :     FactorizedRankTwoTensorTempl<T> A = *this;
     283           4 :     for (auto & eigval : A._eigvals)
     284           3 :       eigval /= a;
     285           2 :     return A;
     286           1 :   }
     287             : }
     288             : 
     289             : typedef FactorizedRankTwoTensorTempl<RankTwoTensor> FactorizedRankTwoTensor;
     290             : typedef FactorizedRankTwoTensorTempl<ADRankTwoTensor> ADFactorizedRankTwoTensor;
     291             : typedef FactorizedRankTwoTensorTempl<SymmetricRankTwoTensor> FactorizedSymmetricRankTwoTensor;
     292             : typedef FactorizedRankTwoTensorTempl<ADSymmetricRankTwoTensor> ADFactorizedSymmetricRankTwoTensor;

Generated by: LCOV version 1.14