Source code for struphy.geometry.transform_kernels

# coding: utf-8

"""
1. Basic pull-back (physical --> logical) operations between scalar fields, vector fields and differential p-forms:

- 0-form :  a^0                  = a
- 1-form : (a^1_1, a^1_2, a^1_3) =           DF^T    (ax, ay, az)
- 2-form : (a^2_1, a^2_2, a^2_3) = |det(DF)| DF^(-1) (ax, ay, az)
- 3-form :  a^3                  = |det(DF)| a
- vector : (a_1  , a_2  , a_3  ) =           DF^(-1) (ax, ay, az)

2. Basic push-forward (logical --> physical) operations between scalar fields, vector fields and differential p-forms:

- 0-form :  a           = a^0
- 1-form : (ax, ay, az) =             DF^(-T) (a^1_1, a^1_2, a^1_3)
- 2-form : (ax, ay, az) = 1/|det(DF)| DF      (a^2_1, a^2_2, a^2_3)
- 3-form :  a           = 1/|det(DF)| a^3
- vector : (ax, ay, az) =             DF      (a_1  , a_2  , a_3  )

3. Basic transformations between scalar fields, vector fields and differential p-forms:

- 0-form --> 3-form : a^3 = a^0 * |det(DF)|
- 3-form --> 0-form : a^0 = a^3 / |det(DF)|
- 1-form --> 2-form : (a^2_1, a^2_2, a^2_3) = G^(-1) * (a^1_1, a^1_2, a^1_3) * |det(DF)|
- 2-form --> 1-form : (a^1_1, a^1_2, a^1_3) = G      * (a^2_1, a^2_2, a^2_3) / |det(DF)|

- norm vector --> vector : (a_1, a_2, a_3) = (a^*_1/sqrt(sum(DF[:,0]^2)),
                                              a^*_2/sqrt(sum(DF[:,1]^2)),
                                              a^*_3/sqrt(sum(DF[:,2]^2)))

- norm vector --> 1-form : (a^1_1, a^1_2, a^1_3) = G * (a^*_1/sqrt(sum(DF[:,0]^2)),
                                                        a^*_2/sqrt(sum(DF[:,1]^2)),
                                                        a^*_3/sqrt(sum(DF[:,2]^2)))

- norm vector --> 2-form : (a^2_1, a^2_2, a^2_3) =     (a^*_1/sqrt(sum(DF[:,0]^2)),
                                                        a^*_2/sqrt(sum(DF[:,1]^2)),
                                                        a^*_3/sqrt(sum(DF[:,2]^2))) * |det(DF)|

- vector --> 1-form : (a^1_1, a^1_2, a^1_3) = G * (a_1, a_2, a_3)
- vector --> 2-form : (a^2_1, a^2_2, a^2_3) =     (a_1, a_2, a_3) * |det(DF)|

- 1-form --> vector : (a_1, a_2, a_3) = G^(-1) * (a^1_1, a^1_2, a^1_3)
- 2-form --> vector : (a_1, a_2, a_3) =          (a^2_1, a^2_2, a^2_3) / |det(DF)|

Let h_i = ||DF[:, i]||. The normalized-vector representation stores a^*_i = h_i a_i.
Consequently, the inverse transformations added here are 1-form --> norm, 2-form --> norm,
and vector --> norm: each first obtains the Cartesian vector and then multiplies component i
by h_i. These are used when :meth:`Domain.transform` converts a saved FEEC field to the
``"norm"`` representation.
"""

from numpy import empty, shape, sqrt, zeros
from pyccel.decorators import stack_array

import struphy.geometry.evaluation_kernels as evaluation_kernels
import struphy.kernel_arguments.pusher_args_kernels as pusher_args_kernels  # do not remove; needed to identify dependencies
import struphy.linear_algebra.linalg_kernels as linalg_kernels
from struphy.kernel_arguments.pusher_args_kernels import DerhamArguments, DomainArguments


[docs] @stack_array("dfmat1", "dfmat2") def pull( a: "float[:]", eta1: float, eta2: float, eta3: float, kind_fun: int, args_domain: "DomainArguments", out: "float[:]", ): """ Pull-back of a Cartesian scalar/vector field to a differential p-form. Parameters ---------- a : float[:] Value of scalar field a[0] or values of Cartesian components of vector field (a[0], a[1], a[2]). eta1, eta2, eta3 : float Logical evaluation points. kind_fun : int Which pull-back to be performed. args_domain : DomainArguments Domain info. out : float[:] Output values. """ dfmat1 = empty((3, 3), dtype=float) dfmat2 = empty((3, 3), dtype=float) # evaluate Jacobian matrix and its determinant if kind_fun > 0: evaluation_kernels.df(eta1, eta2, eta3, args_domain, dfmat1) detdf = linalg_kernels.det(dfmat1) # 0-form if kind_fun == 0: out[0] = a[0] # 3-form elif kind_fun == 1: out[0] = a[0] * abs(detdf) # 1-form elif kind_fun == 10: linalg_kernels.transpose(dfmat1, dfmat2) linalg_kernels.matrix_vector(dfmat2, a, out) # 2-form elif kind_fun == 11: linalg_kernels.matrix_inv_with_det(dfmat1, 1.0, dfmat2) linalg_kernels.matrix_vector(dfmat2, a, out) if detdf < 0.0: out[:] = -out # vector elif kind_fun == 12: linalg_kernels.matrix_inv(dfmat1, dfmat2) linalg_kernels.matrix_vector(dfmat2, a, out)
[docs] @stack_array("dfmat1", "dfmat2", "dfmat3") def push( a: "float[:]", eta1: float, eta2: float, eta3: float, kind_fun: int, args_domain: "DomainArguments", out: "float[:]", ): """ Pushforward of a differential p-forms to a Cartesian scalar/vector field. Parameters ---------- a : float[:] Value of scalar p-form a[0] or values of components of vector valued p-form (a[0], a[1], a[2]). eta1, eta2, eta3 : float Logical evaluation points. kind_fun : int Which pushforward to be performed. args_domain : DomainArguments Domain info. out : float[:] Output values. """ dfmat1 = empty((3, 3), dtype=float) dfmat2 = empty((3, 3), dtype=float) dfmat3 = empty((3, 3), dtype=float) # evaluate Jacobian matrix and its determinant if kind_fun > 0: evaluation_kernels.df(eta1, eta2, eta3, args_domain, dfmat1) detdf = linalg_kernels.det(dfmat1) # 0-form if kind_fun == 0: out[0] = a[0] # 3-form elif kind_fun == 1: out[0] = a[0] / abs(detdf) # 1-form elif kind_fun == 10: linalg_kernels.matrix_inv_with_det(dfmat1, detdf, dfmat2) linalg_kernels.transpose(dfmat2, dfmat3) linalg_kernels.matrix_vector(dfmat3, a, out) # 2-form elif kind_fun == 11: linalg_kernels.matrix_vector(dfmat1, a, out) out[:] = out / abs(detdf) # vector elif kind_fun == 12: linalg_kernels.matrix_vector(dfmat1, a, out)
[docs] @stack_array("dfmat1", "dfmat2", "dfmat3", "vec1", "vec2") def tran( a: "float[:]", eta1: float, eta2: float, eta3: float, kind_fun: int, args_domain: "DomainArguments", out: "float[:]", ): """ Transformations between differential p-forms and/or vector fields. Parameters ---------- a : float[:] Value of scalar function a[0] or values of components of vector valued functions (a[0], a[1], a[2]). eta1, eta2, eta3 : float Logical evaluation points. kind_fun : int Which transformation to perform. The values are assigned by ``Domain.dict_transformations["tran"]``: - 0, 1: ``0_to_3``, ``3_to_0`` - 10, 11: ``1_to_2``, ``2_to_1`` - 12, 13, 14: ``norm_to_v``, ``norm_to_1``, ``norm_to_2`` - 15, 16: ``v_to_1``, ``v_to_2`` - 17, 18: ``1_to_v``, ``2_to_v`` - 19, 20, 21: ``1_to_norm``, ``2_to_norm``, ``v_to_norm`` args_domain : DomainArguments Domain info. out : float[:] Output values. """ dfmat1 = empty((3, 3), dtype=float) dfmat2 = empty((3, 3), dtype=float) dfmat3 = empty((3, 3), dtype=float) vec1 = empty(3, dtype=float) vec2 = empty(3, dtype=float) # evaluate Jacobian matrix and its determinant evaluation_kernels.df(eta1, eta2, eta3, args_domain, dfmat1) detdf = linalg_kernels.det(dfmat1) # 0-form to 3-form if kind_fun == 0: out[0] = a[0] * abs(detdf) # 3-form to 0-form elif kind_fun == 1: out[0] = a[0] / abs(detdf) # 1-form to 2-form (a^2 = G^(-1) * a^1 * |det(DF)|) elif kind_fun == 10: linalg_kernels.matrix_inv_with_det(dfmat1, detdf, dfmat2) linalg_kernels.transpose(dfmat2, dfmat3) linalg_kernels.matrix_vector(dfmat3, a, vec1) linalg_kernels.matrix_vector(dfmat2, vec1, out) out[:] = out * abs(detdf) # 2-form to 1-form (a^1 = G * a^2 / |det(DF)|) elif kind_fun == 11: linalg_kernels.transpose(dfmat1, dfmat2) linalg_kernels.matrix_vector(dfmat1, a, vec1) linalg_kernels.matrix_vector(dfmat2, vec1, out) out[:] = out / abs(detdf) # norm vector to vector elif kind_fun == 12: out[0] = a[0] / sqrt(dfmat1[0, 0] ** 2 + dfmat1[1, 0] ** 2 + dfmat1[2, 0] ** 2) out[1] = a[1] / sqrt(dfmat1[0, 1] ** 2 + dfmat1[1, 1] ** 2 + dfmat1[2, 1] ** 2) out[2] = a[2] / sqrt(dfmat1[0, 2] ** 2 + dfmat1[1, 2] ** 2 + dfmat1[2, 2] ** 2) # norm vector to 1-form (a^1 = G * a) elif kind_fun == 13: vec1[0] = a[0] / sqrt(dfmat1[0, 0] ** 2 + dfmat1[1, 0] ** 2 + dfmat1[2, 0] ** 2) vec1[1] = a[1] / sqrt(dfmat1[0, 1] ** 2 + dfmat1[1, 1] ** 2 + dfmat1[2, 1] ** 2) vec1[2] = a[2] / sqrt(dfmat1[0, 2] ** 2 + dfmat1[1, 2] ** 2 + dfmat1[2, 2] ** 2) linalg_kernels.transpose(dfmat1, dfmat2) linalg_kernels.matrix_vector(dfmat1, vec1, vec2) linalg_kernels.matrix_vector(dfmat2, vec2, out) # norm vector to 2-form (a^2 = |det(DF)| * a) elif kind_fun == 14: out[0] = a[0] / sqrt(dfmat1[0, 0] ** 2 + dfmat1[1, 0] ** 2 + dfmat1[2, 0] ** 2) out[1] = a[1] / sqrt(dfmat1[0, 1] ** 2 + dfmat1[1, 1] ** 2 + dfmat1[2, 1] ** 2) out[2] = a[2] / sqrt(dfmat1[0, 2] ** 2 + dfmat1[1, 2] ** 2 + dfmat1[2, 2] ** 2) out[:] = out * abs(detdf) # vector to 1-form (a^1 = G * a) elif kind_fun == 15: linalg_kernels.transpose(dfmat1, dfmat2) linalg_kernels.matrix_vector(dfmat1, a, vec1) linalg_kernels.matrix_vector(dfmat2, vec1, out) # vector to 2-form (a^2 = |det(DF)| * a) elif kind_fun == 16: out[:] = a * abs(detdf) # 1-form to vector (a = G^(-1) * a^1) elif kind_fun == 17: linalg_kernels.matrix_inv_with_det(dfmat1, detdf, dfmat2) linalg_kernels.transpose(dfmat2, dfmat3) linalg_kernels.matrix_vector(dfmat3, a, vec1) linalg_kernels.matrix_vector(dfmat2, vec1, out) # 2-form to vector (a = a^2 / |det(DF)|) elif kind_fun == 18: out[:] = a / abs(detdf) # 1-form to normalized vector elif kind_fun == 19: linalg_kernels.matrix_inv_with_det(dfmat1, detdf, dfmat2) linalg_kernels.transpose(dfmat2, dfmat3) linalg_kernels.matrix_vector(dfmat3, a, vec1) linalg_kernels.matrix_vector(dfmat2, vec1, out) out[0] = out[0] * sqrt(dfmat1[0, 0] ** 2 + dfmat1[1, 0] ** 2 + dfmat1[2, 0] ** 2) out[1] = out[1] * sqrt(dfmat1[0, 1] ** 2 + dfmat1[1, 1] ** 2 + dfmat1[2, 1] ** 2) out[2] = out[2] * sqrt(dfmat1[0, 2] ** 2 + dfmat1[1, 2] ** 2 + dfmat1[2, 2] ** 2) # 2-form to normalized vector elif kind_fun == 20: out[:] = a / abs(detdf) out[0] = out[0] * sqrt(dfmat1[0, 0] ** 2 + dfmat1[1, 0] ** 2 + dfmat1[2, 0] ** 2) out[1] = out[1] * sqrt(dfmat1[0, 1] ** 2 + dfmat1[1, 1] ** 2 + dfmat1[2, 1] ** 2) out[2] = out[2] * sqrt(dfmat1[0, 2] ** 2 + dfmat1[1, 2] ** 2 + dfmat1[2, 2] ** 2) # Cartesian vector to normalized vector elif kind_fun == 21: out[0] = a[0] * sqrt(dfmat1[0, 0] ** 2 + dfmat1[1, 0] ** 2 + dfmat1[2, 0] ** 2) out[1] = a[1] * sqrt(dfmat1[0, 1] ** 2 + dfmat1[1, 1] ** 2 + dfmat1[2, 1] ** 2) out[2] = a[2] * sqrt(dfmat1[0, 2] ** 2 + dfmat1[1, 2] ** 2 + dfmat1[2, 2] ** 2)