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
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
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
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
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
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