Source code for coordinate_transformation

"""
Compute the coordinate transformation related variables for a mapping,

    .. math::

        \\Phi : \\Omega_{\\mathrm{ref}}\\to\\Omega

We get an instance of class ``CoordinateTransformation``. The
transformations are its methods.

⭕ To access the source code, click on the [source] button at the right
side or click on
:download:`[coordinate_transformation.py]</contents/LIBRARY/ptc/mathischeap_ptc/coordinate_transformation.py>`.
Dependence may exist. In case of error, check import and install
required packages or download required scripts. © mathischeap.com

"""

import numpy as np
from numpy import sin as sin
from numpy import cos as cos
from numpy import pi as pi


def Phi(xi, et, sg):  # define a mapping; for testing
    r, s, t = (xi + 1) / 2, (et + 1) / 2, (sg + 1) / 2
    x = r + 0.1 * sin(2 * pi * r) * sin(2 * pi * s) * sin(2 * pi * t)
    y = s + 0.1 * sin(2 * pi * r) * sin(2 * pi * s) * sin(2 * pi * t)
    z = t + 0.1 * sin(2 * pi * r) * sin(2 * pi * s) * sin(2 * pi * t)
    return x, y, z


def d_Phi(xi, et, sg):  # the Jacobian matrix of above mapping
    r, s, t = (xi + 1) / 2, (et + 1) / 2, (sg + 1) / 2
    x_xi = (1 + 0.2*pi*cos(2*pi * r) * sin(2*pi * s) * sin(2*pi * t))/2
    x_et = (    0.2*pi*sin(2*pi * r) * cos(2*pi * s) * sin(2*pi * t))/2
    x_sg = (    0.2*pi*sin(2*pi * r) * sin(2*pi * s) * cos(2*pi * t))/2
    y_xi = (    0.2*pi*cos(2*pi * r) * sin(2*pi * s) * sin(2*pi * t))/2
    y_et = (1 + 0.2*pi*sin(2*pi * r) * cos(2*pi * s) * sin(2*pi * t))/2
    y_sg = (    0.2*pi*sin(2*pi * r) * sin(2*pi * s) * cos(2*pi * t))/2
    z_xi = (    0.2*pi*cos(2*pi * r) * sin(2*pi * s) * sin(2*pi * t))/2
    z_et = (    0.2*pi*sin(2*pi * r) * cos(2*pi * s) * sin(2*pi * t))/2
    z_sg = (1 + 0.2*pi*sin(2*pi * r) * sin(2*pi * s) * cos(2*pi * t))/2
    return (x_xi, x_et, x_sg), (y_xi, y_et, y_sg), (z_xi, z_et, z_sg)



[docs]class CoordinateTransformation(object): """ The coordinate transformation class. :param Phi: The mapping :math:`\\Phi`. It should be a function which returns three components of the mapping, i.e., .. math:: \\Phi = (\\Phi_x, \\Phi_y, \\Phi_z). :type Phi: function :param d_Phi: The Jacobian matrix of :math:`\\Phi`, :math:`\\mathcal{J}`. It should be a function return the 9 components of the Jacobian matrix, i.e., ( :math:`\\dfrac{\\partial x}{\\partial\\xi}`, :math:`\\dfrac{\\partial x}{\\partial\\eta}`, :math:`\\dfrac{\\partial x}{\\partial\\varsigma}`), ( :math:`\\dfrac{\\partial y}{\\partial\\xi}`, :math:`\\dfrac{\\partial y}{\\partial\\eta}`, :math:`\\dfrac{\\partial y}{\\partial\\varsigma}`), ( :math:`\\dfrac{\\partial z}{\\partial\\xi}`, :math:`\\dfrac{\\partial z}{\\partial\\eta}`, :math:`\\dfrac{\\partial z}{\\partial\\varsigma}`). :type d_Phi: function :example: >>> ct = CoordinateTransformation(Phi, d_Phi) # generate a CT instance >>> xi = np.linspace(-0.9, 0.6, 3) >>> et = np.linspace(-0.7, 0.9, 3) >>> sg = np.linspace(-0.8, 0.7, 3) >>> xi, et, sg = np.meshgrid(xi, et, sg, indexing='ij') >>> x, y, z = ct.mapping(xi, et, sg) >>> x # doctest: +ELLIPSIS array([[[0.06469463, 0.05391086, 0.02977458],... >>> y # doctest: +ELLIPSIS array([[[0.16469463, 0.15391086, 0.12977458],... >>> z # doctest: +ELLIPSIS array([[[0.11469463, 0.47891086, 0.82977458],... >>> J = ct.Jacobian_matrix(xi, et, sg) >>> J[0][0] # J_{1,1} # doctest: +ELLIPSIS array([[[0.64207986, 0.53781345, 0.30444385],... >>> J[1][1] # J_{2,2} # doctest: +ELLIPSIS array([[[0.53354051, 0.50892654, 0.45383545],... >>> detJ = ct.Jacobian(xi, et, sg) >>> detJ # doctest: +ELLIPSIS array([[[0.1847901 , 0.11729178, 0.07611096],... >>> iJ = ct.inverse_Jacobian_matrix(xi, et, sg) >>> iJ[2][2] # J^{-1}_{3,3} # doctest: +ELLIPSIS array([[[1.82807508, 2.33068327, 1.69672867],... >>> iJ[1][2] # J^{-1}_{2,3} # doctest: +ELLIPSIS array([[[-0.17192492, 0.33068327, -0.30327133],... >>> G = ct.metric_matrix(xi, et, sg) >>> G[0][1] # g_{1,2} # doctest: +ELLIPSIS array([[[ 0.10210648, 0.02438263, -0.09377707],... >>> G[1][2] # g_{2,3} # doctest: +ELLIPSIS array([[[ 0.05493377, -0.03640053, -0.0063935 ],... >>> g = ct.metric(xi, et, sg) >>> g # doctest: +ELLIPSIS array([[[0.03414738, 0.01375736, 0.00579288],... >>> iG = ct.inverse_metric_matrix(xi, et, sg) >>> iG[1][2] # g^{2,3} # doctest: +ELLIPSIS array([[[-0.33977063, 0.72204401, 1.83434454],... """ def __init__(self, Phi, d_Phi): self.Phi = Phi self.d_Phi = d_Phi
[docs] def mapping(self, xi, et, sg): """A wrap of the input mapping, ``Phi``, i.e., :math:`\\Phi`. :param xi: :math:`\\xi`. :param et: :math:`\\eta`. :param sg: :math:`\\varsigma`. :return: a tuple :math:`(x,y,z) = \\Phi(\\xi,\\eta,\\varsigma)`. """ return self.Phi(xi, et, sg)
[docs] def Jacobian_matrix(self, xi, et, sg): """A wrap of the input Jacobian matrix, ``d_Phi``, i.e., :math:`\\mathcal{J}`. :return: Return the Jacobian matrix :math:`\\mathcal{J}`: .. math:: \\mathcal{J} = \\begin{bmatrix} \\dfrac{\\partial x}{\\partial \\xi} & \\dfrac{\\partial x}{\\partial \\eta} & \\dfrac{\\partial x}{\\partial \\varsigma} \\\\ \\dfrac{\\partial y}{\\partial \\xi} & \\dfrac{\\partial y}{\\partial \\eta} & \\dfrac{\\partial y}{\\partial \\varsigma} \\\\ \\dfrac{\\partial z}{\\partial \\xi} & \\dfrac{\\partial z}{\\partial \\eta} & \\dfrac{\\partial z}{\\partial \\varsigma} \\end{bmatrix}\\,. """ return self.d_Phi(xi, et, sg)
[docs] def Jacobian(self, xi, et, sg): """Compute the Jacobian :math:`\\mathrm{det}(\\mathcal{J})` of the mapping. :return: The Jacobian :math:`\\mathrm{det}(\\mathcal{J})`. """ J = self.Jacobian_matrix(xi, et, sg) return + J[0][0]*J[1][1]*J[2][2] + J[0][1]*J[1][2]*J[2][0] \ + J[0][2]*J[1][0]*J[2][1] - J[0][0]*J[1][2]*J[2][1] \ - J[0][1]*J[1][0]*J[2][2] - J[0][2]*J[1][1]*J[2][0]
[docs] def metric_matrix(self, xi, et, sg): """Compute the metric matrix :math:`\\mathcal{G}`. :return: Return the metric matrix :math:`\\mathcal{G}`: .. math:: \\mathcal{G} = \\begin{bmatrix} g_{1,1} & g_{1,2} & g_{1,3} \\\\ g_{2,1} & g_{2,2} & g_{2,3} \\\\ g_{3,1} & g_{3,2} & g_{3,3} \\end{bmatrix}\\,. """ J = self.Jacobian_matrix(xi, et, sg) G = [[None for _ in range(3)] for __ in range(3)] for i in range(3): for j in range(i, 3): G[i][j] = J[0][i] * J[0][j] for l in range(1, 3): G[i][j] += J[l][i] * J[l][j] if i != j: G[j][i] = G[i][j] return G
[docs] def metric(self, xi, et, sg): """The metric :math:`g:= \\mathrm{det}(\\mathcal{G}):=(\mathrm{det}(\\mathcal{J}))^2`. """ detJ = self.Jacobian(xi, et, sg) return detJ ** 2
[docs] def inverse_Jacobian_matrix(self, xi, et, sg): """Compute the Jacobian matrix of the inverse mapping :math:`\\Phi^{-1}`, .. math:: (\\xi,\\eta,\\varsigma) = \\Phi^{-1}(x,y,z). :return: Return the inverse Jacobian matrix : :math:`\\mathcal{J}^{-1}`: .. math:: \\mathcal{J}^{-1} = \\begin{bmatrix} \\dfrac{\\partial \\xi}{\\partial x} & \\dfrac{\\partial \\xi}{\\partial y} & \\dfrac{\\partial \\xi}{\\partial z} \\\\ \\dfrac{\\partial \\eta}{\\partial x} & \\dfrac{\\partial \\eta}{\\partial y} & \\dfrac{\\partial \\eta}{\\partial z} \\\\ \\dfrac{\\partial \\varsigma}{\\partial x} & \\dfrac{\\partial \\varsigma}{\\partial y} & \\dfrac{\\partial \\varsigma}{\\partial z} \\end{bmatrix}\\,. """ J = self.Jacobian_matrix(xi, et, sg) Jacobian = + J[0][0]*J[1][1]*J[2][2] + J[0][1]*J[1][2]*J[2][0] \ + J[0][2]*J[1][0]*J[2][1] - J[0][0]*J[1][2]*J[2][1] \ - J[0][1]*J[1][0]*J[2][2] - J[0][2]*J[1][1]*J[2][0] reciprocalJacobian = 1 / Jacobian del Jacobian iJ00 = reciprocalJacobian * (J[1][1] * J[2][2] - J[1][2] * J[2][1]) iJ01 = reciprocalJacobian * (J[2][1] * J[0][2] - J[2][2] * J[0][1]) iJ02 = reciprocalJacobian * (J[0][1] * J[1][2] - J[0][2] * J[1][1]) iJ10 = reciprocalJacobian * (J[1][2] * J[2][0] - J[1][0] * J[2][2]) iJ11 = reciprocalJacobian * (J[2][2] * J[0][0] - J[2][0] * J[0][2]) iJ12 = reciprocalJacobian * (J[0][2] * J[1][0] - J[0][0] * J[1][2]) iJ20 = reciprocalJacobian * (J[1][0] * J[2][1] - J[1][1] * J[2][0]) iJ21 = reciprocalJacobian * (J[2][0] * J[0][1] - J[2][1] * J[0][0]) iJ22 = reciprocalJacobian * (J[0][0] * J[1][1] - J[0][1] * J[1][0]) return [[iJ00, iJ01, iJ02], [iJ10, iJ11, iJ12], [iJ20, iJ21, iJ22]]
[docs] def inverse_Jacobian(self, xi, et, sg): """Compute the inverse Jacobian, the determinant of the inverse Jacobian matrix, :math:`\\mathrm{det}(\\mathcal{J}^{-1})`.""" iJ = self.inverse_Jacobian_matrix(xi, et, sg) # noinspection PyUnresolvedReferences return + iJ[0][0]*iJ[1][1]*iJ[2][2] + iJ[0][1]*iJ[1][2]*iJ[2][0]\ + iJ[0][2]*iJ[1][0]*iJ[2][1] - iJ[0][0]*iJ[1][2]*iJ[2][1]\ - iJ[0][1]*iJ[1][0]*iJ[2][2] - iJ[0][2]*iJ[1][1]*iJ[2][0]
[docs] def inverse_metric_matrix(self, xi, et, sg): """Compute the inverse metric matrix, :math:`\\mathcal{G}^{-1}`. :return: Return the inverse metric matrix : :math:`\\mathcal{G}^{-1}`: .. math:: \\mathcal{G}^{-1} = \\begin{bmatrix} g^{1,1} & g^{1,2} & g^{1,3} \\\\ g^{2,1} & g^{2,2} & g^{2,3} \\\\ g^{3,1} & g^{3,2} & g^{3,3} \\end{bmatrix}\\,. """ iJ = self.inverse_Jacobian_matrix(xi, et, sg) iG = [[None for _ in range(3)] for __ in range(3)] for i in range(3): for j in range(i, 3): # noinspection PyTypeChecker iG[i][j] = iJ[i][0] * iJ[j][0] for l in range(1, 3): iG[i][j] += iJ[i][l] * iJ[j][l] if i != j: iG[j][i] = iG[i][j] return iG
if __name__ == '__main__': import doctest doctest.testmod()