Esempio n. 1
0
def grad(f, dx, dy, dz, x=None, y=None, coordinate_system='cartesian'):
    """
    Take the gradient of a pencil code scalar array f in various coordinate systems.

    Keyword arguments:

    *f*:
      Pencil code scalar array f.

    *dx, dy, dz*:
      Grid spacing in the three dimensions.

    *x, y*:
      Radial (x) and polar (y) coordinates, 1d arrays.

    *coordinate_system*:
      Coordinate system under which to take the divergence.
      Takes 'cartesian', 'cylindrical' and 'spherical'.
    """

    import numpy as np
    from pencil.math.derivatives.der import xder, yder, zder

    if f.ndim != 3:
        print("grad: must have scalar 3-D array f[mz, my, mx] for gradient.")
        raise ValueError

    grad_value = np.zeros((3, ) + f.shape)

    if coordinate_system == 'cartesian':
        grad_value[0] = xder(f, dx)
        grad_value[1] = yder(f, dy)
        grad_value[2] = zder(f, dz)

    if coordinate_system == 'cylindrical':
        if x is None:
            print(
                'ERROR: need to specify x (radius) for cylindrical coordinates.'
            )
            raise ValueError
        # Make sure x has compatible dimensions.
        x = x[np.newaxis, np.newaxis, :]
        grad_value[0] = xder(f, dx)
        grad_value[1] = yder(f, dy) / x
        grad_value[2] = zder(f, dz)

    if coordinate_system == 'spherical':
        if (x is None) or (y is None):
            print(
                'ERROR: need to specify x (radius) and y (polar angle) for spherical coordinates.'
            )
            raise ValueError
        # Make sure x and y have compatible dimensions.
        x = x[np.newaxis, np.newaxis, :]
        y = y[np.newaxis, :, np.newaxis]
        grad_value[0] = xder(f, dx)
        grad_value[1] = yder(f, dy) / x
        grad_value[2] = zder(f, dz) / (x * np.sin(y))

    return grad_value
Esempio n. 2
0
def div(f, dx, dy, dz, x=None, y=None, coordinate_system="cartesian"):
    """
    div(f, dx, dy, dz, x=None, y=None, coordinate_system="cartesian")

    Take divervenge of pencil code vector array f in various coordinate systems.

    Parameters
    ----------
    f : ndarray
        Pencil code vector array f.

    dx, dy, dz : floats
        Grid spacing in the three dimensions.

    x, y : ndarrays
        Radial (x) and polar (y) coordinates, 1d arrays.

    coordinate_system : string
        Coordinate system under which to take the divergence.
        Takes 'cartesian', 'cylindrical' and 'spherical'.
    """

    import numpy as np
    from pencil.math.derivatives.der import xder, yder, zder

    if f.ndim != 4:
        print(
            "div: must have vector 4-D array f[mvar, mz, my, mx] for divergence."
        )
        raise ValueError

    if coordinate_system == "cartesian":
        return xder(f[0], dx) + yder(f[1], dy) + zder(f[2], dz)

    if coordinate_system == "cylindrical":
        if x is None:
            print(
                "ERROR: need to specify x (radius) for cylindrical coordinates."
            )
            raise ValueError
        # Make sure x has compatible dimensions.
        x = x[np.newaxis, np.newaxis, :]
        return xder(x * f[0], dx) / x + yder(f[1], dy) / x + zder(f[2], dz)

    if coordinate_system == "spherical":
        if (x is None) or (y is None):
            print(
                "ERROR: need to specify x (radius) and y (polar angle) for spherical coordinates."
            )
            raise ValueError
        # Make sure x and y have compatible dimensions.
        x = x[np.newaxis, np.newaxis, :]
        y = y[np.newaxis, :, np.newaxis]
        return (xder(x**2 * f[0], dx) / x**2 + yder(np.sin(y) * f[1], dy) /
                (x * np.sin(y)) + zder(f[2], dz) / (x * np.sin(y)))

    print("ERROR: could not recognize coordinate system {0}".format(
        coordinate_system))
    raise ValueError
