LCOV - code coverage report
Current view: top level - include/utils - RankTwoTensor.h (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 2bf808 Lines: 98 114 86.0 %
Date: 2025-07-17 01:28:37 Functions: 37 71 52.1 %
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 "ADSymmetricRankTwoTensorForward.h"
      18             : #include "MooseUtils.h"
      19             : #include "MathUtils.h"
      20             : 
      21             : // Any requisite includes here
      22             : #include "libmesh/libmesh.h"
      23             : #include "libmesh/tensor_value.h"
      24             : #include "libmesh/vector_value.h"
      25             : #include "libmesh/int_range.h"
      26             : 
      27             : #include "metaphysicl/raw_type.h"
      28             : 
      29             : #include <petscsys.h>
      30             : #include <vector>
      31             : 
      32             : // Forward declarations
      33             : class MooseEnum;
      34             : template <typename T>
      35             : class MooseArray;
      36             : typedef MooseArray<Real> VariableValue;
      37             : template <typename>
      38             : class ColumnMajorMatrixTempl;
      39             : namespace libMesh
      40             : {
      41             : template <typename>
      42             : class TypeVector;
      43             : template <typename>
      44             : class TypeTensor;
      45             : template <typename>
      46             : class TensorValue;
      47             : namespace TensorTools
      48             : {
      49             : template <>
      50             : struct IncrementRank<RankTwoTensor>
      51             : {
      52             :   typedef RankThreeTensor type;
      53             : };
      54             : }
      55             : }
      56             : 
      57             : namespace MathUtils
      58             : {
      59             : template <typename T>
      60             : void mooseSetToZero(T & v);
      61             : 
      62             : /**
      63             :  * Helper function template specialization to set an object to zero.
      64             :  * Needed by DerivativeMaterialInterface
      65             :  */
      66             : template <>
      67             : void mooseSetToZero<RankTwoTensor>(RankTwoTensor & v);
      68             : 
      69             : /**
      70             :  * Helper function template specialization to set an object to zero.
      71             :  * Needed by DerivativeMaterialInterface
      72             :  */
      73             : template <>
      74             : void mooseSetToZero<ADRankTwoTensor>(ADRankTwoTensor & v);
      75             : }
      76             : 
      77             : /**
      78             :  * RankTwoTensorTempl is designed to handle the Stress or Strain Tensor for a fully anisotropic
      79             :  * material. It is designed to allow for maximum clarity of the mathematics and ease of use.
      80             :  * Original class authors: A. M. Jokisaari, O. Heinonen, M. R. Tonks
      81             :  *
      82             :  * RankTwoTensorTempl holds the 9 separate Sigma_ij or Epsilon_ij entries.
      83             :  * The entries are accessed by index, with i, j equal to 1, 2, or 3, or
      84             :  * internally i, j = 0, 1, 2.
      85             :  */
      86             : template <typename T>
      87             : class RankTwoTensorTempl : public libMesh::TensorValue<T>
      88             : {
      89             : public:
      90             :   /// @{
      91             : 
      92             :   /**
      93             :    * @brief Tensor dimension, i.e. number of rows/columns of the second order tensor
      94             :    */
      95             :   static constexpr unsigned int N = Moose::dim;
      96             : 
      97             :   /**
      98             :    * @brief The square of the tensor dimension.
      99             :    */
     100             :   static constexpr unsigned int N2 = N * N;
     101             : 
     102             :   /**
     103             :    * @brief The initialization method.
     104             :    * @see fillFromInputVector()
     105             :    * @see RankTwoTensorTempl(const std::vector<T> &)
     106             :    */
     107             :   enum InitMethod
     108             :   {
     109             :     initNone,
     110             :     initIdentity
     111             :   };
     112             : 
     113             :   /**
     114             :    * To fill up the 9 entries in the 2nd-order tensor, fillFromInputVector
     115             :    * is called with one of the following fill_methods.
     116             :    * See the fill*FromInputVector functions for more details
     117             :    */
     118             :   enum FillMethod
     119             :   {
     120             :     autodetect = 0,
     121             :     isotropic1 = 1,
     122             :     diagonal3 = 3,
     123             :     symmetric6 = 6,
     124             :     general = 9
     125             :   };
     126             : 
     127             :   /**
     128             :    * @brief Initialize the random seed based on an unsigned integer.
     129             :    * Deprecated in favor of MooseRandom::seed().
     130             :    */
     131             :   static void initRandom(unsigned int);
     132             : 
     133             :   /**
     134             :    * @brief Get the available `FillMethod` options.
     135             :    *
     136             :    * This method is useful in validParams().
     137             :    */
     138             :   [[nodiscard]] static MooseEnum fillMethodEnum();
     139             : 
     140             :   /**
     141             :    * @brief Fill a `libMesh::TensorValue<T>` from this second order tensor
     142             :    */
     143             :   void fillRealTensor(libMesh::TensorValue<T> &);
     144             : 
     145             :   /// Print the rank two tensor
     146             :   void print(std::ostream & stm = Moose::out) const;
     147             : 
     148             :   /// Print the Real part of the RankTwoTensorTempl<ADReal>
     149             :   void printReal(std::ostream & stm = Moose::out) const;
     150             : 
     151             :   /// Print the Real part of the RankTwoTensorTempl<ADReal> along with its first nDual dual numbers
     152             :   void printADReal(unsigned int nDual, std::ostream & stm = Moose::out) const;
     153             : 
     154             :   /// @}
     155             : 
     156             :   /// @{
     157             : 
     158             :   /**
     159             :    * @brief Empty constructor; fills to zero
     160             :    *
     161             :    * \f$ A_{ij} = 0 \f$
     162             :    *
     163             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
     164             :    * RankTwoTensor A;
     165             :    * // A = [ 0 0 0
     166             :    * //       0 0 0
     167             :    * //       0 0 0 ]
     168             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     169             :    */
     170             :   RankTwoTensorTempl();
     171             : 
     172             :   /**
     173             :    * @brief Select specific initialization pattern.
     174             :    *
     175             :    * `initNone` initializes an empty second order tensor.
     176             :    *
     177             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
     178             :    * RankTwoTensor A(RankTwoTensor::initNone);
     179             :    * // A = [ 0 0 0
     180             :    * //       0 0 0
     181             :    * //       0 0 0 ]
     182             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     183             :    *
     184             :    * `initIdentity` initializes a second order identity tensor.
     185             :    *
     186             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
     187             :    * RankTwoTensor A(RankTwoTensor::initIdentity);
     188             :    * // A = [ 1 0 0
     189             :    * //       0 1 0
     190             :    * //       0 0 1 ]
     191             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     192             :    */
     193             :   RankTwoTensorTempl(const InitMethod);
     194             : 
     195             :   /**
     196             :    * @brief Initialize from row vectors.
     197             :    * @see initializeFromRows()
     198             :    *
     199             :    * Deprecated in favor of initializeFromRows()
     200             :    *
     201             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
     202             :    * RealVectorValue row1(1, 2, 3);
     203             :    * RealVectorValue row2(4, 5, 6);
     204             :    * RealVectorValue row3(7, 8, 9);
     205             :    * RankTwoTensor A(row1, row2, row3);
     206             :    * // A = [ 1 2 3
     207             :    * //       4 5 6
     208             :    * //       7 8 9 ]
     209             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     210             :    */
     211             :   RankTwoTensorTempl(const libMesh::TypeVector<T> & row1,
     212             :                      const libMesh::TypeVector<T> & row2,
     213             :                      const libMesh::TypeVector<T> & row3);
     214             : 
     215             :   /**
     216             :    * @brief Constructor that proxies the fillFromInputVector() method
     217             :    * @see fillFromInputVector()
     218             :    */
     219           9 :   RankTwoTensorTempl(const std::vector<T> & input) { this->fillFromInputVector(input); };
     220             : 
     221             :   /**
     222             :    * @brief Initialize a symmetric second order tensor using the 6 arguments.
     223             :    *
     224             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
     225             :    * RankTwoTensor A(1, 2, 3, 4, 5, 6);
     226             :    * // A = [ 1 6 5
     227             :    * //       6 2 4
     228             :    * //       5 4 3 ]
     229             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     230             :    */
     231             :   RankTwoTensorTempl(
     232             :       const T & S11, const T & S22, const T & S33, const T & S23, const T & S13, const T & S12);
     233             : 
     234             :   /**
     235             :    * @brief Initialize a second order tensor using the 9 arguments in a column-major fashion.
     236             :    *
     237             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
     238             :    * RankTwoTensor A(1, 2, 3, 4, 5, 6, 7, 8, 9);
     239             :    * // A = [ 1 4 7
     240             :    * //       2 5 8
     241             :    * //       3 6 9 ]
     242             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     243             :    */
     244             :   RankTwoTensorTempl(const T & S11,
     245             :                      const T & S21,
     246             :                      const T & S31,
     247             :                      const T & S12,
     248             :                      const T & S22,
     249             :                      const T & S32,
     250             :                      const T & S13,
     251             :                      const T & S23,
     252             :                      const T & S33);
     253             : 
     254             :   /**
     255             :    * @brief The copy constructor
     256             :    *
     257             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
     258             :    * RankTwoTensor A(1, 2, 3, 4, 5, 6, 7, 8, 9);
     259             :    * RankTwoTensor B = A;
     260             :    * // A = B = [ 1 4 7
     261             :    * //           2 5 8
     262             :    * //           3 6 9 ]
     263             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     264             :    */
     265          22 :   RankTwoTensorTempl(const RankTwoTensorTempl<T> & a) = default;
     266             : 
     267             :   /**
     268             :    * @brief The conversion operator from a `libMesh::TensorValue`
     269             :    */
     270      264056 :   RankTwoTensorTempl(const libMesh::TensorValue<T> & a) : libMesh::TensorValue<T>(a) {}
     271             : 
     272             :   /**
     273             :    * @brief The conversion operator from a `libMesh::TypeTensor`
     274             :    */
     275      797213 :   RankTwoTensorTempl(const libMesh::TypeTensor<T> & a) : libMesh::TensorValue<T>(a) {}
     276             : 
     277             :   /**
     278             :    * @brief The conversion operator from a `SymmetricRankTwoTensorTempl`
     279             :    */
     280             :   template <typename T2>
     281           2 :   RankTwoTensorTempl(const SymmetricRankTwoTensorTempl<T2> & a)
     282           0 :     : RankTwoTensorTempl<T>(a(0),
     283           2 :                             a(1),
     284           2 :                             a(2),
     285           2 :                             a(3) / MathUtils::sqrt2,
     286           2 :                             a(4) / MathUtils::sqrt2,
     287           4 :                             a(5) / MathUtils::sqrt2)
     288             :   {
     289           2 :   }
     290             : 
     291             :   /**
     292             :    * @brief The conversion operator from `RankTwoTensorTempl<T2>` to `RankTwoTensorTempl<T>` where
     293             :    * `T2` is convertible to `T`.
     294             :    */
     295             :   template <typename T2>
     296          36 :   RankTwoTensorTempl(const RankTwoTensorTempl<T2> & a) : libMesh::TensorValue<T>(a)
     297             :   {
     298          36 :   }
     299             :   /// @} end Constructor
     300             : 
     301             :   /// @{
     302             : 
     303             :   /**
     304             :    * @brief Named constructor for initializing symmetrically.
     305             :    *
     306             :    * The supplied vectors are used as row and column vectors to construct two tensors respectively,
     307             :    * that are averaged to create a symmetric tensor.
     308             :    *
     309             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
     310             :    * RealVectorValue row1(1, 2, 3);
     311             :    * RealVectorValue row2(4, 5, 6);
     312             :    * RealVectorValue row3(7, 8, 9);
     313             :    * auto A = RankTwoTensor::initializeSymmetric(row1, row2, row3);
     314             :    * // A = [ 1 3 5
     315             :    * //       3 5 7
     316             :    * //       5 7 9 ]
     317             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     318             :    */
     319             :   [[nodiscard]] static RankTwoTensorTempl initializeSymmetric(const libMesh::TypeVector<T> & v0,
     320             :                                                               const libMesh::TypeVector<T> & v1,
     321             :                                                               const libMesh::TypeVector<T> & v2);
     322             : 
     323             :   /**
     324             :    * @brief Named constructor for initializing from row vectors.
     325             :    *
     326             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
     327             :    * RealVectorValue row1(1, 2, 3);
     328             :    * RealVectorValue row2(4, 5, 6);
     329             :    * RealVectorValue row3(7, 8, 9);
     330             :    * auto A = RankTwoTensor::initializeFromRows(row1, row2, row3);
     331             :    * // A = [ 1 2 3
     332             :    * //       4 5 6
     333             :    * //       7 8 9 ]
     334             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     335             :    */
     336             :   [[nodiscard]] static RankTwoTensorTempl initializeFromRows(const libMesh::TypeVector<T> & row0,
     337             :                                                              const libMesh::TypeVector<T> & row1,
     338             :                                                              const libMesh::TypeVector<T> & row2);
     339             : 
     340             :   /**
     341             :    * @brief Named constructor for initializing from row vectors.
     342             :    *
     343             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
     344             :    * RealVectorValue col1(1, 2, 3);
     345             :    * RealVectorValue col2(4, 5, 6);
     346             :    * RealVectorValue col3(7, 8, 9);
     347             :    * auto A = RankTwoTensor::initializeFromColumns(col1, col2, col3);
     348             :    * // A = [ 1 4 7
     349             :    * //       2 5 8
     350             :    * //       3 6 9 ]
     351             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     352             :    */
     353             :   [[nodiscard]] static RankTwoTensorTempl
     354             :   initializeFromColumns(const libMesh::TypeVector<T> & col0,
     355             :                         const libMesh::TypeVector<T> & col1,
     356             :                         const libMesh::TypeVector<T> & col2);
     357             : 
     358             :   /**
     359             :    * @brief Initialize a second order identity tensor.
     360             :    *
     361             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
     362             :    * auto A = RankTwoTensor::Identity();
     363             :    * // A = [ 1 0 0
     364             :    * //       0 1 0
     365             :    * //       0 0 1 ]
     366             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     367             :    */
     368           0 :   [[nodiscard]] static RankTwoTensorTempl Identity() { return RankTwoTensorTempl(initIdentity); }
     369             : 
     370             :   /**
     371             :    * @brief Initialize a second order tensor with expression \f$ B_{ij} = F_{ij} F_{ji} \f$.
     372             :    *
     373             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
     374             :    * RankTwoTensor F(1, 2, 3, 4, 5, 6, 7, 8, 9);
     375             :    * // F = [ 1 4 7
     376             :    * //       2 5 8
     377             :    * //       3 6 9 ]
     378             :    * auto B = RankTwoTensor::timesTranspose(F);
     379             :    * // B = [ 66 78  90
     380             :    * //       78 93  108
     381             :    * //       90 108 126 ]
     382             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     383             :    */
     384             :   [[nodiscard]] static RankTwoTensorTempl<T> timesTranspose(const RankTwoTensorTempl<T> &);
     385             : 
     386             :   /**
     387             :    * @brief Initialize a second order tensor with expression \f$ C_{ij} = F_{ji} F_{ij} \f$.
     388             :    *
     389             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
     390             :    * RankTwoTensor F(1, 2, 3, 4, 5, 6, 7, 8, 9);
     391             :    * // F = [ 1 4 7
     392             :    * //       2 5 8
     393             :    * //       3 6 9 ]
     394             :    * auto C = RankTwoTensor::transposeTimes(F);
     395             :    * // C = [ 14 32  50
     396             :    * //       32 77  122
     397             :    * //       50 122 194 ]
     398             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     399             :    */
     400             :   [[nodiscard]] static RankTwoTensorTempl<T> transposeTimes(const RankTwoTensorTempl<T> &);
     401             : 
     402             :   /**
     403             :    * @brief Initialize a second order tensor with expression \f$ E_{ij} = C_{ij} + C_{ji} \f$.
     404             :    *
     405             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
     406             :    * RankTwoTensor C(1, 2, 3, 4, 5, 6, 7, 8, 9);
     407             :    * // C = [ 1 4 7
     408             :    * //       2 5 8
     409             :    * //       3 6 9 ]
     410             :    * auto E = RankTwoTensor::plusTranspose(C);
     411             :    * // E = [ 2  6  10
     412             :    * //       6  10 14
     413             :    * //       10 14 18 ]
     414             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     415             :    */
     416             :   [[nodiscard]] static RankTwoTensorTempl<T> plusTranspose(const RankTwoTensorTempl<T> &);
     417             : 
     418             :   /**
     419             :    * @brief Initialize a second order tensor as the outer product of two vectors, i.e. \f$ A_{ij} =
     420             :    * a_i b_j \f$.
     421             :    *
     422             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
     423             :    * RealVectorValue a(1, 2, 3);
     424             :    * RealVectorValue b(4, 5, 6);
     425             :    * auto A = RankTwoTensor::outerProduct(a, b);
     426             :    * // A = [ 4  5  6
     427             :    * //       8  10 12
     428             :    * //       12 15 18 ]
     429             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     430             :    */
     431             :   [[nodiscard]] static RankTwoTensorTempl<T> outerProduct(const libMesh::TypeVector<T> &,
     432             :                                                           const libMesh::TypeVector<T> &);
     433             : 
     434             :   /**
     435             :    * @brief Initialize a second order tensor as the outer product of a vector with itself, i.e. \f$
     436             :    * A_{ij} = a_i a_j \f$.
     437             :    *
     438             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
     439             :    * RealVectorValue a(1, 2, 3);
     440             :    * auto A = RankTwoTensor::selfOuterProduct(a);
     441             :    * // A = [ 1 2 3
     442             :    * //       2 4 6
     443             :    * //       3 6 9 ]
     444             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     445             :    */
     446             :   [[nodiscard]] static RankTwoTensorTempl<T> selfOuterProduct(const libMesh::TypeVector<T> &);
     447             : 
     448             :   /**
     449             :    * @brief Generate a random second order tensor with all 9 components treated as independent
     450             :    * random variables following a Gaussian distribution.
     451             :    *
     452             :    * @param stddev The standard deviation of the Gaussian distribution
     453             :    * @param mean   The mean of the Gaussian distribution
     454             :    */
     455             :   [[nodiscard]] static RankTwoTensorTempl<T> genRandomTensor(T stddev, T mean);
     456             : 
     457             :   /**
     458             :    * @brief Generate a random symmetric second order tensor with the 6 upper-triangular components
     459             :    * treated as independent random variables following a Gaussian distribution.
     460             :    *
     461             :    * @param stddev The standard deviation of the Gaussian distribution
     462             :    * @param mean   The mean of the Gaussian distribution
     463             :    */
     464             :   [[nodiscard]] static RankTwoTensorTempl<T> genRandomSymmTensor(T stddev, T mean);
     465             : 
     466             :   /// @}
     467             : 
     468             :   /// @{
     469             : 
     470             :   /**
     471             :    * @brief Get the i-th column of the second order tensor.
     472             :    *
     473             :    * @param i The column number, i = 0, 1, 2
     474             :    * @return The i-th column of the second order tensor.
     475             :    *
     476             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
     477             :    * RankTwoTensor A(1, 2, 3, 4, 5, 6, 7, 8, 9);
     478             :    * RealVectorValue col = A.column(1);
     479             :    * // col = [ 4
     480             :    * //         5
     481             :    * //         6 ]
     482             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     483             :    */
     484             :   libMesh::VectorValue<T> column(const unsigned int i) const;
     485             : 
     486             :   /// @}
     487             : 
     488             :   /// @{
     489             : 
     490             :   /**
     491             :    * @brief Assignment operator
     492             :    *
     493             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
     494             :    * RankTwoTensor A;
     495             :    * // A = [ 0 0 0
     496             :    * //       0 0 0
     497             :    * //       0 0 0 ]
     498             :    * RankTwoTensor B(9, 8, 7, 6, 5, 4, 3, 2, 1);
     499             :    * // B = [ 9 6 3
     500             :    * //       8 5 2
     501             :    * //       7 4 1 ]
     502             :    * A = B;
     503             :    * // A = [ 9 6 3
     504             :    * //       8 5 2
     505             :    * //       7 4 1 ]
     506             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     507             :    */
     508       96449 :   RankTwoTensorTempl<T> & operator=(const RankTwoTensorTempl<T> & a) = default;
     509             : 
     510             :   /**
     511             :    * @brief Assignment operator (from a ColumnMajorMatrixTempl<T>)
     512             :    *
     513             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
     514             :    * RankTwoTensor A;
     515             :    * // A = [ 0 0 0
     516             :    * //       0 0 0
     517             :    * //       0 0 0 ]
     518             :    * RealVectorValue col1(1, 2, 3);
     519             :    * RealVectorValue col2(4, 5, 6);
     520             :    * RealVectorValue col3(7, 8, 9);
     521             :    * ColumnMajorMatrix B(col1, col2, col3);
     522             :    * // B = [ 1 4 7
     523             :    * //       2 5 8
     524             :    * //       3 6 9 ]
     525             :    * A = B;
     526             :    * // A = [ 1 4 7
     527             :    * //       2 5 8
     528             :    * //       3 6 9 ]
     529             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     530             :    */
     531             :   RankTwoTensorTempl<T> & operator=(const ColumnMajorMatrixTempl<T> & a);
     532             : 
     533             :   /**
     534             :    * @brief Assignment-from-scalar operator.  Used only to zero out the tensor.
     535             :    *
     536             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
     537             :    * RankTwoTensor A(1, 2, 3, 4, 5, 6, 7, 8, 9);
     538             :    * // A = [ 1 2 3
     539             :    * //       2 4 6
     540             :    * //       3 6 9 ]
     541             :    * A = 0;
     542             :    * // A = [ 0 0 0
     543             :    * //       0 0 0
     544             :    * //       0 0 0 ]
     545             :    * A = 1;
     546             :    * // This triggers an assertion failure.
     547             :    * A = 0.0;
     548             :    * // This triggers an assertion failure.
     549             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     550             :    */
     551             :   template <typename Scalar>
     552             :   typename libMesh::boostcopy::enable_if_c<libMesh::ScalarTraits<Scalar>::value,
     553             :                                            RankTwoTensorTempl &>::type
     554             :   operator=(const Scalar & libmesh_dbg_var(p))
     555             :   {
     556             :     libmesh_assert_equal_to(p, Scalar(0));
     557             :     this->zero();
     558             :     return *this;
     559             :   }
     560             : 
     561             :   /**
     562             :    * Add another second order tensor to this one
     563             :    *
     564             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
     565             :    * RankTwoTensor A(1, 2, 3, 4, 5, 6, 7, 8, 9);
     566             :    * // A = [ 1 2 3
     567             :    * //       2 4 6
     568             :    * //       3 6 9 ]
     569             :    * RankTwoTensor B(9, 8, 7, 6, 5, 4, 3, 2, 1);
     570             :    * // B = [ 9 6 3
     571             :    * //       8 5 2
     572             :    * //       7 4 1 ]
     573             :    * A += B;
     574             :    * // A = [ 10 8  6
     575             :    * //       10 9  8
     576             :    * //       10 10 10 ]
     577             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     578             :    */
     579             :   RankTwoTensorTempl<T> & operator+=(const RankTwoTensorTempl<T> & a);
     580             : 
     581             :   /**
     582             :    * Subtract another second order tensor from this one
     583             :    *
     584             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
     585             :    * RankTwoTensor A(1, 2, 3, 4, 5, 6, 7, 8, 9);
     586             :    * // A = [ 1 2 3
     587             :    * //       2 4 6
     588             :    * //       3 6 9 ]
     589             :    * RankTwoTensor B(9, 8, 7, 6, 5, 4, 3, 2, 1);
     590             :    * // B = [ 9 6 3
     591             :    * //       8 5 2
     592             :    * //       7 4 1 ]
     593             :    * A -= B;
     594             :    * // A = [ -8 -4 0
     595             :    * //       -6 -1 4
     596             :    * //       -4  2 8 ]
     597             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     598             :    */
     599             :   RankTwoTensorTempl<T> & operator-=(const RankTwoTensorTempl<T> & a);
     600             : 
     601             :   /**
     602             :    * Multiply this tensor by a scalar (component-wise)
     603             :    *
     604             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
     605             :    * RankTwoTensor A(1, 2, 3, 4, 5, 6, 7, 8, 9);
     606             :    * // A = [ 1 2 3
     607             :    * //       2 4 6
     608             :    * //       3 6 9 ]
     609             :    * A *= 2;
     610             :    * // A = [ 2 4  6
     611             :    * //       4 8  12
     612             :    * //       6 12 18 ]
     613             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     614             :    */
     615             :   RankTwoTensorTempl<T> & operator*=(const T & a);
     616             : 
     617             :   /**
     618             :    * Divide this tensor by a scalar (component-wise)
     619             :    *
     620             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
     621             :    * RankTwoTensor A(1, 2, 3, 4, 5, 6, 7, 8, 9);
     622             :    * // A = [ 1 2 3
     623             :    * //       2 4 6
     624             :    * //       3 6 9 ]
     625             :    * A /= 2;
     626             :    * // A = [ 0.5 1.0 1.5
     627             :    * //       1.0 2.0 3.0
     628             :    * //       1.5 3.0 4.5 ]
     629             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     630             :    */
     631             :   RankTwoTensorTempl<T> & operator/=(const T & a);
     632             : 
     633             :   /**
     634             :    * Multiplication with another second order tensor
     635             :    *
     636             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
     637             :    * RankTwoTensor A(1, 2, 3, 4, 5, 6, 7, 8, 9);
     638             :    * // A = [ 1 2 3
     639             :    * //       2 4 6
     640             :    * //       3 6 9 ]
     641             :    * RankTwoTensor B(9, 8, 7, 6, 5, 4, 3, 2, 1);
     642             :    * // B = [ 9 6 3
     643             :    * //       8 5 2
     644             :    * //       7 4 1 ]
     645             :    * A *= B;
     646             :    * // A = [ 90  54 18
     647             :    * //       114 69 24
     648             :    * //       138 84 30 ]
     649             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     650             :    */
     651             :   RankTwoTensorTempl<T> & operator*=(const libMesh::TypeTensor<T> & a);
     652             : 
     653             :   /**
     654             :    * @brief The smart mutator that determines how to fill the second order tensor based on the size
     655             :    * of the input vector.
     656             :    *
     657             :    * @param input The input vector, can be of size 1, 3, 6, or 9
     658             :    * @param fill_method The fill method, default to autodetect.
     659             :    *
     660             :    * When `input.size() == 1`, the vector value is used to fill the diagonal components of the
     661             :    * second order tensor:
     662             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
     663             :    * RankTwoTensor A;
     664             :    * A.fillFromInputVector({1.5});
     665             :    * // A = [ 1.5 0   0
     666             :    * //       0   1.5 0
     667             :    * //       0   0   1.5 ]
     668             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     669             :    *
     670             :    * When `input.size() == 3`, the vector values are used to fill the diagonal components of the
     671             :    * second order tensor:
     672             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
     673             :    * RankTwoTensor A;
     674             :    * A.fillFromInputVector({1, 2, 3});
     675             :    * // A = [ 1 0 0
     676             :    * //       0 2 0
     677             :    * //       0 0 3 ]
     678             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     679             :    *
     680             :    * When `input.size() == 6`, the second order tensor is filled symmetrically using the Voigt
     681             :    * notation:
     682             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
     683             :    * RankTwoTensor A;
     684             :    * A.fillFromInputVector({1, 2, 3, 4, 5, 6});
     685             :    * // A = [ 1 6 5
     686             :    * //       6 2 4
     687             :    * //       5 4 3 ]
     688             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     689             :    *
     690             :    * When `input.size() == 9`, all components of the second order tensor are filled in a
     691             :    * column-major fashion:
     692             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
     693             :    * RankTwoTensor A;
     694             :    * A.fillFromInputVector({1, 2, 3, 4, 5, 6, 7, 8, 9});
     695             :    * // A = [ 1 4 7
     696             :    * //       2 5 8
     697             :    * //       3 6 9 ]
     698             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     699             :    */
     700             :   void fillFromInputVector(const std::vector<T> & input, FillMethod fill_method = autodetect);
     701             : 
     702             :   /**
     703             :    * @brief The smart mutator that determines how to fill the second order tensor based on the order
     704             :    * of the scalar_variable.
     705             :    *
     706             :    * @param scalar_variable The input scalar variable. Supported orders are FIRST, THIRD, and SIXTH.
     707             :    *
     708             :    * When `scalar_variable.size() == 1`, the scalar value is used to fill the very first component
     709             :    * of the second order tensor:
     710             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
     711             :    & // Suppose v[0] = 1
     712             :    * RankTwoTensor A;
     713             :    * A.fillFromScalarVariable(v);
     714             :    * // A = [ 1 0 0
     715             :    * //       0 0 0
     716             :    * //       0 0 0 ]
     717             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     718             :    *
     719             :    * When `scalar_variable.size() == 3`, the scalar values are used to fill the in-plane components
     720             :    * of the second order tensor using the Voigt notation:
     721             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
     722             :    * // Suppose v[0] = 1
     723             :    * //         v[1] = 2
     724             :    * //         v[2] = 3
     725             :    * RankTwoTensor A;
     726             :    * A.fillFromScalarVariable(v);
     727             :    * // A = [ 1 3 0
     728             :    * //       3 2 0
     729             :    * //       0 0 0 ]
     730             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     731             :    *
     732             :    * When `scalar_variable.size() == 6`, the second order tensor is filled symmetrically using the
     733             :    * Voigt notation:
     734             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
     735             :    * // Suppose v[0] = 1
     736             :    * //         v[1] = 2
     737             :    * //         v[2] = 3
     738             :    * //         v[3] = 4
     739             :    * //         v[4] = 5
     740             :    * //         v[5] = 6
     741             :    * RankTwoTensor A;
     742             :    * A.fillFromScalarVariable(v);
     743             :    * // A = [ 1 6 5
     744             :    * //       6 2 4
     745             :    * //       5 4 3 ]
     746             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     747             :    */
     748             :   void fillFromScalarVariable(const VariableValue & scalar_variable);
     749             : 
     750             :   /**
     751             :    * sets _coords[0][0], _coords[0][1], _coords[1][0], _coords[1][1] to input,
     752             :    * and the remainder to zero
     753             :    */
     754             :   void surfaceFillFromInputVector(const std::vector<T> & input);
     755             : 
     756             :   /**
     757             :    * @brief Set the values of the second order tensor to be the outer product of two vectors, i.e.
     758             :    * \f$ A_{ij} = a_i b_j \f$.
     759             :    *
     760             :    * Deprecated in favor of outerProduct()
     761             :    *
     762             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
     763             :    * RealVectorValue a(1, 2, 3);
     764             :    * RealVectorValue b(4, 5, 6);
     765             :    * RankTwoTensor A;
     766             :    * A.vectorOuterProduct(a, b);
     767             :    * // A = [ 4  5  6
     768             :    * //       8  10 12
     769             :    * //       12 15 18 ]
     770             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     771             :    */
     772             :   void vectorOuterProduct(const libMesh::TypeVector<T> &, const libMesh::TypeVector<T> &);
     773             : 
     774             :   /**
     775             :    * @brief Assign values to a specific row of the second order tensor.
     776             :    *
     777             :    * @param r The row number, r = 0, 1, 2
     778             :    * @param v The values to be set
     779             :    *
     780             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
     781             :    * RealVectorValue a(1, 2, 3);
     782             :    * RankTwoTensor A;
     783             :    * // A = [ 0 0 0
     784             :    * //       0 0 0
     785             :    * //       0 0 0 ]
     786             :    * A.fillRow(1, a);
     787             :    * // A = [ 0 0 0
     788             :    * //       1 2 3
     789             :    * //       0 0 0 ]
     790             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     791             :    */
     792             :   void fillRow(unsigned int r, const libMesh::TypeVector<T> & v);
     793             : 
     794             :   /**
     795             :    * @brief Assign values to a specific column of the second order tensor.
     796             :    *
     797             :    * @param c The column number, c = 0, 1, 2
     798             :    * @param v The values to be set
     799             :    *
     800             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
     801             :    * RealVectorValue a(1, 2, 3);
     802             :    * RankTwoTensor A;
     803             :    * // A = [ 0 0 0
     804             :    * //       0 0 0
     805             :    * //       0 0 0 ]
     806             :    * A.fillColumn(1, a);
     807             :    * // A = [ 0 1 0
     808             :    * //       0 2 0
     809             :    * //       0 3 0 ]
     810             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     811             :    */
     812             :   void fillColumn(unsigned int c, const libMesh::TypeVector<T> & v);
     813             : 
     814             :   /**
     815             :    * @brief Set the tensor to identity.
     816             :    *
     817             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
     818             :    * RankTwoTensor A;
     819             :    * // A = [ 0 0 0
     820             :    * //       0 0 0
     821             :    * //       0 0 0 ]
     822             :    * A.setToIdentity();
     823             :    * // A = [ 1 0 0
     824             :    * //       0 1 0
     825             :    * //       0 0 1 ]
     826             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     827             :    */
     828             :   void setToIdentity();
     829             : 
     830             :   /// Add identity times a to _coords
     831             :   /**
     832             :    * @brief Add a scalar to diagonal components \f$ A_{ij} + a\delta_{ij} \f$
     833             :    *
     834             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
     835             :    * RankTwoTensor A;
     836             :    * // A = [ 0 0 0
     837             :    * //       0 0 0
     838             :    * //       0 0 0 ]
     839             :    * A.addIa(1.5);
     840             :    * // A = [ 1.5 0   0
     841             :    * //       0   1.5 0
     842             :    * //       0   0   1.5 ]
     843             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     844             :    */
     845             :   void addIa(const T & a);
     846             : 
     847             :   /**
     848             :    * Rotate the tensor in-place given a rotation tensor
     849             :    * \f$ A_{ij} \leftarrow R_{ij} A_{jk} R_{jk} \f$
     850             :    * @param R The rotation tensor
     851             :    *
     852             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
     853             :    * RankTwoTensor A(1, 2, 3, 4, 5, 6, 7, 8, 9);
     854             :    * // A = [ 1 4 7
     855             :    * //       2 5 8
     856             :    * //       3 6 9 ]
     857             :    * RankTwoTensor R(0, 1, 0, 1, 0, 0, 0, 0, 1);
     858             :    * // R = [ 0 1 0
     859             :    * //       1 0 0
     860             :    * //       0 0 1 ]
     861             :    * A.rotate(R);
     862             :    * // A = [ 5 2 8
     863             :    * //       4 1 7
     864             :    * //       6 3 9 ]
     865             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     866             :    */
     867             :   void rotate(const RankTwoTensorTempl<T> & R);
     868             : 
     869             :   /// @}
     870             : 
     871             :   /// @{
     872             : 
     873             :   /**
     874             :    * @brief Return \f$ A_{ij} = A_{ik}A_{kj} \f$
     875             :    *
     876             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
     877             :    * RankTwoTensor A(1, 2, 3, 4, 5, 6, 7, 8, 9);
     878             :    * // A = [ 1 4 7
     879             :    * //       2 5 8
     880             :    * //       3 6 9 ]
     881             :    * RankTwoTensor B = A.square();
     882             :    * // B = [ 30 66 102
     883             :    * //       36 81 126
     884             :    * //       42 96 150 ]
     885             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     886             :    */
     887             :   RankTwoTensorTempl<T> square() const;
     888             : 
     889             :   /**
     890             :    * Return the rotated tensor given a rotation tensor
     891             :    * \f$ A'_{ij} = R_{ij} A_{jk} R_{jk} \f$
     892             :    * @param R The rotation tensor
     893             :    *
     894             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
     895             :    * RankTwoTensor A(1, 2, 3, 4, 5, 6, 7, 8, 9);
     896             :    * // A = [ 1 4 7
     897             :    * //       2 5 8
     898             :    * //       3 6 9 ]
     899             :    * RankTwoTensor R(0, 1, 0, 1, 0, 0, 0, 0, 1);
     900             :    * // R = [ 0 1 0
     901             :    * //       1 0 0
     902             :    * //       0 0 1 ]
     903             :    * RankTwoTensor A_rotated = A.rotated(R);
     904             :    * // A_rotated = [ 5 2 8
     905             :    * //               4 1 7
     906             :    * //               6 3 9 ]
     907             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     908             :    */
     909             :   RankTwoTensorTempl<T> rotated(const RankTwoTensorTempl<T> & R) const;
     910             : 
     911             :   /**
     912             :    * Rotate the tensor about the z-axis
     913             :    * @param a The rotation angle in radians
     914             :    */
     915             :   RankTwoTensorTempl<T> rotateXyPlane(T a);
     916             : 
     917             :   /**
     918             :    * Return the tensor transposed
     919             :    *
     920             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
     921             :    * RankTwoTensor A(1, 2, 3, 4, 5, 6, 7, 8, 9);
     922             :    * // A = [ 1 4 7
     923             :    * //       2 5 8
     924             :    * //       3 6 9 ]
     925             :    * RankTwoTensor At = A.transpose();
     926             :    * // At = [ 1 2 3
     927             :    * //        4 5 6
     928             :    * //        7 8 9 ]
     929             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     930             :    */
     931             :   RankTwoTensorTempl<T> transpose() const;
     932             : 
     933             :   /**
     934             :    * Return the sum of two second order tensors
     935             :    *
     936             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
     937             :    * RankTwoTensor A(1, 2, 3, 4, 5, 6, 7, 8, 9);
     938             :    * // A = [ 1 2 3
     939             :    * //       2 4 6
     940             :    * //       3 6 9 ]
     941             :    * RankTwoTensor B(9, 8, 7, 6, 5, 4, 3, 2, 1);
     942             :    * // B = [ 9 6 3
     943             :    * //       8 5 2
     944             :    * //       7 4 1 ]
     945             :    * RankTwoTensor C = A + B;
     946             :    * // C = [ 10 8  6
     947             :    * //       10 9  8
     948             :    * //       10 10 10 ]
     949             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     950             :    */
     951             :   template <typename T2>
     952             :   RankTwoTensorTempl<typename libMesh::CompareTypes<T, T2>::supertype>
     953             :   operator+(const libMesh::TypeTensor<T2> & a) const;
     954             : 
     955             :   /**
     956             :    * Return the subtraction of two second order tensors
     957             :    *
     958             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
     959             :    * RankTwoTensor A(1, 2, 3, 4, 5, 6, 7, 8, 9);
     960             :    * // A = [ 1 2 3
     961             :    * //       2 4 6
     962             :    * //       3 6 9 ]
     963             :    * RankTwoTensor B(9, 8, 7, 6, 5, 4, 3, 2, 1);
     964             :    * // B = [ 9 6 3
     965             :    * //       8 5 2
     966             :    * //       7 4 1 ]
     967             :    * RankTwoTensor C = A - B;
     968             :    * // C = [ -8 -4 0
     969             :    * //       -6 -1 4
     970             :    * //       -4  2 8 ]
     971             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     972             :    */
     973             :   template <typename T2>
     974             :   RankTwoTensorTempl<typename libMesh::CompareTypes<T, T2>::supertype>
     975             :   operator-(const libMesh::TypeTensor<T2> & a) const;
     976             : 
     977             :   /**
     978             :    * Return the negation of this tensor
     979             :    *
     980             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
     981             :    * RankTwoTensor A(1, 2, 3, 4, 5, 6, 7, 8, 9);
     982             :    * // A = [ 1 2 3
     983             :    * //       2 4 6
     984             :    * //       3 6 9 ]
     985             :    * RankTwoTensor B = -A;
     986             :    * // B = [ -1 -2 -3
     987             :    * //       -2 -4 -6
     988             :    * //       -3 -6 -9 ]
     989             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     990             :    */
     991             :   RankTwoTensorTempl<T> operator-() const;
     992             : 
     993             :   /**
     994             :    * Return this tensor multiplied by a scalar (component-wise)
     995             :    *
     996             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
     997             :    * RankTwoTensor A(1, 2, 3, 4, 5, 6, 7, 8, 9);
     998             :    * // A = [ 1 2 3
     999             :    * //       2 4 6
    1000             :    * //       3 6 9 ]
    1001             :    * RankTwoTensor B = A * 2;
    1002             :    * // B = [ 2 4  6
    1003             :    * //       4 8  12
    1004             :    * //       6 12 18 ]
    1005             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1006             :    */
    1007             :   template <typename T2, typename std::enable_if<libMesh::ScalarTraits<T2>::value, int>::type = 0>
    1008             :   RankTwoTensorTempl<typename libMesh::CompareTypes<T, T2>::supertype>
    1009             :   operator*(const T2 & a) const;
    1010             : 
    1011             :   /**
    1012             :    * Return this tensor divided by a scalar (component-wise)
    1013             :    *
    1014             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
    1015             :    * RankTwoTensor A(1, 2, 3, 4, 5, 6, 7, 8, 9);
    1016             :    * // A = [ 1 2 3
    1017             :    * //       2 4 6
    1018             :    * //       3 6 9 ]
    1019             :    * RankTwoTensor B = A / 2;
    1020             :    * // B = [ 0.5 1.0 1.5
    1021             :    * //       1.0 2.0 3.0
    1022             :    * //       1.5 3.0 4.5 ]
    1023             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1024             :    */
    1025             :   template <typename T2, typename std::enable_if<libMesh::ScalarTraits<T2>::value, int>::type = 0>
    1026             :   RankTwoTensorTempl<typename libMesh::CompareTypes<T, T2>::supertype>
    1027             :   operator/(const T2 & a) const;
    1028             : 
    1029             :   /**
    1030             :    * Return this tensor multiplied by a vector. \f$ b_i = A_{ij} a_j \f$
    1031             :    *
    1032             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
    1033             :    * RankTwoTensor A(1, 2, 3, 4, 5, 6, 7, 8, 9);
    1034             :    * // A = [ 1 2 3
    1035             :    * //       2 4 6
    1036             :    * //       3 6 9 ]
    1037             :    * RealVectorValue a(1, 2, 3);
    1038             :    * // a = [ 1
    1039             :    * //       2
    1040             :    * //       3 ]
    1041             :    * RealVectorValue b = A * a;
    1042             :    * // b = [ 30
    1043             :    * //       36
    1044             :    * //       42 ]
    1045             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1046             :    */
    1047             :   template <typename T2>
    1048             :   libMesh::TypeVector<typename libMesh::CompareTypes<T, T2>::supertype>
    1049             :   operator*(const libMesh::TypeVector<T2> & a) const;
    1050             : 
    1051             :   /**
    1052             :    * Multiplication with another second order tensor
    1053             :    *
    1054             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
    1055             :    * RankTwoTensor A(1, 2, 3, 4, 5, 6, 7, 8, 9);
    1056             :    * // A = [ 1 2 3
    1057             :    * //       2 4 6
    1058             :    * //       3 6 9 ]
    1059             :    * RankTwoTensor B(9, 8, 7, 6, 5, 4, 3, 2, 1);
    1060             :    * // B = [ 9 6 3
    1061             :    * //       8 5 2
    1062             :    * //       7 4 1 ]
    1063             :    * RankTwoTensor C = A * B;
    1064             :    * // C = [ 90  54 18
    1065             :    * //       114 69 24
    1066             :    * //       138 84 30 ]
    1067             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1068             :    */
    1069             :   template <typename T2>
    1070             :   RankTwoTensorTempl<typename libMesh::CompareTypes<T, T2>::supertype>
    1071             :   operator*(const libMesh::TypeTensor<T2> & a) const;
    1072             : 
    1073             :   /**
    1074             :    * Return the double contraction with another second order tensor \f$ A_{ij} B_{ij} \f$
    1075             :    *
    1076             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
    1077             :    * RankTwoTensor A(1, 2, 3, 4, 5, 6, 7, 8, 9);
    1078             :    * // A = [ 1 2 3
    1079             :    * //       2 4 6
    1080             :    * //       3 6 9 ]
    1081             :    * RankTwoTensor B(9, 8, 7, 6, 5, 4, 3, 2, 1);
    1082             :    * // B = [ 9 6 3
    1083             :    * //       8 5 2
    1084             :    * //       7 4 1 ]
    1085             :    * Real result = A.doubleContraction(B);
    1086             :    * // result = 143
    1087             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1088             :    */
    1089             : 
    1090             :   T doubleContraction(const RankTwoTensorTempl<T> & a) const;
    1091             : 
    1092             :   /**
    1093             :    * Return the general tensor product of this second order tensor and another second order tensor
    1094             :    * defined as \f$ C_{ijkl} = A_{\mathcal{M}(n)\mathcal{M}(o)} B_{\mathcal{M}(p)\mathcal{M}(q)} \f$
    1095             :    * where the multiplication order is defined by the index map \f$ \mathcal{M}: \{n,o,p,q\} \to
    1096             :    * \{i,j,k,l\} \f$. The index map is specified using the template parameters. See examples below
    1097             :    * for detailed explanation.
    1098             :    *
    1099             :    * Suppose we have two second order tensors A and B, and we denote the output indices as i, j, k,
    1100             :    * l:
    1101             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
    1102             :    * usingTensorIndices(i, j, k, l);
    1103             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1104             :    *
    1105             :    * The outer product of A and B is defined as \f$ A_{ij} B_{kl} \f$, hence the template
    1106             :    * specialization should be `times<i, j, k, l>`
    1107             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
    1108             :    * RankFourTensor C = A.times<i, j, k, l>(B);
    1109             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1110             :    *
    1111             :    * The tensor product of A and B, i.e. \f$ A_{ik} B_{jl} \f$ can be expressed using the template
    1112             :    * specialization `times<i, k, j, l>`
    1113             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
    1114             :    * RankFourTensor C = A.times<i, k, j, l>(B);
    1115             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1116             :    *
    1117             :    * Similarly, another tensor product of A and B, i.e. \f$ A_{il} B_{jk} \f$ can be expressed using
    1118             :    * the template specialization `times<i, l, j, k>`
    1119             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
    1120             :    * RankFourTensor C = A.times<i, l, j, k>(B);
    1121             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1122             :    *
    1123             :    * The combination goes on...
    1124             :    */
    1125             :   template <int n, int o, int p, int q>
    1126             :   RankFourTensorTempl<T> times(const RankTwoTensorTempl<T> & b) const;
    1127             : 
    1128             :   /**
    1129             :    * Return the single contraction of this second order tensor with a fourth order tensor defined as
    1130             :    * \f$ C_{ijkl} = A_{\mathcal{M}(m)\mathcal{M}(n)}
    1131             :    * B_{\mathcal{M}(p)\mathcal{M}(q)\mathcal{M}(r)\mathcal{M}(s)} \f$ where the multiplication order
    1132             :    * is defined by the index map \f$ \mathcal{M}: \{m,n,p,q,r,s\} \to \{i,j,k,l\} \f$. The index map
    1133             :    * is specified using the template parameters. See examples below for detailed explanation.
    1134             :    *
    1135             :    * Suppose we have a second order tensors A and a fourth order tensor B, and we denote the indices
    1136             :    * (four output indices and a dummy index to be contracted) as i, j, k, l, m:
    1137             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
    1138             :    * usingTensorIndices(i, j, k, l, m);
    1139             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1140             :    *
    1141             :    * The single contraction of A and B defined as \f$ A_{im} B_{mjkl} \f$ can be expressed using the
    1142             :    * template specialization `times<i, m, m, j, k, l>`
    1143             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
    1144             :    * RankFourTensor C = A.times<i, m, m, j, k, l>(B);
    1145             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1146             :    *
    1147             :    * Similarly, another single contraction of A and B, i.e. \f$ A_{m, i} A_{j, k, m, l} \f$ can be
    1148             :    * expressed using the template specialization `times<m, i, j, k, m, l>`
    1149             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
    1150             :    * RankFourTensor C = A.times<m, i, j, k, m, l>(B);
    1151             :    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1152             :    *
    1153             :    * The combination goes on. Note that this method assumes exactly one repeated index.
    1154             :    */
    1155             :   template <int n, int o, int p, int q, int r, int s>
    1156             :   RankFourTensorTempl<T> times(const RankFourTensorTempl<T> & b) const;
    1157             : 
    1158             :   /**
    1159             :    * @brief Return the outer product \f$ C_{ijkl} = A_{ij} B_{kl} \f$
    1160             :    */
    1161          19 :   RankFourTensorTempl<T> outerProduct(const RankTwoTensorTempl<T> & b) const
    1162             :   {
    1163             :     usingTensorIndices(i_, j_, k_, l_);
    1164          19 :     return times<i_, j_, k_, l_>(b);
    1165             :   }
    1166             : 
    1167             :   /**
    1168             :    * @brief Return the single contraction of this second order tensor with a third order tensor \f$
    1169             :    * C_{ikl} = A_{ij} B_{jkl} \f$
    1170             :    */
    1171             :   RankThreeTensorTempl<T> contraction(const RankThreeTensorTempl<T> & b) const;
    1172             : 
    1173             :   /**
    1174             :    * @brief Return the tensor product of this second order tensor with a vector \f$ C_{ijk} = A_{jk}
    1175             :    * b_{i} \f$
    1176             :    */
    1177             :   RankThreeTensorTempl<T> mixedProductJkI(const libMesh::VectorValue<T> & b) const;
    1178             : 
    1179             :   /**
    1180             :    * @brief Return the positive projection tensor
    1181             :    *
    1182             :    * Consider the eigenvalue decomposition of this second order tensor \f$ A = V D V^T \f$, the part
    1183             :    * of this tensor that lies on the positive spectrum is defined as \f$ A_+ = V \left<D\right> V^T
    1184             :    * \f$ where the angled brackets are the Macaulay brackets. The positive projection tensor is the
    1185             :    * linear projection from the full spectrum to the positive spectrum, i.e. \f$ A_+ = P A \f$. The
    1186             :    * derivation of this positive projection tensor can be found in C. Miehe and M. Lambrecht,
    1187             :    * Commun. Numer. Meth. Engng 2001; 17:337~353
    1188             :    *
    1189             :    * @param eigvals The three eigenvalues of this second order tensor will be filled into this
    1190             :    * vector.
    1191             :    * @param eigvecs The three eigenvectors of this second order tensor will be filled into this
    1192             :    * tensor.
    1193             :    * @return The fourth order positive projection tensor.
    1194             :    */
    1195             :   RankFourTensorTempl<T> positiveProjectionEigenDecomposition(std::vector<T> &,
    1196             :                                                               RankTwoTensorTempl<T> &) const;
    1197             : 
    1198             :   /**
    1199             :    * @brief Return the deviatoric part of this tensor \f$ A_{ij} - \frac{1}{3} A_{kk} \delta_{ij}
    1200             :    * \f$
    1201             :    */
    1202             :   RankTwoTensorTempl<T> deviatoric() const;
    1203             : 
    1204             :   /**
    1205             :    * @brief A wrapper for tr()
    1206             :    * @see tr()
    1207             :    */
    1208             :   T trace() const;
    1209             : 
    1210             :   /**
    1211             :    * Return the derivative of the trace w.r.t. this second order tensor itself \f$ \frac{\partial
    1212             :    * A_{kk}}{\partial A_{ij}} = \delta_{ij} \f$
    1213             :    */
    1214             :   RankTwoTensorTempl<T> dtrace() const;
    1215             : 
    1216             :   /**
    1217             :    * @brief Return the inverse of this second order tensor
    1218             :    */
    1219             :   RankTwoTensorTempl<T> inverse() const;
    1220             : 
    1221             :   /**
    1222             :    * @brief Return the principal second invariant of this second order tensor
    1223             :    *
    1224             :    * \f$ I_2 = \frac{1}{2} \left( A_{kk}^2 - A_{ij}A_{ij} \right) \f$
    1225             :    */
    1226             :   T generalSecondInvariant() const;
    1227             : 
    1228             :   /**
    1229             :    * @brief Return the main second invariant of this second order tensor
    1230             :    *
    1231             :    * \f$ J_2 = \frac{1}{2} \left( S_{ij}S_{ij} \right) \f$, where \f$ S_{ij} = A_{ij} -
    1232             :    * \frac{1}{3}A_{kk}\delta_{ij} \f$
    1233             :    */
    1234             :   T secondInvariant() const;
    1235             : 
    1236             :   /**
    1237             :    * Return the derivative of the main second invariant w.r.t. this second order tensor itself \f$
    1238             :    * \frac{\partial J_2}{\partial A_{ij}} = S_{ij} = A_{ij} -
    1239             :    * \frac{1}{3}A_{kk}\delta_{ij} \f$
    1240             :    */
    1241             :   RankTwoTensorTempl<T> dsecondInvariant() const;
    1242             : 
    1243             :   /**
    1244             :    * Return the second derivative of the main second invariant w.r.t. this second order tensor
    1245             :    * itself \f$ \frac{\partial^2 J_2}{\partial A_{ij}A_{kl}} = \delta_{ik}\delta_{jl} -
    1246             :    * \frac{1}{3}\delta_{ij}\delta_{kl} \f$
    1247             :    */
    1248             :   RankFourTensorTempl<T> d2secondInvariant() const;
    1249             : 
    1250             :   /**
    1251             :    * @brief Sin(3*Lode_angle)
    1252             :    *
    1253             :    * If secondInvariant() <= r0 then return r0_value
    1254             :    * This is to gaurd against precision-loss errors.
    1255             :    * Note that sin(3*Lode_angle) is not defined for secondInvariant() = 0
    1256             :    */
    1257             :   T sin3Lode(const T & r0, const T & r0_value) const;
    1258             : 
    1259             :   /**
    1260             :    * d(sin3Lode)/dA_ij
    1261             :    * If secondInvariant() <= r0 then return zero
    1262             :    * This is to gaurd against precision-loss errors.
    1263             :    * Note that sin(3*Lode_angle) is not defined for secondInvariant() = 0
    1264             :    */
    1265             :   RankTwoTensorTempl<T> dsin3Lode(const T & r0) const;
    1266             : 
    1267             :   /**
    1268             :    * d^2(sin3Lode)/dA_ij/dA_kl
    1269             :    * If secondInvariant() <= r0 then return zero
    1270             :    * This is to gaurd against precision-loss errors.
    1271             :    * Note that sin(3*Lode_angle) is not defined for secondInvariant() = 0
    1272             :    */
    1273             :   RankFourTensorTempl<T> d2sin3Lode(const T & r0) const;
    1274             : 
    1275             :   /**
    1276             :    * Denote the _coords[i][j] by A_ij, then
    1277             :    * S_ij = A_ij - de_ij*tr(A)/3
    1278             :    * Then this returns det(S + S.transpose())/2
    1279             :    * Note the explicit symmeterisation
    1280             :    */
    1281             :   T thirdInvariant() const;
    1282             : 
    1283             :   /**
    1284             :    * Denote the _coords[i][j] by A_ij, then
    1285             :    * this returns d(thirdInvariant()/dA_ij
    1286             :    */
    1287             :   RankTwoTensorTempl<T> dthirdInvariant() const;
    1288             : 
    1289             :   /**
    1290             :    * Denote the _coords[i][j] by A_ij, then this returns
    1291             :    * d^2(thirdInvariant)/dA_ij/dA_kl
    1292             :    */
    1293             :   RankFourTensorTempl<T> d2thirdInvariant() const;
    1294             : 
    1295             :   /**
    1296             :    * Denote the _coords[i][j] by A_ij, then this returns
    1297             :    * d(det)/dA_ij
    1298             :    */
    1299             :   RankTwoTensorTempl<T> ddet() const;
    1300             : 
    1301             :   /// Sqrt(_coords[i][j]*_coords[i][j])
    1302             :   T L2norm() const;
    1303             : 
    1304             :   /**
    1305             :    * computes eigenvalues, assuming tens is symmetric, and places them
    1306             :    * in ascending order in eigvals
    1307             :    */
    1308             :   void symmetricEigenvalues(std::vector<T> & eigvals) const;
    1309             : 
    1310             :   /**
    1311             :    * computes eigenvalues and eigenvectors, assuming tens is symmetric, and places them
    1312             :    * in ascending order in eigvals.  eigvecs is a matrix with the first column
    1313             :    * being the first eigenvector, the second column being the second, etc.
    1314             :    */
    1315             :   void symmetricEigenvaluesEigenvectors(std::vector<T> & eigvals,
    1316             :                                         RankTwoTensorTempl<T> & eigvecs) const;
    1317             : 
    1318             :   /**
    1319             :    * computes eigenvalues, and their symmetric derivatives wrt vals,
    1320             :    * assuming tens is symmetric
    1321             :    * @param eigvals are the eigenvalues of the matrix, in ascending order
    1322             :    * @param deigvals Here digvals[i](j,k) = (1/2)*(d(eigvals[i])/dA_jk + d(eigvals[i]/dA_kj))
    1323             :    * Note the explicit symmeterisation here.
    1324             :    * For equal eigenvalues, these derivatives are not gauranteed to
    1325             :    * be the ones you expect, since the derivatives in this case are
    1326             :    * often defined by continuation from the un-equal case, and that is
    1327             :    * too sophisticated for this routine.
    1328             :    */
    1329             :   void dsymmetricEigenvalues(std::vector<T> & eigvals,
    1330             :                              std::vector<RankTwoTensorTempl<T>> & deigvals) const;
    1331             : 
    1332             :   /**
    1333             :    * Computes second derivatives of Eigenvalues of a rank two tensor
    1334             :    * @param deriv store second derivative of the current tensor in here
    1335             :    */
    1336             :   void d2symmetricEigenvalues(std::vector<RankFourTensorTempl<T>> & deriv) const;
    1337             : 
    1338             :   /**
    1339             :    * Uses the petscblaslapack.h LAPACKsyev_ routine to perform RU decomposition and obtain the
    1340             :    * rotation tensor.
    1341             :    */
    1342             :   void getRUDecompositionRotation(RankTwoTensorTempl<T> & rot) const;
    1343             : 
    1344             :   /// returns this_ij * b_ijkl
    1345             :   RankTwoTensorTempl<T> initialContraction(const RankFourTensorTempl<T> & b) const;
    1346             : 
    1347             :   /// @}
    1348             : 
    1349             :   /// @{
    1350             : 
    1351             :   /// Defines logical equality with another RankTwoTensorTempl<T>
    1352             :   bool operator==(const RankTwoTensorTempl<T> & a) const;
    1353             : 
    1354             :   /// Test for symmetry
    1355             :   bool isSymmetric() const;
    1356             : 
    1357             :   /// @}
    1358             : 
    1359             : protected:
    1360             :   /**
    1361             :    * Uses the petscblaslapack.h LAPACKsyev_ routine to find, for symmetric _coords:
    1362             :    *  (1) the eigenvalues (if calculation_type == "N")
    1363             :    *  (2) the eigenvalues and eigenvectors (if calculation_type == "V")
    1364             :    * @param calculation_type If "N" then calculation eigenvalues only
    1365             :    * @param eigvals Eigenvalues are placed in this array, in ascending order
    1366             :    * @param a Eigenvectors are placed in this array if calculation_type == "V".
    1367             :    * See code in dsymmetricEigenvalues for extracting eigenvectors from the a output.
    1368             :    */
    1369             :   void syev(const char * calculation_type, std::vector<T> & eigvals, std::vector<T> & a) const;
    1370             : 
    1371             : private:
    1372             :   static constexpr Real identityCoords[N2] = {1, 0, 0, 0, 1, 0, 0, 0, 1};
    1373             : 
    1374             :   template <class T2>
    1375             :   friend void dataStore(std::ostream &, RankTwoTensorTempl<T2> &, void *);
    1376             : 
    1377             :   using libMesh::TensorValue<T>::_coords;
    1378             : 
    1379             :   template <class T2>
    1380             :   friend void dataLoad(std::istream &, RankTwoTensorTempl<T2> &, void *);
    1381             :   template <class T2>
    1382             :   friend class RankFourTensorTempl;
    1383             :   template <class T2>
    1384             :   friend class RankThreeTensorTempl;
    1385             : };
    1386             : 
    1387             : namespace MetaPhysicL
    1388             : {
    1389             : template <typename T>
    1390             : struct RawType<RankTwoTensorTempl<T>>
    1391             : {
    1392             :   typedef RankTwoTensorTempl<typename RawType<T>::value_type> value_type;
    1393             : 
    1394          26 :   static value_type value(const RankTwoTensorTempl<T> & in)
    1395             :   {
    1396          26 :     value_type ret;
    1397         104 :     for (auto i : libMesh::make_range(RankTwoTensorTempl<T>::N))
    1398         312 :       for (auto j : libMesh::make_range(RankTwoTensorTempl<T>::N))
    1399         234 :         ret(i, j) = raw_value(in(i, j));
    1400             : 
    1401          26 :     return ret;
    1402           0 :   }
    1403             : };
    1404             : }
    1405             : 
    1406             : template <typename T>
    1407             : template <typename T2>
    1408             : RankTwoTensorTempl<typename libMesh::CompareTypes<T, T2>::supertype>
    1409        1348 : RankTwoTensorTempl<T>::operator+(const libMesh::TypeTensor<T2> & b) const
    1410             : {
    1411        1348 :   return libMesh::TensorValue<T>::operator+(b);
    1412             : }
    1413             : 
    1414             : template <typename T>
    1415             : template <typename T2>
    1416             : RankTwoTensorTempl<typename libMesh::CompareTypes<T, T2>::supertype>
    1417      792400 : RankTwoTensorTempl<T>::operator-(const libMesh::TypeTensor<T2> & b) const
    1418             : {
    1419      792400 :   return libMesh::TensorValue<T>::operator-(b);
    1420             : }
    1421             : 
    1422             : template <typename T>
    1423             : template <typename T2, typename std::enable_if<libMesh::ScalarTraits<T2>::value, int>::type>
    1424             : RankTwoTensorTempl<typename libMesh::CompareTypes<T, T2>::supertype>
    1425        1341 : RankTwoTensorTempl<T>::operator*(const T2 & b) const
    1426             : {
    1427        1341 :   return libMesh::TensorValue<T>::operator*(b);
    1428             : }
    1429             : 
    1430             : template <typename T>
    1431             : template <typename T2>
    1432             : libMesh::TypeVector<typename libMesh::CompareTypes<T, T2>::supertype>
    1433          14 : RankTwoTensorTempl<T>::operator*(const libMesh::TypeVector<T2> & b) const
    1434             : {
    1435          14 :   return libMesh::TensorValue<T>::operator*(b);
    1436             : }
    1437             : 
    1438             : template <typename T>
    1439             : template <typename T2>
    1440             : RankTwoTensorTempl<typename libMesh::CompareTypes<T, T2>::supertype>
    1441          25 : RankTwoTensorTempl<T>::operator*(const libMesh::TypeTensor<T2> & b) const
    1442             : {
    1443          25 :   return libMesh::TensorValue<T>::operator*(b);
    1444             : }
    1445             : 
    1446             : template <typename T>
    1447             : template <typename T2, typename std::enable_if<libMesh::ScalarTraits<T2>::value, int>::type>
    1448             : RankTwoTensorTempl<typename libMesh::CompareTypes<T, T2>::supertype>
    1449         254 : RankTwoTensorTempl<T>::operator/(const T2 & b) const
    1450             : {
    1451         254 :   return libMesh::TensorValue<T>::operator/(b);
    1452             : }
    1453             : 
    1454             : template <typename T>
    1455             : RankFourTensorTempl<T>
    1456           1 : RankTwoTensorTempl<T>::positiveProjectionEigenDecomposition(std::vector<T> & eigval,
    1457             :                                                             RankTwoTensorTempl<T> & eigvec) const
    1458             : {
    1459             :   if constexpr (MooseUtils::IsLikeReal<T>::value)
    1460             :   {
    1461             :     // Compute eigenvectors and eigenvalues of this tensor
    1462           1 :     this->symmetricEigenvaluesEigenvectors(eigval, eigvec);
    1463             : 
    1464             :     // Separate out positive and negative eigen values
    1465           0 :     std::array<T, N> epos;
    1466           0 :     std::array<T, N> d;
    1467           4 :     for (auto i : libMesh::make_range(N))
    1468             :     {
    1469           3 :       epos[i] = (std::abs(eigval[i]) + eigval[i]) / 2.0;
    1470           3 :       d[i] = 0 < eigval[i] ? 1.0 : 0.0;
    1471             :     }
    1472             : 
    1473             :     // projection tensor
    1474           1 :     RankFourTensorTempl<T> proj_pos;
    1475           1 :     RankFourTensorTempl<T> Gab, Gba;
    1476             : 
    1477           4 :     for (auto a : libMesh::make_range(N))
    1478             :     {
    1479           3 :       const auto Ma = RankTwoTensorTempl<T>::selfOuterProduct(eigvec.column(a));
    1480           3 :       proj_pos += d[a] * Ma.outerProduct(Ma);
    1481             :     }
    1482             : 
    1483             :     usingTensorIndices(i_, j_, k_, l_);
    1484           4 :     for (const auto a : libMesh::make_range(N))
    1485           6 :       for (const auto b : libMesh::make_range(a))
    1486             :       {
    1487           3 :         const auto Ma = RankTwoTensorTempl<T>::selfOuterProduct(eigvec.column(a));
    1488           3 :         const auto Mb = RankTwoTensorTempl<T>::selfOuterProduct(eigvec.column(b));
    1489             : 
    1490           3 :         Gab = Ma.template times<i_, k_, j_, l_>(Mb) + Ma.template times<i_, l_, j_, k_>(Mb);
    1491           3 :         Gba = Mb.template times<i_, k_, j_, l_>(Ma) + Mb.template times<i_, l_, j_, k_>(Ma);
    1492             : 
    1493           0 :         T theta_ab;
    1494           3 :         if (!MooseUtils::absoluteFuzzyEqual(eigval[a], eigval[b]))
    1495           3 :           theta_ab = 0.5 * (epos[a] - epos[b]) / (eigval[a] - eigval[b]);
    1496             :         else
    1497           0 :           theta_ab = 0.25 * (d[a] + d[b]);
    1498             : 
    1499           3 :         proj_pos += theta_ab * (Gab + Gba);
    1500             :       }
    1501           1 :     return proj_pos;
    1502           0 :   }
    1503             :   else
    1504             :     mooseError("positiveProjectionEigenDecomposition is only available for ordered tensor "
    1505             :                "component types");
    1506             : }
    1507             : 
    1508             : template <typename T>
    1509             : T
    1510          32 : RankTwoTensorTempl<T>::sin3Lode(const T & r0, const T & r0_value) const
    1511             : {
    1512             :   if constexpr (MooseUtils::IsLikeReal<T>::value)
    1513             :   {
    1514          32 :     T bar = secondInvariant();
    1515          32 :     if (bar <= r0)
    1516             :       // in this case the Lode angle is not defined
    1517           0 :       return r0_value;
    1518             :     else
    1519             :       // the min and max here gaurd against precision-loss when bar is tiny but nonzero.
    1520          32 :       return std::max(std::min(-1.5 * std::sqrt(3.0) * thirdInvariant() / std::pow(bar, 1.5), 1.0),
    1521          64 :                       -1.0);
    1522           0 :   }
    1523             :   else
    1524             :     mooseError("sin3Lode is only available for ordered tensor component types");
    1525             : }
    1526             : 
    1527             : template <typename T>
    1528             : RankTwoTensorTempl<T>
    1529         248 : RankTwoTensorTempl<T>::dsin3Lode(const T & r0) const
    1530             : {
    1531             :   if constexpr (MooseUtils::IsLikeReal<T>::value)
    1532             :   {
    1533         248 :     T bar = secondInvariant();
    1534         248 :     if (bar <= r0)
    1535           0 :       return RankTwoTensorTempl<T>();
    1536             :     else
    1537           0 :       return -1.5 * std::sqrt(3.0) *
    1538           0 :              (dthirdInvariant() / std::pow(bar, 1.5) -
    1539         248 :               1.5 * dsecondInvariant() * thirdInvariant() / std::pow(bar, 2.5));
    1540           0 :   }
    1541             :   else
    1542             :     mooseError("dsin3Lode is only available for ordered tensor component types");
    1543             : }
    1544             : 
    1545             : template <typename T>
    1546             : RankFourTensorTempl<T>
    1547           2 : RankTwoTensorTempl<T>::d2sin3Lode(const T & r0) const
    1548             : {
    1549             :   if constexpr (MooseUtils::IsLikeReal<T>::value)
    1550             :   {
    1551           2 :     T bar = secondInvariant();
    1552           2 :     if (bar <= r0)
    1553           0 :       return RankFourTensorTempl<T>();
    1554             : 
    1555           2 :     T J3 = thirdInvariant();
    1556           2 :     RankTwoTensorTempl<T> dII = dsecondInvariant();
    1557           2 :     RankTwoTensorTempl<T> dIII = dthirdInvariant();
    1558           2 :     RankFourTensorTempl<T> deriv = d2thirdInvariant() / std::pow(bar, 1.5) -
    1559           2 :                                    1.5 * d2secondInvariant() * J3 / std::pow(bar, 2.5);
    1560             : 
    1561           8 :     for (unsigned i = 0; i < N; ++i)
    1562          24 :       for (unsigned j = 0; j < N; ++j)
    1563          72 :         for (unsigned k = 0; k < N; ++k)
    1564         216 :           for (unsigned l = 0; l < N; ++l)
    1565         324 :             deriv(i, j, k, l) += (-1.5 * dII(i, j) * dIII(k, l) - 1.5 * dIII(i, j) * dII(k, l)) /
    1566         324 :                                      std::pow(bar, 2.5) +
    1567         162 :                                  1.5 * 2.5 * dII(i, j) * dII(k, l) * J3 / std::pow(bar, 3.5);
    1568             : 
    1569           2 :     deriv *= -1.5 * std::sqrt(3.0);
    1570           2 :     return deriv;
    1571           2 :   }
    1572             :   else
    1573             :     mooseError("d2sin3Lode is only available for ordered tensor component types");
    1574             : }
    1575             : 
    1576             : template <typename T>
    1577             : template <int n, int o, int p, int q>
    1578             : RankFourTensorTempl<T>
    1579          91 : RankTwoTensorTempl<T>::times(const RankTwoTensorTempl<T> & b) const
    1580             : {
    1581          91 :   RankFourTensorTempl<T> result;
    1582             :   std::size_t x[4];
    1583         364 :   for (x[0] = 0; x[0] < N; ++x[0])
    1584        1092 :     for (x[1] = 0; x[1] < N; ++x[1])
    1585        3276 :       for (x[2] = 0; x[2] < N; ++x[2])
    1586        9828 :         for (x[3] = 0; x[3] < N; ++x[3])
    1587        7371 :           result(x[0], x[1], x[2], x[3]) = (*this)(x[n], x[o]) * b(x[p], x[q]);
    1588             : 
    1589         182 :   return result;
    1590           0 : }
    1591             : 
    1592             : template <typename T>
    1593             : template <int n, int o, int p, int q, int r, int s>
    1594             : RankFourTensorTempl<T>
    1595           3 : RankTwoTensorTempl<T>::times(const RankFourTensorTempl<T> & b) const
    1596             : {
    1597           3 :   RankFourTensorTempl<T> result;
    1598             :   std::size_t x[5];
    1599          12 :   for (x[0] = 0; x[0] < N; ++x[0])
    1600          36 :     for (x[1] = 0; x[1] < N; ++x[1])
    1601         108 :       for (x[2] = 0; x[2] < N; ++x[2])
    1602         324 :         for (x[3] = 0; x[3] < N; ++x[3])
    1603         972 :           for (x[4] = 0; x[4] < N; ++x[4])
    1604         729 :             result(x[0], x[1], x[2], x[3]) += (*this)(x[n], x[o]) * b(x[p], x[q], x[r], x[s]);
    1605             : 
    1606           6 :   return result;
    1607             : }

Generated by: LCOV version 1.14