{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "$$\n",
    "\\newcommand{\\RR}{\\mathbb{R}}\n",
    "\\newcommand{\\R}{\\mathbb{R}}\n",
    "\\newcommand{\\N}{\\mathbb{N}}\n",
    "$$\n",
    "\n",
    "\n",
    "## L3 Mathématiques - 2023/24 - Univ. Paris-Saclay\n",
    "## Analyse théorique et numérique des EDO \n",
    "---------------------------------------------------------------------------------------------------------------\n",
    "\n",
    "## TP 2 : Représentation des solutions d'un systèmes d'EDO. Le modèle de Lotka-Volterra.\n",
    "---------------------------------------------------------------------------------------------------------------\n",
    "\n",
    "## Partie 1. Représentation des solutions et champs de vecteurs pour un système d'EDO.\n",
    "\n",
    "Soit $F:\\mathbb{R}\\times\\mathbb{R^2}\\longrightarrow\\mathbb{R^2},\\ \\ \\big(t,(x,y)\\big)\\mapsto\\big(F_1(t,(x,y)),F_2(t,(x,y))\\big)$, une fonction de classe $C^1$ et considérons le système différentiel\n",
    "$$\n",
    "(S)\\ \\ \\ \\ \\ \\ \\ \n",
    "\\begin{cases}\n",
    "x'(t)=F_1\\big(t,(x(t),y(t))\\big)\\\\\n",
    "y'(t)=F_2\\big(t,(x(t),y(t))\\big)\n",
    "\\end{cases}\n",
    "$$\n",
    "\n",
    "\n",
    "Pour représenter graphiquement les solutions de $(S)$, il y a plusieurs choix possibles :\n",
    "\n",
    "- Tracer dans $\\RR^3$ le graphe de la fonction $t \\mapsto (x(t), y(t))$ ;\n",
    "- Tracer dans $\\RR^2$ les graphes des fonctions $t \\mapsto x(t)$ et $t \\mapsto y(t)$ ;\n",
    "- Tracer dans $\\RR^2$ la courbe paramétrée $\\{(x(t), y(t)) | t ∈ J\\}$ ; c’est la projection du graphe de $t\\mapsto(x(t),y(t))$ dans le plan $(x, y)$, appelé *plan de phase*.\n",
    "\n",
    "Pour un *système autonome*, c'est-à-dire tel que $F_1$ et $F_2$ ne dépendent pas de $t$, il est utile de représenter également dans le plan $(x,y)$ le champ de vecteurs associé au système\n",
    "$(S)$, qui est l'application \n",
    "$$\n",
    "V:(x,y)\\mapsto\\big(F_1(x,y),F_2(x,y)\\big).\n",
    "$$\n",
    "Pour tout $t$, le vecteur $\\big(F_1\\big(x(t),y(t)\\big),F_2\\big(x(t),y(t)\\big)\\big)$ est tangent à la courbe représentant une solution de $(S)$ au point $(x(t),y(t))$. Représenter le champ de vecteurs aide à comprendre la direction des trajectoires dans le plan de phase, car avec cette représentation on perd l'information précise sur l'évolution en temps de la solution.\n",
    "\n",
    "### Exercice 1. Représentation des solutions d'une EDO et des champs de vecteurs.\n",
    "\n",
    "On s'intérèsse au système différentiel linéaire $X' = AX$, avec\n",
    "$$\n",
    "A=\\begin{bmatrix}\n",
    "0 & 1\\\\\n",
    "−2 &−3\n",
    "\\end{bmatrix}.\n",
    "$$\n",
    "\n",
    "**Question 1).** Tracer dans le plan $(x,y)$ le champ de vecteurs associé dans le carré $[−5, 5]\\times[−5; 5]$.\n",
    "Tracer sur la même figure, les trajectoires des solutions $(x(t),y(t))$ de ce système, avec $t$ variant de −$10$ à $10$, pour chacune des conditions initiales suivantes :\n",
    "$(x(−10), y(−10)) = (1, 2),\\ (−2, −2),\\  (0, −4),\\ (1, -2)$ et $(3, 4)$. Déterminer également les sous-espaces propres de A et les représenter sur la même figure.\n",
    "\n",
    "*Les vecteurs propres de $A$ sont $-1$ et $-2$ et les vecteurs propres associés sont respectivement $(1,-1)$ et $(1,-2)$. La solution du problème de Cauchy $X'=AX,\\ X(t_0)=X_0$ est déjà programmée.*\n",
    "\n",
    "*Pour tracer le champ de vecteurs vous pouvez utiliser les commandes programmées*.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Text(0.5, 1.0, 'Représentation des solutions et champs de vecteurs pour le système (S)')"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 240928 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "%matplotlib inline\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "# Fonction F définissant l'EDO\n",
    "def F(Y):\n",
    "    x=Y[0]\n",
    "    y=Y[1]\n",
    "    A=np.array([[0,1],[-2,-3]])\n",
    "    return np.dot(A,Y)\n",
    "\n",
    "# ou \n",
    "def F1(x,y):\n",
    "    return y\n",
    "\n",
    "def F2(x,y):\n",
    "    return -2*x-3*y\n",
    "\n",
    "# Solution exacte de Y'=AY, Y(t_0)=Y_0\n",
    "def uex(t,t0,Y0):\n",
    "    U1=np.array([1,-1])\n",
    "    U2=np.array([1,-2])\n",
    "    P=np.ones((2,2))\n",
    "    P[:,0]=U1\n",
    "    P[:,1]=U2\n",
    "    C=np.linalg.solve(P,Y0)\n",
    "    return np.array([(C[0]*np.exp(-(t-t0))*U1[0]+C[1]*np.exp(-2*(t-t0))*U2[0]),(C[0]*np.exp(-(t-t0))*U1[1]+C[1]*np.exp(-2*(t-t0))*U2[1])])\n",
    "\n",
    "## Représentation des solutions pour chaque valeur de la donnée initiale \n",
    "tt = np.linspace(-10, 10, 100)\n",
    "t0 = tt[0]\n",
    "for x, y in zip([1, -2, 0, 1, 3], [2, -2, -4, -2, 4]):\n",
    "    sol = uex(tt, t0, [x, y])\n",
    "    plt.plot(sol[0], sol[1], label=f'$((x0, y0) = ({x}, {y})$')\n",
    "    plt.scatter(x, y)\n",
    "\n",
    "#Tracé du champ de vecteurs\n",
    "x=np.linspace(-5,5,26)\n",
    "y=x\n",
    "xx,yy=np.meshgrid(x,y)\n",
    "U=F1(xx,yy)/np.sqrt(F1(xx,yy)**2+F2(xx,yy)**2)\n",
    "V=F2(xx,yy)/np.sqrt(F1(xx,yy)**2+F2(xx,yy)**2)\n",
    "plt.quiver(xx,yy,U,V,angles='xy', scale=20, color='gray')\n",
    "plt.axis([-5.,5,-5,5])\n",
    "\n",
    "## Représentation des espaces propres \n",
    "plt.plot(tt, -tt, label=f'SEP associé à -1', linewidth=3)\n",
    "plt.plot(tt, -2*tt, label=f'SEP associé à -2', linewidth=3)\n",
    "\n",
    "plt.legend(fontsize=7)\n",
    "plt.title('Représentation des solutions et champs de vecteurs pour le système (S)')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "tags": []
   },
   "source": [
    "## Partie 2. Le modèle de Lotka-Volterra\n",
    "\n",
    "On se donne deux populations $H(t)$ de sardines (les proies) et $P(t)$ de requins (les prédateurs) au temps $t,$ dont l'évolution au cours du temps suit la loi\n",
    "\n",
    "\\begin{equation}\n",
    "(LV)\\ \\ \\   \n",
    "\\begin{cases}\n",
    "    H'(t) = H(t)(a - b P(t)) \\\\\n",
    "    P'(t) = P(t)(-c  + d H(t)),\n",
    "  \\end{cases}\n",
    "\\end{equation}\n",
    "\n",
    "où $a,b,c,d >0$. On suppose connues les populations de sardines et de requins à l'instant initial $t_0=0$ :\n",
    "\n",
    "\\begin{equation}\n",
    "  \\begin{cases}\n",
    "    H(0) = H_0, \\\\\n",
    "    P(0) = P_0,\n",
    "  \\end{cases}\n",
    "\\end{equation}\n",
    "où $H_0\\ge 0$ et $P_0\\ge 0$ sont donnés.\n",
    "\n",
    "\n",
    "**Pour les applications numériques, on choisira \n",
    "$a=0,1$, $b=d=5\\cdot 10^{-5},$ $c=0,04$, $T=200$ ans et une population initiale de $H_0=2000$ sardines et $P_0=1000$ requins.**\n",
    "\n",
    "### Exercice 1.\n",
    "**Question 1).** En posant $X = (H,P)$, réécrire le système $(LV)$\n",
    "sous la forme $X' = F(X)$, où $F=(F_1,F_2)$ avec $F_1,F_2$ deux fonctions définies sur $\\R^2$ à valeurs dans $\\R$. Justifier que le problème de Cauchy pour $(LV)$ admet une unique solution maximale.\n",
    "\n",
    "\n",
    "**Question 2).** Donner la solution (maximale) du problème de Cauchy dans chacun des quatre cas suivants :\n",
    "- $(H_0,P_0)=(0,0)$ ;\n",
    "- $(H_0,P_0)=(\\frac cd,\\frac ab)$ ; \n",
    "- $H_0=0$ et $P_0>0$ ;\n",
    "- $H_0>0$ et $P_0=0$.\n",
    "\n",
    "**A faire en python.** Dans le plan $(H,P)$, représentez  les points d'équilibre du système (les points $(H^*,P^*)$ tels que $F(H^*,P^*)=(0,0)$. Étudier le signe des dérivées $H'$ et $P'$ selon la position de $H,P$ par rapport aux points d'équilibre, en représentant le champs de vecteurs dans le plan $(H,P)$ (représentez également les droites $H=H^*,\\ P=P^*$). Intuitez quel sera le comportement des solutions $(H,P)$ suivant la condition initiale. \n",
    "\n",
    "*Pour représenter le champs de vecteurs, vous pourrez utiliser les commandes suivantes :*\n",
    "\n",
    "`h,p = np.meshgrid(np.linspace(0 , 3000, 20),np.linspace (0 , 4500, 30))`\n",
    "\n",
    "`n=np.sqrt(F1(h,p)**2+F2(h,p)**2)` \n",
    "\n",
    "`n=np.sqrt(F1(h,p)**2+F2(h,p)**2))` \n",
    "\n",
    "`plt.quiver (h , p, F1(h , p)/n, F2 (h , p)/n,angles='xy',scale=20,color='blue')`\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "a, b, c, d = 0.1, 5e-5, 0.04, 5e-5\n",
    "H0, P0 = 2000, 1000\n",
    "He, Pe = c/d, a/b\n",
    "\n",
    "def F1(H, P):\n",
    "    return H * (a - b*P)\n",
    "\n",
    "def F2(H, P):\n",
    "    return P * (-c + d*H)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/tmp/ipykernel_342/685358994.py:4: RuntimeWarning: invalid value encountered in divide\n",
      "  plt.quiver(h, p, F1(h,p)/n, F2(h,p)/n, angles='xy', scale=20, color='gray')\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<matplotlib.legend.Legend at 0x7f7c298d14b0>"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 186820 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "xx, yy = np.linspace(0, 3000, 20), np.linspace (0, 4500, 30)\n",
    "h,p = np.meshgrid(xx, yy)\n",
    "n=np.sqrt(F1(h,p)**2+F2(h,p)**2)\n",
    "plt.quiver(h, p, F1(h,p)/n, F2(h,p)/n, angles='xy', scale=20, color='gray')\n",
    "\n",
    "plt.vlines(He, 0, 4500, label=f'H=He={He}')\n",
    "plt.hlines(Pe, 0, 3000, label=f'P=Pe={Pe}')\n",
    "plt.scatter(He, Pe, label=f'(H0, P0) = (He, Pe)')\n",
    "plt.scatter(H0, P0, label=f'(H, P)=(H0, P0)=({H0},{P0})', color='red')\n",
    "\n",
    "plt.title('Le modèle de Lotka-Volterra')\n",
    "plt.legend(fontsize=7)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exercice 2. Analyse théorique du modèle (voir TD3).\n",
    "\n",
    "**Question 1).**\n",
    "Soit $Q = \\{ (x,y)\\in \\R^2\\mid x,y >0\\}$. Démontrer que si la\n",
    "condition initiale $(H_0,P_0)\\in Q$, alors $(H(t),P(t)) \\in Q$ pour\n",
    "tout temps $t>0$ où la solution est définie.\n",
    "\n",
    "*Indication : Utiliser l'unicité dans le théorème de Cauchy-Lipschitz pour montrer que le graphe de $(H,P)$ ne peut pas croiser le graphe d'une solution bien choisie qui passe par la droite $x=0$ ou $y=0.$*\n",
    "\n",
    "**Question 2).**\n",
    "On suppose que $(H_0,P_0) \\in Q$ et soit \n",
    "  $(H,P)$ la solution maximale du problème de Cauchy pour $(LV)$, de donnée initiale $(H_0,P_0)$.\n",
    "\n",
    "- Montrer une inégalité différentielle faisant apparaître la quantité $\\phi(t) := dH(t) + bP(t)$ au cours du temps. En déduire que la solution $(H,P)$ est définie sur $\\R^+$.\n",
    "\n",
    "*Indication : Dériver $\\phi,$ obtenir ensuite une majoration pour $\\phi$ et appliquer le théorème des bouts.*\n",
    "\n",
    "- ($*$) En étudiant la relation entre $(-c+dH)H'/H$ et $(a-bP)P'/P$, construire une fonction $E(x,y) = k(x) + \\ell(y)$ vérifiant $E(H(t),P(t)) = \\mathrm{cst}$ et telle que $\\lim_{X\\in Q,\\|X\\|\\to +\\infty} E(X) = +\\infty$. En déduire que les trajectoires de la solution maximale restent bornées.\n",
    "\n",
    "*Indication : Étudier la relation entre $(-c+dH)H'/H$ et $(a-bP)P'/P$. Déduire de la relation $E(H,P)=cst$ que l'on ne peut pas avoir $\\|(H,P)\\|\\to\\infty$ en un instant $t$ fini et utiliser le théorème des bouts.*\n",
    "\n",
    "- Démontrez que si $(H,P)$ converge quand $t\\rightarrow+\\infty$, c'est nécessairement vers un point d'équilibre.\n",
    "\n",
    "*Indication : Si $(H,P)$ converge, vers quoi converge $(H',P')$ ?*\n",
    "\n",
    "- ($**$) Tracer sur un schéma les *nullclines* $\\{ (x,y)\\in Q\\mid F_i(x,y) = 0 \\}$ et les points d'équilibre. Les nullclines divisent le quart de plan $Q$ en quatre ouverts\n",
    "\\begin{align*}\n",
    "  &A = \\{ (x,y) \\in Q \\mid F_1(x,y) > 0 \\hbox{ et } F_2(x,y) < 0 \\},\\\\\n",
    "  &B = \\{ (x,y) \\in Q \\mid F_1(x,y) > 0 \\hbox{ et } F_2(x,y) > 0 \\},\\\\\n",
    "  &C = \\{ (x,y) \\in Q \\mid F_1(x,y) < 0 \\hbox{ et } F_2(x,y) > 0 \\},\\\\\n",
    "  &D = \\{ (x,y) \\in Q \\mid F_1(x,y) < 0 \\hbox{ et } F_2(x,y) < 0 \\}.\n",
    "\\end{align*}\n",
    "Démontrer que si $(H_0,P_0)\\in A$, alors la trajectoire de la solution maximale $(H(t),P(t))$\n",
    "va parcourir successivement les ensembles $A,B,C,D,A,B,$ etc. Montrer\n",
    "que les deux points de passage successifs de la solution à l'interface\n",
    "$AB$ sont égaux, et en déduire que la solution $(H,P)$ est périodique.\n",
    "\n",
    "*Indication: Utiliser la monotonie de $H'$ et $P'$ dans chacune\n",
    "  des zones $A,B,C,D$ et le fait que la solution est bornée pour\n",
    "  déduire que si la trajectoire ne quitte pas une zone en temps fini,\n",
    "  alors elle doit converger vers un des points d'équilibre. Conclure\n",
    "  par l'absurde.*"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exercice 3. Approximation numérique (à faire en python).\n",
    "\n",
    "On s'intéresse dans cette partie, à faire sur python, à l'approximation numérique de la solution du problème de Cauchy pour le système $(LV)$, dans un intervalle de temps de la forme $[0,T].$ \n",
    "\n",
    "On choisira de nouveau\n",
    "$a=0,1$, $b=d=5\\cdot 10^{-5},$ $c=0,04$, $T=200$ ans, $H_0=2000$ sardines et $P_0=1000$ requins.\n",
    "\n",
    "On s'intéresse à calculer une solution approchée du problème de Cauchy par la méthode d'Euler explicite, vue au TP1. On reprend les mêmes notations que dans le TP1 : on se donne un pas $h=\\frac{T}{N}>0,$ où $N\\in\\N,$ on considère une subdivision uniforme de pas $h$ de l'intervalle $[0, T],$ définie par les $(N+1)$ points $t_n=nh,\\ n=0,\\dots,N$, \n",
    "$$\n",
    "t_0=0,\\ t_1:=h,\\ \\cdots,\\ t_N:=Nh=T, \n",
    "$$\n",
    "et on note note $H^n$ (resp. $P^n$) la valeur approchée de $H(t_n)$ (resp. $P(t_n)$) à l'instant $t_n$ pour $n=0,\\cdots,N$. \n",
    "\n",
    "**Question 1).**\n",
    "Ecrire le schéma d'Euler explicite associé au modèle de Lotka Volterra.\n",
    "\n",
    "Ecrire une fonction python `voltEE(T,X0,h)` prenant en argument le temps final $T$, la donnée initiale $X_0=[H_0,P_0]$ correspondant aux valeurs des populations initiales en $t=0$ et le pas de temps $h$ (on pourra prendre en argument $N$ le nombre de points de la discrétisation, au lieu de $h$), et qui calcule une solution approchée de $(LV)$ de donnée initiale $X_0$ par le schéma d'Euler explicite.\n",
    "\n",
    "Cette fonction retournera trois tableaux:\n",
    "-  `[$t_0,...,t_N$]` tableau numpy de taille $(N+1)$ contenant les instants de la subdivision en temps ;\n",
    "- `[$H_0,...,H_N$]` tableau numpy de taille $(N+1)$ contenant les valeurs approchées aux instantes $t_n$ de la population de sardines ;\n",
    "- `[$P_0,...,P_N$]`  tableau numpy de taille $(N+1)$ contenant les valeurs approchées aux instantes $t_n$ de la population de requins.\n",
    "\n",
    "\n",
    "**Question 2).**\n",
    "  Tracer dans la même figure les solutions approchées $[H_0,H_1,\\ldots,H_N]$ et $[P_0,P_1,\\ldots,P_N]$ en fonction du temps\n",
    "  avec $h=0.01$. Rajouter des légendes et des titres à votre figure.\n",
    "\n",
    "Créer une seconde figure et tracer sur cette figure $P$ en fonction de $H$ dans l'espace des phases $(H,P)$. Refaire cette représentation dans la même figure de l'exercice 1, avec les champs de vecteurs.\n",
    "\n",
    "**Question 3).** Calculer la solution approchée de $(LV)$, en prenant comme condition initiale un des points d'équilibre du système. Ceci confirme-t-il la solution théorique?\n",
    "\n",
    "**Question 4) (Modélisation de l'impact de la pêche).**\n",
    "Nous pêchons maintenant une même proportion $p$ de requins et de sardines ce qui se traduit par les deux termes négatifs $-pH(t)$ et $-pP(t)$ dans les équations. Le modèle devient\n",
    "\\begin{equation*}\n",
    "     \\begin{cases}\n",
    "        H'(t)&=(a-p)H(t)-bH(t)P(t),\\\\\n",
    "        P'(t)&=(-c-p)P(t)+dH(t)P(t).\n",
    "     \\end{cases}\n",
    "\\end{equation*}\n",
    "On choisit $p=0.02$. Reprendre les questions précédentes et observer l'impact de la pêche sur l'évolution des populations. Quelle espèce est favorisée par la pêche? "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "a, b, c, d = 0.1, 5e-5, 0.04, 5e-5\n",
    "T=200\n",
    "H0, P0 = 2000, 1000\n",
    "He, Pe = c/d, a/b\n",
    "p=0.02\n",
    "\n",
    "def voltEE(T, X0, h):\n",
    "    t = np.arange(0, T+h, h)\n",
    "    H = 0 * t\n",
    "    P = 0 * t\n",
    "    H[0], P[0] = X0\n",
    "    for n in range(len(t)-1):\n",
    "        H[n+1] = H[n] + h * F1(H[n], P[n])\n",
    "        P[n+1] = P[n] + h * F2(H[n], P[n])\n",
    "    return np.array([t, H, P])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/tmp/ipykernel_342/4001628450.py:10: RuntimeWarning: invalid value encountered in divide\n",
      "  plt.quiver (h, p, F1(h,p)/n, F2(h,p)/n, angles='xy', scale=20, color='gray')\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[<matplotlib.lines.Line2D at 0x7f7c29b11f60>]"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 46592 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 196072 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "t, H, P = voltEE(T, [H0, P0], 0.001)\n",
    "plt.plot(t, H, label='Population de sardines')\n",
    "plt.plot(t, P, label='Population de requins')\n",
    "plt.legend(fontsize=7)\n",
    "\n",
    "plt.figure()\n",
    "xx, yy = np.linspace(0, 3000, 20), np.linspace (0, 4500, 30)\n",
    "h,p = np.meshgrid(xx, yy)\n",
    "n=np.sqrt(F1(h,p)**2 + F2(h,p)**2)\n",
    "plt.quiver (h, p, F1(h,p)/n, F2(h,p)/n, angles='xy', scale=20, color='gray')\n",
    "\n",
    "plt.vlines(He, 0, 4500, label=f'H=He={He}')\n",
    "plt.hlines(Pe, 0, 3000, label=f'P=Pe={Pe}')\n",
    "plt.scatter(He, Pe, label=f'(H0, P0) = (He, Pe)')\n",
    "plt.scatter(H0, P0, label=f'(H, P)=(H0, P0)=({H0},{P0})', color='red')\n",
    "\n",
    "plt.title('Le modèle de Lotka-Volterra')\n",
    "plt.legend(fontsize=7)\n",
    "plt.plot(H, P)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "a, b, c, d = 0.1, 5e-5, 0.04, 5e-5\n",
    "T=200\n",
    "H0, P0 = 2000, 1000\n",
    "He, Pe = c/d, a/b\n",
    "p=0.02\n",
    "\n",
    "def F1_p(H, P):\n",
    "    return (a - p) * H - b * H * P\n",
    "\n",
    "def F2_p(H, P):\n",
    "    return (-c-p) * P + d * H * P\n",
    "\n",
    "def voltEE_p(T, X0, h):\n",
    "    t = np.arange(0, T+h, h)\n",
    "    H = 0 * t\n",
    "    P = 0 * t\n",
    "    H[0], P[0] = X0\n",
    "    for n in range(len(t)-1):\n",
    "        H[n+1] = H[n] + h * F1_p(H[n], P[n])\n",
    "        P[n+1] = P[n] + h * F2_p(H[n], P[n])\n",
    "    return np.array([t, H, P])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/tmp/ipykernel_342/3981288686.py:10: RuntimeWarning: invalid value encountered in divide\n",
      "  plt.quiver (h, p, F1(h,p)/n, F2(h,p)/n, angles='xy', scale=20, color='gray')\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[<matplotlib.lines.Line2D at 0x7f7c2987e320>]"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 52812 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 191980 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "t, H, P = voltEE_p(T, [H0, P0], 0.001)\n",
    "plt.plot(t, H, label='Population de sardines')\n",
    "plt.plot(t, P, label='Population de requins')\n",
    "plt.legend(fontsize=7)\n",
    "\n",
    "plt.figure()\n",
    "xx, yy = np.linspace(0, 3000, 20), np.linspace (0, 4500, 30)\n",
    "h,p = np.meshgrid(xx, yy)\n",
    "n=np.sqrt(F1(h,p)**2 + F2(h,p)**2)\n",
    "plt.quiver (h, p, F1(h,p)/n, F2(h,p)/n, angles='xy', scale=20, color='gray')\n",
    "\n",
    "plt.vlines(He, 0, 4500, label=f'H=He={He}')\n",
    "plt.hlines(Pe, 0, 3000, label=f'P=Pe={Pe}')\n",
    "plt.scatter(He, Pe, label=f'(H0, P0) = (He, Pe)')\n",
    "plt.scatter(H0, P0, label=f'(H, P)=(H0, P0)=({H0},{P0})', color='red')\n",
    "\n",
    "plt.title('Le modèle de Lotka-Volterra')\n",
    "plt.legend(fontsize=7)\n",
    "plt.plot(H, P)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Partie 3 . La méthode du point milieu et étude de l'erreur.\n",
    "\n",
    "A l'image de la partie 2 du TP1, programmer le **schéma du point milieu** pour discrétiser le problème de Cauchy\n",
    "\n",
    "$$\n",
    "(P)\\ \\ \\ \\\n",
    "\\begin{cases}\n",
    "y'(t)=\\frac{\\cos(t)-y(t)}{1+t},\\\\\n",
    "y(0)=-\\frac14, \n",
    "\\end{cases}\n",
    "$$\n",
    "dont la solution exacte est \n",
    "$$\n",
    "y(t) = \\frac{\\sin(t)-1/4}{1 + t}.\n",
    "$$\n",
    "\n",
    "La méthode du point milieu est donnée par la suite :\n",
    "\n",
    "$$\n",
    "\\begin{cases}\n",
    "y^0=y_0,\\\\\n",
    "y^{n+1}=y^{n}+h f\\big(t_n+\\frac h2,y^{n}+\\frac h2f(t_n,y^n)\\big),\\ \\ \\ \\textrm{pour }\\ n\\in\\{0,\\dots,N-1\\}.\n",
    "\\end{cases}.\n",
    "$$  \n",
    "\n",
    "**Question 1).** Tracer sur une même fenêtre graphique :\n",
    "\n",
    "- La solution exacte sur l'intervalle $[0,20]$ discrétisée avec un pas de temps de $10^{-4}$ ;\n",
    "\n",
    "- Les 3 solutions approchées sur le même intervalle obtenues avec la méthode du point milieu pour les trois pas de temps $h=1/5,\\ h=1/10,\\ h=1/50$.\n",
    "\n",
    "**Question 2).** Pour chaque valeur du pas de temps $h=1/5,\\ h=1/10,\\ h=1/50$, tracer sur une fenêtre graphique les 3 courbes suivantes : la solution exacte sur l'intervalle $[0,20]$ discrétisée avec un pas de temps de $10^{-4}$, la solution approchée sur le même intervalle obtenue avec la méthode du point milieu pour la valeur du pas égale à $h$ et la solution approchée obtenue avec la méthode d'Euler explicite avec la valeur de pas $h$ (il faut faire trois figures, une pour chaque valeur du pas $h$). Quelle méthode semble approcher le mieux la solution exacte ?\n",
    "\n",
    "---------------------------------------------------------------------------------------------------------------\n",
    "\n",
    "On essaie de comprendre ce que c'est l'erreur associé à un schéma numérique et ce que c'est un schéma numérique convergent.\n",
    " \n",
    "Soit $t\\mapsto y(t)$ la solution exacte d'un problème de Cauchy, de donnée initiale $y(t_0)=y_0$, et $(y^0,\\dots,y^N)_{N\\in\\N}$ la solution approchée de ce problème dans l'intervalle $[t_0,t_0+T]$, obtenue par une méthode numérique, associée, pour chaque $N$, à une discrétisation de pas $h=T/N$ de l'intervalle $[t_0,t_0+T]$.\n",
    "\n",
    "Pour un certain pas de temps $h$ fixé (ou pour un certain nombre de points de la discrétisation $N$ fixé), l'erreur globale entre la solution approchée associée à une discrétisation de pas $h$ de l'intervalle $[t_0,t_0+T]$ et la solution exacte est donnée par :\n",
    "\n",
    "\\begin{equation*}\n",
    "E_h =  \\max_{n=0,\\cdots,N}( |y(t_n)-y^{n}|). \n",
    "\\end{equation*}\n",
    "\n",
    "Ci dessus, $y(t_n)$ est la solution exacte à l'instant $t_n$ et $y^{n}$ la valeur approchée de $y(t_n),$ donnée par le schéma numérique.\n",
    "\n",
    "**Remarque:**  l'erreur globale $E$ dépend du pas $h$, ou, de manière équivalente, du nombre de points $N$ de la discrétisation. Pour des valeurs de $N$ différentes, ou de manière équivalente pour des valeurs de $h$ différentes, les  discrétisations de l'intervalle $[t_0,t_0+T]$ sont différentes (elles ont un nombre de points différent), et les solutions approchées sont différentes. On s'attend à que, lorsque $N$ augmente, ou de manière équivalente lorsque $h$ diminue, l'erreur $E_h$ diminue, puisque l'on considère dans ce cas de plus en plus de points dans la discrétisation de l'intervalle $[t_0,t_0+T]$ et les approximations que l'on a faites pour construire le schéma numérique deviennent alors de plus en plus précises.\n",
    "\n",
    "On dira qu'une méthode numérique converge si $\\displaystyle{\\lim_{h\\to0}E_h}=0$.\n",
    "\n",
    "**Question 3).** Calculez les solutions approchées de $(P)$ obtenues avec le schéma d'Euler explicite, avec $h=1/2^s$ pour $s = 1,2,...,8$ ; représentez dans la même figure la différence en valeur absolue entre la solution exacte et la solution approchée, en fonction du temps, pour chaque valeur de $h$. Faites de même pour la méthode du point milieu, dans une autre figure.\n",
    "\n",
    "**Question 4).** Représentez ensuite, en échelle logarithmique, l'erreur en fonction du pas de temps $h$, autrement dit, représentez $\\log(E_h)$ en fonction de $\\log(h)$, pour les deux méthodes. Vous devez obtenir dans chaque cas, des points qui sont à peu près alignés sur des droites. Vérifiez graphiquement que c'est le cas, en estimant la pente de la droite passant au plus prêt des points (ou en représentant une droite de pente $1$ ou $2$ qui passe par un des points et en vérifiant que tous les points sont à peu près sur cette droite).\n",
    "\n",
    "*Pour la méthode d'Euler explicite, on a $\\log(E_h) \\sim C+\\log(h)$ et donc $E_h\\sim \\widetilde{C}h$, pour certaines constantes $C$ et $\\widetilde{C}$. On dit que la méthode d'Euler explicite est d' ordre 1 : c'est l'ordre de la puissance de $h$ dans cette relation. On a donc que l'erreur globale $E_h$ tend vers 0 comme $h$. L'ordre d'une méthode donne une indication sur sa vitesse de convergence. Une méthode d'ordre $p$ est une méthode dont l'erreur globale tend vers $0$ comme $h^p$. Donc plus l'ordre est élevé, plus la méthode converge plus vite*\n",
    "\n",
    "**Remarque :** pour étudier numériquement l'ordre d'une méthode, on utilise souvent l'échelle logarithmique pour tracer l'erreur en fonction du pas de discrétisation $h$. La pente de la droite obtenue donne l'ordre $p$ de la méthode : si $E_h \\sim Ch^p$ alors $\\log(E_h)\\sim \\log(C) + p\\log(h)$, autrement dit la courbe de $\\log(E_h)$ en fonction de $\\log(h)$ correspond à peu près à une droite de pente $p$.\n",
    "\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Partie 4 (pour ceux qui vont plus vite). Un exemple de problème modélisé par des EDO et sa simulation numérique.\n",
    "\n",
    "On donne ici un exemple où les équations différentielles ordinaires sont utilisées pour construire des modèles mathématiques décrivant des phénomènes issus d'autres disciplines, et de montrer comment on peut utiliser l'analyse numérique pour simuler ces modèles dont les solutions exactes sont inconnues. Cela est une partie du travail de modélisation mathématique, qui consiste en : proposer des modèles décrivant certains phénomènes physiques, biologiques, économiques,..., simuler ces modèles, confronter les résultats des simulations aux résultats prédits par la théorie ou par l'expérience, prédire de nouveaux phénomènes, éventuellement chercher à améliorer ces modèles, et recommencer...\n",
    "\n",
    "### Aglomération des globules rouges\n",
    "\n",
    "**(Extrait d'un problème de l'agrégation de mathématiques).**\n",
    "\n",
    "On considère un système d'équations différentielles décrivant l'évolution d'une famille de globules rouges.\n",
    "\n",
    "Il est vérifié expérimentalement que les globules rouges dans le sang ont tendance à s'agglomérer, ce qui suggère l'existence de forces d'interaction entre eux. Le modèle que l'on présente ici décrit ce phénomène d'agglomération dans une situation très simplifiée, mono-dimensionnelle.\n",
    "\n",
    "On considère une famille de $N+2$ globules rouges que l'on assimile à des particules ponctuelles, évoluant dans l'intervalle $[0,1]$. Les globules rouges interagissent entre eux par une force d’interaction liée à la distance entre deux globules.\n",
    "Chaque globule rouge interagit avec ses deux voisins, à l'exception du premier et du dernier, fixés respectivement aux points $0$ et $1$.  On note $x_i(t)$ la position du globule rouge $i$ à l'instant $t$. Les globules rouges sont sujets à une force d'interaction donnée par une fonction $\\varphi$, qui est attractive quand la distance entre deux globules est assez grande, qui décroît vers 0 lorsque  cette distance tend vers l’infini. Pour prendre en compte la taille des globules, la force d’interaction devient répulsive lorsque la distance entre les globules devient plus petite qu'une longueur $r$ représentant la taille caractéristique du globule rouge. On considère ici la fonction $\\varphi$ définie par\n",
    "$$\n",
    "\\varphi(d)=\\frac{\\gamma}{d}\\ln\\Big(\\frac{d}{r}\\Big),\n",
    "$$\n",
    "pour $d>0$, avec $\\gamma$ un paramètre d'intensité de la force. \n",
    "\n",
    "Pour deux globules voisins $x_i$ et $x_{i+1}$, $\\varphi(x_{i+1} − x_i)$ représente la force exercée par le globule $i + 1$ sur le globule $i$, qui est l’opposée de la force exercée par $i$ sur $ i + 1$.\n",
    "On suppose aussi que chaque particule subit du fluide environnant une force de frottement\n",
    "proportionnelle à sa vitesse, et qui s’oppose au mouvement.\n",
    "\n",
    "Le système d'équations différentielles résultant de\n",
    "ce modèle est le système\n",
    "$$\n",
    "m\\,x_i''=\\varphi(x_{i+1}-x_i)-\\varphi(x_{i}-x_{i-1})-\\lambda x_i',\\ \\ i=1,\\dots,N,\n",
    "$$\n",
    "avec $x_0=0$ et $x_{N+1}=1$, $\\lambda$ le coefficient de frottement et $m$ la masse d'un globule rouge, supposée égale à 1.\n",
    "\n",
    "Nous simulons ce système ci-dessous pour $N=50$, en prenant une configuration initiale de 50 points pris aléatoirement dans l'intervalle $[0,1]$.\n",
    "\n",
    "Nous avons utilisé le schéma d'Euler explicite pour le système d'EDO associé au système d'EDO d'ordre 2 précédent."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Text(0.5, 1.0, 'position x_i des globules rouges au cours du temps')"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 1012476 characters]",
      "text/plain": [
       "<Figure size 2400x1800 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "gamma=0.5\n",
    "a=0.004\n",
    "lm=10\n",
    "\n",
    "def fphi(d):\n",
    "    return (gamma/d)*np.log(d/a)\n",
    "\n",
    "def F(X):\n",
    "    (n,m)=np.shape(X)\n",
    "    Y=np.zeros((n,m))\n",
    "    Y[0,:]=X[1,:]\n",
    "    Xaux=np.zeros(m+2)\n",
    "    Xaux[-1]=1\n",
    "    Xaux[1:-1]=X[0,:]\n",
    "    Y[1,:]=fphi(Xaux[2:]-Xaux[1:-1])-fphi(Xaux[1:-1]-Xaux[0:-2])-lm*X[1,:]\n",
    "    return Y\n",
    "\n",
    "h=0.0002\n",
    "T=15\n",
    "N=100\n",
    "\n",
    "t=np.arange(0,T+h,h)\n",
    "Nt=np.size(t)\n",
    "X=np.zeros((2,N,Nt))\n",
    "R0=-1+2*np.random.rand(N)\n",
    "X0=np.arange(1/(N+1),1,1/(N+1))+0.1*R0*(1/(N+1))\n",
    "\n",
    "X[0,:,0]=X0\n",
    "X[1,:,0]=X0\n",
    "\n",
    "plt.figure(1,figsize=(24,18))\n",
    "for n in range(Nt-1):\n",
    "    Y=F(X[:,:,n])\n",
    "    X[:,:,n+1]=X[:,:,n]+(h/2)*Y+(h/2)*F(X[:,:,n]+h*Y)\n",
    "    \n",
    "for i in range(N):\n",
    "    plt.plot(t,X[0,i,:],'k')\n",
    "plt.xlabel('t')\n",
    "plt.ylabel('$x_i$')\n",
    "plt.title('position x_i des globules rouges au cours du temps')\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.8"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  },
  "varInspector": {
   "cols": {
    "lenName": 16,
    "lenType": 16,
    "lenVar": 40
   },
   "kernels_config": {
    "python": {
     "delete_cmd_postfix": "",
     "delete_cmd_prefix": "del ",
     "library": "var_list.py",
     "varRefreshCmd": "print(var_dic_list())"
    },
    "r": {
     "delete_cmd_postfix": ") ",
     "delete_cmd_prefix": "rm(",
     "library": "var_list.r",
     "varRefreshCmd": "cat(var_dic_list()) "
    }
   },
   "types_to_exclude": [
    "module",
    "function",
    "builtin_function_or_method",
    "instance",
    "_Feature"
   ],
   "window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