Esempio n. 3
0
def gij(f, dx, dy, dz, nder=6):
    """
    Calculate del6 (defined here as d^6/dx^6 + d^6/dy^6 + d^6/dz^6, rather
    than del2^3) of a scalar f for hyperdiffusion.
    """

    import numpy as np

    if f.ndim != 4 or f.shape[0] != 3:
        print("curl3: must have vector 4-D array f[3, mz, my, mx] for curl3.")
        raise ValueError
    gij = np.array(f, f, f)
    for i in range(3):
        if nder == 1:
            from pencil.math.derivatives.der import xder, yder, zder

            gij[i, 0] = xder(f[i], dx, dy, dz)
            gij[i, 1] = yder(f[i], dx, dy, dz)
            gij[i, 2] = zder(f[i], dx, dy, dz)
        elif nder == 2:
            from pencil.math.derivatives.der import xder2, yder2, zder2

            gij[i, 0] = xder2(f[i], dx, dy, dz)
            gij[i, 1] = yder2(f[i], dx, dy, dz)
            gij[i, 2] = zder2(f[i], dx, dy, dz)
        elif nder == 3:
            from pencil.math.derivatives.der import xder3, yder3, zder3

            gij[i, 0] = xder3(f[i], dx, dy, dz)
            gij[i, 1] = yder3(f[i], dx, dy, dz)
            gij[i, 2] = zder3(f[i], dx, dy, dz)
        elif nder == 4:
            from pencil.math.derivatives.der import xder4, yder4, zder4

            gij[i, 0] = xder4(f[i], dx, dy, dz)
            gij[i, 1] = yder4(f[i], dx, dy, dz)
            gij[i, 2] = zder4(f[i], dx, dy, dz)
        elif nder == 5:
            from pencil.math.derivatives.der import xder5, yder5, zder5

            gij[i, 0] = xder5(f[i], dx, dy, dz)
            gij[i, 1] = yder5(f[i], dx, dy, dz)
            gij[i, 2] = zder5(f[i], dx, dy, dz)
        elif nder == 6:
            from pencil.math.derivatives.der import xder6, yder6, zder6

            gij[i, 0] = xder6(f[i], dx, dy, dz)
            gij[i, 1] = yder6(f[i], dx, dy, dz)
            gij[i, 2] = zder6(f[i], dx, dy, dz)

    return gij
Esempio n. 4
0
def del2(f, dx, dy, dz, x=None, y=None, coordinate_system="cartesian"):
    """
    del2(f, dx, dy, dz, x=None, y=None, coordinate_system="cartesian")

    Calculate del2, the Laplacian of a scalar field f.

    Parameters
    ----------
    x, y : ndarrays
        Radial (x) and polar (y) coordinates, 1d arrays.

    run2D : bool
        Deals with pure 2-D snapshots (solved the (x,z)-plane pb).
        !Only for Cartesian grids at the moment!

    coordinate_system : string
        Coordinate system under which to take the divergence.
        Takes 'cartesian', 'cylindrical' and 'spherical'.
    """

    import numpy as np
    from pencil.math.derivatives.der import xder2, yder2, zder2, xder, yder

    if coordinate_system == "cartesian":
        del2_value = xder2(f, dx) + yder2(f, dy) + zder2(f, dz)
    if coordinate_system == "cylindrical":
        if x is None:
            print("ERROR: need to specify x (radius)")
            raise ValueError
        # Make sure x has compatible dimensions.
        x = x[np.newaxis, np.newaxis, :]
        del2_value = (xder(f, dx) / x + xder2(f, dx) + yder2(f, dy) / (x**2) +
                      zder2(f, dz))
    if coordinate_system == "spherical":
        if x is None or y is None:
            print("ERROR: need to specify x (radius) and y (polar angle)")
            raise ValueError
        # Make sure x and y have compatible dimensions.
        x = x[np.newaxis, np.newaxis, :]
        y = y[np.newaxis, :, np.newaxis]
        del2_value = (2 * xder(f, dx) / x + xder2(f, dx) +
                      np.cos(y) * yder(f, dy) / ((x**2) * np.sin(y)) +
                      yder2(f, dy) / (x**2) + zder2(f, dz) /
                      ((x * np.sin(y))**2))
    return del2_value
