/**
* Provide a class that stores symmetric tensors of rank 2,4,... efficiently,
* i.e. only store those off-diagonal elements of the full tensor that are not
- * redundant. For example, for symmetric 2x2 tensors, this would be the
+ * redundant. For example, for symmetric $2\times 2$ tensors, this would be the
* elements 11, 22, and 12, while the element 21 is equal to the 12 element.
+ * Within this documentation, second order symmetric tensors are denoted as
+ * bold-faced upper-case Latin letters such as $\mathbf A, \mathbf B, \dots$
+ * or bold-faced Greek letters such as $\boldsymbol{\varepsilon}$,
+ * $\boldsymbol{\sigma}$. The Cartesian coordinates of a second-order tensor
+ * such as $\mathbf A$ are represented as $A_{ij}$ where $i,j$ are indices
+ * ranging from 0 to <tt>dim-1</tt>.
*
* Using this class for symmetric tensors of rank 2 has advantages over
* matrices in many cases since the dimension is known to the compiler as well
* the tensor represents a symmetric object.
*
* For tensors of higher rank, the savings in storage are even higher. For
- * example for the 3x3x3x3 tensors of rank 4, only 36 instead of the full 81
- * entries have to be stored.
+ * example for the $3 \times 3 \times 3 \times 3$ tensors of rank 4, only 36
+ * instead of the full 81 entries have to be stored. These rank 4 tensors are
+ * denoted by blackboard-style upper-case Latin letters such as $\mathbb A$
+ * with components $\mathcal{A}_{ijkl}$.
*
* While the definition of a symmetric rank-2 tensor is obvious, tensors of
* rank 4 are considered symmetric if they are operators mapping symmetric
- * rank-2 tensors onto symmetric rank-2 tensors. This entails certain symmetry
- * properties on the elements in their 4-dimensional index space, in
- * particular that
- * <tt>C<sub>ijkl</sub>=C<sub>jikl</sub>=C<sub>ijlk</sub></tt>. However, it
- * does not imply the relation <tt>C<sub>ijkl</sub>=C<sub>klij</sub></tt>.
+ * rank-2 tensors onto symmetric rank-2 tensors. This so-called minor symmetry
+ * of the rank 4 tensor requires that for every set of four indices
+ * $i, j, k, l$, the identity $\mathcal{C}_{ijkl} = \mathcal{C}_{jikl} =
+ * \mathcal{C}_{ijlk}$ holds. However, it does not imply the relation
+ * $\mathcal{C}_{ijkl} = \mathcal{C}_{klij}$.
* Consequently, symmetric tensors of rank 4 as understood here are only
* tensors that map symmetric tensors onto symmetric tensors, but they do not
- * necessarily induce a symmetric scalar product <tt>a:C:b=b:C:a</tt> or even
- * a positive (semi-)definite form <tt>a:C:a</tt>, where <tt>a,b</tt> are
- * symmetric rank-2 tensors and the colon indicates the common double-index
- * contraction that acts as a product for symmetric tensors.
+ * necessarily induce a symmetric scalar product $\mathbf A : \mathbb C :
+ * \mathbf B = \mathbf B : \mathbb C : \mathbf A$ or even
+ * a positive (semi-)definite form $\mathbf A : \mathbb C : \mathbf A$, where
+ * $\mathbf A, \mathbf B$ are symmetric rank-2 tensors and the colon indicates
+ * the common double-index contraction that acts as a scalar product for
+ * symmetric tensors.
*
* Symmetric tensors are most often used in structural and fluid
* mechanics, where strains and stresses are usually symmetric
*
* <h3>Accessing elements</h3>
*
- * The elements of a tensor <tt>t</tt> can be accessed using the bracket
- * operator, i.e. for a tensor of rank 4, <tt>t[0][1][0][1]</tt> accesses the
- * element <tt>t<sub>0101</sub></tt>. This access can be used for both reading
+ * The elements of a tensor $\mathbb C$ can be accessed using the bracket
+ * operator, i.e. for a tensor of rank 4, <tt>C[0][1][0][1]</tt> accesses the
+ * element $\mathcal{C}_{0101}$. This access can be used for both reading
* and writing (if the tensor is non-constant at least). You may also perform
* other operations on it, although that may lead to confusing situations
* because several elements of the tensor are stored at the same location. For
* example, for a rank-2 tensor that is assumed to be zero at the beginning,
- * writing <tt>t[0][1]+=1; t[1][0]+=1;</tt> will lead to the same element
+ * writing <tt>A[0][1]+=1; A[1][0]+=1;</tt> will lead to the same element
* being increased by one <em>twice</em>, because even though the accesses use
* different indices, the elements that are accessed are symmetric and
* therefore stored at the same location. It may therefore be useful in
* only up to round-off error: if the incoming tensor is not exactly
* symmetric, then an exception is thrown. If you know that incoming tensor
* is symmetric only up to round-off, then you may want to call the
- * <tt>symmetrize</tt> function first. If you aren't sure, it is good
- * practice to check before calling <tt>symmetrize</tt>.
+ * <tt>symmetrize()</tt> function first. If you aren't sure, it is good
+ * practice to check before calling <tt>symmetrize()</tt>.
*
* Because we check for symmetry via a non-constexpr function call, you will
* have to use the symmetrize() function in constexpr contexts instead.
* rank 2.
*
* The size of the array passed is equal to
- * SymmetricTensor<rank_,dim>::n_independent_component; the reason for using
+ * SymmetricTensor<rank_,dim>::n_independent_components; the reason for using
* the object from the internal namespace is to work around bugs in some
* older compilers.
*/
* This operator assigns a scalar to a tensor. To avoid confusion with what
* exactly it means to assign a scalar value to a tensor, zero is the only
* value allowed for <tt>d</tt>, allowing the intuitive notation
- * <tt>t=0</tt> to reset all elements of the tensor to zero.
+ * $\mathbf A = 0$ to reset all elements of the tensor to zero.
*/
DEAL_II_CONSTEXPR SymmetricTensor &
operator=(const Number &d);
operator-() const;
/**
- * Product between the present symmetric tensor and a tensor of rank 2. For
- * example, if the present object is also a rank-2 tensor, then this is the
- * scalar-product double contraction <tt>a<sub>ij</sub>b<sub>ij</sub></tt>
- * over all indices <tt>i,j</tt>. In this case, the return value evaluates
- * to a single scalar. While it is possible to define other scalar product
- * (and associated induced norms), this one seems to be the most appropriate
- * one.
+ * Double contraction product between the present symmetric tensor and a
+ * tensor of rank 2. For example, if the present object is the symmetric
+ * rank-2 tensor $\mathbf{A}$ and it is multiplied by another symmetric
+ * rank-2 tensor $\mathbf{B}$, then the result is the scalar-product double
+ * contraction $\mathbf A : \mathbf B = \sum_{i,j} A_{ij} B_{ij}$.
+ * In this case, the return value evaluates to a single
+ * scalar. While it is possible to define other scalar products (and
+ * associated induced norms), this one seems to be the most appropriate one.
*
- * If the present object is a rank-4 tensor, then the result is a rank-2
- * tensor, i.e., the operation contracts over the last two indices of the
- * present object and the indices of the argument, and the result is a
- * tensor of rank 2.
+ * If the present object is a rank-4 tensor such as $\mathbb A$, then the
+ * result is a rank-2 tensor $\mathbf C = \mathbb A : \mathbf B$, i.e.,
+ * the operation contracts over the last two indices of the present object
+ * and the indices of the argument, and the result is a tensor of rank 2
+ * ($C_{ij} = \sum_{k,l} \mathcal{A}_{ijkl} B_{kl}$).
*
* Note that the multiplication operator for symmetric tensors is defined to
* be a double contraction over two indices, while it is defined as a single
/**
* Access to an element according to unrolled index. The function
* <tt>s.access_raw_entry(unrolled_index)</tt> does the same as
- * <tt>s[s.unrolled_to_component_indices(i)]</tt>, but more efficiently.
+ * <tt>s[s.unrolled_to_component_indices(unrolled_index)]</tt>, but more
+ * efficiently.
*/
DEAL_II_CONSTEXPR const Number &
access_raw_entry(const unsigned int unrolled_index) const;
/**
* Access to an element according to unrolled index. The function
* <tt>s.access_raw_entry(unrolled_index)</tt> does the same as
- * <tt>s[s.unrolled_to_component_indices(i)]</tt>, but more efficiently.
+ * <tt>s[s.unrolled_to_component_indices(unrolled_index)]</tt>, but more
+ * efficiently.
*/
DEAL_II_CONSTEXPR Number &
access_raw_entry(const unsigned int unrolled_index);
*
* If possible (e.g. when @p Number and @p OtherNumber are of the same type,
* or if the result of <code>Number() + OtherNumber()</code> is another @p Number),
- * you should use <tt>operator +=</tt> instead since this does not require the
+ * you should use <tt>operator+=</tt> instead since this does not require the
* creation of a temporary variable.
*
* @relatesalso SymmetricTensor
* operation.
*
* If possible (e.g. when @p Number and @p OtherNumber are of the same type,
- * or if the result of <code>Number() + OtherNumber()</code> is another @p Number),
- * you should use <tt>operator +=</tt> instead since this does not require the
+ * or if the result of <code>Number() - OtherNumber()</code> is another @p Number),
+ * you should use <tt>operator-=</tt> instead since this does not require the
* creation of a temporary variable.
*
* @relatesalso SymmetricTensor
/**
- * Compute the determinant of a tensor or rank 2. The determinant is also
- * commonly referred to as the third invariant of rank-2 tensors.
+ * Compute the determinant of a rank 2 symmetric tensor. The determinant is
+ * also commonly referred to as the third invariant of rank-2 tensors.
*
* For a one-dimensional tensor, the determinant equals the only element and
* is therefore equivalent to the trace.
*
- * For greater notational simplicity, there is also a <tt>third_invariant</tt>
+ * For greater notational simplicity, there is also a
+ * <tt>third_invariant()</tt>
* function that returns the determinant of a tensor.
*
* @relatesalso SymmetricTensor
/**
- * Compute the determinant of a tensor or rank 2. This function therefore
- * computes the same value as the <tt>determinant()</tt> functions and is only
- * provided for greater notational simplicity (since there are also functions
- * first_invariant() and second_invariant()).
+ * Compute the determinant of a rank 2 symmetric tensor. This function
+ * therefore computes the same value as the <tt>determinant()</tt> functions
+ * and is only provided for greater notational simplicity (since there are
+ * also functions first_invariant() and second_invariant()).
+ * \f[
+ * I_3 (\mathbf A) = III (\mathbf A) = \det (\mathbf A)
+ * \f]
*
* @relatesalso SymmetricTensor
* @author Wolfgang Bangerth, 2005
/**
* Compute and return the trace of a tensor of rank 2, i.e. the sum of its
* diagonal entries. The trace is the first invariant of a rank-2 tensor.
+ * \f[
+ * \text{tr} \mathbf A = \sum_i A_{ii}
+ * \f]
*
* @relatesalso SymmetricTensor
* @author Wolfgang Bangerth, 2005
/**
- * Compute the trace of a tensor or rank 2. This function therefore computes
- * the same value as the <tt>trace()</tt> functions and is only provided for
- * greater notational simplicity (since there are also functions
+ * Compute the trace of a rank 2 symmetric tensor. This function therefore
+ * computes the same value as the <tt>trace()</tt> functions and is only
+ * provided for greater notational simplicity (since there are also functions
* second_invariant() and third_invariant()).
+ * \f[
+ * I_1 (\mathbf A) = I (\mathbf A) = \text{tr} \mathbf A = \sum_i A_{ii}
+ * \f]
*
* @relatesalso SymmetricTensor
* @author Wolfgang Bangerth, 2005
/**
* Compute the second invariant of a tensor of rank 2. The second invariant of
- * a tensor $\sigma$ is defined as
- * $II(\sigma) = \frac 12 \left[ (\text{trace}\ \sigma)^2
- * -\text{trace}\ (\sigma^2) \right]$.
+ * a tensor $\mathbf A$ is defined as
+ * $I_2 (\mathbf A) = II(\mathbf A) = \frac 12
+ * \left[ (\text{tr} \mathbf A)^2 - \text{tr} (\mathbf{A}^2) \right]$.
*
* For the kind of arguments to this function, i.e., a rank-2 tensor of
* size 1, the result is simply zero.
/**
* Compute the second invariant of a tensor of rank 2. The second invariant of
- * a tensor $\sigma$ is defined as
- * $II(\sigma) = \frac 12 \left[ (\text{trace}\ \sigma)^2
- * -\text{trace}\ (\sigma^2) \right]$.
+ * a tensor $\mathbf A$ is defined as
+ * $I_2 (\mathbf A) = II(\mathbf A) = \frac 12
+ * \left[ (\text{tr} \mathbf A)^2 - \text{tr} (\mathbf{A}^2) \right]$.
*
- * For the kind of arguments to this function, i.e., a rank-2 tensor of
- * size 2, the result is (counting indices starting at one)
- * $II(\sigma) = \frac 12 \left[ (\sigma_{11} + \sigma_{22})^2
- * -(\sigma_{11}^2+2\sigma_{12}^2+\sigma_{22}^2)
- * \right] = \sigma_{11}\sigma_{22} - \sigma_{12}^2$. As expected, for the
+ * For the kind of arguments to this function, i.e., a symmetric rank-2 tensor
+ * of size 2, the result is (counting indices starting at one)
+ * $I_2(\mathbf A) = II(\mathbf A) = \frac 12
+ * \left[ (A_{11} + A_{22})^2 - (A_{11}^2+2 A_{12}^2+ A_{22}^2) \right]
+ * = A_{11} A_{22} - A_{12}^2$. As expected, for the
* $2\times 2$ symmetric tensors this function handles, this equals the
* determinant of the tensor. (This is so because for $2\times 2$ symmetric
* tensors, there really are only two invariants, so the second and third
/**
* Compute the second invariant of a tensor of rank 2. The second invariant of
- * a tensor $\sigma$ is defined as
- * $II(\sigma) = \frac 12 \left[ (\text{trace}\ \sigma)^2
- * -\text{trace}\ (\sigma^2) \right]$.
+ * a tensor $\mathbf A$ is defined as
+ * $I_2 (\mathbf A) = II(\mathbf A) = \frac 12
+ * \left[ (\text{tr} \mathbf A)^2 - \text{tr} (\mathbf{A}^2) \right]$.
*
* @relatesalso SymmetricTensor
* @author Wolfgang Bangerth, 2005, 2010
/**
- * Return the eigenvalues of a symmetric 1x1 tensor of rank 2.
+ * Return the eigenvalues of a symmetric $1 \times 1$ tensor.
* The (single) entry of the tensor is, of course, equal to the (single)
* eigenvalue.
*
/**
- * Return the eigenvalues of a symmetric 2x2 tensor of rank 2.
+ * Return the eigenvalues of a symmetric $2\times 2$ tensor.
* The array of eigenvalues is sorted in descending order.
*
- * For 2x2 tensors, the eigenvalues of tensor $T$ are the roots of
- * <a
+ * For $2\times 2$ tensors, the eigenvalues of tensor $\mathbf T$ are the
+ * roots of <a
* href="https://en.wikipedia.org/wiki/Eigenvalue_algorithm#2.C3.972_matrices">the
- * characteristic polynomial</a> $0 = \lambda^{2} - \lambda\textrm{tr}(T) +
- * \textrm{det}(T)$ as given by
- * $\lambda = \frac{\textrm{tr}(T) \pm \sqrt{[\textrm{tr}(T)]^{2} -
- * 4\textrm{det}(T)}}{2}$.
+ * characteristic polynomial</a> $0 = \lambda^2
+ * - \lambda\;\text{tr}\mathbf{T} + \det \mathbf{T}$ as given by
+ * $\lambda_1, \lambda_2 = \frac{1}{2} \left[ \text{tr} \mathbf{T} \pm
+ * \sqrt{(\text{tr} \mathbf{T})^2 - 4 \det \mathbf{T}} \right]$.
*
* @warning The algorithm employed here determines the eigenvalues by
* computing the roots of the characteristic polynomial. In the case that there
/**
- * Return the eigenvalues of a symmetric 3x3 tensor of rank 2.
+ * Return the eigenvalues of a symmetric $3\times 3$ tensor.
* The array of eigenvalues is sorted in descending order.
*
- * For 3x3 tensors, the eigenvalues of tensor $T$ are the roots of
- * <a
+ * For $3\times 3$ tensors, the eigenvalues of tensor $\mathbf T$ are the
+ * roots of <a
* href="https://en.wikipedia.org/wiki/Eigenvalue_algorithm#3.C3.973_matrices">the
- * characteristic polynomial</a> $0 = \lambda^{3} - \lambda^{2}\textrm{tr}(T) -
- * \frac{1}{2} \lambda (\textrm{tr}(T^{2}) - [\textrm{tr}(T)]^{2}) -
- * \textrm{det}(T)$.
+ * characteristic polynomial</a> $0 = \lambda^3 - \lambda^2\;\text{tr}\mathbf T
+ * - \frac{1}{2} \lambda
+ * \left[\text{tr}(\mathbf{T}^2) - (\text{tr}\mathbf T)^2\right] -
+ * \det \mathbf T$.
*
* @warning The algorithm employed here determines the eigenvalues by
* computing the roots of the characteristic polynomial. In the case that there
/**
* Return the eigenvalues and eigenvectors of a real-valued rank-2 symmetric
- * tensor $T$. The array of matched eigenvalue and eigenvector pairs is sorted
- * in descending order (determined by the eigenvalues).
+ * tensor $\mathbf T$. The array of matched eigenvalue and eigenvector pairs
+ * is sorted in descending order (determined by the eigenvalues).
*
* The specialized algorithms utilized in computing the eigenvectors are
* presented in
/**
- * Compute the deviator of a symmetric tensor, which is defined as <tt>dev[s]
- * = s - 1/dim*tr[s]*I</tt>, where <tt>I</tt> is the identity operator. This
+ * Compute the deviator of a symmetric tensor, which is defined as
+ * $\text{dev} \mathbf T = \mathbf T -
+ * \frac{1}{\text{dim}} \text{tr}\mathbf T \; \mathbf I$, where $\mathbf I$
+ * is the identity operator. This
* quantity equals the original tensor minus its contractive or dilative
* component and refers to the shear in, for example, elasticity.
*
/**
- * Return a unit symmetric tensor of rank 2, i.e., the dim-by-dim identity
- * matrix.
+ * Return a unit symmetric tensor of rank 2, i.e., the
+ * $\text{dim}\times\text{dim}$ identity matrix $\mathbf I$.
*
* @relatesalso SymmetricTensor
* @author Wolfgang Bangerth, 2005
/**
- * Return a unit symmetric tensor of rank 2, i.e., the dim-by-dim identity
- * matrix. This specialization of the function uses <code>double</code> as the
- * data type for the elements.
+ * unit_symmetric_tensor<dim>() is the specialization of the function
+ * unit_symmetric_tensor<dim,Number>() which
+ * uses <code>double</code> as the data type for the elements.
*
* @relatesalso SymmetricTensor
* @author Wolfgang Bangerth, 2005
/**
* Return the tensor of rank 4 that, when multiplied by a symmetric rank 2
- * tensor <tt>t</tt> returns the deviator $\textrm{dev}\ t$. It is the
- * operator representation of the linear deviator operator.
+ * tensor $\mathbf T$ returns the deviator $\text{dev}\ \mathbf T$. It is the
+ * operator representation of the linear deviator operator $\mathbb P$, also
+ * known as the volumetric projection tensor, calculated as:
+ * \f{align*}{
+ * \mathbb{P} &=\mathbb{I} -\frac{1}{\text{dim}} \mathbf I \otimes \mathbf I
+ * \\
+ * \mathcal{P}_{ijkl} &= \frac 12 \left(\delta_{ik} \delta_{jl} +
+ * \delta_{il} \delta_{jk} \right)
+ * - \frac{1}{\text{dim}} \delta_{ij} \delta_{kl}
+ * \f}
*
- * For every tensor <tt>t</tt>, there holds the identity
- * <tt>deviator(t)==deviator_tensor<dim>()*t</tt>, up to numerical
- * round-off. The reason this operator representation is provided is that one
- * sometimes needs to invert operators like <tt>identity_tensor<dim>() +
- * delta_t*deviator_tensor<dim>()</tt> or similar.
+ * For every tensor <tt>T</tt>, there holds the identity
+ * <tt>deviator<dim,Number>(T) == deviator_tensor<dim,Number>() * T</tt>,
+ * up to numerical round-off.
+ * \f[
+ * \text{dev}\mathbf T = \mathbb P : \mathbf T
+ * \f]
+ *
+ * @note The reason this operator representation is provided is to simplify
+ * taking derivatives of the deviatoric part of tensors:
+ * \f[
+ * \frac{\partial \text{dev}\mathbf{T}}{\partial \mathbf T} = \mathbb P.
+ * \f]
*
* @relatesalso SymmetricTensor
* @author Wolfgang Bangerth, 2005
/**
- * Return the tensor of rank 4 that, when multiplied by a symmetric rank 2
- * tensor <tt>t</tt> returns the deviator <tt>dev t</tt>. It is the operator
- * representation of the linear deviator operator.
- *
- * For every tensor <tt>t</tt>, there holds the identity
- * <tt>deviator(t)==deviator_tensor<dim>()*t</tt>, up to numerical
- * round-off. The reason this operator representation is provided is that one
- * sometimes needs to invert operators like <tt>identity_tensor<dim>() +
- * delta_t*deviator_tensor<dim>()</tt> or similar.
+ * This version of the deviator_tensor<dim>() function is a specialization of
+ * deviator_tensor<dim,Number>() that uses <tt>double</tt> as the
+ * data type for the elements of the tensor.
*
* @relatesalso SymmetricTensor
* @author Wolfgang Bangerth, 2005
/**
- * Return the fourth-order symmetric identity tensor which maps symmetric
- * second-order tensors to themselves.
+ * Return the fourth-order symmetric identity tensor $\mathbb I$ which maps
+ * symmetric second-order tensors, such as $\mathbf A$, to themselves.
+ * \f[
+ * \mathbb I : \mathbf A = \mathbf A
+ * \f]
*
* Note that this tensor, even though it is the identity, has a somewhat funny
* form, and in particular does not only consist of zeros and ones. For
* example, for <tt>dim=2</tt>, the identity tensor has all zero entries
- * except for <tt>id[0][0][0][0]=id[1][1][1][1]=1</tt> and
- * <tt>id[0][1][0][1]=id[0][1][1][0]=id[1][0][0][1]=id[1][0][1][0]=1/2</tt>.
- * To see why this factor of 1/2 is necessary, consider computing <tt>A=Id :
- * B</tt>. For the element <tt>a_01</tt> we have <tt>a_01=id_0100 b_00 +
- * id_0111 b_11 + id_0101 b_01 + id_0110 b_10</tt>. On the other hand, we need
- * to have <tt>a_01=b_01</tt>, and symmetry implies <tt>b_01=b_10</tt>,
- * leading to <tt>a_01=(id_0101+id_0110) b_01</tt>, or, again by symmetry,
- * <tt>id_0101=id_0110=1/2</tt>. Similar considerations hold for the three-
- * dimensional case.
+ * except for
+ * \f[
+ * \mathcal{I}_{0000} = \mathcal{I}_{1111} = 1
+ * \f]
+ * \f[
+ * \mathcal{I}_{0101} = \mathcal{I}_{0110} = \mathcal{I}_{1001}
+ * = \mathcal{I}_{1010} = \frac 12.
+ * \f]
+ * In index notation, we can write the general form
+ * \f[
+ * \mathcal{I}_{ijkl} = \frac 12 \left( \delta_{ik} \delta_{jl} +
+ * \delta_{il} \delta_{jl} \right).
+ * \f]
+ * To see why this factor of $1 / 2$ is necessary, consider computing
+ * $\mathbf A= \mathbb I : \mathbf B$.
+ * For the element $A_{01}$ we have $A_{01} = \mathcal{I}_{0100} B_{00} +
+ * \mathcal{I}_{0111} B_{11} + \mathcal{I}_{0101} B_{01} +
+ * \mathcal{I}_{0110} B_{10}$. On the other hand, we need
+ * to have $A_{01} = B_{01}$, and symmetry implies $B_{01}=B_{10}$,
+ * leading to $A_{01} = (\mathcal{I}_{0101} + \mathcal{I}_{0110}) B_{01}$, or,
+ * again by symmetry, $\mathcal{I}_{0101} = \mathcal{I}_{0110} = \frac 12$.
+ * Similar considerations hold for the three-dimensional case.
*
* This issue is also explained in the introduction to step-44.
*
/**
- * Return the tensor of rank 4 that, when multiplied by a symmetric rank 2
- * tensor <tt>t</tt> returns the deviator <tt>dev t</tt>. It is the operator
- * representation of the linear deviator operator.
- *
- * Note that this tensor, even though it is the identity, has a somewhat funny
- * form, and in particular does not only consist of zeros and ones. For
- * example, for <tt>dim=2</tt>, the identity tensor has all zero entries
- * except for <tt>id[0][0][0][0]=id[1][1][1][1]=1</tt> and
- * <tt>id[0][1][0][1]=id[0][1][1][0]=id[1][0][0][1]=id[1][0][1][0]=1/2</tt>.
- * To see why this factor of 1/2 is necessary, consider computing <tt>A=Id .
- * B</tt>. For the element <tt>a_01</tt> we have <tt>a_01=id_0100 b_00 +
- * id_0111 b_11 + id_0101 b_01 + id_0110 b_10</tt>. On the other hand, we need
- * to have <tt>a_01=b_01</tt>, and symmetry implies <tt>b_01=b_10</tt>,
- * leading to <tt>a_01=(id_0101+id_0110) b_01</tt>, or, again by symmetry,
- * <tt>id_0101=id_0110=1/2</tt>. Similar considerations hold for the three-
- * dimensional case.
+ * This version of the identity_tensor<dim>() function is the specialization of
+ * identity_tensor<dim,Number>() which uses <tt>double</tt> as the
+ * data type for the elements of the tensor.
*
* @relatesalso SymmetricTensor
* @author Wolfgang Bangerth, 2005
/**
* Return the tensor of rank 4 that is the outer product of the two tensors
- * given as arguments, i.e. the result $T=t1 \otimes t2$ satisfies <tt>T phi =
- * t1 (t2 : phi)</tt> for all symmetric tensors <tt>phi</tt>.
+ * given as arguments, i.e. the result
+ * $\mathbb A = \mathbf{T}_1 \otimes \mathbf{T}_2$ satisfies
+ * $\mathbb A : \mathbf B = (\mathbf{T}_2 : \mathbf B) \mathbf{T}_1$
+ * for all symmetric tensors $\mathbf B$. In index notation
+ * \f[
+ * \mathcal{A}_{ijkl} = (T_1)_{ij} (T_2)_{kl}
+ * \f]
*
- * For example, the deviator tensor can be computed as
- * <tt>identity_tensor<dim,Number>() -
- * 1/d*outer_product(unit_symmetric_tensor<dim,Number>(),
- * unit_symmetric_tensor<dim,Number>())</tt>, since the (double) contraction
- * with the unit tensor yields the trace of a symmetric tensor.
+ * For example, the deviator tensor
+ * $\mathbb P = \mathbb I - \frac{1}{\text{dim}} \mathbf I \otimes \mathbf I$
+ * can be computed as
+ * <tt>identity_tensor<dim>() - 1/d *
+ * outer_product (unit_symmetric_tensor<dim>(),
+ * unit_symmetric_tensor<dim>())</tt>,
+ * since the (double) contraction with the unit tensor yields the trace
+ * of a symmetric tensor ($\mathbf I : \mathbf B = \text{tr} \mathbf B$).
*
* @relatesalso SymmetricTensor
* @author Wolfgang Bangerth, 2005
/**
* Return the symmetrized version of a full rank-2 tensor, i.e.
- * (t+transpose(t))/2, as a symmetric rank-2 tensor. This is the version for
- * general dimensions.
+ * $\text{sym}\mathbf A = \frac 12 \left(\mathbf A + \mathbf{A}^T\right)$,
+ * as a symmetric rank-2 tensor. This is the version for general dimensions.
*
* @relatesalso SymmetricTensor
* @author Wolfgang Bangerth, 2005
}
/**
- * Compute the scalar product $a:b=\sum_{i,j} a_{ij}b_{ij}$ between two
- * tensors $a,b$ of rank 2. In the current case where both arguments are
- * symmetric tensors, this is equivalent to calling the expression
- * <code>t1*t2</code> which uses the overloaded <code>operator*</code> between
- * two symmetric tensors of rank 2.
+ * Compute the scalar product $\mathbf A: \mathbf B=\sum_{i,j} A_{ij}B_{ij}$
+ * between two tensors $\mathbf A, \mathbf B$ of rank 2. In the current case
+ * where both arguments are symmetric tensors, this is equivalent to calling
+ * the expression <code>A*B</code> which uses
+ * <code>SymmetricTensor::operator*()</code>.
*
* @relatesalso SymmetricTensor
*/
/**
- * Compute the scalar product $a:b=\sum_{i,j} a_{ij}b_{ij}$ between two
- * tensors $a,b$ of rank 2. We don't use <code>operator*</code> for this
+ * Compute the scalar product $\mathbf A: \mathbf B=\sum_{i,j} A_{ij}B_{ij}$
+ * between two tensors $\mathbf A, \mathbf B$ of rank 2. We don't use
+ * <code>operator*</code> for this
* operation since the product between two tensors is usually assumed to be
* the contraction over the last index of the first tensor and the first index
- * of the second tensor, for example $(a\cdot b)_{ij}=\sum_k a_{ik}b_{kj}$.
+ * of the second tensor. For example, if <tt>B</tt> is a Tensor, calling
+ * <tt>A*B</tt> (instead of <tt>scalar_product(A,B)</tt>) provides
+ * $(\mathbf A \cdot\mathbf B)_{ij}=\sum_k A_{ik}B_{kj}$.
*
- * @relatesalso Tensor @relatesalso SymmetricTensor
+ * @relatesalso Tensor
+ * @relatesalso SymmetricTensor
*/
template <int dim, typename Number, typename OtherNumber>
DEAL_II_CONSTEXPR inline DEAL_II_ALWAYS_INLINE
/**
- * Compute the scalar product $a:b=\sum_{i,j} a_{ij}b_{ij}$ between two
- * tensors $a,b$ of rank 2. We don't use <code>operator*</code> for this
+ * Compute the scalar product $\mathbf A:\mathbf B=\sum_{i,j} A_{ij}B_{ij}$
+ * between two tensors $\mathbf A, \mathbf B$ of rank 2.
+ * We don't use <code>operator*</code> for this
* operation since the product between two tensors is usually assumed to be
* the contraction over the last index of the first tensor and the first index
- * of the second tensor, for example $(a\cdot b)_{ij}=\sum_k a_{ik}b_{kj}$.
+ * of the second tensor. For example, if <tt>A</tt> is a Tensor, calling
+ * <tt>A*B</tt> (instead of <tt>scalar_product(A,B)</tt>) provides
+ * $(\mathbf A \cdot\mathbf B)_{ij}=\sum_k A_{ik}B_{kj}$.
*
- * @relatesalso Tensor @relatesalso SymmetricTensor
+ * @relatesalso Tensor
+ * @relatesalso SymmetricTensor
*/
template <int dim, typename Number, typename OtherNumber>
constexpr DEAL_II_ALWAYS_INLINE typename ProductType<Number, OtherNumber>::type
* to this function. This operation is the symmetric tensor analogon of a
* matrix-vector multiplication.
*
- * This function does the same as the member operator* of the SymmetricTensor
- * class. It should not be used, however, since the member operator has
+ * This function does the same as SymmetricTensor::operator*().
+ * It should not be used, however, since the member operator has
* knowledge of the actual data storage format and is at least 2 orders of
* magnitude faster. This function mostly exists for compatibility purposes
- * with the general tensor class.
+ * with the general Tensor class.
*
* @relatesalso SymmetricTensor
* @author Wolfgang Bangerth, 2005
* to this function. This operation is the symmetric tensor analogon of a
* matrix-vector multiplication.
*
- * This function does the same as the member operator* of the SymmetricTensor
- * class. It should not be used, however, since the member operator has
+ * This function does the same as SymmetricTensor::operator*().
+ * It should not be used, however, since the member operator has
* knowledge of the actual data storage format and is at least 2 orders of
* magnitude faster. This function mostly exists for compatibility purposes
- * with the general tensor class.
+ * with the general Tensor class.
*
* @relatesalso SymmetricTensor
* @author Wolfgang Bangerth, 2005
* to this function. This operation is the symmetric tensor analogon of a
* matrix-vector multiplication.
*
- * This function does the same as the member operator* of the SymmetricTensor
- * class. It should not be used, however, since the member operator has
+ * This function does the same as SymmetricTensor::operator*().
+ * It should not be used, however, since the member operator has
* knowledge of the actual data storage format and is at least 2 orders of
* magnitude faster. This function mostly exists for compatibility purposes
- * with the general tensor class.
+ * with the general Tensor class.
*
- * @relatesalso SymmetricTensor @author Wolfgang Bangerth, 2005
+ * @relatesalso SymmetricTensor
+ * @author Wolfgang Bangerth, 2005
*/
template <typename Number, typename OtherNumber>
DEAL_II_CONSTEXPR inline void double_contract(
* to this function. This operation is the symmetric tensor analogon of a
* matrix-vector multiplication.
*
- * This function does the same as the member operator* of the SymmetricTensor
- * class. It should not be used, however, since the member operator has
+ * This function does the same as SymmetricTensor::operator*().
+ * It should not be used, however, since the member operator has
* knowledge of the actual data storage format and is at least 2 orders of
* magnitude faster. This function mostly exists for compatibility purposes
- * with the general tensor class.
+ * with the general Tensor class.
*
* @relatesalso SymmetricTensor
* @author Wolfgang Bangerth, 2005
* to this function. This operation is the symmetric tensor analogon of a
* matrix-vector multiplication.
*
- * This function does the same as the member operator* of the SymmetricTensor
- * class. It should not be used, however, since the member operator has
+ * This function does the same as SymmetricTensor::operator*().
+ * It should not be used, however, since the member operator has
* knowledge of the actual data storage format and is at least 2 orders of
* magnitude faster. This function mostly exists for compatibility purposes
- * with the general tensor class.
+ * with the general Tensor class.
*
* @relatesalso SymmetricTensor
* @author Wolfgang Bangerth, 2005
* to this function. This operation is the symmetric tensor analogon of a
* matrix-vector multiplication.
*
- * This function does the same as the member operator* of the SymmetricTensor
- * class. It should not be used, however, since the member operator has
+ * This function does the same as SymmetricTensor::operator*().
+ * It should not be used, however, since the member operator has
* knowledge of the actual data storage format and is at least 2 orders of
* magnitude faster. This function mostly exists for compatibility purposes
- * with the general tensor class.
+ * with the general Tensor class.
*
* @relatesalso SymmetricTensor
* @author Wolfgang Bangerth, 2005
* tensors of rank 1 or put into external templated functions, e.g. the
* <tt>contract</tt> family.
*
+ * The rank of a tensor specifies which types of physical quantities it can
+ * represent:
+ * <ul>
+ * <li> A rank-0 tensor is a scalar that can store quantities such as
+ * temperature or pressure. These scalar quantities are shown in this
+ * documentation as simple lower-case Latin letters e.g. $a, b, c, \dots$.
+ * </li>
+ * <li> A rank-1 tensor is a vector with @p dim components and it can
+ * represent vector quantities such as velocity, displacement, electric
+ * field, etc. They can also describe the gradient of a scalar field.
+ * The notation used for rank-1 tensors is bold-faced lower-case Latin
+ * letters e.g. $\mathbf a, \mathbf b, \mathbf c, \dots$.
+ * The components of a rank-1 tensor such as $\mathbf a$ are represented
+ * as $a_i$ where $i$ is an index between 0 and <tt>dim-1</tt>.
+ * </li>
+ * <li> A rank-2 tensor is a linear operator that can transform a vector
+ * into another vector. These tensors are similar to matrices with
+ * $\text{dim} \times \text{dim}$ components. There is a related class
+ * SymmetricTensor<2,dim> for tensors of rank 2 whose elements are
+ * symmetric. Rank-2 tensors are usually denoted by bold-faced upper-case
+ * Latin letters such as $\mathbf A, \mathbf B, \dots$ or bold-faced Greek
+ * letters for example $\boldsymbol{\varepsilon}, \boldsymbol{\sigma}$.
+ * The components of a rank 2 tensor such as $\mathbf A$ are shown with
+ * two indices $(i,j)$ as $A_{ij}$. These tensors usually describe the
+ * gradients of vector fields (deformation gradient, velocity gradient,
+ * etc.) or Hessians of scalar fields. Additionally, mechanical stress
+ * tensors are rank-2 tensors that map the unit normal vectors of internal
+ * surfaces into local traction (force per unit area) vectors.
+ * </li>
+ * <li> Tensors with ranks higher than 2 are similarly defined in a
+ * consistent manner. They have $\text{dim}^{\text{rank}}$ components and
+ * the number of indices required to identify a component equals
+ * <tt>rank</tt>. For rank-4 tensors, a symmetric variant called
+ * SymmetricTensor<4,dim> exists.
+ * </li>
+ * </ul>
+ *
* Using this tensor class for objects of rank 2 has advantages over matrices
* in many cases since the dimension is known to the compiler as well as the
* location of the data. It is therefore possible to produce far more
* transforms) and matrices (which we consider as operators on arbitrary
* vector spaces related to linear algebra things).
*
- * @tparam rank_ An integer that denotes the rank of this tensor. A rank-0
- * tensor is a scalar, a rank-1 tensor is a vector with @p dim components, a
- * rank-2 tensor is a matrix with dim-by-dim components, etc. There are
- * specializations of this class for rank-0 and rank-1 tensors. There is also
- * a related class SymmetricTensor for tensors of even rank whose elements are
- * symmetric.
+ * @tparam rank_ An integer that denotes the rank of this tensor. A
+ * specialization of this class exists for rank-0 tensors.
*
* @tparam dim An integer that denotes the dimension of the space in which
* this tensor operates. This of course equals the number of coordinates that
unroll(Vector<OtherNumber> &result) const;
/**
- * Return an unrolled index in the range [0,dim^rank-1] for the element of
- * the tensor indexed by the argument to the function.
+ * Return an unrolled index in the range $[0,\text{dim}^{\text{rank}}-1]$
+ * for the element of the tensor indexed by the argument to the function.
*/
static DEAL_II_CONSTEXPR unsigned int
component_to_unrolled_index(const TableIndices<rank_> &indices);
/**
* Opposite of component_to_unrolled_index: For an index in the range
- * [0,dim^rank-1], return which set of indices it would correspond to.
+ * $[0, \text{dim}^{\text{rank}}-1]$, return which set of indices it would
+ * correspond to.
*/
static DEAL_II_CONSTEXPR TableIndices<rank_>
unrolled_to_component_indices(const unsigned int i);
* Output operator for tensors of rank 0. Since such tensors are scalars, we
* simply print this one value.
*
- * @relatesalso Tensor<0,dim,Number>
+ * @relatesalso Tensor
*/
template <int dim, typename Number>
inline std::ostream &
*
* @note This function can also be used in CUDA device code.
*
- * @relatesalso Tensor<0,dim,Number>
+ * @relatesalso Tensor
*/
template <int dim, typename Number, typename Other>
DEAL_II_CONSTEXPR DEAL_II_CUDA_HOST_DEV inline DEAL_II_ALWAYS_INLINE
*
* @note This function can also be used in CUDA device code.
*
- * @relatesalso Tensor<0,dim,Number>
+ * @relatesalso Tensor
*/
template <int dim, typename Number, typename Other>
DEAL_II_CONSTEXPR DEAL_II_CUDA_HOST_DEV inline DEAL_II_ALWAYS_INLINE
*
* @note This function can also be used in CUDA device code.
*
- * @relatesalso Tensor<0,dim,Number>
+ * @relatesalso Tensor
*/
template <int dim, typename Number, typename OtherNumber>
DEAL_II_CUDA_HOST_DEV constexpr DEAL_II_ALWAYS_INLINE
*
* @note This function can also be used in CUDA device code.
*
- * @relatesalso Tensor<0,dim,Number>
+ * @relatesalso Tensor
*/
template <int dim, typename Number, typename OtherNumber>
DEAL_II_CUDA_HOST_DEV constexpr DEAL_II_ALWAYS_INLINE
*
* @note This function can also be used in CUDA device code.
*
- * @relatesalso Tensor<0,dim,Number>
+ * @relatesalso Tensor
*/
template <int dim, typename Number, typename OtherNumber>
constexpr DEAL_II_ALWAYS_INLINE DEAL_II_CUDA_HOST_DEV
*
* @note This function can also be used in CUDA device code.
*
- * @relatesalso Tensor<0,dim,Number>
+ * @relatesalso Tensor
*/
template <int dim, typename Number, typename OtherNumber>
constexpr DEAL_II_ALWAYS_INLINE DEAL_II_CUDA_HOST_DEV
* new tensor of size <rank, dim>:
* @f[
* \text{result}_{i, j}
- * = \text{left}_{i, j}\cdot
+ * = \text{left}_{i, j}\circ
* \text{right}_{i, j}
* @f]
*
/**
* Return the adjugate of the given tensor of rank 2.
- * The adjugate of a tensor $\left(\bullet\right)$ is defined as
+ * The adjugate of a tensor $\mathbf A$ is defined as
* @f[
- * \textrm{adj}\left(\bullet\right)
- * \dealcoloneq \textrm{det}\left(\bullet\right) \; \left(\bullet\right)^{-1}
+ * \textrm{adj}\mathbf A
+ * \dealcoloneq \textrm{det}\mathbf A \; \mathbf{A}^{-1}
* \; .
* @f]
*
/**
* Return the cofactor of the given tensor of rank 2.
- * The cofactor of a tensor $\left(\bullet\right)$ is defined as
+ * The cofactor of a tensor $\mathbf A$ is defined as
* @f[
- * \textrm{cof}\left(\bullet\right)
- * \dealcoloneq \textrm{det}\left(\bullet\right) \; \left(\bullet\right)^{-T}
- * = \left[ \textrm{adj}\left(\bullet\right) \right]^{T} \; .
+ * \textrm{cof}\mathbf A
+ * \dealcoloneq \textrm{det}\mathbf A \; \mathbf{A}^{-T}
+ * = \left[ \textrm{adj}\mathbf A \right]^{T} \; .
* @f]
*
* @note This requires that the tensor is invertible.
/**
* Return the nearest orthogonal matrix using a SVD if the determinant is
* more than a tolerance away from one. The orthogonalization is done by
- * combining the products of the SVD decomposition: $U V^T$, where
- * $U$ and $V$ are computed from the SVD decomposition: $\mathbf U \mathbf S
- * \mathbf V^T$, effectively replacing $\mathbf S$ with the identity matrix.
+ * combining the products of the SVD decomposition: $\mathbf U \mathbf{V}^T$,
+ * where $\mathbf U$ and $\mathbf V$ are computed from the SVD decomposition:
+ * $\mathbf U \mathbf S \mathbf V^T$,
+ * effectively replacing $\mathbf S$ with the identity matrix.
* @param tensor The tensor which to find the closest orthogonal
* tensor to.
* @param tolerance If the $\text{determinant} - 1$ is smaller than
/**
- * Return the $l_1$ norm of the given rank-2 tensor, where $||t||_1 = \max_j
- * \sum_i |t_{ij}|$ (maximum of the sums over columns).
+ * Return the $l_1$ norm of the given rank-2 tensor, where
+ * $\|\mathbf T\|_1 = \max_j \sum_i |T_{ij}|$
+ * (maximum of the sums over columns).
*
* @relatesalso Tensor
* @author Wolfgang Bangerth, 2012
/**
- * Return the $l_\infty$ norm of the given rank-2 tensor, where $||t||_\infty
- * = \max_i \sum_j |t_{ij}|$ (maximum of the sums over rows).
+ * Return the $l_\infty$ norm of the given rank-2 tensor, where
+ * $\|\mathbf T\|_\infty = \max_i \sum_j |T_{ij}|$
+ * (maximum of the sums over rows).
*
* @relatesalso Tensor
* @author Wolfgang Bangerth, 2012