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

"""Predator-prey solver (:mod:`fluidsim.solvers.models0d.predaprey.solver`)
===========================================================================

This module provides classes to solve the Lotka-Volterra equations.

.. autoclass:: InfoSolverPredaPrey
   :members:
   :private-members:

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

.. autoclass:: StatePredaPrey
   :members:
   :private-members:

"""

from fluidsim.base.setofvariables import SetOfVariables

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


[docs] class StatePredaPrey(StateBase):
[docs] @staticmethod def _complete_info_solver(info_solver): """Complete the `info_solver` container (static method).""" info_solver.classes.State._set_attribs( { "keys_state_phys": ["X", "Y"], "keys_computable": [], "keys_phys_needed": ["X", "Y"], "keys_linear_eigenmodes": ["X", "Y"], } )
[docs] class InfoSolverPredaPrey(InfoSolverBase): """Contain the information on the solver predaprey.""" def _init_root(self): super()._init_root() package = "fluidsim.solvers.models0d.predaprey" self.module_name = package + ".solver" self.class_name = "Simul" self.short_name = "predaprey" classes = self.classes classes.State.module_name = package + ".solver" classes.State.class_name = "StatePredaPrey" classes.Output.module_name = package + ".output" classes.Output.class_name = "Output"
[docs] class Simul(SimulBase): """Solve the Lotka-Volterra equations.""" InfoSolver = InfoSolverPredaPrey
[docs] @staticmethod def _complete_params_with_default(params): """Complete the `params` container (static method).""" SimulBase._complete_params_with_default(params) attribs = {"A": 1.0, "B": 1.0, "C": 1.0, "D": 0.5} params._set_attribs(attribs)
def __init__(self, *args, **kargs): super().__init__(*args, **kargs) p = self.params self.Xs = p.C / p.D self.Ys = p.A / p.B
[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 = AX - B XY, \dot Y = -CY + D XY. """ p = self.params if state is None: state = self.state.state_phys X = state.get_var("X") Y = state.get_var("Y") if old is None: tendencies = SetOfVariables(like=self.state.state_phys) else: tendencies = old tendencies.set_var("X", p.A * X - p.B * X * Y) tendencies.set_var("Y", -p.C * Y + p.D * X * Y) if self.params.forcing.enable: tendencies += self.forcing.get_forcing() return tendencies
if __name__ == "__main__": import fluiddyn as fld params = Simul.create_default_params() params.time_stepping.deltat0 = 0.1 params.time_stepping.t_end = 20 params.output.periods_print.print_stdout = 0.01 sim = Simul(params) sim.state.state_phys.set_var("X", 2) sim.state.state_phys.set_var("Y", 1.1) # sim.output.phys_fields.plot() sim.time_stepping.start() fld.show()