Esempio n. 5
0
def curl3(f, dx, dy, dz, x=None, y=None, coordinate_system='cartesian'):
    """
    Take the triple curl of a pencil code vector array f.

    *x, y*:
      Radial (x) and polar (y) coordinates, 1d arrays.

    *run2D*:
      Deals with pure 2-D snapshots (solved the (x,z)-plane pb).
      !Only for Cartesian grids at the moment!

    *coordinate_system*:
      Coordinate system under which to take the divergence.
      Takes 'cartesian' and 'cylindrical'.
    """

    import numpy as np
    from pencil.math.derivatives.der import xder, yder, zder, xder2, yder2, zder2, xder3, yder3, zder3

    if (f.ndim != 4 or f.shape[0] != 3):
        print("curl3: must have vector 4-D array f[3, mz, my, mx] for curl3.")
        raise ValueError

    curl3_value = np.zeros(f.shape)

    if coordinate_system == 'cartesian':
        curl3_value[0] = zder(xder2(f[1], dx) + yder2(f[1], dy), dz) + zder3(f[1], dz) - \
                         yder(xder2(f[2], dx) + zder2(f[2], dz), dy) - yder3(f[2], dy)
        curl3_value[1] = xder3(f[2], dx) + xder(yder2(f[2], dy) + zder2(f[2], dz), dx) - \
                         zder(xder2(f[0], dx) + yder2(f[0], dy), dz) - zder3(f[0], dz)
        curl3_value[2] = yder(xder2(f[0], dx) + zder2(f[0], dz), dy) + yder3(f[0], dy) - \
                         xder3(f[1], dx) - xder(yder2(f[1], dy) + zder2(f[1], dz), dx)
    if coordinate_system == 'cylindrical':
        if x is None:
            print(
                'ERROR: need to specify x (radius) for cylindrical coordinates.'
            )
            raise ValueError
        # Make sure x has compatible dimensions.
        x = x[np.newaxis, np.newaxis, :]
        curl3_value[0] = 2*yder(zder(f[0], dz), dy)/x**2 - yder(zder(f[2], dz), dy)/x**2 \
                         - xder2(yder(f[2], dy), dx)/x - yder3(f[2], dy)/x**3 \
                         + yder2(zder(f[1], dz), dy)/x**2 - yder(zder2(f[2], dz), dy)/x \
                         + zder3(f[1], dz) - zder(f[1], dz)/x**2 \
                         + xder(zder(f[1], dz), dx)/x + xder2(zder(f[1], dz), dx)
        curl3_value[1] = 2*yder(zder(f[1], dz), dy)/x**2 - yder2(zder(f[0], dz), dy)/x**2 \
                         - zder3(f[0], dz) + xder(zder2(f[2], dz), dx) \
                         - xder(zder(f[0], dz), dx)/x + zder(f[0], dz)/x**2 \
                         - xder2(zder(f[0], dz), dx) + xder(zder(f[2], dz), dx)/x \
                         - zder(f[2], dz)/x**2 + xder3(f[2], dx) \
                         + xder(yder2(f[2], dy), dx)/x**2 - 2*yder2(f[2], dy)/x**3
        curl3_value[2] = - xder(zder2(f[1], dz), dx) - zder2(f[1], dz)/x \
                         + xder(f[1], dx) /x**2 - f[1]/x**3 \
                         - xder3(f[1], dx) + xder2(yder(f[0], dy), dx)/x \
                         - xder(yder(f[0], dy), dx)/x**2 + yder(f[0], dy)/x**3 \
                         - yder2(f[1], dy)/x**3 - xder(yder2(f[1], dy), dx)/x**2 \
                         + yder3(f[0], dy)/x**3 + yder(zder2(f[0], dz), dy)/x \
                         -2*xder2(f[1], dx)/x
    if coordinate_system == 'spherical':
        if x is None or y is None:
            print(
                'ERROR: need to specify x (radius) and y (polar angle) for spherical coordinates'
            )
            raise ValueError
        # Make sure x and y have compatible dimensions.
        x = x[np.newaxis, np.newaxis, :]
        y = y[np.newaxis, :, np.newaxis]
        # TODO: This one needs some fixing.
        curl3_value[0] = (-1/x**3) * (np.sin(y)*((np.cos(y)**2 - 1)*(yder2(zder(f[1], dz), dy)) + \
                         (-np.cos(y)**2 * np.sin(y) + np.sin(y))*(yder3(f[2], dy)) \
                         -x**2 *(xder2(zder(f[1], dz), dx)) - zder3(f[1], dz) + \
                         np.sin(y)*(xder2(yder(f[2], dy), dx))*x**2 + (yder(zder2(f[2], dz), dy))*np.sin(y) \
                         +(-6*np.cos(y)**3 + 6* np.cos(y))*(yder2(f[2], dy))- 2*x*(xder(zder(f[1], dz), dx)) \
                         -3*np.sin(y)*np.cos(y)*(yder(zder(f[1], dz), dy)) + np.cos(y)*(xder2(f[2], dx))*x**2 + \
                         2*np.sin(y)*(xder(yder(f[2], dy), dx))*x + (zder2(f[2], dz))*np.cos(y) + \
                         (-2*np.cos(y)**2 + 1)*(zder(f[1], dz)) + (11*np.cos(y)**2 * np.sin(y) - 4*np.sin(y))*(yder(f[2], dy)) \
                         + 2*np.cos(y)*(xder(f[2], dx))*x + (6*np.cos(y)**3 - 5*np.cos(y))*f[2]))
        curl3_value[1] = 1/(x**3*np.sin(y)) * ((np.cos(y)**2 - 1)*(yder2(zder(f[0], dz), dy)) + \
                         (-x * np.cos(y)**2 + x)*np.sin(y)*(xder(yder2(f[2], dy), dx)) \
                         - (xder2(zder(f[0], dz), dx))*x**2 - zder3(f[0], dz) + x**3*(xder3(f[2], dx))*np.sin(y) + \
                         x*(xder(zder2(f[2], dz), dx))*np.sin(y) + (-2*np.cos(y)**2 + 2)*(yder(zder(f[1], dz), dy)) + \
                         3*x**2*xder2(f[2], dx)*np.sin(y) + zder2(f[2], dz)*np.sin(y) + (2*x*np.cos(y)**2 - x)*np.sin(y)*(xder(f[2], dx)) \
                         + (3*np.cos(y)**3 - 3*np.cos(y))*(yder(f[2], dy)) + 2*np.sin(y)*np.cos(y)*(zder(f[1], dz)) + \
                         (-2*np.cos(y)**2 + 1)*np.sin(y)*f[2])
        curl3_value[2] = 1/x**3 * ((yder3(f[0], dy))*(1-np.cos(y)**2) + (x*np.cos(y)**2 - x)*(xder(yder2(f[1], dy), dx)) + \
                         (xder2(yder(f[1], dy), dx))*x**2 + yder(zder2(f[0], dz), dy) - (xder3(f[1], dx))*x**3 - \
                         (xder(zder2(f[1], dz), dx))*x + (np.cos(y)**2 - 1)*(yder2(f[1], dy)) \
                         + 3*(yder2(f[1], dy))*np.sin(y)*np.cos(y) - 3*(xder2(f[1], dx))*x**2 - \
                         3*(xder(yder(f[1], dy), dx))*np.sin(y)*np.cos(y)*x + zder2(f[1], dz) - \
                         2*(yder(zder(f[2], dz), dy))*np.sin(y) + (2*np.cos(y)**2 - 1)*(yder(f[1], dy)) + \
                         (-2*np.cos(y)**2 + x)*(xder(f[1], dx)) - 3*(yder(f[1], dy))*np.sin(y)*np.cos(y) - \
                         2*(zder(f[2], dz))*np.cos(y) + (-2*np.cos(y)**2 +1)*f[1])
    return curl3_value
Esempio n. 6
0
def del2v(f, dx, dy, dz, x=None, y=None, coordinate_system='cartesian'):
    """
    Calculate del2, the Laplacian of a vector field f.

    *x, y*:
      Radial (x) and polar (y) coordinates, 1d arrays.

    *run2D*:
      Deals with pure 2-D snapshots (solved the (x,z)-plane pb).
      !Only for Cartesian grids at the moment!

    *coordinate_system*:
      Coordinate system under which to take the divergence.
      Takes 'cartesian', 'cylindrical' and 'spherical'.
    """

    if f.shape[0] != 3:
        print(
            "Vector Laplacian: must have a vector 4D array f(3, mz, my, mx) for Vector Laplacian"
        )
        raise ValueError

    import numpy as np
    from pencil.math.derivatives.der import xder2, yder2, zder2, yder, zder

    del2v_value = np.zeros(f.shape)

    if coordinate_system == 'cartesian':
        del2v_value[0] = xder2(f[0], dx) + yder2(f[0], dy) + zder2(f[0], dz)
        del2v_value[1] = xder2(f[1], dx) + yder2(f[1], dy) + zder2(f[1], dz)
        del2v_value[2] = xder2(f[2], dx) + yder2(f[2], dy) + zder2(f[2], dz)
    if coordinate_system == 'cylindrical':
        if x is None:
            print('Error: need to specify x (radius)')
            raise ValueError
        # Make sure x has compatible dimensions.
        x = x[np.newaxis, np.newaxis, :]
        del2v_value[0] = del2(f[0], dx, dy, dz, x=x, y=y, coordinate_system='cylindrical') \
                        - f[0]/(x**2) - 2*yder(f[1], dy)/x**2
        del2v_value[1] = del2(f[1], dx, dy, dz, x=x, y=y, coordinate_system='cylindrical') \
                         - f[1]/(x**2) + 2*yder(f[0], dy)/x**2
        del2v_value[2] = del2(f[2],
                              dx,
                              dy,
                              dz,
                              x=x,
                              y=y,
                              coordinate_system='cylindrical')
    if coordinate_system == 'spherical':
        if x is None or y is None:
            print('ERROR: need to specify x (radius) and y (polar angle)')
        # Make sure x and y have compatible dimensions.
        x = x[np.newaxis, np.newaxis, :]
        y = y[np.newaxis, :, np.newaxis]
        del2v_value[0] = del2(f[0], dx, dy, dz, x=x, y=y, coordinate_system='spherical') \
                         - 2*f[0]/x**2 - 2*yder(f[1], dy)/x**2 - 2*np.cos(y)*f[1]/(x**2*np.sin(y)) - 2*zder(f[2], dz)/(x**2*np.sin(y))
        del2v_value[1] = del2(f[1], dx, dy, dz, x=x, y=y, coordinate_system='spherical') \
                         - f[1]/(x*np.sin(y))**2 + 2*yder(f[0], dy)/(x**2) - (2*np.cos(y))*zder(f[2], dz)/(x*np.sin(y))**2
        del2v_value[2] = del2(f[2], dx, dy, dz, x=x, y=y, coordinate_system='spherical') \
                         - f[2]/(x*np.sin(y))**2 + 2*zder(f[0], dz)/(np.sin(y)*x**2) - (2*np.cos(y))*zder(f[1], dz)/(x*np.sin(y))**2
    return del2v_value
Esempio n. 7
0
def curl2(f, dx, dy, dz, x=None, y=None, coordinate_system='cartesian'):
    """
    Take the double curl of a pencil code vector array f.

    *x, y*:
      Radial (x) and polar (y) coordinates, 1d arrays.

    *run2D*:
      Deals with pure 2-D snapshots (solved the (x,z)-plane pb).
      !Only for Cartesian grids at the moment!

    *coordinate_system*:
      Coordinate system under which to take the divergence.
      Takes 'cartesian', 'cylindrical' and 'spherical'.
    """

    import numpy as np
    from pencil.math.derivatives.der import xder, yder, zder, xder2, yder2, zder2

    if (f.ndim != 4 or f.shape[0] != 3):
        print("curl2: must have vector 4-D array f[3, mz, my, mx] for curl2.")
        raise ValueError

    curl2_value = np.zeros(f.shape)

    if coordinate_system == 'cartesian':
        curl2_value[0] = xder(yder(f[1], dy) + zder(f[2], dz), dx) \
                              -yder2(f[0], dy) - zder2(f[0], dz)
        curl2_value[1] = yder(xder(f[0], dx) + zder(f[2], dz), dy) \
                              -xder2(f[1], dx) - zder2(f[1], dz)
        curl2_value[2] = zder(xder(f[0], dx) + yder(f[1], dy), dz) \
                              -xder2(f[2], dx) - yder2(f[2], dy)
    if coordinate_system == 'cylindrical':
        if x is None:
            print(
                'ERROR: need to specify x (radius) for cylindrical coordinates.'
            )
            raise ValueError
        # Make sure x has compatible dimensions.
        x = x[np.newaxis, np.newaxis, :]
        curl2_value[0] = yder(f[1], dy)/x**2 + xder(yder(f[1], dy), dx)/x \
                         - yder2(f[0], dy)/x**2 - zder2(f[0], dz) + xder(zder(f[2], dz), dx)
        curl2_value[1] = yder(zder(f[2], dz), dy)/x - zder2(f[1], dz) + f[1]/x**2 \
                         - xder(f[1], dx)/x - xder2(f[1], dx) + xder(yder(f[0], dy), dx)/x \
                         - yder(f[0], dy)/x**2
        curl2_value[2] = zder(f[0], dz)/x + xder(zder(f[0], dz), dx) - zder(f[2], dx)/x \
                         - xder2(f[2], dx) - yder2(f[2], dy)/x**2 + yder(zder(f[1], dz), dy)/x
    if coordinate_system == 'spherical':
        if x is None or y is None:
            print(
                'ERROR: need to specify x (radius) and y (polar angle) for spherical coordinates.'
            )
            raise ValueError
        # Make sure x and y have compatible dimensions.
        x = x[np.newaxis, np.newaxis, :]
        y = y[np.newaxis, :, np.newaxis]
        curl2_value[0] = (yder(
            np.sin(y) * (xder(x * f[1], dx) - yder(f[0], dy)) / x, dy) - zder(
                (zder(f[0], dz) / np.sin(y) - xder(x * f[2], dx)) / x, dz)) / (
                    x * np.sin(y))
        curl2_value[1] = (zder(
            (yder(np.sin(y) * f[2], dy) - zder(f[1], dz)) /
            (x * np.sin(y)), dz) / np.sin(y) - xder(
                (xder(x * f[1], dx) - yder(f[0], dy)), dx)) / x
        curl2_value[2] = (xder(
            (zder(f[0], dz) / np.sin(y) - xder(x * f[2], dx)), dx) - yder(
                (yder(np.sin(y) * f[2], dy) - zder(f[1], dz)) /
                (x * np.sin(y)), dy)) / x
    return curl2_value
Esempio n. 8
0
def curl(f,
         dx,
         dy,
         dz,
         x=None,
         y=None,
         run2D=False,
         coordinate_system='cartesian'):
    """
    Take the curl of a pencil code vector array f in various coordinate systems.

    Keyword arguments:

    *f*:
      Pencil code scalar array f.

    *dx, dy, dz*:
      Grid spacing in the three dimensions.

    *x, y*:
      Radial (x) and polar (y) coordinates, 1d arrays.

    *run2D*:
      Deals with pure 2-D snapshots (solved the (x,z)-plane pb).
      !Only for Cartesian grids at the moment!

    *coordinate_system*:
      Coordinate system under which to take the divergence.
      Takes 'cartesian', 'cylindrical' and 'spherical'.
      !Does not work for 2d runs yet!
    """

    import numpy as np
    from pencil.math.derivatives.der import xder, yder, zder

    if f.shape[0] != 3:
        print("curl: must have vector 4-D array f[3, mz, my, mx] for curl.")
        raise ValueError

    curl_value = np.zeros_like(f)

    if (dy != 0. and dz != 0.):
        # 3-D case
        if coordinate_system == 'cartesian':
            curl_value[0] = yder(f[2], dy) - zder(f[1], dz)
            curl_value[1] = zder(f[0], dz) - xder(f[2], dx)
            curl_value[2] = xder(f[1], dx) - yder(f[0], dy)
        if coordinate_system == 'cylindrical':
            if x is None:
                print(
                    'ERROR: need to specify x (radius) for cylindrical coordinates.'
                )
                raise ValueError
            # Make sure x has compatible dimensions.
            x = x[np.newaxis, np.newaxis, :]
            curl_value[0] = (1 / x) * yder(f[2], dy) - zder(f[1], dz)
            curl_value[1] = zder(f[0], dz) - xder(f[2], dx)
            curl_value[2] = (1 / x) * xder(x * f[1], dx) - (1 / x) * yder(
                f[0], dy)
        if coordinate_system == 'spherical':
            if (x is None) or (y is None):
                print(
                    'ERROR: need to specify x (radius) and y (polar angle) for spherical coordinates.'
                )
                raise ValueError
            # Make sure x and y have compatible dimensions.
            x = x[np.newaxis, np.newaxis, :]
            y = y[np.newaxis, :, np.newaxis]
            curl_value[0] = (yder(np.sin(y) * f[2], dy) -
                             zder(f[1], dz)) / (x * np.sin(y))
            curl_value[1] = (zder(f[0], dz) / np.sin(y) -
                             xder(x * f[2], dx)) / x
            curl_value[2] = (xder(x * f[1], dx) - yder(f[0], dy)) / x
    elif dy == 0.:
        # 2-D case in the xz-plane
        curl_value[0] = zder(f, dz, run2D)[0] - xder(f, dx)[2]
    else:
        # 2-D case in the xy-plane
        curl_value[0] = xder(f, dx)[1] - yder(f, dy)[0]

    return curl_value
