diff --git a/tp/edo-general.ipynb b/tp/edo-general.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..1f8c20ded18e824b6c3433b4443d824716a101c0 --- /dev/null +++ b/tp/edo-general.ipynb @@ -0,0 +1,702 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "<img src=\"https://gitlab.irit.fr/toc/ens-n7/texCoursN7/-/raw/main/LOGO_INP_N7.png\" alt=\"N7\" height=\"100\"/>\n", + "\n", + "<img src=\"https://gitlab.irit.fr/toc/ens-n7/texCoursN7/-/raw/main/logo-insa.png\" alt=\"INSA\" height=\"100\"/>\n", + "\n", + "# Intégration numérique\n", + "\n", + "- Date : 2023-2024\n", + "- Durée approximative : 1h" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Introduction\n", + "\n", + "Pour la documentation du package `Julia` sur l'intégration numérique, voir\n", + "[documentation de DifferentialEquations.jl](https://diffeq.sciml.ai/stable/).\n", + "\n", + "Il nous faut tout d'abord importer les bons packages de Julia." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# activate local project\n", + "using Pkg\n", + "Pkg.activate(\".\")\n", + "\n", + "# load packages\n", + "using DifferentialEquations\n", + "using ForwardDiff\n", + "using LinearAlgebra\n", + "using Plots" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exemple 1\n", + "\n", + "Nous allons ici résoudre le problème à valeur initiale\n", + "$$(IVP)\\left\\{\\begin{array}{l}\n", + "\\dot{x}_1(t)=x_1(t)+x_2(t)+\\sin t\\\\\n", + "\\dot{x}_2(t)=-x_1(t)+3x_2(t)\\\\\n", + "x_1(0)=-9/25\\\\\n", + "x_2(0)=-4/25,\n", + "\\end{array}\\right.\n", + "$$\n", + "\n", + "- Ecrire la fonction $f$ qui permet d'écrire l'équation différentielle sous la forme $\\dot{x}(t)=f(t,x(t))$.\n", + "- Vérifier que la solution de $(IVP)$ est\n", + "$$\\begin{align*}\n", + "x_1(t)&= (-1/25)(13\\sin t+9\\cos t)\\\\\n", + "x_2(t)&= (-1/25)(3\\sin t+4\\cos t).\n", + "\\end{align*}$$\n", + "- Coder la fonction $f$ et exécuter le code ci-dessous. Commentaires ?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Remarque : \n", + "# un problème IVP est une équation différentielle ordinaire \n", + "# (EDO en français, ODE en anglais)\n", + "# avec en plus une condition initiale.\n", + "\n", + "\"\"\"\n", + " Second membre de l'IVP\n", + " x : vecteur d'état\n", + " λ : vecteur de paramètres\n", + " t : variable de temps\n", + "\"\"\"\n", + "function exemple1(x, λ, t)\n", + "\n", + " xpoint = similar(x)\n", + " \n", + " # A COMPLETER/MODIFIER\n", + " xpoint[:] = zeros(size(x))\n", + "\n", + " return xpoint\n", + "end\n", + "\n", + "λ = [] # pas de paramètres\n", + "\n", + "t0 = 0\n", + "tf = 10\n", + "tspan = (t0, tf) # intervalle d'intégration\n", + "\n", + "x0 = [-9/25, -4/25] # condition initiale\n", + "\n", + "prob = ODEProblem(exemple1, x0, tspan, λ) # définition du problème IVP\n", + "sol = solve(prob) # résolution du problème IVP\n", + "p1 = plot(sol, label = [\"x₁(t)\" \"x₂(t)\"], title = \"default options\") # affichage de la solution" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Le contrôle du pas\n", + "Les bons intégrateurs numériques ont une mise à jour automatique du pas. Pour les \n", + "[méthodes de Runge-Kutta](https://fr.wikipedia.org/wiki/Méthodes_de_Runge-Kutta) \n", + "par exemple, sur un pas $[t_0, t_{1}]$ on calcule par 2 schémas différents deux solutions approchées à l'instant $t_{1}$ : $x_{1}$ et $\\hat{x}_{1}$ dont l'erreur locale est respectivement en $O(h^p)$ et $O(h^{p+1})$ (les erreurs globales sont elles en $O(h^{p-1})$ et $O(h^p)$). Ainsi on peut estimer l'erreur locale du schéma le moins précis à l'aide de la différence $x_{1}-\\hat{x}_{1}$. On peut alors estimer le pas de façon à avoir la norme de cette différence inférieure à une tolérance donnée `Tol` ou encore à avoir \n", + "$$\\frac{\\|x_{1}-\\hat{x}_{1}\\|}{\\mathrm{Tol}}<1.$$\n", + "\n", + "En pratique on considère des tolérences absolue et relative composante par composante et on définit : $\\mathrm{sc}_i = \\mathrm{abstol}_i + \\mathrm{reltol}_i \\times \\max(|x_{0i}|,|x_{1i}|)$. On calcule alors le pas de façon à avoir \n", + "\n", + "$$\\mathrm{err} = \\sqrt{\\frac{1}{n}\\sum_{i=1}^n\\left(\\frac{x_{1i}-\\hat{x}_{1i}}{\\mathrm{sc}_i}\\right)^2}<1.$$\n", + "\n", + "\n", + "Référence : [Hairer, Nørsett, Wanner (2008) Solving Ordinary Differential Equations I Nonstiff Problems](https://link.springer.com/book/10.1007/978-3-540-78862-1).\n", + "\n", + "Dans `Julia`, on peut modifier les valeurs par défaut : reltol = 1.e-3 et abstol = 1.e-6\n", + "(lorsque ces valeurs sont des scalaires, on considère les mêmes quantités pour toutes les composantes).\n", + "\n", + "Réaliser l'intégration numérique pour \n", + "- reltol = 1e-3 et abstol = 1e-6\n", + "- reltol = 1e-6 et abstol = 1e-9\n", + "- reltol = 1e-10 et abstol = 1e-15\n", + "\n", + "et afficher les résultats en ajoutant la solution." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# calcul avec les options par défaut\n", + "sol = solve(prob, reltol = 1e-3, abstol = 1e-6)\n", + "p1 = plot(sol, label = [\"x₁(t)\" \"x₂(t)\"], title = \"reltol=1e-3, abstol=1e-6\")\n", + "\n", + "# A COMPLETER/MODIFIER\n", + "#\n", + "p2 = plot()\n", + "\n", + "#\n", + "p3 = plot()\n", + "\n", + "# solution exacte\n", + "T = t0:(tf-t0)/100:tf\n", + "sinT = sin.(T) # opération vectorielle\n", + "cosT = cos.(T)\n", + "p4 = plot(T,[(-1/25)*(13*sinT+9*cosT) (-1/25)*(3*sinT+4*cosT)], label = [\"x₁(t)\" \"x₂(t)\"], title = \"Solution exacte\")\n", + "\n", + "# affichage\n", + "plot(p1, p2, p3, p4, size=(900, 600))" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Pendule simple\n", + "\n", + "On s'intéresse ici au [pendule simple](https://fr.wikipedia.org/wiki/Pendule_simple). Les principes physiques de la mécanique classique donnent comme équation qui régit l'évolution du mouvement\n", + "\n", + "$$ ml^2\\ddot{\\alpha}(t)+mlg\\sin(\\alpha(t)) +k\\dot{\\alpha}(t)=0,$$\n", + "où $\\ddot{\\alpha}(t)$ désigne la dérivée seconde de l'angle $\\alpha$ par rapport au temps $t$. \n", + "\n", + "- En prenant comme variable d'état $x=(x_1,x_2)=(\\alpha, \\dot{\\alpha})$, écrire la fonction $f$ qui permet d'écrire l'équation différentielle sous la forme $\\dot{x}(t) = f(t,x(t))$.\n", + "- Coder cette fonction ci-dessous et exécuter le code. D'après-vous, observez-vous une oscillation ou une rotation du pendule ? \n", + "- Remplacer la vitesse angulaire initiale $\\dot{\\alpha}(0)$ par $2$. Commentaires." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "\"\"\"\n", + " Second membre de l'IVP\n", + " x : vecteur d'état\n", + " λ : vecteur de paramètres\n", + " t : variable de temps. Ici le temps n'intervient pas explicitement, le système est autonome.\n", + "\"\"\"\n", + "function pendule(x, λ, t)\n", + "\n", + " xpoint = similar(x)\n", + " g, l, k, m = λ\n", + " \n", + " # A COMPLETER/MODIFIER\n", + " xpoint[:] = zeros(size(x))\n", + " \n", + " return xpoint \n", + " \n", + "end\n", + "\n", + "#\n", + "g = 9.81\n", + "l = 10\n", + "k = 0\n", + "m = 1\n", + "λ = [g, l, k, m] # paramètres constants\n", + "\n", + "theta0 = pi/3\n", + "x0 = [theta0, 0] # état initial\n", + "\n", + "t0 = 0\n", + "tf = 3*pi*sqrt(l/g)*(1 + theta0^2/16 + theta0^4/3072) # 2*approximation de la période\n", + "tspan = (t0, tf) # instants initial et terminal\n", + "\n", + "prob = ODEProblem(pendule, x0, tspan, λ, reltol = 1.e-8, abstol = 1.e-8) # définition du problème en Julia\n", + "sol = solve(prob) # intégration numérique\n", + "\n", + "plot(sol, label = [\"x₁(t)\" \"x₂(t)\"]) # affichage de la solution" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Diagramme de phases.**\n", + "\n", + "- Exécutez le code ci-dessous et interprétez le graphique: où sont les oscillations, les rotations et les points d'équilibre stables et instables ?\n", + "- On considère le cas où $k=0.15$ (on introduit un frottement). Que se passe-t-il ?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#\n", + "g = 9.81\n", + "l = 1.5\n", + "k = 0\n", + "m = 1\n", + "λ = [g, l, k, m] # paramètres constants\n", + "\n", + "plt = plot(xlabel = \"x₁\", ylabel = \"x₂\", legend = false) # initialisation du plot\n", + "\n", + "for theta0 in 0:(2*pi)/10:2*pi\n", + " theta0_princ = theta0\n", + " tf = 3*pi*sqrt(l/g)*(1 + theta0_princ^2/16 + theta0_princ^4/3072) # 2*approximation of the period\n", + " tspan = (0.0,tf)\n", + " x0 = [theta0 0]\n", + " prob = ODEProblem(pendule, x0, tspan, λ, reltol = 1.e-8, abstol = 1.e-8)\n", + " sol = solve(prob)\n", + " plot!(plt, sol, idxs=(1,2), color=\"blue\") # lw = linewidth\n", + "end\n", + "\n", + "theta0 = pi-10*eps()\n", + "x0 = [theta0 0]\n", + "tf = 50 # problem for tf=50 1/4 of the period!\n", + "tspan = (0.0,tf)\n", + "prob = ODEProblem(pendule, x0, tspan, λ, reltol = 1.e-8, abstol = 1.e-8)\n", + "sol = solve(prob)\n", + "plot!(plt, sol, idxs=(1,2), xlims = (-2*pi,4*pi), color=\"green\") # lw = linewidth\n", + "\n", + "theta0 = pi+10*eps()\n", + "x0 = [theta0 0]\n", + "tf = 50\n", + "tspan = (0.0,tf)\n", + "prob = ODEProblem(pendule, x0, tspan, λ, reltol = 1.e-8, abstol = 1.e-8)\n", + "sol = solve(prob)\n", + "plot!(plt, sol, idxs=(1,2), xlims = (-2*pi,4*pi), color=\"green\") # lw = linewidth\n", + "\n", + "# circulation case\n", + "for thetapoint0 in 0:1.:4 \n", + " tf = 10\n", + " tspan = (0.,tf)\n", + " x0 = [-pi thetapoint0] # thetapoint0 > 0 so theta increases from -pi to ...\n", + " prob = ODEProblem(pendule, x0, tspan, λ, reltol = 1.e-8, abstol = 1.e-8)\n", + " sol = solve(prob)\n", + " plot!(plt, sol, idxs=(1,2), color=\"red\") # lw = linewidth\n", + "end\n", + "for thetapoint0 in -4:1.:0\n", + " tf = 10\n", + " tspan = (0.,tf)\n", + " x0 = [3*pi thetapoint0] # thetapoint0 < 0 so theta decreases from 3pi to ...\n", + " prob = ODEProblem(pendule, x0, tspan, λ, reltol = 1.e-8, abstol = 1.e-8)\n", + " sol = solve(prob)\n", + " plot!(plt, sol, idxs=(1,2), color=\"purple\") # lw = linewidth\n", + "end\n", + "plot!(plt, [-pi 0 pi 2*pi 3*pi], [0 0 0 0 0], seriestype=:scatter)\n", + "plot!(plt, xlims = (-pi,3*pi), size=(900, 600))\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Modèle de Van der Pol\n", + "\n", + "L'équation différentielle considérée est l'[équation de Van der Pol](https://fr.wikipedia.org/wiki/Oscillateur_de_Van_der_Pol)\n", + "$$(IVP)\\left\\{\\begin{array}{l}\n", + "\\dot{x}_1(t)=x_2(t)\\\\\n", + "\\dot{x}_2(t)=(1-x_1^2(t))x_2(t)-x_1(t)\\\\\n", + "x_1(0)=2.00861986087484313650940188\\\\\n", + "x_2(0)=0\n", + "\\end{array}\\right.\n", + "$$\n", + "jusqu'au temps $t_f=T=6.6632868593231301896996820305$, où $T$ est la période de la solution.\n", + "\n", + "Codez le second membre de l'IVP ci-dessous et exécutez le code. Commentaires." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "\"\"\"\n", + " Second membre de l'IVP: modèle de Van der Pol\n", + " x : vecteur d'état\n", + " λ : vecteur de paramètres\n", + " t : variable de temps. Ici le temps n'intervient pas explicitement, le système est autonome.\n", + "\"\"\"\n", + "function vdp(x, λ, t)\n", + "\n", + " xpoint = similar(x)\n", + " \n", + " # A COMPLETER/MODIFIER\n", + " xpoint[:] = zeros(size(x))\n", + " \n", + " return xpoint\n", + " \n", + "end\n", + "\n", + "#\n", + "t0 = 0\n", + "tf = 6.6632868593231301896996820305\n", + "tspan = (t0, tf)\n", + "\n", + "#\n", + "plot(xlabel = \"x₁\", ylabel = \"x₂\", legend = false)\n", + "\n", + "# Trajectoires intérieures\n", + "for x01 in -2:0.4:0\n", + " x0 = [x01,0]\n", + " prob = ODEProblem(vdp, x0, tspan, reltol = 1.e-8, abstol = 1.e-8)\n", + " sol = solve(prob)\n", + " plot!(sol, idxs=(1,2), color = \"blue\") \n", + "end\n", + "\n", + "# Trajectoires extérieures\n", + "for x02 in 2.5:0.5:4\n", + " x0 = [0,x02]\n", + " prob = ODEProblem(vdp, x0, tspan, reltol = 1.e-8, abstol = 1.e-8)\n", + " sol = solve(prob)\n", + " plot!(sol, idxs=(1,2), color = \"green\")\n", + "end\n", + "\n", + "# Cycle limite périodique\n", + "x0 = [2.00861986087484313650940188,0]\n", + "prob = ODEProblem(vdp, x0, tspan, reltol = 1.e-8, abstol = 1.e-8)\n", + "sol = solve(prob)\n", + "plot!(sol, idxs=(1,2), color = \"red\", lw = 2.)\n", + "\n", + "#\n", + "plot!([0], [0], seriestype=:scatter) # point d'équilibre\n", + "plot!(xlims = (-2.5, 2.5), ylims = (-3, 5), size=(900, 600))" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Stabilité.**\n", + "\n", + "On calcule ci-dessous les valeurs propres de la matrice jacobienne du second membre de l'IVP au point d'équilibre $x_e = (0, 0)$. Commentaires (pour les étuidants N7 rappelez-vous votre cours d'[automatique](https://gitlab.irit.fr/toc/etu-n7/controle-optimal/-/raw/master/ressources/notes-autom-2021.pdf))." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Jacobienne de la fonction vdp \n", + "dvdp(x) = ForwardDiff.jacobian(x -> vdp(x, [], 0), x)\n", + "\n", + "# Point d'équilibre et la matrice Jacobienne en ce point\n", + "xe = [0, 0]\n", + "A = dvdp(xe)\n", + "\n", + "# Valeurs propres de la matrice Jacobienne\n", + "eigvals(A)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Modèle proie-prédateur (modèle de Lotka-Volterra)\n", + "\n", + "L'équation différentielle considérée est donnée par les [équations de prédation de Lotka-Volterra](https://fr.wikipedia.org/wiki/Équations_de_prédation_de_Lotka-Volterra)\n", + "\n", + "$$\\left\\{\\begin{array}{l}\n", + "\\dot{x}_1(t)= \\phantom{-}x_1(t) ( \\alpha - \\beta x_2(t)) \\\\[0.5em]\n", + "\\dot{x}_2(t)= -x_2(t) ( \\gamma - \\delta x_1(t))\n", + "\\end{array}\\right.\n", + "$$\n", + "\n", + "où\n", + "\n", + "- $t$ est le temps ;\n", + "- $x(t)$ est l'effectif des proies en fonction du temps ;\n", + "- $y(t)$ est l'effectif des prédateurs en fonction du temps ;\n", + "\n", + "Les paramètres suivants caractérisent les interactions entre les deux espèces :\n", + "\n", + "- $\\alpha$, taux de reproduction intrinsèque des proies (constant, indépendant du nombre de prédateurs) ;\n", + "- $\\beta$, taux de mortalité des proies dû aux prédateurs rencontrés ;\n", + "- $\\delta$, taux de reproduction des prédateurs en fonction des proies rencontrées et mangées ;\n", + "- $\\gamma$, taux de mortalité intrinsèque des prédateurs (constant, indépendant du nombre de proies) ;\n", + "\n", + "**Questions.**\n", + "\n", + "- Le point $(0, 0)$ est clairement un point d'équilibre stable. Il existe un autre point d'équilibre, lequel ?\n", + "- Afficher l'autre point d'équilibre ainsi que quelques trajectoires du système dans le plan de phase, qui rentrent dans les limites du plot ci-dessous. Qu'observez-vous sur les trajectoires." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# ------------------------------\n", + "# DEBUT A COMPLETER/MODIFIER LE SECOND MEMBRE DE L'IVP\n", + "# ...\n", + "\n", + "# FIN A COMPLETER/MODIFIER LE SECOND MEMBRE DE L'IVP\n", + "# ------------------------------\n", + "\n", + "# paramètres\n", + "α = 2/3\n", + "β = 4/3\n", + "γ = 1\n", + "δ = 1\n", + "λ = [α, β, γ, δ]\n", + "\n", + "t0 = 0\n", + "tf = 20\n", + "tspan = (t0, tf)\n", + "\n", + "plt = plot(xlabel = \"x₁\", ylabel = \"x₂\", legend = false)\n", + "\n", + "# ------------------------------\n", + "# DEBUT A COMPLETER/MODIFIER L'AFFICHAGE\n", + "# ...\n", + "\n", + "# FIN A COMPLETER/MODIFIER L'AFFICHAGE\n", + "# ------------------------------\n", + "\n", + "plot!(xlims = (0, 4), ylims = (0, 2.5), size=(900, 600))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Phénomène de résonance\n", + "\n", + "Soit $\\omega$ et $\\omega_0$ deux réels strictement positifs. On considère l'équation différentielle\n", + "\n", + "$$\\ddot{y}(t) + \\omega_0^2 y(t) = \\cos(\\omega t).$$\n", + "\n", + "- En prenant comme variable d'état $x=(x_1,x_2)=(y, \\dot{y})$, écrire la fonction $f$ qui permet d'écrire l'équation différentielle sous la forme $\\dot{x}(t) = f(t,x(t))$.\n", + "- Coder cette fonction ci-dessous et exécuter le code : les solutions sont-elles bornées ?\n", + "- Remplacer la vitesse angulaire pour avoir $\\omega = \\omega_0$. Commentaires." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "\"\"\"\n", + " Second membre de l'IVP\n", + " x : vecteur d'état\n", + " λ : vecteur de paramètres\n", + " t : variable de temps. Ici le temps intervient explicitement, le système est non autonome.\n", + "\"\"\"\n", + "function resonance(x, λ, t)\n", + "\n", + " xpoint = similar(x)\n", + " \n", + " # A COMPLETER/MODIFIER\n", + " xpoint[:] = zeros(size(x))\n", + " \n", + " return xpoint\n", + "\n", + "end\n", + "\n", + "# parameters\n", + "ω = 1\n", + "ω₀ = 1/2\n", + "λ = [ω, ω₀]\n", + "\n", + "# integration times\n", + "t0 = 0\n", + "tf = 100\n", + "tspan = (t0, tf)\n", + "\n", + "# initial condition\n", + "x0 = [0, 0]\n", + "\n", + "# define the problem and solve it\n", + "prob = ODEProblem(resonance, x0, tspan, λ, reltol = 1.e-8, abstol = 1.e-8)\n", + "sol = solve(prob)\n", + "\n", + "function makegif()\n", + "\n", + " #\n", + " plt = plot(xlabel = \"x₁\", ylabel = \"x₂\", zlabel = \"t\", legend = false)\n", + "\n", + " #\n", + " ω == ω₀ ? lim = 50 : lim = 5\n", + " plot!(xlims = (-lim, lim), ylims = (-lim, lim), zlims = (t0, tf), size=(900, 600))\n", + "\n", + " # get x1, x2, t from sol\n", + " x1 = [sol.u[i][1] for i ∈ 1:length(sol.u)]\n", + " x2 = [sol.u[i][2] for i ∈ 1:length(sol.u)]\n", + " t = sol.t\n", + "\n", + " # plot the trajectory step by step and make a gif\n", + " i = 1\n", + " @gif for j ∈ 2:2:length(sol.t)\n", + " # plot the trajectory part from i to j\n", + " plot!(plt, x1[i:j], x2[i:j], t[i:j], color=:blue)\n", + " # update i \n", + " i = j\n", + " end\n", + "\n", + "end\n", + "\n", + "makegif()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Attracteur de Lorenz\n", + "\n", + "L'équation différentielle considérée est l'[équation de Lorenz](https://fr.wikipedia.org/wiki/Attracteur_de_Lorenz) donnée par\n", + "\n", + "$$\\left\\{\\begin{array}{l}\n", + "\\dot{x}_1(t)= \\phantom{-}\\sigma (x_2(t) - x_1(t)) \\\\[0.5em]\n", + "\\dot{x}_2(t)= \\rho\\, x_1(t) - x_2(t) - x_1(t)\\, x_3(t) \\\\[0.5em]\n", + "\\dot{x}_3(t)= x_1(t)\\, x_2(t) - \\beta x_3(t)\n", + "\\end{array}\\right.\n", + "$$\n", + "\n", + "où \n", + "\n", + "- $t$ est le temps ;\n", + "- $x(t)$ est proportionnel à l'intensité du mouvement de convection ;\n", + "- $y(t)$ est proportionnel à la différence de température entre les courants ascendants et descendants ;\n", + "- $z(t)$ est proportionnel à la déviation du profil vertical de température par rapport à la valeur linéaire de référence.\n", + "- $\\sigma$, $\\beta$ et $r$ sont des paramètres réels positifs.\n", + "- $\\sigma$ est le nombre de Prandtl ;\n", + "- $\\rho$ est le nombre de \"Rayleigh\".\n", + "\n", + "On fixe souvent $\\sigma = 10$, $\\beta = 8/3$ et $\\rho = 28$ pour illustrer le phénomène de chaos.\n", + "\n", + "Compléter le code ci-dessous et exécuter le. Observer le phénomène de chaos. Vous pouvez modifer la condition initiale." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "\"\"\"\n", + " Second membre de l'IVP\n", + " x : vecteur d'état\n", + " λ : vecteur de paramètres\n", + " t : variable de temps. Ici le temps intervient explicitement, le système est non autonome.\n", + "\"\"\"\n", + "function Lorentz(x, λ, t)\n", + "\n", + " xpoint = similar(x)\n", + " \n", + " # A COMPLETER/MODIFIER\n", + " xpoint[:] = zeros(size(x))\n", + " \n", + " return xpoint\n", + " \n", + "end\n", + "\n", + "# parameters\n", + "σ = 10\n", + "ρ = 28\n", + "β = 8/3\n", + "λ = [σ, ρ, β]\n", + "\n", + "# integration times\n", + "t0 = 0\n", + "tf = 100\n", + "tspan = (t0, tf)\n", + "\n", + "# initial condition\n", + "x0 = [0, 1, 0]\n", + "\n", + "# define the problem and solve it\n", + "prob = ODEProblem(Lorentz, x0, tspan, λ, reltol = 1.e-8, abstol = 1.e-8)\n", + "sol = solve(prob)\n", + "\n", + "function makegif()\n", + "\n", + " #\n", + " plt = plot(xlabel = \"x₁\", ylabel = \"x₂\", zlabel = \"x₃\", legend = false)\n", + "\n", + " # \n", + " plot!(plt, background_color = :royalblue4)\n", + "\n", + " # update the color of axis of the figure to white\n", + " plot!(plt, axiscolor = :white, tickfontcolor = :white, bordercolor = :white, fg_color_guide = :white)\n", + "\n", + " # plot the three equilibrium points\n", + " plot!(plt, [0], [0], [0], seriestype=:scatter, color=:red)\n", + " plot!(plt, [ sqrt(β*(ρ-1))], [ sqrt(β*(ρ-1))], [ρ-1], seriestype=:scatter, color=:red)\n", + " plot!(plt, [-sqrt(β*(ρ-1))], [-sqrt(β*(ρ-1))], [ρ-1], seriestype=:scatter, color=:red)\n", + "\n", + " # get x1, x2, t from sol\n", + " x1 = [sol.u[i][1] for i ∈ 1:length(sol.u)]\n", + " x2 = [sol.u[i][2] for i ∈ 1:length(sol.u)]\n", + " x3 = [sol.u[i][3] for i ∈ 1:length(sol.u)]\n", + "\n", + " # print min and max of each coordinate\n", + " #println(\"x1 : \", minimum(x1), \" \", maximum(x1))\n", + " #println(\"x2 : \", minimum(x2), \" \", maximum(x2))\n", + " #println(\"x3 : \", minimum(x3), \" \", maximum(x3))\n", + "\n", + " #\n", + " plot!(xlims = (-20, 20), ylims = (-25, 30), zlims = (0, 50), size=(900, 600))\n", + "\n", + " # print length of the time grid\n", + " #println(\"t : \", length(sol.t))\n", + "\n", + " # \n", + " duration = 10\n", + " fps = 10\n", + " frames = fps*duration\n", + " step = length(sol.t) ÷ frames\n", + "\n", + " # plot the trajectory step by step and make a gif\n", + " i = 1\n", + " animation = @animate for j ∈ 2:step:length(sol.t)\n", + " # plot the trajectory part from i to j\n", + " plot!(plt, x1[i:j], x2[i:j], x3[i:j], color=:gold2)\n", + " # update i \n", + " i = j\n", + " end\n", + "\n", + " gif(animation, \"lorentz.gif\", fps=fps)\n", + "\n", + "end\n", + "\n", + "makegif()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Julia 1.9.0", + "language": "julia", + "name": "julia-1.9" + }, + "language_info": { + "file_extension": ".jl", + "mimetype": "application/julia", + "name": "julia", + "version": "1.9.0" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +}