Source code for fluidsim.base.forcing.kolmogorov

"""Kolmogorov flow (:mod:`fluidsim.base.forcing.kolmogorov`)
============================================================

.. autoclass:: KolmogorovFlow
   :members:
   :private-members:

.. autoclass:: KolmogorovFlowNormalized
   :members:
   :private-members:

"""

from warnings import warn

import numpy as np

from fluiddyn.util import mpi

from fluidsim_core.extend_simul import SimulExtender, extend_simul_class

from fluidsim.base.forcing.specific import (
    SpecificForcingPseudoSpectralSimple,
    NormalizedForcing,
)

__all__ = ["extend_simul_class", "KolmogorovFlow", "KolmogorovFlowNormalized"]


class _KolmogorovFlowBase(SimulExtender):
    _module_name = "fluidsim.base.forcing.kolmogorov"
    tag = "kolmogorov_flow"

    @classmethod
    def get_modif_info_solver(cls):
        def modif_info_solver(info_solver):
            info_solver.classes.Forcing.classes._set_child(
                cls.tag,
                attribs={
                    "module_name": cls._module_name,
                    "class_name": cls.__name__,
                },
            )

        return modif_info_solver

    @classmethod
    def complete_params_with_default(cls, params):
        params.forcing.available_types.append(cls.tag)
        if not hasattr(params.forcing, "kolmo"):
            params.forcing._set_child(
                "kolmo",
                attribs={"ik": 3, "amplitude": None, "letter_gradient": None},
            )

    def __init__(self, sim):
        if len(sim.oper.axes) == 3:
            self._key_forced_default = "vx_fft"
        else:
            self._key_forced_default = "ux_fft"

        super().__init__(sim)

        if self.tag == "kolmogorov_flow_normalized" and mpi.rank > 0:
            return

        params = sim.params

        ik = params.forcing.kolmo.ik
        amplitude = params.forcing.kolmo.amplitude

        if self.tag == "kolmogorov_flow_normalized" and amplitude is not None:
            warn(
                "For this forcing type ('kolmogorov_flow_normalized'), "
                "the parameter `params.forcing.kolmo.amplitude` has no effect. "
                "The amplitude is controlled with `params.forcing.forcing_rate`."
            )

        if amplitude is None:
            amplitude = 1.0

        key_forced = params.forcing.key_forced
        letter_gradient = params.forcing.kolmo.letter_gradient

        oper = self._get_oper()

        if len(oper.axes) == 3:
            coords = oper.get_XYZ_loc()
            lengths = [params.oper.Lx, params.oper.Ly, params.oper.Lz]
            letters = "xyz"
            if key_forced is None:
                key_forced = "vx"
        else:
            coords = [oper.X, oper.Y]
            lengths = [params.oper.Lx, params.oper.Ly]
            letters = "xy"
            if key_forced is None:
                key_forced = "ux"

        if key_forced.endswith("_fft"):
            key_forced = key_forced[: -len("_fft")]

        if letter_gradient is None:
            letter_gradient = letters[-1]

        if letter_gradient not in letters:
            raise ValueError

        index = letters.index(letter_gradient)
        variable = coords[index]
        length = lengths[index]

        self._init_forcing(key_forced, amplitude, ik, length, variable)

    def _get_oper(self):
        raise NotImplementedError

    def _init_forcing(self, key_forced, amplitude, ik, length, variable):
        raise NotImplementedError


[docs] class KolmogorovFlow(_KolmogorovFlowBase, SpecificForcingPseudoSpectralSimple): """Kolmogorov flow forcing This forcing can be used with solvers based on ns2d or ns3d. By default, the flow is forced along the x axis with a gradient along the z axis for 3D solvers and the y axis for the 2D solvers. Examples -------- .. code-block:: python from fluidsim.solvers.ns3d.solver import Simul as SimulNotExtended from fluidsim.base.forcing.kolmogorov import extend_simul_class, KolmogorovFlow Simul = extend_simul_class(SimulNotExtended, KolmogorovFlow) params = Simul.create_default_params() params.forcing.enable = True params.forcing.type = "kolmogorov_flow" The parameters can be modified as follow: .. code-block:: python params.forcing.kolmo.ik = 3 params.forcing.kolmo.amplitude = 2.0 params.forcing.key_forced = "ux_fft" params.forcing.kolmo.letter_gradient = "y" """ def _get_oper(self): return self.sim.oper def _init_forcing(self, key_forced, amplitude, ik, length, variable): self.fstate.init_statephys_from( **{key_forced: amplitude * np.sin(2 * np.pi * ik / length * variable)} ) self.fstate.statespect_from_statephys()
[docs] def compute(self): # nothing to do here pass
[docs] class KolmogorovFlowNormalized(_KolmogorovFlowBase, NormalizedForcing): """Kolmogorov flow forcing with constant energy injection rate This forcing can be used with solvers based on ns2d or ns3d. By default, the flow is forced along the x axis with a gradient along the z axis for 3D solvers and the y axis for the 2D solvers. Examples -------- .. code-block:: python from fluidsim.solvers.ns3d.solver import Simul as SimulNotExtended from fluidsim.base.forcing.kolmogorov import extend_simul_class, KolmogorovFlowNormalized Simul = extend_simul_class(SimulNotExtended, KolmogorovFlowNormalized) params = Simul.create_default_params() params.forcing.enable = True params.forcing.type = "kolmogorov_flow_normalized" The parameters can be modified as follow: .. code-block:: python params.forcing.kolmo.ik = 3 params.forcing.forcing_rate = 10.0 Note that ``params.forcing.kolmo.amplitude`` has no effect for this forcing type. """ tag = "kolmogorov_flow_normalized" def _get_oper(self): return self.oper_coarse def _init_forcing(self, key_forced, amplitude, ik, length, variable): del key_forced field = amplitude * np.sin(2 * np.pi * ik / length * variable) self._f_fft = self.oper_coarse.fft(field) def forcingc_raw_each_time(self, _): # nothing to do here return self._f_fft