Esempio n. 9
0
def curl3(f, dx, dy, dz, x=None, y=None, coordinate_system="cartesian"):
    """
    curl3(f, dx, dy, dz, x=None, y=None, coordinate_system="cartesian")

    Take the triple curl of a pencil code vector array f.

    Parameters
    ----------
    x, y : ndarrays
        Radial (x) and polar (y) coordinates, 1d arrays.

    run2D : bool
        Deals with pure 2-D snapshots (solved the (x,z)-plane pb).
        !Only for Cartesian grids at the moment!

    coordinate_system : string
        Coordinate system under which to take the divergence.
        Takes 'cartesian' and 'cylindrical'.
    """

    import numpy as np
    from pencil.math.derivatives.der import (
        xder,
        yder,
        zder,
        xder2,
        yder2,
        zder2,
        xder3,
        yder3,
        zder3,
    )

    if f.ndim != 4 or f.shape[0] != 3:
        print("curl3: must have vector 4-D array f[3, mz, my, mx] for curl3.")
        raise ValueError

    curl3_value = np.zeros(f.shape)

    if coordinate_system == "cartesian":
        curl3_value[0] = (zder(xder2(f[1], dx) + yder2(f[1], dy), dz) +
                          zder3(f[1], dz) -
                          yder(xder2(f[2], dx) + zder2(f[2], dz), dy) -
                          yder3(f[2], dy))
        curl3_value[1] = (xder3(f[2], dx) +
                          xder(yder2(f[2], dy) + zder2(f[2], dz), dx) -
                          zder(xder2(f[0], dx) + yder2(f[0], dy), dz) -
                          zder3(f[0], dz))
        curl3_value[2] = (yder(xder2(f[0], dx) + zder2(f[0], dz), dy) +
                          yder3(f[0], dy) - xder3(f[1], dx) -
                          xder(yder2(f[1], dy) + zder2(f[1], dz), dx))
    if coordinate_system == "cylindrical":
        if x is None:
            print(
                "ERROR: need to specify x (radius) for cylindrical coordinates."
            )
            raise ValueError
        # Make sure x has compatible dimensions.
        x = x[np.newaxis, np.newaxis, :]
        curl3_value[0] = (2 * yder(zder(f[0], dz), dy) / x**2 -
                          yder(zder(f[2], dz), dy) / x**2 -
                          xder2(yder(f[2], dy), dx) / x -
                          yder3(f[2], dy) / x**3 +
                          yder2(zder(f[1], dz), dy) / x**2 -
                          yder(zder2(f[2], dz), dy) / x + zder3(f[1], dz) -
                          zder(f[1], dz) / x**2 +
                          xder(zder(f[1], dz), dx) / x +
                          xder2(zder(f[1], dz), dx))
        curl3_value[1] = (2 * yder(zder(f[1], dz), dy) / x**2 -
                          yder2(zder(f[0], dz), dy) / x**2 - zder3(f[0], dz) +
                          xder(zder2(f[2], dz), dx) -
                          xder(zder(f[0], dz), dx) / x +
                          zder(f[0], dz) / x**2 - xder2(zder(f[0], dz), dx) +
                          xder(zder(f[2], dz), dx) / x -
                          zder(f[2], dz) / x**2 + xder3(f[2], dx) +
                          xder(yder2(f[2], dy), dx) / x**2 -
                          2 * yder2(f[2], dy) / x**3)
        curl3_value[2] = (-xder(zder2(f[1], dz), dx) - zder2(f[1], dz) / x +
                          xder(f[1], dx) / x**2 - f[1] / x**3 -
                          xder3(f[1], dx) + xder2(yder(f[0], dy), dx) / x -
                          xder(yder(f[0], dy), dx) / x**2 +
                          yder(f[0], dy) / x**3 - yder2(f[1], dy) / x**3 -
                          xder(yder2(f[1], dy), dx) / x**2 +
                          yder3(f[0], dy) / x**3 +
                          yder(zder2(f[0], dz), dy) / x -
                          2 * xder2(f[1], dx) / x)
    if coordinate_system == "spherical":
        if x is None or y is None:
            print(
                "ERROR: need to specify x (radius) and y (polar angle) for spherical coordinates"
            )
            raise ValueError
        # Make sure x and y have compatible dimensions.
        x = x[np.newaxis, np.newaxis, :]
        y = y[np.newaxis, :, np.newaxis]
        # TODO: This one needs some fixing.
        curl3_value[0] = (-1 / x**3) * (np.sin(y) * (
            (np.cos(y)**2 - 1) * (yder2(zder(f[1], dz), dy)) +
            (-np.cos(y)**2 * np.sin(y) + np.sin(y)) *
            (yder3(f[2], dy)) - x**2 *
            (xder2(zder(f[1], dz), dx)) - zder3(f[1], dz) + np.sin(y) *
            (xder2(yder(f[2], dy), dx)) * x**2 +
            (yder(zder2(f[2], dz), dy)) * np.sin(y) +
            (-6 * np.cos(y)**3 + 6 * np.cos(y)) * (yder2(f[2], dy)) - 2 * x *
            (xder(zder(f[1], dz), dx)) - 3 * np.sin(y) * np.cos(y) *
            (yder(zder(f[1], dz), dy)) + np.cos(y) *
            (xder2(f[2], dx)) * x**2 + 2 * np.sin(y) *
            (xder(yder(f[2], dy), dx)) * x + (zder2(f[2], dz)) * np.cos(y) +
            (-2 * np.cos(y)**2 + 1) * (zder(f[1], dz)) +
            (11 * np.cos(y)**2 * np.sin(y) - 4 * np.sin(y)) *
            (yder(f[2], dy)) + 2 * np.cos(y) * (xder(f[2], dx)) * x +
            (6 * np.cos(y)**3 - 5 * np.cos(y)) * f[2]))
        curl3_value[1] = (1 / (x**3 * np.sin(y)) * (
            (np.cos(y)**2 - 1) * (yder2(zder(f[0], dz), dy)) +
            (-x * np.cos(y)**2 + x) * np.sin(y) * (xder(yder2(f[2], dy), dx)) -
            (xder2(zder(f[0], dz), dx)) * x**2 - zder3(f[0], dz) + x**3 *
            (xder3(f[2], dx)) * np.sin(y) + x *
            (xder(zder2(f[2], dz), dx)) * np.sin(y) + (-2 * np.cos(y)**2 + 2) *
            (yder(zder(f[1], dz), dy)) + 3 * x**2 * xder2(f[2], dx) * np.sin(y)
            + zder2(f[2], dz) * np.sin(y) +
            (2 * x * np.cos(y)**2 - x) * np.sin(y) * (xder(f[2], dx)) +
            (3 * np.cos(y)**3 - 3 * np.cos(y)) *
            (yder(f[2], dy)) + 2 * np.sin(y) * np.cos(y) * (zder(f[1], dz)) +
            (-2 * np.cos(y)**2 + 1) * np.sin(y) * f[2]))
        curl3_value[2] = (1 / x**3 * (
            (yder3(f[0], dy)) * (1 - np.cos(y)**2) + (x * np.cos(y)**2 - x) *
            (xder(yder2(f[1], dy), dx)) +
            (xder2(yder(f[1], dy), dx)) * x**2 + yder(zder2(f[0], dz), dy) -
            (xder3(f[1], dx)) * x**3 - (xder(zder2(f[1], dz), dx)) * x +
            (np.cos(y)**2 - 1) * (yder2(f[1], dy)) + 3 *
            (yder2(f[1], dy)) * np.sin(y) * np.cos(y) - 3 *
            (xder2(f[1], dx)) * x**2 - 3 *
            (xder(yder(f[1], dy), dx)) * np.sin(y) * np.cos(y) * x +
            zder2(f[1], dz) - 2 * (yder(zder(f[2], dz), dy)) * np.sin(y) +
            (2 * np.cos(y)**2 - 1) * (yder(f[1], dy)) +
            (-2 * np.cos(y)**2 + x) * (xder(f[1], dx)) - 3 *
            (yder(f[1], dy)) * np.sin(y) * np.cos(y) - 2 *
            (zder(f[2], dz)) * np.cos(y) + (-2 * np.cos(y)**2 + 1) * f[1]))
    return curl3_value