LCOV - code coverage report
Current view: top level - include/utils - RankFourTensor.h (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 2bf808 Lines: 159 166 95.8 %
Date: 2025-07-17 01:28:37 Functions: 25 55 45.5 %
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 "Moose.h"
      13             : #include "MooseTypes.h"
      14             : #include "ADRankTwoTensorForward.h"
      15             : #include "ADRankFourTensorForward.h"
      16             : #include "ADRankThreeTensorForward.h"
      17             : #include "MooseError.h"
      18             : 
      19             : #include "libmesh/libmesh.h"
      20             : #include "libmesh/tuple_of.h"
      21             : #include "libmesh/int_range.h"
      22             : 
      23             : #include "metaphysicl/raw_type.h"
      24             : 
      25             : #include <petscsys.h>
      26             : 
      27             : #include <Eigen/Core>
      28             : #include <Eigen/Dense>
      29             : 
      30             : using libMesh::tuple_of;
      31             : namespace libMesh
      32             : {
      33             : template <typename>
      34             : class TensorValue;
      35             : template <typename>
      36             : class TypeTensor;
      37             : template <typename>
      38             : class VectorValue;
      39             : }
      40             : 
      41             : // Forward declarations
      42             : class MooseEnum;
      43             : 
      44             : namespace MathUtils
      45             : {
      46             : template <typename T>
      47             : void mooseSetToZero(T & v);
      48             : 
      49             : /**
      50             :  * Helper function template specialization to set an object to zero.
      51             :  * Needed by DerivativeMaterialInterface
      52             :  */
      53             : template <>
      54             : void mooseSetToZero<RankFourTensor>(RankFourTensor & v);
      55             : template <>
      56             : void mooseSetToZero<ADRankFourTensor>(ADRankFourTensor & v);
      57             : }
      58             : 
      59             : /**
      60             :  * RankFourTensorTempl is designed to handle any N-dimensional fourth order tensor, C.
      61             :  * Since N is hard-coded to 3, RankFourTensorTempl holds 81 separate C_ijkl entries,
      62             :  * with i,j,k,l = 0, 1, 2.
      63             :  */
      64             : template <typename T>
      65             : class RankFourTensorTempl
      66             : {
      67             : public:
      68             :   ///@{ tensor dimension and powers of the dimension
      69             :   static constexpr unsigned int N = Moose::dim;
      70             :   static constexpr unsigned int N2 = N * N;
      71             :   static constexpr unsigned int N3 = N * N * N;
      72             :   static constexpr unsigned int N4 = N * N * N * N;
      73             :   ///@}
      74             : 
      75             :   typedef tuple_of<4, unsigned int> index_type;
      76             :   typedef T value_type;
      77             : 
      78             :   /// Initialization method
      79             :   enum InitMethod
      80             :   {
      81             :     initNone,
      82             :     initIdentity,
      83             :     initIdentityFour,
      84             :     initIdentitySymmetricFour,
      85             :     initIdentityDeviatoric
      86             :   };
      87             : 
      88             :   /**
      89             :    * To fill up the 81 entries in the 4th-order tensor, fillFromInputVector
      90             :    * is called with one of the following fill_methods.
      91             :    * See the fill*FromInputVector functions for more details
      92             :    */
      93             :   enum FillMethod
      94             :   {
      95             :     antisymmetric,
      96             :     symmetric9,
      97             :     symmetric21,
      98             :     general_isotropic,
      99             :     symmetric_isotropic,
     100             :     symmetric_isotropic_E_nu,
     101             :     antisymmetric_isotropic,
     102             :     axisymmetric_rz,
     103             :     general,
     104             :     principal,
     105             :     orthotropic
     106             :   };
     107             : 
     108             :   template <template <typename> class Tensor, typename Scalar>
     109             :   struct TwoTensorMultTraits
     110             :   {
     111             :     static const bool value = false;
     112             :   };
     113             :   template <typename Scalar>
     114             :   struct TwoTensorMultTraits<RankTwoTensorTempl, Scalar>
     115             :   {
     116             :     static const bool value = libMesh::ScalarTraits<Scalar>::value;
     117             :   };
     118             :   template <typename Scalar>
     119             :   struct TwoTensorMultTraits<TensorValue, Scalar>
     120             :   {
     121             :     static const bool value = libMesh::ScalarTraits<Scalar>::value;
     122             :   };
     123             :   template <typename Scalar>
     124             :   struct TwoTensorMultTraits<TypeTensor, Scalar>
     125             :   {
     126             :     static const bool value = libMesh::ScalarTraits<Scalar>::value;
     127             :   };
     128             : 
     129             :   /// Default constructor; fills to zero
     130             :   RankFourTensorTempl();
     131             : 
     132             :   /// Select specific initialization pattern
     133             :   RankFourTensorTempl(const InitMethod);
     134             : 
     135             :   /// Fill from vector
     136             :   RankFourTensorTempl(const std::vector<T> &, FillMethod);
     137             : 
     138             :   /// Copy assignment operator must be defined if used
     139           0 :   RankFourTensorTempl(const RankFourTensorTempl<T> & a) = default;
     140             : 
     141             :   /**
     142             :    * Copy constructor
     143             :    */
     144             :   template <typename T2>
     145             :   RankFourTensorTempl(const RankFourTensorTempl<T2> & copy);
     146             : 
     147             :   /**
     148             :    * The conversion operator from a `SymmetricRankFourTensorTempl`
     149             :    */
     150             :   template <typename T2>
     151             :   RankFourTensorTempl(const SymmetricRankFourTensorTempl<T2> & t)
     152             :   {
     153             :     for (const auto a : make_range(SymmetricRankFourTensorTempl<T2>::N))
     154             :       for (const auto b : make_range(SymmetricRankFourTensorTempl<T2>::N))
     155             :       {
     156             :         const auto & idx = SymmetricRankFourTensorTempl<T2>::full_index[a][b];
     157             :         const auto i = idx[0];
     158             :         const auto j = idx[1];
     159             :         const auto k = idx[2];
     160             :         const auto l = idx[3];
     161             : 
     162             :         // Rijkl = Rjikl = Rijlk = Rjilk
     163             :         (*this)(i, j, k, l) = t(a, b) / SymmetricRankFourTensorTempl<T2>::mandelFactor(a, b);
     164             :         (*this)(j, i, k, l) = t(a, b) / SymmetricRankFourTensorTempl<T2>::mandelFactor(a, b);
     165             :         (*this)(i, j, l, k) = t(a, b) / SymmetricRankFourTensorTempl<T2>::mandelFactor(a, b);
     166             :         (*this)(j, i, l, k) = t(a, b) / SymmetricRankFourTensorTempl<T2>::mandelFactor(a, b);
     167             :       }
     168             :   }
     169             : 
     170             :   // Named constructors
     171           0 :   static RankFourTensorTempl<T> Identity() { return RankFourTensorTempl<T>(initIdentity); }
     172           1 :   static RankFourTensorTempl<T> IdentityFour() { return RankFourTensorTempl<T>(initIdentityFour); };
     173             :   /// Identity of type \delta_{ik} \delta_{jl} - \delta_{ij} \delta_{kl} / 3
     174           0 :   static RankFourTensorTempl<T> IdentityDeviatoric()
     175             :   {
     176           0 :     return RankFourTensorTempl<T>(initIdentityDeviatoric);
     177             :   };
     178             : 
     179             :   /// Gets the value for the indices specified. Takes indices ranging from 0-2 for i, j, k, and l.
     180   159177514 :   inline T & operator()(unsigned int i, unsigned int j, unsigned int k, unsigned int l)
     181             :   {
     182   159177514 :     return _vals[i * N3 + j * N2 + k * N + l];
     183             :   }
     184             : 
     185             :   /**
     186             :    * Gets the value for the indices specified. Takes indices ranging from 0-2 for i, j, k, and l.
     187             :    * used for const
     188             :    */
     189     1672104 :   inline const T & operator()(unsigned int i, unsigned int j, unsigned int k, unsigned int l) const
     190             :   {
     191     1672104 :     return _vals[i * N3 + j * N2 + k * N + l];
     192             :   }
     193             : 
     194             :   /// Zeros out the tensor.
     195             :   void zero();
     196             : 
     197             :   /// Print the rank four tensor
     198             :   void print(std::ostream & stm = Moose::out) const;
     199             : 
     200             :   friend std::ostream & operator<<(std::ostream & os, const RankFourTensorTempl<T> & t)
     201             :   {
     202             :     t.print(os);
     203             :     return os;
     204             :   }
     205             : 
     206             :   /// Print the values of the rank four tensor
     207             :   void printReal(std::ostream & stm = Moose::out) const;
     208             : 
     209             :   /// copies values from a into this tensor
     210    63763446 :   RankFourTensorTempl<T> & operator=(const RankFourTensorTempl<T> & a) = default;
     211             : 
     212             :   /**
     213             :    * Assignment-from-scalar operator.  Used only to zero out the tensor.
     214             :    *
     215             :    * \returns A reference to *this.
     216             :    */
     217             :   template <typename Scalar>
     218             :   typename libMesh::boostcopy::enable_if_c<libMesh::ScalarTraits<Scalar>::value,
     219             :                                            RankFourTensorTempl &>::type
     220             :   operator=(const Scalar & libmesh_dbg_var(p))
     221             :   {
     222             :     libmesh_assert_equal_to(p, Scalar(0));
     223             :     this->zero();
     224             :     return *this;
     225             :   }
     226             : 
     227             :   /// C_ijkl*a_kl
     228             :   template <template <typename> class Tensor, typename T2>
     229             :   auto operator*(const Tensor<T2> & a) const ->
     230             :       typename std::enable_if<TwoTensorMultTraits<Tensor, T2>::value,
     231             :                               RankTwoTensorTempl<decltype(T() * T2())>>::type;
     232             : 
     233             :   /// C_ijkl*a
     234             :   template <typename T2>
     235             :   auto operator*(const T2 & a) const ->
     236             :       typename std::enable_if<libMesh::ScalarTraits<T2>::value,
     237             :                               RankFourTensorTempl<decltype(T() * T2())>>::type;
     238             : 
     239             :   /// C_ijkl *= a
     240             :   RankFourTensorTempl<T> & operator*=(const T & a);
     241             : 
     242             :   /// C_ijkl/a
     243             :   template <typename T2>
     244             :   auto operator/(const T2 & a) const ->
     245             :       typename std::enable_if<libMesh::ScalarTraits<T2>::value,
     246             :                               RankFourTensorTempl<decltype(T() / T2())>>::type;
     247             : 
     248             :   /// C_ijkl /= a  for all i, j, k, l
     249             :   RankFourTensorTempl<T> & operator/=(const T & a);
     250             : 
     251             :   /// C_ijkl += a_ijkl  for all i, j, k, l
     252             :   RankFourTensorTempl<T> & operator+=(const RankFourTensorTempl<T> & a);
     253             : 
     254             :   /// C_ijkl + a_ijkl
     255             :   template <typename T2>
     256             :   auto operator+(const RankFourTensorTempl<T2> & a) const
     257             :       -> RankFourTensorTempl<decltype(T() + T2())>;
     258             : 
     259             :   /// C_ijkl -= a_ijkl
     260             :   RankFourTensorTempl<T> & operator-=(const RankFourTensorTempl<T> & a);
     261             : 
     262             :   /// C_ijkl - a_ijkl
     263             :   template <typename T2>
     264             :   auto operator-(const RankFourTensorTempl<T2> & a) const
     265             :       -> RankFourTensorTempl<decltype(T() - T2())>;
     266             : 
     267             :   /// -C_ijkl
     268             :   RankFourTensorTempl<T> operator-() const;
     269             : 
     270             :   /// C_ijpq*a_pqkl
     271             :   template <typename T2>
     272             :   auto operator*(const RankFourTensorTempl<T2> & a) const
     273             :       -> RankFourTensorTempl<decltype(T() * T2())>;
     274             : 
     275             :   /// sqrt(C_ijkl*C_ijkl)
     276             :   T L2norm() const;
     277             : 
     278             :   /**
     279             :    * This returns A_ijkl such that C_ijkl*A_klmn = 0.5*(de_im de_jn + de_in de_jm)
     280             :    * This routine assumes that C_ijkl = C_jikl = C_ijlk
     281             :    */
     282             :   RankFourTensorTempl<T> invSymm() const;
     283             : 
     284             :   /**
     285             :    * This returns A_ijkl such that C_ijkl*A_klmn = de_im de_jn
     286             :    * i.e. the general rank four inverse
     287             :    */
     288             :   RankFourTensorTempl<T> inverse() const;
     289             : 
     290             :   /**
     291             :    * Rotate the tensor using
     292             :    * C_ijkl = R_im R_jn R_ko R_lp C_mnop
     293             :    */
     294             :   void rotate(const TypeTensor<T> & R);
     295             : 
     296             :   /**
     297             :    * Transpose the tensor by swapping the first pair with the second pair of indices
     298             :    * @return C_klji
     299             :    */
     300             :   RankFourTensorTempl<T> transposeMajor() const;
     301             : 
     302             :   /**
     303             :    * Transpose the tensor by swapping the first two indeces
     304             :    * @return C_jikl
     305             :    */
     306             :   RankFourTensorTempl<T> transposeIj() const;
     307             : 
     308             :   /**
     309             :    * Transpose the tensor by swapping the last two indeces
     310             :    * @return C_ijlk
     311             :    */
     312             :   RankFourTensorTempl<T> transposeKl() const;
     313             : 
     314             :   /**
     315             :    * single contraction of a RankFourTensor with a vector over index m
     316             :    * @return C_xxx = a_ijkl*b_m where m={i,j,k,l} and xxx the remaining indices
     317             :    */
     318             :   template <int m>
     319             :   RankThreeTensorTempl<T> contraction(const libMesh::VectorValue<T> & b) const;
     320             : 
     321             :   /**
     322             :    * Fills the tensor entries ignoring the last dimension (ie, C_ijkl=0 if any of i, j, k, or l =
     323             :    * 3).
     324             :    * Fill method depends on size of input
     325             :    * Input size = 2.  Then C_1111 = C_2222 = input[0], and C_1122 = input[1], and C_1212 = (input[0]
     326             :    * - input[1])/2,
     327             :    *                  and C_ijkl = C_jikl = C_ijlk = C_klij, and C_1211 = C_1222 = 0.
     328             :    * Input size = 9.  Then C_1111 = input[0], C_1112 = input[1], C_1122 = input[3],
     329             :    *                       C_1212 = input[4], C_1222 = input[5], C_1211 = input[6]
     330             :    *                       C_2211 = input[7], C_2212 = input[8], C_2222 = input[9]
     331             :    *                       and C_ijkl = C_jikl = C_ijlk
     332             :    */
     333             :   void surfaceFillFromInputVector(const std::vector<T> & input);
     334             : 
     335             :   /// Static method for use in validParams for getting the "fill_method"
     336             :   static MooseEnum fillMethodEnum();
     337             : 
     338             :   /**
     339             :    * fillFromInputVector takes some number of inputs to fill
     340             :    * the Rank-4 tensor.
     341             :    * @param input the numbers that will be placed in the tensor
     342             :    * @param fill_method this can be:
     343             :    *             antisymmetric (use fillAntisymmetricFromInputVector)
     344             :    *             symmetric9 (use fillSymmetric9FromInputVector)
     345             :    *             symmetric21 (use fillSymmetric21FromInputVector)
     346             :    *             general_isotropic (use fillGeneralIsotropicFrominputVector)
     347             :    *             symmetric_isotropic (use fillSymmetricIsotropicFromInputVector)
     348             :    *             antisymmetric_isotropic (use fillAntisymmetricIsotropicFromInputVector)
     349             :    *             axisymmetric_rz (use fillAxisymmetricRZFromInputVector)
     350             :    *             general (use fillGeneralFromInputVector)
     351             :    *             principal (use fillPrincipalFromInputVector)
     352             :    */
     353             :   void fillFromInputVector(const std::vector<T> & input, FillMethod fill_method);
     354             : 
     355             :   ///@{ Vector-less fill API functions. See docs of the corresponding ...FromInputVector methods
     356             :   void fillGeneralIsotropic(const T & i0, const T & i1, const T & i2);
     357             :   void fillAntisymmetricIsotropic(const T & i0);
     358             :   void fillSymmetricIsotropic(const T & i0, const T & i1);
     359             :   void fillSymmetricIsotropicEandNu(const T & E, const T & nu);
     360             :   ///@}
     361             : 
     362             :   /**
     363             :    * fillSymmetric9FromInputVector takes 9 inputs to fill in
     364             :    * the Rank-4 tensor with the appropriate crystal symmetries maintained. I.e., C_ijkl = C_klij,
     365             :    * C_ijkl = C_ijlk, C_ijkl = C_jikl
     366             :    * @param input is:
     367             :    *                C1111 C1122 C1133 C2222 C2233 C3333 C2323 C1313 C1212
     368             :    *                In the isotropic case this is (la is first Lame constant, mu is second (shear)
     369             :    * Lame constant)
     370             :    *                la+2mu la la la+2mu la la+2mu mu mu mu
     371             :    */
     372             :   template <typename T2>
     373             :   void fillSymmetric9FromInputVector(const T2 & input);
     374             : 
     375             :   /**
     376             :    * fillSymmetric21FromInputVector takes either 21 inputs to fill in
     377             :    * the Rank-4 tensor with the appropriate crystal symmetries maintained. I.e., C_ijkl = C_klij,
     378             :    * C_ijkl = C_ijlk, C_ijkl = C_jikl
     379             :    * @param input is
     380             :    *                C1111 C1122 C1133 C1123 C1113 C1112 C2222 C2233 C2223 C2213 C2212 C3333 C3323
     381             :    * C3313 C3312 C2323 C2313 C2312 C1313 C1312 C1212
     382             :    */
     383             :   template <typename T2>
     384             :   void fillSymmetric21FromInputVector(const T2 & input);
     385             : 
     386             :   /// Inner product of the major transposed tensor with a rank two tensor
     387             :   RankTwoTensorTempl<T> innerProductTranspose(const RankTwoTensorTempl<T> &) const;
     388             : 
     389             :   /// Sum C_ijkl M_kl for a given i,j
     390             :   T contractionIj(unsigned int, unsigned int, const RankTwoTensorTempl<T> &) const;
     391             : 
     392             :   /// Sum M_ij C_ijkl for a given k,l
     393             :   T contractionKl(unsigned int, unsigned int, const RankTwoTensorTempl<T> &) const;
     394             : 
     395             :   /// Calculates the sum of Ciijj for i and j varying from 0 to 2
     396             :   T sum3x3() const;
     397             : 
     398             :   /// Calculates the vector a[i] = sum over j Ciijj for i and j varying from 0 to 2
     399             :   libMesh::VectorValue<T> sum3x1() const;
     400             : 
     401             :   /// Calculates C_imnt A_jm B_kn C_lt
     402             :   RankFourTensorTempl<T> tripleProductJkl(const RankTwoTensorTempl<T> &,
     403             :                                           const RankTwoTensorTempl<T> &,
     404             :                                           const RankTwoTensorTempl<T> &) const;
     405             :   /// Calculates C_mjnt A_im B_kn C_lt
     406             :   RankFourTensorTempl<T> tripleProductIkl(const RankTwoTensorTempl<T> &,
     407             :                                           const RankTwoTensorTempl<T> &,
     408             :                                           const RankTwoTensorTempl<T> &) const;
     409             :   /// Calculates C_mnkt A_im B_jn C_lt
     410             :   RankFourTensorTempl<T> tripleProductIjl(const RankTwoTensorTempl<T> &,
     411             :                                           const RankTwoTensorTempl<T> &,
     412             :                                           const RankTwoTensorTempl<T> &) const;
     413             :   /// Calculates C_mntl A_im B_jn C_kt
     414             :   RankFourTensorTempl<T> tripleProductIjk(const RankTwoTensorTempl<T> &,
     415             :                                           const RankTwoTensorTempl<T> &,
     416             :                                           const RankTwoTensorTempl<T> &) const;
     417             : 
     418             :   /// Calculates C_mjkl A_im
     419             :   RankFourTensorTempl<T> singleProductI(const RankTwoTensorTempl<T> &) const;
     420             :   /// Calculates C_imkl A_jm
     421             :   RankFourTensorTempl<T> singleProductJ(const RankTwoTensorTempl<T> &) const;
     422             :   /// Calculates C_ijml A_km
     423             :   RankFourTensorTempl<T> singleProductK(const RankTwoTensorTempl<T> &) const;
     424             :   /// Calculates C_ijkm A_lm
     425             :   RankFourTensorTempl<T> singleProductL(const RankTwoTensorTempl<T> &) const;
     426             : 
     427             :   /// checks if the tensor is symmetric
     428             :   bool isSymmetric() const;
     429             : 
     430             :   /// checks if the tensor is isotropic
     431             :   bool isIsotropic() const;
     432             : 
     433             : protected:
     434             :   /// The values of the rank-four tensor stored by
     435             :   /// index=(((i * LIBMESH_DIM + j) * LIBMESH_DIM + k) * LIBMESH_DIM + l)
     436             :   T _vals[N4];
     437             : 
     438             :   /**
     439             :    * fillAntisymmetricFromInputVector takes 6 inputs to fill the
     440             :    * the antisymmetric Rank-4 tensor with the appropriate symmetries maintained.
     441             :    * I.e., B_ijkl = -B_jikl = -B_ijlk = B_klij
     442             :    * @param input this is B1212, B1213, B1223, B1313, B1323, B2323.
     443             :    */
     444             :   void fillAntisymmetricFromInputVector(const std::vector<T> & input);
     445             : 
     446             :   /**
     447             :    * fillGeneralIsotropicFromInputVector takes 3 inputs to fill the
     448             :    * Rank-4 tensor with symmetries C_ijkl = C_klij, and isotropy, ie
     449             :    * C_ijkl = la*de_ij*de_kl + mu*(de_ik*de_jl + de_il*de_jk) + a*ep_ijm*ep_klm
     450             :    * where la is the first Lame modulus, mu is the second (shear) Lame modulus,
     451             :    * and a is the antisymmetric shear modulus, and ep is the permutation tensor
     452             :    * @param input this is la, mu, a in the above formula
     453             :    */
     454             :   void fillGeneralIsotropicFromInputVector(const std::vector<T> & input);
     455             : 
     456             :   /**
     457             :    * fillAntisymmetricIsotropicFromInputVector takes 1 input to fill the
     458             :    * the antisymmetric Rank-4 tensor with the appropriate symmetries maintained.
     459             :    * I.e., C_ijkl = a * ep_ijm * ep_klm, where epsilon is the permutation tensor (and sum on m)
     460             :    * @param input this is a in the above formula
     461             :    */
     462             :   void fillAntisymmetricIsotropicFromInputVector(const std::vector<T> & input);
     463             : 
     464             :   /**
     465             :    * fillSymmetricIsotropicFromInputVector takes 2 inputs to fill the
     466             :    * the symmetric Rank-4 tensor with the appropriate symmetries maintained.
     467             :    * C_ijkl = lambda*de_ij*de_kl + mu*(de_ik*de_jl + de_il*de_jk)
     468             :    * where lambda is the first Lame modulus, mu is the second (shear) Lame modulus,
     469             :    * @param input this is lambda and mu in the above formula
     470             :    */
     471             :   void fillSymmetricIsotropicFromInputVector(const std::vector<T> & input);
     472             : 
     473             :   /**
     474             :    * fillSymmetricIsotropicEandNuFromInputVector is a variation of the
     475             :    * fillSymmetricIsotropicFromInputVector which takes as inputs the
     476             :    * more commonly used Young's modulus (E) and Poisson's ratio (nu)
     477             :    * constants to fill the isotropic elasticity tensor. Using well-known formulas,
     478             :    * E and nu are used to calculate lambda and mu and then the vector is passed
     479             :    * to fillSymmetricIsotropicFromInputVector.
     480             :    * @param input Young's modulus (E) and Poisson's ratio (nu)
     481             :    */
     482             :   void fillSymmetricIsotropicEandNuFromInputVector(const std::vector<T> & input);
     483             : 
     484             :   /**
     485             :    * fillAxisymmetricRZFromInputVector takes 5 inputs to fill the axisymmetric
     486             :    * Rank-4 tensor with the appropriate symmetries maintatined for use with
     487             :    * axisymmetric problems using coord_type = RZ.
     488             :    * I.e. C1111 = C2222, C1133 = C2233, C2323 = C3131 and C1212 = 0.5*(C1111-C1122)
     489             :    * @param input this is C1111, C1122, C1133, C3333, C2323.
     490             :    */
     491             :   void fillAxisymmetricRZFromInputVector(const std::vector<T> & input);
     492             : 
     493             :   /**
     494             :    * fillGeneralFromInputVector takes 81 inputs to fill the Rank-4 tensor
     495             :    * No symmetries are explicitly maintained
     496             :    * @param input  C(i,j,k,l) = input[i*N*N*N + j*N*N + k*N + l]
     497             :    */
     498             :   void fillGeneralFromInputVector(const std::vector<T> & input);
     499             : 
     500             :   /**
     501             :    * fillPrincipalFromInputVector takes 9 inputs to fill a Rank-4 tensor
     502             :    * C1111 = input0
     503             :    * C1122 = input1
     504             :    * C1133 = input2
     505             :    * C2211 = input3
     506             :    * C2222 = input4
     507             :    * C2233 = input5
     508             :    * C3311 = input6
     509             :    * C3322 = input7
     510             :    * C3333 = input8
     511             :    * with all other components being zero
     512             :    */
     513             : 
     514             :   void fillPrincipalFromInputVector(const std::vector<T> & input);
     515             : 
     516             :   /**
     517             :    * fillGeneralOrhotropicFromInputVector takes 10  inputs to fill the Rank-4 tensor
     518             :    * It defines a general orthotropic tensor for which some constraints among
     519             :    * elastic parameters exist
     520             :    * @param input  Ea, Eb, Ec, Gab, Gbc, Gca, nuba, nuca, nucb, nuab, nuac, nubc
     521             :    */
     522             :   void fillGeneralOrthotropicFromInputVector(const std::vector<T> & input);
     523             : 
     524             :   template <class T2>
     525             :   friend void dataStore(std::ostream &, RankFourTensorTempl<T2> &, void *);
     526             : 
     527             :   template <class T2>
     528             :   friend void dataLoad(std::istream &, RankFourTensorTempl<T2> &, void *);
     529             : 
     530             :   template <typename T2>
     531             :   friend class RankTwoTensorTempl;
     532             :   template <typename T2>
     533             :   friend class RankFourTensorTempl;
     534             :   template <typename T2>
     535             :   friend class RankThreeTensorTempl;
     536             : };
     537             : 
     538             : namespace MetaPhysicL
     539             : {
     540             : template <typename T>
     541             : struct RawType<RankFourTensorTempl<T>>
     542             : {
     543             :   typedef RankFourTensorTempl<typename RawType<T>::value_type> value_type;
     544             : 
     545           6 :   static value_type value(const RankFourTensorTempl<T> & in)
     546             :   {
     547           6 :     constexpr auto N = RankFourTensorTempl<T>::N;
     548           6 :     value_type ret;
     549          24 :     for (auto i : libMesh::make_range(N))
     550          72 :       for (auto j : libMesh::make_range(N))
     551         216 :         for (auto k : libMesh::make_range(N))
     552         648 :           for (auto l : libMesh::make_range(N))
     553         486 :             ret(i, j, k, l) = raw_value(in(i, j, k, l));
     554             : 
     555           6 :     return ret;
     556             :   }
     557             : };
     558             : }
     559             : 
     560             : template <typename T1, typename T2>
     561             : inline auto
     562          38 : operator*(const T1 & a, const RankFourTensorTempl<T2> & b) ->
     563             :     typename std::enable_if<libMesh::ScalarTraits<T1>::value,
     564             :                             RankFourTensorTempl<decltype(T1() * T2())>>::type
     565             : {
     566          38 :   return b * a;
     567             : }
     568             : 
     569             : template <typename T>
     570             : template <typename T2>
     571         492 : RankFourTensorTempl<T>::RankFourTensorTempl(const RankFourTensorTempl<T2> & copy)
     572             : {
     573         492 :   for (auto i : libMesh::make_range(N4))
     574         486 :     _vals[i] = copy._vals[i];
     575           6 : }
     576             : 
     577             : template <typename T>
     578             : template <typename T2>
     579             : auto
     580          41 : RankFourTensorTempl<T>::operator*(const T2 & b) const ->
     581             :     typename std::enable_if<libMesh::ScalarTraits<T2>::value,
     582             :                             RankFourTensorTempl<decltype(T() * T2())>>::type
     583             : {
     584             :   typedef decltype(T() * T2()) ValueType;
     585          41 :   RankFourTensorTempl<ValueType> result;
     586             : 
     587        3362 :   for (auto i : libMesh::make_range(N4))
     588        3321 :     result._vals[i] = _vals[i] * b;
     589             : 
     590          41 :   return result;
     591           0 : }
     592             : 
     593             : template <typename T>
     594             : template <typename T2>
     595             : auto
     596           5 : RankFourTensorTempl<T>::operator/(const T2 & b) const ->
     597             :     typename std::enable_if<libMesh::ScalarTraits<T2>::value,
     598             :                             RankFourTensorTempl<decltype(T() / T2())>>::type
     599             : {
     600           5 :   RankFourTensorTempl<decltype(T() / T2())> result;
     601         410 :   for (auto i : libMesh::make_range(N4))
     602         405 :     result._vals[i] = _vals[i] / b;
     603           5 :   return result;
     604           0 : }
     605             : 
     606             : template <typename T>
     607             : template <typename T2>
     608             : void
     609           2 : RankFourTensorTempl<T>::fillSymmetric9FromInputVector(const T2 & input)
     610             : {
     611             :   mooseAssert(input.size() == 9,
     612             :               "To use fillSymmetric9FromInputVector, your input must have size 9.");
     613           2 :   zero();
     614             : 
     615           2 :   (*this)(0, 0, 0, 0) = input[0]; // C1111
     616           2 :   (*this)(1, 1, 1, 1) = input[3]; // C2222
     617           2 :   (*this)(2, 2, 2, 2) = input[5]; // C3333
     618             : 
     619           2 :   (*this)(0, 0, 1, 1) = input[1]; // C1122
     620           2 :   (*this)(1, 1, 0, 0) = input[1];
     621             : 
     622           2 :   (*this)(0, 0, 2, 2) = input[2]; // C1133
     623           2 :   (*this)(2, 2, 0, 0) = input[2];
     624             : 
     625           2 :   (*this)(1, 1, 2, 2) = input[4]; // C2233
     626           2 :   (*this)(2, 2, 1, 1) = input[4];
     627             : 
     628           2 :   (*this)(1, 2, 1, 2) = input[6]; // C2323
     629           2 :   (*this)(2, 1, 2, 1) = input[6];
     630           2 :   (*this)(2, 1, 1, 2) = input[6];
     631           2 :   (*this)(1, 2, 2, 1) = input[6];
     632             : 
     633           2 :   (*this)(0, 2, 0, 2) = input[7]; // C1313
     634           2 :   (*this)(2, 0, 2, 0) = input[7];
     635           2 :   (*this)(2, 0, 0, 2) = input[7];
     636           2 :   (*this)(0, 2, 2, 0) = input[7];
     637             : 
     638           2 :   (*this)(0, 1, 0, 1) = input[8]; // C1212
     639           2 :   (*this)(1, 0, 1, 0) = input[8];
     640           2 :   (*this)(1, 0, 0, 1) = input[8];
     641           2 :   (*this)(0, 1, 1, 0) = input[8];
     642           2 : }
     643             : template <typename T>
     644             : template <typename T2>
     645             : void
     646           6 : RankFourTensorTempl<T>::fillSymmetric21FromInputVector(const T2 & input)
     647             : {
     648             :   mooseAssert(input.size() == 21,
     649             :               "To use fillSymmetric21FromInputVector, your input must have size 21.");
     650             : 
     651           6 :   (*this)(0, 0, 0, 0) = input[0];  // C1111
     652           6 :   (*this)(1, 1, 1, 1) = input[6];  // C2222
     653           6 :   (*this)(2, 2, 2, 2) = input[11]; // C3333
     654             : 
     655           6 :   (*this)(0, 0, 1, 1) = input[1]; // C1122
     656           6 :   (*this)(1, 1, 0, 0) = input[1];
     657             : 
     658           6 :   (*this)(0, 0, 2, 2) = input[2]; // C1133
     659           6 :   (*this)(2, 2, 0, 0) = input[2];
     660             : 
     661           6 :   (*this)(1, 1, 2, 2) = input[7]; // C2233
     662           6 :   (*this)(2, 2, 1, 1) = input[7];
     663             : 
     664           6 :   (*this)(0, 0, 0, 2) = input[4]; // C1113
     665           6 :   (*this)(0, 0, 2, 0) = input[4];
     666           6 :   (*this)(0, 2, 0, 0) = input[4];
     667           6 :   (*this)(2, 0, 0, 0) = input[4];
     668             : 
     669           6 :   (*this)(0, 0, 0, 1) = input[5]; // C1112
     670           6 :   (*this)(0, 0, 1, 0) = input[5];
     671           6 :   (*this)(0, 1, 0, 0) = input[5];
     672           6 :   (*this)(1, 0, 0, 0) = input[5];
     673             : 
     674           6 :   (*this)(1, 1, 1, 2) = input[8]; // C2223
     675           6 :   (*this)(1, 1, 2, 1) = input[8];
     676           6 :   (*this)(1, 2, 1, 1) = input[8];
     677           6 :   (*this)(2, 1, 1, 1) = input[8];
     678             : 
     679           6 :   (*this)(1, 1, 1, 0) = input[10];
     680           6 :   (*this)(1, 1, 0, 1) = input[10];
     681           6 :   (*this)(1, 0, 1, 1) = input[10];
     682           6 :   (*this)(0, 1, 1, 1) = input[10]; // C2212 //flipped for filling purposes
     683             : 
     684           6 :   (*this)(2, 2, 2, 1) = input[12];
     685           6 :   (*this)(2, 2, 1, 2) = input[12];
     686           6 :   (*this)(2, 1, 2, 2) = input[12];
     687           6 :   (*this)(1, 2, 2, 2) = input[12]; // C3323 //flipped for filling purposes
     688             : 
     689           6 :   (*this)(2, 2, 2, 0) = input[13];
     690           6 :   (*this)(2, 2, 0, 2) = input[13];
     691           6 :   (*this)(2, 0, 2, 2) = input[13];
     692           6 :   (*this)(0, 2, 2, 2) = input[13]; // C3313 //flipped for filling purposes
     693             : 
     694           6 :   (*this)(0, 0, 1, 2) = input[3]; // C1123
     695           6 :   (*this)(0, 0, 2, 1) = input[3];
     696           6 :   (*this)(1, 2, 0, 0) = input[3];
     697           6 :   (*this)(2, 1, 0, 0) = input[3];
     698             : 
     699           6 :   (*this)(1, 1, 0, 2) = input[9];
     700           6 :   (*this)(1, 1, 2, 0) = input[9];
     701           6 :   (*this)(0, 2, 1, 1) = input[9]; // C2213  //flipped for filling purposes
     702           6 :   (*this)(2, 0, 1, 1) = input[9];
     703             : 
     704           6 :   (*this)(2, 2, 0, 1) = input[14];
     705           6 :   (*this)(2, 2, 1, 0) = input[14];
     706           6 :   (*this)(0, 1, 2, 2) = input[14]; // C3312 //flipped for filling purposes
     707           6 :   (*this)(1, 0, 2, 2) = input[14];
     708             : 
     709           6 :   (*this)(1, 2, 1, 2) = input[15]; // C2323
     710           6 :   (*this)(2, 1, 2, 1) = input[15];
     711           6 :   (*this)(2, 1, 1, 2) = input[15];
     712           6 :   (*this)(1, 2, 2, 1) = input[15];
     713             : 
     714           6 :   (*this)(0, 2, 0, 2) = input[18]; // C1313
     715           6 :   (*this)(2, 0, 2, 0) = input[18];
     716           6 :   (*this)(2, 0, 0, 2) = input[18];
     717           6 :   (*this)(0, 2, 2, 0) = input[18];
     718             : 
     719           6 :   (*this)(0, 1, 0, 1) = input[20]; // C1212
     720           6 :   (*this)(1, 0, 1, 0) = input[20];
     721           6 :   (*this)(1, 0, 0, 1) = input[20];
     722           6 :   (*this)(0, 1, 1, 0) = input[20];
     723             : 
     724           6 :   (*this)(1, 2, 0, 2) = input[16];
     725           6 :   (*this)(0, 2, 1, 2) = input[16]; // C2313 //flipped for filling purposes
     726           6 :   (*this)(2, 1, 0, 2) = input[16];
     727           6 :   (*this)(1, 2, 2, 0) = input[16];
     728           6 :   (*this)(2, 0, 1, 2) = input[16];
     729           6 :   (*this)(0, 2, 2, 1) = input[16];
     730           6 :   (*this)(2, 1, 2, 0) = input[16];
     731           6 :   (*this)(2, 0, 2, 1) = input[16];
     732             : 
     733           6 :   (*this)(1, 2, 0, 1) = input[17];
     734           6 :   (*this)(0, 1, 1, 2) = input[17]; // C2312 //flipped for filling purposes
     735           6 :   (*this)(2, 1, 0, 1) = input[17];
     736           6 :   (*this)(1, 2, 1, 0) = input[17];
     737           6 :   (*this)(1, 0, 1, 2) = input[17];
     738           6 :   (*this)(0, 1, 2, 1) = input[17];
     739           6 :   (*this)(2, 1, 1, 0) = input[17];
     740           6 :   (*this)(1, 0, 2, 1) = input[17];
     741             : 
     742           6 :   (*this)(0, 2, 0, 1) = input[19];
     743           6 :   (*this)(0, 1, 0, 2) = input[19]; // C1312 //flipped for filling purposes
     744           6 :   (*this)(2, 0, 0, 1) = input[19];
     745           6 :   (*this)(0, 2, 1, 0) = input[19];
     746           6 :   (*this)(1, 0, 0, 2) = input[19];
     747           6 :   (*this)(0, 1, 2, 0) = input[19];
     748           6 :   (*this)(2, 0, 1, 0) = input[19];
     749           6 :   (*this)(1, 0, 2, 0) = input[19];
     750           6 : }
     751             : 
     752             : template <typename T>
     753             : RankFourTensorTempl<T>
     754           4 : RankFourTensorTempl<T>::inverse() const
     755             : {
     756             : 
     757             :   // The inverse of a 3x3x3x3 in the C_ijkl*A_klmn = de_im de_jn sense is
     758             :   // simply the inverse of the 9x9 matrix of the tensor entries.
     759             :   // So all we need to do is inverse _vals (with the appropriate row-major
     760             :   // storage)
     761             : 
     762           4 :   RankFourTensorTempl<T> result;
     763             : 
     764             :   if constexpr (RankFourTensorTempl<T>::N4 * sizeof(T) > EIGEN_STACK_ALLOCATION_LIMIT)
     765             :   {
     766             :     // Allocate on the heap if you're going to exceed the stack size limit
     767           1 :     Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> mat(9, 9);
     768          82 :     for (auto i : libMesh::make_range(9 * 9))
     769          81 :       mat(i) = _vals[i];
     770             : 
     771           1 :     mat = mat.inverse();
     772             : 
     773          82 :     for (auto i : libMesh::make_range(9 * 9))
     774          81 :       result._vals[i] = mat(i);
     775           1 :   }
     776             :   else
     777             :   {
     778             :     // Allocate on the stack if small enough
     779           3 :     const Eigen::Map<const Eigen::Matrix<T, 9, 9, Eigen::RowMajor>> mat(&_vals[0]);
     780           3 :     Eigen::Map<Eigen::Matrix<T, 9, 9, Eigen::RowMajor>> res(&result._vals[0]);
     781           3 :     res = mat.inverse();
     782             :   }
     783             : 
     784           4 :   return result;
     785           0 : }
     786             : 
     787             : template <typename T>
     788             : template <int m>
     789             : RankThreeTensorTempl<T>
     790           2 : RankFourTensorTempl<T>::contraction(const libMesh::VectorValue<T> & b) const
     791             : {
     792           2 :   RankThreeTensorTempl<T> result;
     793             :   static constexpr std::size_t z[4][3] = {{1, 2, 3}, {0, 2, 3}, {0, 1, 3}, {0, 1, 2}};
     794             :   std::size_t x[4];
     795           8 :   for (x[0] = 0; x[0] < N; ++x[0])
     796          24 :     for (x[1] = 0; x[1] < N; ++x[1])
     797          72 :       for (x[2] = 0; x[2] < N; ++x[2])
     798         216 :         for (x[3] = 0; x[3] < N; ++x[3])
     799         162 :           result(x[z[m][0]], x[z[m][1]], x[z[m][2]]) += (*this)(x[0], x[1], x[2], x[3]) * b(x[m]);
     800             : 
     801           4 :   return result;
     802             : }

Generated by: LCOV version 1.14