Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

3D periodic piece-wise emission distribution model: mappers.pyx #399

Open
MMoscheni opened this issue Jan 18, 2023 · 1 comment
Open

3D periodic piece-wise emission distribution model: mappers.pyx #399

MMoscheni opened this issue Jan 18, 2023 · 1 comment

Comments

@MMoscheni
Copy link

MMoscheni commented Jan 18, 2023

Dear CHERAB team,

is there any interest in having a new mapper which, given a 2D function defined in the poloidal plane, maps such function in a 3D one which is periodic along the toroidal direction? For instance, the resulting 3D function could be alternatively zero or non-zero (and matching what one would obtain with the already existing AxisymmetricMapper) along the toridal direction. This could be useful given the usual shaping of the plasma-facing components in tokamaks and resulting emission in their proximity (see Fig. 3 of this paper for an example).

An idea of implementation could be the following:

cdef class DiscreteToroidalMapper(Function3D):
    """
    Performs a periodic (of period = periodicity) discrete rotation of a 2D function
    (defined on the xz plane) around the z-axis. The resulting 3D function is a piece-
    wise function, which is non-zero over a range of where_non_zero [rad] in each slice.

    Due to the nature of this mapping, only the positive region of the x range
    of the supplied function is mapped.
    
    :param Function2D function2d: The function to be mapped.
    :param float periodicity: Periodicity [rad] of the 3D mapping,
                               i.e. 1 / periodicity = number of slices.
    :param float where_non_zero: Angle [rad] in each slice where the resulting function
                                  is non-zero.

    .. code-block:: pycon

       >>> import numpy as np
       >>> from cherab.core.math import DiscreteToroidalMapper
       >>>
       >>> def f1(r, z):
       >>>     return r
       >>>
       >>> periodicity = 2 * np.pi / 2      # 2 slices (x>0 and x<0 half-spaces)
       >>> where_non_zero = periodicity / 2 # half of each slice is non-zero (1st and 3rd quadrants)
       >>>
       >>> f2 = DiscreteToroidalMapper(f1,
                                       periodicity = periodicity,
                                       where_non_zero = where_non_zero)
       >>>
       >>> f2(+1/np.sqrt(2), +1/np.sqrt(2), 0)
       0.99999999
       >>> f2(+1/np.sqrt(2), -1/np.sqrt(2), 0)
       0.0
    """

    def __init__(self, object function2d, double periodicity, double where_non_zero):

        if not callable(function2d):
            raise TypeError("Function3D is not callable.")

        if where_non_zero > periodicity:
            raise ValueError("where_non_zero must be smaller than periodicity.")

        self.function2d = autowrap_function2d(function2d)

        self.periodicity = periodicity        # [rad]
        self.where_non_zero = where_non_zero  # [rad]

    def __call__(self, double x, double y, double z):
        return self.evaluate(x, y, z)

    @cython.boundscheck(False)
    @cython.wraparound(False)
    @cython.cdivision(True)
    @cython.initializedcheck(False)
    cdef double evaluate(self, double x, double y, double z) except? -1e999:
        """Return the value of function2d when it is y-axis symmetrically
        extended to the 3D space and falling in where_non_zero range.
        Return 0 otherwise."""

        cdef:
            double phi, phi_dw, phi_up
            int n, num

        # toroidal angle [rad]
        phi = atan2(y, x) + M_PI

        # number of slices
        num = int(2 * M_PI / self.periodicity)

        # check if zero must be returned (more efficient)
        for n from 0 <= n < num by 1:
            phi_dw = n * self.periodicity + self.where_non_zero
            phi_up = (n + 1) * self.periodicity
            if phi > phi_dw and phi < phi_up:
                return 0.0

        return self.function2d.evaluate(sqrt(x*x + y*y), z)
@vsnever
Copy link
Member

vsnever commented Aug 1, 2024

I think that periodic and cylindrical transform function added in #388 solve the problem.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants