Source code for fluidsim.solvers.models0d.lorenz.solver

"""Lorenz model solver (:mod:`fluidsim.solvers.models0d.lorenz.solver`)
=======================================================================

This module provides classes to solve the Lorenz model.

.. autoclass:: InfoSolverLorenz
   :members:
   :private-members:

.. autoclass:: Simul
   :members:
   :private-members:

.. autoclass:: StateLorenz
   :members:
   :private-members:

"""

from math import sqrt

from fluidsim.base.setofvariables import SetOfVariables

from fluidsim.base.solvers.base import InfoSolverBase, SimulBase
from fluidsim.base.state import StateBase


[docs] class StateLorenz(StateBase):
[docs] @staticmethod def _complete_info_solver(info_solver): """Complete the `info_solver` container (static method).""" keys = ["X", "Y", "Z"] info_solver.classes.State._set_attribs( { "keys_state_phys": keys, "keys_computable": [], "keys_phys_needed": keys, "keys_linear_eigenmodes": keys, } )
[docs] class InfoSolverLorenz(InfoSolverBase): """Contain the information on the solver predaprey.""" def _init_root(self): super()._init_root() package = "fluidsim.solvers.models0d.lorenz" self.module_name = package + ".solver" self.class_name = "Simul" self.short_name = "lorenz" classes = self.classes classes.State.module_name = package + ".solver" classes.State.class_name = "StateLorenz" classes.Output.module_name = package + ".output" classes.Output.class_name = "Output"
[docs] class Simul(SimulBase): """Solve the Lorenz equations.""" InfoSolver = InfoSolverLorenz
[docs] @staticmethod def _complete_params_with_default(params): """Complete the `params` container (static method).""" SimulBase._complete_params_with_default(params) attribs = {"sigma": 10.0, "beta": 8.0 / 3, "rho": 28.0} params._set_attribs(attribs)
def __init__(self, *args, **kargs): super().__init__(*args, **kargs) p = self.params Zs = self.Zs0 = self.Zs1 = p.rho - 1 self.Xs0 = self.Ys0 = sqrt(p.beta * Zs) self.Xs1 = self.Ys1 = -self.Xs0
[docs] def tendencies_nonlin(self, state=None, old=None): r"""Compute the nonlinear tendencies. Parameters ---------- state : :class:`fluidsim.base.setofvariables.SetOfVariables` optional Array containing the state. If `state is not None`, the variables are computed from it, otherwise, they are taken from the global state of the simulation, `self.state`. These two possibilities are used during the Runge-Kutta time-stepping. Returns ------- tendencies : :class:`fluidsim.base.setofvariables.SetOfVariables` An array containing the tendencies for the variables. Notes ----- The Lotka-Volterra equations can be written .. math:: \dot X = \sigma (Y - X), \dot Y = \rho X - Y - XZ. \dot Z = X Y - \beta Z. """ p = self.params if state is None: state = self.state.state_phys X = state.get_var("X") Y = state.get_var("Y") Z = state.get_var("Z") if old is None: tendencies = SetOfVariables(like=self.state.state_phys) else: tendencies = old tendencies.set_var("X", p.sigma * (Y - X)) tendencies.set_var("Y", p.rho * X - Y - X * Z) tendencies.set_var("Z", X * Y - p.beta * Z) if self.params.forcing.enable: # TODO: Not implemented, but would be nice to study small perturbations # cf: Vallis 2nd edition 11.4 tendencies += self.forcing.get_forcing() return tendencies
if __name__ == "__main__": import fluiddyn as fld params = Simul.create_default_params() params.time_stepping.deltat0 = 0.02 params.time_stepping.t_end = 40 params.output.periods_print.print_stdout = 0.01 sim = Simul(params) sim.state.state_phys.set_var("X", sim.Xs0 + 2.0) sim.state.state_phys.set_var("Y", sim.Ys0) sim.state.state_phys.set_var("Z", sim.Zs0) # sim.output.print_stdout.plot_XYZ() sim.time_stepping.start() fld.show()