From 17e27ee2dd21711bd7445293da4cf2a4cfe1af6b Mon Sep 17 00:00:00 2001 From: Reza Rastak Date: Sun, 5 Apr 2020 10:38:43 -0700 Subject: [PATCH] Doc of Tensor and SymmetricTensor improved. --- include/deal.II/base/symmetric_tensor.h | 390 ++++++++++++++---------- include/deal.II/base/tensor.h | 99 ++++-- 2 files changed, 291 insertions(+), 198 deletions(-) diff --git a/include/deal.II/base/symmetric_tensor.h b/include/deal.II/base/symmetric_tensor.h index 64472c93aa..073c004f57 100644 --- a/include/deal.II/base/symmetric_tensor.h +++ b/include/deal.II/base/symmetric_tensor.h @@ -511,8 +511,14 @@ namespace internal /** * 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 dim-1. * * 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 @@ -523,22 +529,26 @@ namespace internal * 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 - * Cijkl=Cjikl=Cijlk. However, it - * does not imply the relation Cijkl=Cklij. + * 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 a:C:b=b:C:a or even - * a positive (semi-)definite form a:C:a, where a,b 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 @@ -554,14 +564,14 @@ namespace internal * *

Accessing elements

* - * The elements of a tensor t can be accessed using the bracket - * operator, i.e. for a tensor of rank 4, t[0][1][0][1] accesses the - * element t0101. 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, C[0][1][0][1] 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 t[0][1]+=1; t[1][0]+=1; will lead to the same element + * writing A[0][1]+=1; A[1][0]+=1; will lead to the same element * being increased by one twice, 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 @@ -614,8 +624,8 @@ public: * 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 - * symmetrize function first. If you aren't sure, it is good - * practice to check before calling symmetrize. + * symmetrize() function first. If you aren't sure, it is good + * practice to check before calling symmetrize(). * * Because we check for symmetry via a non-constexpr function call, you will * have to use the symmetrize() function in constexpr contexts instead. @@ -634,7 +644,7 @@ public: * rank 2. * * The size of the array passed is equal to - * SymmetricTensor::n_independent_component; the reason for using + * SymmetricTensor::n_independent_components; the reason for using * the object from the internal namespace is to work around bugs in some * older compilers. */ @@ -689,7 +699,7 @@ public: * 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 d, allowing the intuitive notation - * t=0 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); @@ -748,18 +758,20 @@ public: 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 aijbij - * over all indices i,j. 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 @@ -830,7 +842,8 @@ public: /** * Access to an element according to unrolled index. The function * s.access_raw_entry(unrolled_index) does the same as - * s[s.unrolled_to_component_indices(i)], but more efficiently. + * s[s.unrolled_to_component_indices(unrolled_index)], but more + * efficiently. */ DEAL_II_CONSTEXPR const Number & access_raw_entry(const unsigned int unrolled_index) const; @@ -838,7 +851,8 @@ public: /** * Access to an element according to unrolled index. The function * s.access_raw_entry(unrolled_index) does the same as - * s[s.unrolled_to_component_indices(i)], but more efficiently. + * s[s.unrolled_to_component_indices(unrolled_index)], but more + * efficiently. */ DEAL_II_CONSTEXPR Number & access_raw_entry(const unsigned int unrolled_index); @@ -2473,7 +2487,7 @@ SymmetricTensor::serialize(Archive &ar, const unsigned int) * * If possible (e.g. when @p Number and @p OtherNumber are of the same type, * or if the result of Number() + OtherNumber() is another @p Number), - * you should use operator += instead since this does not require the + * you should use operator+= instead since this does not require the * creation of a temporary variable. * * @relatesalso SymmetricTensor @@ -2497,8 +2511,8 @@ DEAL_II_CONSTEXPR inline DEAL_II_ALWAYS_INLINE * operation. * * If possible (e.g. when @p Number and @p OtherNumber are of the same type, - * or if the result of Number() + OtherNumber() is another @p Number), - * you should use operator += instead since this does not require the + * or if the result of Number() - OtherNumber() is another @p Number), + * you should use operator-= instead since this does not require the * creation of a temporary variable. * * @relatesalso SymmetricTensor @@ -2586,13 +2600,14 @@ constexpr DEAL_II_ALWAYS_INLINE /** - * 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 third_invariant + * For greater notational simplicity, there is also a + * third_invariant() * function that returns the determinant of a tensor. * * @relatesalso SymmetricTensor @@ -2628,10 +2643,13 @@ DEAL_II_CONSTEXPR inline DEAL_II_ALWAYS_INLINE Number /** - * Compute the determinant of a tensor or rank 2. This function therefore - * computes the same value as the determinant() 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 determinant() 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 @@ -2648,6 +2666,9 @@ constexpr DEAL_II_ALWAYS_INLINE Number /** * 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 @@ -2664,10 +2685,13 @@ DEAL_II_CONSTEXPR inline DEAL_II_ALWAYS_INLINE Number /** - * Compute the trace of a tensor or rank 2. This function therefore computes - * the same value as the trace() 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 trace() 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 @@ -2682,9 +2706,9 @@ first_invariant(const SymmetricTensor<2, dim, Number> &t) /** * 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. @@ -2703,15 +2727,15 @@ constexpr DEAL_II_ALWAYS_INLINE Number /** * 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 @@ -2731,9 +2755,9 @@ constexpr DEAL_II_ALWAYS_INLINE Number /** * 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 @@ -2749,7 +2773,7 @@ constexpr DEAL_II_ALWAYS_INLINE Number /** - * 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. * @@ -2763,16 +2787,16 @@ eigenvalues(const SymmetricTensor<2, 1, Number> &T); /** - * 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 - * the - * characteristic polynomial $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 $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 @@ -2792,15 +2816,16 @@ eigenvalues(const SymmetricTensor<2, 2, Number> &T); /** - * 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 - * the - * characteristic polynomial $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 $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 @@ -3112,8 +3137,8 @@ enum struct SymmetricTensorEigenvectorMethod /** * 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 @@ -3167,8 +3192,10 @@ constexpr DEAL_II_ALWAYS_INLINE SymmetricTensor /** - * Compute the deviator of a symmetric tensor, which is defined as dev[s] - * = s - 1/dim*tr[s]*I, where I 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. * @@ -3192,8 +3219,8 @@ DEAL_II_CONSTEXPR inline DEAL_II_ALWAYS_INLINE SymmetricTensor<2, dim, Number> /** - * 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 @@ -3227,9 +3254,9 @@ DEAL_II_CONSTEXPR inline DEAL_II_ALWAYS_INLINE SymmetricTensor<2, dim, Number> /** - * Return a unit symmetric tensor of rank 2, i.e., the dim-by-dim identity - * matrix. This specialization of the function uses double as the - * data type for the elements. + * unit_symmetric_tensor() is the specialization of the function + * unit_symmetric_tensor() which + * uses double as the data type for the elements. * * @relatesalso SymmetricTensor * @author Wolfgang Bangerth, 2005 @@ -3245,14 +3272,29 @@ DEAL_II_CONSTEXPR inline DEAL_II_ALWAYS_INLINE SymmetricTensor<2, dim> /** * Return the tensor of rank 4 that, when multiplied by a symmetric rank 2 - * tensor t 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 t, there holds the identity - * deviator(t)==deviator_tensor<dim>()*t, up to numerical - * round-off. The reason this operator representation is provided is that one - * sometimes needs to invert operators like identity_tensor<dim>() + - * delta_t*deviator_tensor<dim>() or similar. + * For every tensor T, there holds the identity + * deviator(T) == deviator_tensor() * T, + * 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 @@ -3286,15 +3328,9 @@ deviator_tensor() /** - * Return the tensor of rank 4 that, when multiplied by a symmetric rank 2 - * tensor t returns the deviator dev t. It is the operator - * representation of the linear deviator operator. - * - * For every tensor t, there holds the identity - * deviator(t)==deviator_tensor<dim>()*t, up to numerical - * round-off. The reason this operator representation is provided is that one - * sometimes needs to invert operators like identity_tensor<dim>() + - * delta_t*deviator_tensor<dim>() or similar. + * This version of the deviator_tensor() function is a specialization of + * deviator_tensor() that uses double as the + * data type for the elements of the tensor. * * @relatesalso SymmetricTensor * @author Wolfgang Bangerth, 2005 @@ -3309,21 +3345,37 @@ DEAL_II_CONSTEXPR inline DEAL_II_ALWAYS_INLINE SymmetricTensor<4, dim> /** - * 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 dim=2, the identity tensor has all zero entries - * except for id[0][0][0][0]=id[1][1][1][1]=1 and - * id[0][1][0][1]=id[0][1][1][0]=id[1][0][0][1]=id[1][0][1][0]=1/2. - * To see why this factor of 1/2 is necessary, consider computing A=Id : - * B. For the element a_01 we have a_01=id_0100 b_00 + - * id_0111 b_11 + id_0101 b_01 + id_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=(id_0101+id_0110) b_01, or, again by symmetry, - * id_0101=id_0110=1/2. 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. * @@ -3357,22 +3409,9 @@ DEAL_II_CONSTEXPR inline DEAL_II_ALWAYS_INLINE SymmetricTensor<4, dim, Number> /** - * Return the tensor of rank 4 that, when multiplied by a symmetric rank 2 - * tensor t returns the deviator dev t. 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 dim=2, the identity tensor has all zero entries - * except for id[0][0][0][0]=id[1][1][1][1]=1 and - * id[0][1][0][1]=id[0][1][1][0]=id[1][0][0][1]=id[1][0][1][0]=1/2. - * To see why this factor of 1/2 is necessary, consider computing A=Id . - * B. For the element a_01 we have a_01=id_0100 b_00 + - * id_0111 b_11 + id_0101 b_01 + id_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=(id_0101+id_0110) b_01, or, again by symmetry, - * id_0101=id_0110=1/2. Similar considerations hold for the three- - * dimensional case. + * This version of the identity_tensor() function is the specialization of + * identity_tensor() which uses double as the + * data type for the elements of the tensor. * * @relatesalso SymmetricTensor * @author Wolfgang Bangerth, 2005 @@ -3429,14 +3468,22 @@ invert(const SymmetricTensor<4, dim, Number> &t) /** * 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 T phi = - * t1 (t2 : phi) for all symmetric tensors phi. + * 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 - * identity_tensor() - - * 1/d*outer_product(unit_symmetric_tensor(), - * unit_symmetric_tensor()), 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 + * identity_tensor() - 1/d * + * outer_product (unit_symmetric_tensor(), + * unit_symmetric_tensor()), + * 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 @@ -3462,8 +3509,8 @@ outer_product(const SymmetricTensor<2, dim, Number> &t1, /** * 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 @@ -3661,11 +3708,11 @@ operator/(const SymmetricTensor &t, const double factor) } /** - * 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 - * t1*t2 which uses the overloaded operator* 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 A*B which uses + * SymmetricTensor::operator*(). * * @relatesalso SymmetricTensor */ @@ -3679,13 +3726,17 @@ scalar_product(const SymmetricTensor<2, dim, Number> & t1, /** - * 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 operator* 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 + * operator* 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 B is a Tensor, calling + * A*B (instead of scalar_product(A,B)) provides + * $(\mathbf A \cdot\mathbf B)_{ij}=\sum_k A_{ik}B_{kj}$. * - * @relatesalso Tensor @relatesalso SymmetricTensor + * @relatesalso Tensor + * @relatesalso SymmetricTensor */ template DEAL_II_CONSTEXPR inline DEAL_II_ALWAYS_INLINE @@ -3703,13 +3754,17 @@ 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 operator* 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 operator* 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 A is a Tensor, calling + * A*B (instead of scalar_product(A,B)) provides + * $(\mathbf A \cdot\mathbf B)_{ij}=\sum_k A_{ik}B_{kj}$. * - * @relatesalso Tensor @relatesalso SymmetricTensor + * @relatesalso Tensor + * @relatesalso SymmetricTensor */ template constexpr DEAL_II_ALWAYS_INLINE typename ProductType::type @@ -3726,11 +3781,11 @@ scalar_product(const Tensor<2, dim, Number> & t1, * 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 @@ -3752,11 +3807,11 @@ DEAL_II_CONSTEXPR inline DEAL_II_ALWAYS_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 @@ -3778,13 +3833,14 @@ 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 + * @relatesalso SymmetricTensor + * @author Wolfgang Bangerth, 2005 */ template DEAL_II_CONSTEXPR inline void double_contract( @@ -3808,11 +3864,11 @@ 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 @@ -3839,11 +3895,11 @@ 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 @@ -3871,11 +3927,11 @@ 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 diff --git a/include/deal.II/base/tensor.h b/include/deal.II/base/tensor.h index c029f419cb..407f1a78a3 100644 --- a/include/deal.II/base/tensor.h +++ b/include/deal.II/base/tensor.h @@ -379,6 +379,43 @@ private: * tensors of rank 1 or put into external templated functions, e.g. the * contract family. * + * The rank of a tensor specifies which types of physical quantities it can + * represent: + *
    + *
  • 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$. + *
  • + *
  • 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 dim-1. + *
  • + *
  • 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. + *
  • + *
  • 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 + * rank. For rank-4 tensors, a symmetric variant called + * SymmetricTensor<4,dim> exists. + *
  • + *
+ * * 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 @@ -389,12 +426,8 @@ private: * 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 @@ -682,15 +715,16 @@ public: unroll(Vector &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 &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 unrolled_to_component_indices(const unsigned int i); @@ -1621,7 +1655,7 @@ operator<<(std::ostream &out, const Tensor &p) * 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 inline std::ostream & @@ -1647,7 +1681,7 @@ operator<<(std::ostream &out, const Tensor<0, dim, Number> &p) * * @note This function can also be used in CUDA device code. * - * @relatesalso Tensor<0,dim,Number> + * @relatesalso Tensor */ template DEAL_II_CONSTEXPR DEAL_II_CUDA_HOST_DEV inline DEAL_II_ALWAYS_INLINE @@ -1667,7 +1701,7 @@ 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 DEAL_II_CONSTEXPR DEAL_II_CUDA_HOST_DEV inline DEAL_II_ALWAYS_INLINE @@ -1687,7 +1721,7 @@ 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 DEAL_II_CUDA_HOST_DEV constexpr DEAL_II_ALWAYS_INLINE @@ -1705,7 +1739,7 @@ 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 DEAL_II_CUDA_HOST_DEV constexpr DEAL_II_ALWAYS_INLINE @@ -1724,7 +1758,7 @@ 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 constexpr DEAL_II_ALWAYS_INLINE DEAL_II_CUDA_HOST_DEV @@ -1741,7 +1775,7 @@ 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 constexpr DEAL_II_ALWAYS_INLINE DEAL_II_CUDA_HOST_DEV @@ -1950,7 +1984,7 @@ inline DEAL_II_CONSTEXPR DEAL_II_ALWAYS_INLINE * new tensor of size : * @f[ * \text{result}_{i, j} - * = \text{left}_{i, j}\cdot + * = \text{left}_{i, j}\circ * \text{right}_{i, j} * @f] * @@ -2555,10 +2589,10 @@ DEAL_II_CONSTEXPR inline DEAL_II_ALWAYS_INLINE Tensor<2, dim, Number> /** * 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] * @@ -2577,11 +2611,11 @@ adjugate(const Tensor<2, dim, Number> &t) /** * 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. @@ -2600,9 +2634,10 @@ cofactor(const Tensor<2, dim, Number> &t) /** * 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 @@ -2642,8 +2677,9 @@ project_onto_orthogonal_tensors(const Tensor<2, dim, Number> &tensor, /** - * 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 @@ -2668,8 +2704,9 @@ l1_norm(const Tensor<2, dim, Number> &t) /** - * 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 -- 2.39.5