# Notebook d'aide/correction pour la séance EPU MAM4 Biomaths (suite 3)
*séance du 22/03/2021*
*séance du 21/03/2022*
*Ludovic Mailleret, Mars 2021*
*Ludovic Mailleret, Mars 2022*
## Populations en interaction : le modèle proies-prédateurs de Lotka et Volterra
### Dynamiques et plan de phase
Nous considérons le modèle de dynamique de populations (classique) de Lotka et Volterra
$$
\left\{\begin{array}{l}
\dot x = rx - c xy\\
\dot y = bxy - m y
\end{array}\right.
$$
Il n'y a pas de difficulté particulière à la simulation par rapport au modèle de la tordeuxe du bourgeon de l'épinette avec population d'oiseaux variables.
%% Cell type:code id: tags:
``` python
# on nettoie l'espace de travail et on reload les modules
%reset -f
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint
# script de simulation
# densités initiales des populations
x0 = 1
y0 = 2.5
# encapsulation de la densité initiale
etat0_LV = np.array([x0, y0])
# définition d'un vecteur tspan pour tracer E_varie()
t_0 = 0 # temps initial
t_fin = 30.0 # temps final, ici on prend un temps final long pour observer les dynamiques lentes
pas_t = 0.01 # pas de temps de récupération des variables entre t_0 et t_fin
Il est intéressant aussi de représenter les trajectoires dans l'espace d'état $(x,y)$, en combinaison avec une analyse qualitative du plan de phase (isoclines nulles, équilibres), une représentation du champs de vecteurs et de quelques morceaux de trajectoires sur le plan.
Commençons par calculer les isoclines nulles et les équilibres.
%% Cell type:code id: tags:
``` python
# array annexes pour le calcul et la représentation des isoclines nulles
xplot = np.arange(0, 3, .1)
yplot = np.arange(0, 3, .1)
# isoclines nulles de xdot
null_x_x = np.zeros_like(yplot) # x = 0 isocline nulle de xdot
null_x_y = np.ones_like(xplot)*(r/c) # y = r/c isocline nulle de xdot
# isoclines nulles de ydot
null_y_y = np.zeros_like(xplot) # y = 0 isocline nulle de ydot
null_y_x = np.ones_like(yplot)*(m/b) # x = m/b isocline nulle de ydot
# équilibres
eq_extinct = [0, 0]
eq_coex = [r/c, m/b]
```
%% Cell type:markdown id: tags:
Puis on commence à tracer le plan de phase:
%% Cell type:code id: tags:
``` python
# création d'une figure, et d'un système d'axe
fig2, ax2 = plt.subplots(1, 1, figsize=(14, 8))
# titre de la figure
fig2.suptitle("Dynamiques Proies - Prédateurs\n modèle de Lotka Volterra", va='top', fontsize='18')
# tracé des isoclines nulles, des équilibres, et de la trajectoire simulée
# isoclines nulles de x
ax2.plot(null_x_x, yplot, color = 'C2')
ax2.plot(xplot, null_x_y, color = 'C2', label = "isoclines nulles de $\dot x$")
# isoclines nulles de y
ax2.plot(xplot, null_y_y, color = 'C1')
ax2.plot(null_y_x, yplot, color = 'C1', label = "isoclines nulles de $\dot y$")
# équilibres
ax2.plot(eq_extinct[0], eq_extinct[1], marker ='.', color = 'C3', markersize = 16)
ax2.plot(eq_coex[0], eq_coex[1], marker ='.', color = 'C0', markersize = 16)
Il est intéressant (et joli) de surimposer sur cette figure une représentation du champs de vecteur et quelques idées de trajectoire.
Pour cela il nous faut définir une grille de valeurs dans le plan $(x,y)$ et utiliser la méthode `quiver()` des systèmes d'axes (champs de vecteurs) et la méthode `streamplot()` (échantillons de trajectoires).
La définition de la grille se fait par la fonction `meshgrid()` de `numpy` sur la base d'`array` définissant l'amplitude et le pas des variations de $x$ et $y$.
%% Cell type:code id: tags:
``` python
# définition de l'échantillonnage selon $x$ et $y$
x_grid = np.linspace(0.1, 3.0, 10) # au passage on change un peu de np.arange()
y_grid = np.linspace(0.1, 3.0, 10)
# grille X,Y selon x_grid et y_grid
X, Y = np.meshgrid(x_grid, y_grid)
```
%% Cell type:markdown id: tags:
On calcule ensuite les valeurs des dérivées $\dot x$ et $\dot y$ sur cette grille:
%% Cell type:code id: tags:
``` python
# dérivées dot_x et dot_y sur la grille
dx, dy = modele_LV([X, Y], 0, params_LV)
```
%% Cell type:markdown id: tags:
A partir de là on peut tracer le champs de vecteur et l'échantillon de trajectoires dans le système d'axes `ax2`:
%% Cell type:code id: tags:
``` python
# tracé du champs de vecteurs
# Attention à l'option angles ='xy' les fleches sont tracees avec orientation en unité naturelle de l'ecran
# et pas en unité naturelle de la figure
ax2.quiver(X, Y, dx, dy, angles = 'xy', color = 'grey', width = .002)
# tracé des échantillons de trajectoires
ax2.streamplot(X, Y, dx, dy, density = 0.4, maxlength = 0.25, color = "purple")
Et finalement représenter ces quantités en 3D, en fonction des valeurs de $x$ et $y$. Pour cela nous utilisons une grille, comme plus haut pour le plan de phase, et evaluons la fonction sur cette grille.
%% Cell type:code id: tags:
``` python
# définition de l'échantillonnage selon $x$ et $y$
x_grid = np.linspace(0.15, 3.0, 30) # au passage on change un peu de np.arange()
Puis nous surimposons le plan correspondant à la valeur initiale de l'intégrale première en fonction de $x$ et $y$, ainsi que l'évolution de cette quantité au cours du temps le long de la trajectoire simulée.
%% Cell type:code id: tags:
``` python
# tracé du plan correspondant a la valeur initiale de l'intégrale première
ax4.plot_surface(X, Y, np.ones_like(int_premiere_grid)*int_premiere([x0, y0], params_LV),
antialiased=True, alpha =.3)
# tracé de la valeur de l'intégrale première le long de la trajectoire simulée