:py:mod:`pyloggrid.LogGrid.Grid` ================================ .. py:module:: pyloggrid.LogGrid.Grid .. autoapi-nested-parse:: Class that directly handles the log grid & related maths Module Contents --------------- Classes ~~~~~~~ .. autoapisummary:: pyloggrid.LogGrid.Grid.Grid pyloggrid.LogGrid.Grid.Maths pyloggrid.LogGrid.Grid.Physics Functions ~~~~~~~~~ .. autoapisummary:: pyloggrid.LogGrid.Grid._setup_convolver_c .. py:function:: _setup_convolver_c(convolver_c) -> None Setup the imported C function. Important to avoid segfaults. We keep the convolver as an argument to allow importing this function elsewhere .. py:class:: Grid(D: int, l_params: dict[str, Union[float, bool]], N_points: int, fields_name: list[str], k_min: float = None, k0: bool = False, n_threads: int = None) Main class that handles the log grid .. py:method:: init_fields() -> None Creates the arrays corresponding to the field names .. py:method:: get_l_from_params() -> float Sets the grid spacing from the grid's parameters. :returns: the grid spacing See :class:`pyoggrid.LogGrid.Framework.Solver` for more information. Reference: Campolina & Mailybaev 2020, *Fluid dynamics on logarithmic lattices* .. py:method:: generate_points(k_min: float) -> tuple[numpy.ndarray, numpy.ndarray, numpy.ndarray, numpy.ndarray] Create the grid's wavevector arrays :param k_min: the minimum wavevector :returns: (array of wave vectors along X axis ``[N,]``, logmean of array of wave vectors along X axis [N,], array of wave vectors ``[D, N, (2N, 2N)]``, array of wave vector modulus ``[N, (2N, 2N)]``) .. py:method:: load_fields(fields: dict[str, numpy.ndarray]) -> Grid Load fields from a grid of another dimension. If the new grid is smaller, discard outer fields. If bigger, set new fields to 0. :param fields: fields from the previous grid. fields names must correspond for both grids, as well as ``k_min``. .. py:method:: enforce_grid_symmetry() -> None Force the ``f(-k)=f(k).conj`` symmetries along 0 axes for all fields .. py:method:: field(*args) -> list[numpy.ndarray] | numpy.ndarray get fields by name .. py:method:: to_new_size(fields: dict) -> Grid return a new grid with the same parameters as this one but a new size :param fields: the new fields .. py:method:: to_new_size_empty(N_points: int) -> Grid return a new grid with the same parameters as this one but a new size, empty :param N_points: the new size .. py:class:: Maths(grid: Grid, n_threads: int = 0) Functions to perform maths on log grids .. attribute:: convolve_batch Convolve a list of convolutions at once. More efficient that calling :func:`convolve` several times. Use as ``convolve_batch([(f0,g0), (f1,g1), ...])`` :type: Callable .. py:property:: dx :type: numpy.ndarray x-derivative .. py:property:: dy :type: numpy.ndarray y-derivative .. py:property:: dz :type: numpy.ndarray z-derivative .. py:property:: d2x :type: numpy.ndarray 2nd x-derivative .. py:property:: d2y :type: numpy.ndarray 2nd y-derivative .. py:property:: d2z :type: numpy.ndarray 2nd z-derivative .. py:property:: rot2D_inv :type: numpy.ndarray Inverse rotational for 2D fields, *assuming div = 0* .. py:property:: laplacian :type: numpy.ndarray laplacian .. py:property:: laplacian_inv :type: numpy.ndarray inverse laplacian .. py:attribute:: cached_conv_kernel .. py:method:: generate_convolution_kernel() -> tuple[numpy.ndarray, numpy.ndarray, numpy.ndarray, numpy.ndarray, numpy.ndarray, numpy.ndarray] Generate the convolution kernel (who interacts with who) for log grid convolutions :returns: (kernel offsets, kernel signs) | signs are used to determine when to take the complex conjugate (+1 = normal, -1 = conjugate) .. py:method:: convolve(f: numpy.ndarray, g: numpy.ndarray) -> numpy.ndarray Convolve the two arrays. :returns: the convolved array .. py:method:: _convolve_batch_V_inner(fgs: list[tuple[numpy.ndarray, numpy.ndarray]], V: int) -> numpy.ndarray Inner function for <_convolve_batch_V>. Convolves in batch V couples, calling the corresponding ``convolve_list_batch_V`` function in C. .. py:method:: _convolve_batch_V(fgs: list[tuple[numpy.ndarray, numpy.ndarray]]) -> numpy.ndarray from couples ``((f0, g0), (f1, g1), ...)``, computes their convolution :returns: the convolved arrays ``f0*g0``, ``f1*g1``, etc. .. py:method:: _convolve_batch_list_slower(fgs: list[tuple[numpy.ndarray, numpy.ndarray]]) -> numpy.ndarray from couples ``((f0, g0), (f1, g1), ...)``, computes their convolution using batched OMP-supported convolutions :returns: the convolved arrays ``f0*g0``, ``f1*g1``, etc. .. py:method:: _convolve_batch_list(fgs: list[tuple[numpy.ndarray, numpy.ndarray]]) -> Iterable[numpy.ndarray] from couples ``((f0, g0), (f1, g1), ...)``, computes their convolution :returns: the convolved arrays ``f0*g0``, ``f1*g1``, etc. .. py:method:: cross2D(a: numpy._typing.ArrayLike, b: numpy._typing.ArrayLike) -> numpy.ndarray :staticmethod: 2D cross product .. py:method:: cross3D(a: numpy._typing.ArrayLike, b: numpy._typing.ArrayLike) -> numpy.ndarray :staticmethod: 3D cross product .. py:method:: rot2D(a: numpy._typing.ArrayLike) -> numpy.ndarray 2D rotational .. py:method:: rot3D(a: numpy._typing.ArrayLike) -> numpy.ndarray 3D rotational .. py:method:: rot3D_inv(a: numpy._typing.ArrayLike) -> numpy.ndarray Inverse rotational for 3D fields, *assuming div = 0* .. py:method:: inv(f: numpy._typing.ArrayLike) -> numpy.ndarray :staticmethod: Inverse of a linear operator. it's assumed that where the operator is zero, the function to invert will also be zero .. py:method:: div3D(a: numpy._typing.ArrayLike) -> numpy.ndarray 3D divergence .. py:method:: div2D(a: numpy._typing.ArrayLike) -> numpy.ndarray 2D divergence .. py:method:: inner_product(f: numpy._typing.ArrayLike, g: numpy._typing.ArrayLike) -> float Log grid inner product .. py:method:: self_inner_product(f: numpy._typing.ArrayLike) -> float inner product applied on oneself .. py:method:: P_projector(A: numpy._typing.ArrayLike) -> numpy.ndarray Turns ``dUdt = A - gradP`` into ``dUdt = A'`` :param A: ``dUdt`` without the pressure term :returns: ``A'`` .. py:method:: enforce_grid_symmetry_arr(arr: numpy._typing.ArrayLike) -> numpy.ndarray Force the ``f(-k)=f(k).conj`` symmetries along ``k=0`` axes. Modifies the array in-place .. py:method:: enforce_grid_symmetry_dict(fields: dict) -> dict forces symmetry for all fields of dict, in-place .. py:class:: Physics(grid: Grid) Computes a few classical physical properties .. py:method:: enstrophy() -> float enstrophy Ω=ω²/2 .. py:method:: energy() -> float kinetic energy E=u²/2 .. py:method:: helicity() -> complex helicity H=u*ω .. py:method:: spectrum(fun: Callable[[dict[str, numpy.ndarray], numpy.ndarray], numpy.ndarray]) -> numpy.ndarray Spectrum for the quantity calculated by the callback Callback takes two args: ``fields`` and ``ks``. The first one is ``grid.fields``. The second one is a grid-shaped bool array corresponding to concerned ``ks``. The callback should return a summable np.ndarray ``[observable(k) for k in ks]``. Ex kinetic energy 2D: ``fun(fields, ks) = ux[k]*conj(ux[k]) + uy[k]*conj(uy[k])`` :returns: np.ndarray of the spectrum along each point of grid.ks_1D TODO update utest .. py:method:: cumulative_k(fun: Callable[[dict[str, numpy.ndarray], numpy.ndarray], numpy.ndarray]) -> numpy.ndarray Compute the cumulative quantity between wave number 0 and k, defined by the sum over \|k'| < k of that quantity TODO add utest .. py:method:: compute_by_shell(fun: Callable[[dict[str, numpy.ndarray], numpy.ndarray], numpy.ndarray], normalize: bool = False) -> numpy.ndarray Structure function for the quantity calculated by the callback Callback takes two args: ``fields`` and ``ks``. The first one is ``grid.fields``. The second one is a grid-shaped bool array corresponding to concerned ``ks``. The callback should return a summable np.ndarray ``[observable(k) for k in ks]``. Ex kinetic energy 2D: ``fun(fields, ks) = ux[k]*conj(ux[k]) + uy[k]*conj(uy[k])`` :param fun: the function to compute :param normalize: if True, normalize the result on each shell :returns: np.ndarray of the structure function along each point of grid.ks_1D TODO: add utest