Source code for fenicsR13.tensoroperations

# pylint: disable=invalid-name
# pylint: disable=unsubscriptable-object

"""
Module to gather all additional tensor operations not present in UFL.

This especially includes all 3D operations and operations on tensors with rank
above 2.

.. [STR2005] Struchtrup, H. (2005). Macroscopic transport equations for
    rarefied gas flows. In Macroscopic Transport Equations for Rarefied Gas
    Flows. Springer, Berlin, Heidelberg.

.. [TOR2018] Torrilhon, M. et al. (2018). “Kinetic Theory of Non-Equilibrium
    Gas Flows:
    Theory and Computations”. Lecture Notes. Indian Institute of Technology
    Madras.
"""

import dolfin as df
import ufl


[docs]def gen3DTFdim3(sigma): r""" Return the symmetric and trace-free matrix for a 2-rank tensor if 3D. Returns the same matrix if 2D """ n = sigma.ufl_shape[0] if n == 2: return sigma else: return df.as_tensor([ [sigma[0, 0], sigma[0, 1], sigma[0, 2]], [sigma[1, 0], sigma[1, 1], sigma[1, 2]], [sigma[2, 0], sigma[2, 1], -sigma[0, 0] - sigma[1, 1]]])
[docs]def gen3DTFdim2(sigma): r""" Return the symmetric and trace-free matrix for a 2-rank tensor if 2D. Returns the same matrix if 3D """ n = sigma.ufl_shape[0] if n == 2: sigma1 = df.as_tensor([[sigma[0, 0], sigma[0, 1], 0], [sigma[1, 0], sigma[1, 1], 0], [0, 0, -sigma[0, 0] - sigma[1, 1]]]) else: sigma1 = sigma return sigma1
[docs]def stf3d2(rank2_2d): r""" Return the 3D symmetric and trace-free part of a 2D 2-tensor. .. warning:: Return a 2-tensor with the same dimensions as the input tensor. For the :math:`2 \times 2` case, return the 3D symmetric and trace-free (dev(sym(.))) :math:`B \in \mathbb{R}^{2 \times 2}` of the 2D 2-tensor :math:`A \in \mathbb{R}^{2 \times 2}`. .. math:: A &= \begin{pmatrix} a_{xx} & a_{xy} \\ a_{yx} & a_{yy} \end{pmatrix} \\ B &= (A)_\mathrm{dev} = \frac{1}{2} (A)_\mathrm{sym} - \frac{1}{3} \mathrm{tr}(A) I_{2 \times 2} """ dim = len(rank2_2d[:, 0]) symm = 1 / 2 * (rank2_2d + ufl.transpose(rank2_2d)) return symm - (1 / 3) * ufl.tr(symm) * ufl.Identity(dim)
[docs]def sym3d3(rank3_3d): r""" Return the symmetric part of a 3D 3-tensor. Returns the symmetric part :math:`A_{(i j k)}` of a 3D rank-3 tensor :math:`A \in \mathbb{R}^{3 \times 3 \times 3}` [STR2005]_ [TOR2018]_. .. math:: A_{(i j k)}=\frac{1}{6}\left( A_{i j k}+A_{i k j}+A_{j i k}+A_{j k i}+A_{k i j}+A_{k j i} \right) """ i, j, k = ufl.indices(3) symm_ijk = 1 / 6 * ( # All permutations + rank3_3d[i, j, k] + rank3_3d[i, k, j] + rank3_3d[j, i, k] + rank3_3d[j, k, i] + rank3_3d[k, i, j] + rank3_3d[k, j, i] ) return ufl.as_tensor(symm_ijk, (i, j, k))
[docs]def stf3d3(rank3_3d): r""" Return the symmetric and trace-free part of a 3D 3-tensor. Return the symmetric and trace-free part of a 3D 3-tensor. (dev(sym(.))) Returns the STF part :math:`A_{\langle i j k\rangle}` of a rank-3 tensor :math:`A \in \mathbb{R}^{3 \times 3 \times 3}` [TOR2018]_. .. math:: A_{\langle i j k\rangle}=A_{(i j k)}-\frac{1}{5}\left[A_{(i l l)} \delta_{j k}+A_{(l j l)} \delta_{i k}+A_{(l l k)} \delta_{i j}\right] A gradient :math:`\frac{\partial S_{\langle i j}}{\partial x_{k \rangle}}` of a symmetric 2-tensor :math:`S \in \mathbb{R}^{3 \times 3}` has the deviator [STR2005]_: .. math:: \frac{\partial S_{\langle i j}}{\partial x_{k \rangle}} =& \frac{1}{3}\left( \frac{\partial S_{i j}}{\partial x_{k}} +\frac{\partial S_{i k}}{\partial x_{j}} +\frac{\partial S_{j k}}{\partial x_{i}} \right) -\frac{1}{15} \biggl[ \left( \frac{\partial S_{i r}}{\partial x_{r}} +\frac{\partial S_{i r}}{\partial x_{r}} +\frac{\partial S_{r r}}{\partial x_{i}} \right) \delta_{j k} \\ &+ \left( \frac{\partial S_{j r}}{\partial x_{r}} +\frac{\partial S_{j r}}{\partial x_{r}} +\frac{\partial S_{r r}}{\partial x_{j}} \right) \delta_{i k} +\left( \frac{\partial S_{k r}}{\partial x_{r}} +\frac{\partial S_{k r}}{\partial x_{r}} +\frac{\partial S_{r r}}{\partial x_{k}} \right) \delta_{i j} \biggr] """ i, j, k, L = ufl.indices(4) delta = df.Identity(3) sym_ijk = sym3d3(rank3_3d)[i, j, k] traces_ijk = 1 / 5 * ( + sym3d3(rank3_3d)[i, L, L] * delta[j, k] + sym3d3(rank3_3d)[L, j, L] * delta[i, k] + sym3d3(rank3_3d)[L, L, k] * delta[i, j] ) tracefree_ijk = sym_ijk - traces_ijk return ufl.as_tensor(tracefree_ijk, (i, j, k))
[docs]def div3d3(rank3_3d): r""" Return the 3D divergence of a 3-tensor. Return the 3D divergence of a 3-tensor as .. math:: {(\mathrm{div}(m))}_{ij} = \frac{\partial m_{ijk}}{\partial x_k} Compare with [SCH2009]_ (p. 92). .. [SCH2009] Heinz Schade, Klaus Neemann (2009). “Tensoranalysis”. 2. überarbeitete Auflage. """ i, j, k = ufl.indices(3) div_ij = rank3_3d[i, j, 0].dx(0) + rank3_3d[i, j, 1].dx(1) return ufl.as_tensor(div_ij, (i, j))
[docs]def gen3dTF2(rank2_2d): r""" Generate a 3D tracefree 2-tensor from a 2D 2-tensor. Returns the synthetic 3D version :math:`A \in \mathbb{R}^{3 \times 3}` of a 2D rank-2 tensor :math:`B \in \mathbb{R}^{2 \times 2}`. .. math:: B &= \begin{pmatrix} b_{xx} & b_{xy} \\ b_{yx} & b_{yy} \end{pmatrix} \\ A &= \begin{pmatrix} b_{xx} & b_{xy} & 0 \\ b_{yx} & b_{yy} & 0 \\ 0 & 0 & -(b_{yx}+b_{yy}) \end{pmatrix} Example ------- >>> t2d = df.Expression((("1","2"),("3","4")), degree=1) >>> t3d = gen3dTF2(t2d) >>> print( ... t3d[0,0]==t2d[0,0] and ... t3d[0,1]==t2d[0,1] and ... t3d[0,2]==0 and ... t3d[1,0]==t2d[1,0] and ... t3d[1,1]==t2d[1,1] and ... t3d[1,2]==0 and ... t3d[2,0]==0 and ... t3d[2,1]==0 and ... t3d[2,2]==-t2d[0,0]-t2d[1,1] ... ) True """ return df.as_tensor([ [rank2_2d[0, 0], rank2_2d[0, 1], 0], [rank2_2d[1, 0], rank2_2d[1, 1], 0], [0, 0, -rank2_2d[0, 0] - rank2_2d[1, 1]] ])
[docs]def gen3d1(rank1_2d): r""" Return synthetic 3d version of 2d vector with zero last component. Return synthetic 3d version of 2d vector :math:`s_{\mathrm{in}} = (s_x, s_y)` as :math:`s_{\mathrm{out}} = (s_x, s_y, 0)` . """ return df.as_vector([rank1_2d[0], rank1_2d[1], 0])
[docs]def gen3d2(rank2_2d): r""" Generate a 3D 2-tensor from a 2D 2-tensor (add zeros to last dimensions). Returns the synthetic 3D version :math:`A \in \mathbb{R}^{3 \times 3}` of a 2D rank-2 tensor :math:`B \in \mathbb{R}^{2 \times 2}`. The 3D-components are set to zero. .. math:: B &= \begin{pmatrix} b_{xx} & b_{xy} \\ b_{yx} & b_{yy} \end{pmatrix} \\ A &= \begin{pmatrix} b_{xx} & b_{xy} & 0 \\ b_{yx} & b_{yy} & 0 \\ 0 & 0 & 0 \end{pmatrix} Example ------- >>> t2d = df.Expression((("1","2"),("3","4")), degree=1) >>> t3d = gen3d2(t2d) >>> print( ... t3d[0,0]==t2d[0,0] and ... t3d[0,1]==t2d[0,1] and ... t3d[0,2]==0 and ... t3d[1,0]==t2d[1,0] and ... t3d[1,1]==t2d[1,1] and ... t3d[1,2]==0 and ... t3d[2,0]==0 and ... t3d[2,1]==0 and ... t3d[2,2]==0 ... ) True """ n = rank2_2d.ufl_shape[0] if n == 2: return df.as_tensor([ [rank2_2d[0, 0], rank2_2d[0, 1], 0], [rank2_2d[1, 0], rank2_2d[1, 1], 0], [0, 0, 0] ]) else: return (rank2_2d)
[docs]def grad3dOf2(rank2_3d, dim): r""" Return 3D gradient of 3D 2-tensor. Returns the 3D gradient (w.r.t. :math:`x,y,z`) :math:`\frac{\partial A_{ij}}{\partial x_{k}}` of a 3D :math:`z`-independent rank-2 tensor :math:`A(x,y) \in \mathbb{R}^{3 \times 3}` where .. math:: A_{ij} = \begin{pmatrix} a_{xx}(x,y) & a_{xy}(x,y) & a_{xz}(x,y) \\ a_{yx}(x,y) & a_{yy}(x,y) & a_{yz}(x,y) \\ a_{zx}(x,y) & a_{zy}(x,y) & a_{zz}(x,y) \end{pmatrix} The function then returns the 3-tensor with components :math:`\frac{\partial A_{ij}}{\partial x_{k}}` where .. math:: \frac{\partial A_{ij}}{\partial x_{1}} = \frac{\partial A_{ij}}{\partial x} &= \begin{pmatrix} \partial_x a_{xx}(x,y) & \partial_x a_{xy}(x,y) & \partial_x a_{xz}(x,y) \\ \partial_x a_{yx}(x,y) & \partial_x a_{yy}(x,y) & \partial_x a_{yz}(x,y) \\ \partial_x a_{zx}(x,y) & \partial_x a_{zy}(x,y) & \partial_x a_{zz}(x,y) \end{pmatrix} , \\ \frac{\partial A_{ij}}{\partial x_{2}} = \frac{\partial A_{ij}}{\partial y} &= \begin{pmatrix} \partial_y a_{xx}(x,y) & \partial_y a_{xy}(x,y) & \partial_y a_{xz}(x,y) \\ \partial_y a_{yx}(x,y) & \partial_y a_{yy}(x,y) & \partial_y a_{yz}(x,y) \\ \partial_y a_{zx}(x,y) & \partial_y a_{zy}(x,y) & \partial_y a_{zz}(x,y) \end{pmatrix} , \\ \frac{\partial A_{ij}}{\partial x_{3}} = 0 &= \begin{pmatrix} 0 & 0 & 0 \\ 0 & 0 & 0 \\ 0 & 0 & 0 \end{pmatrix} """ if dim == 2: grad2d = df.grad(rank2_3d) dim3 = df.as_tensor([[0, 0, 0], [0, 0, 0], [0, 0, 0]]) grad3d = df.as_tensor([grad2d[:, :, 0], grad2d[:, :, 1], dim3[:, :]]) return grad3d else: return df.grad(rank2_3d)