diff --git a/tp/ode.ipynb b/tp/ode.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..aace7dd676a87a3f52dba7fffe198a48fe4f5137 --- /dev/null +++ b/tp/ode.ipynb @@ -0,0 +1,906 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "[<img src=\"https://gitlab.irit.fr/toc/etu-n7/controle-optimal/-/raw/master/ressources/Logo-toulouse-inp-N7.png\" alt=\"N7\" height=\"100\"/>](https://gitlab.irit.fr/toc/etu-n7/controle-optimal)\n", + "\n", + "# Intégration numérique\n", + "\n", + "- Date : 2023\n", + "- Durée approximative : 1 séance (à finir à la maison)" + ] + }, + { + "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": [ + "using DifferentialEquations\n", + "using ForwardDiff\n", + "using LinearAlgebra\n", + "using Plots\n", + "include(\"utils.jl\"); # plot_traj!, plot_flow!" + ] + }, + { + "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. Ici le temps intervient explicitement, le système est non autonome.\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=(850, 550))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Sur l'explosion des solutions en temps fini\n", + "\n", + "Nous allons ici résoudre le problème à valeur initiale $\\dot{x}(t) = 1 + x^p(t)$ avec $p \\ge 1$ et $x(0)=0$. \n", + "\n", + "- Coder la fonction $f$ qui permet d'écrire l'équation différentielle sous la forme $\\dot{x}(t)=f(t,x(t))$.\n", + "- Déterminer à partir de quelle valeur de $p\\ge 1$ la solution explose en temps fini (à $0.1$ près) inférieur à la valeur 3." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "\"\"\"\n", + " Second membre de l'IVP\n", + " x : vecteur d'état\n", + " p : scalaire\n", + " t : variable de temps. Ici le temps n'intervient pas explicitement, le système est autonome.\n", + "\"\"\"\n", + "function f(x, p, t)\n", + " return 0.0\n", + "end\n", + "\n", + "#\n", + "x0 = 0.0\n", + "t0 = 0.0\n", + "tf = 3\n", + "tspan = (t0, tf) # instants initial et terminal\n", + "\n", + "#\n", + "xspan = 0:0.01:2\n", + "\n", + "#\n", + "pf = plot()\n", + "px = plot()\n", + "\n", + "#\n", + "p = 1\n", + "prob = ODEProblem(f, x0, tspan, p, reltol = 1.e-8, abstol = 1.e-8) # définition du problème en Julia\n", + "sol = solve(prob) # intégration numérique\n", + "pf = plot!(pf, xspan, x -> (f(x, p, t0)-1), label = \"p=$p\") # affichage du second membre\n", + "px = plot!(px, sol, label = \"p=$p\") # affichage de la solution\n", + "\n", + "#\n", + "####################################\n", + "p = 1 ######### A MODIFIER #########\n", + "####################################\n", + "prob = ODEProblem(f, x0, tspan, p, reltol = 1.e-8, abstol = 1.e-8) # définition du problème en Julia\n", + "sol = solve(prob) # intégration numérique\n", + "pf = plot!(pf, xspan, x -> (f(x, p, t0)-1), label = \"p=$p\") # affichage du second membre\n", + "px = plot!(px, sol, label = \"p=$p\") # affichage de la solution\n", + "\n", + "#\n", + "p = 2\n", + "prob = ODEProblem(f, x0, tspan, p, reltol = 1.e-8, abstol = 1.e-8) # définition du problème en Julia\n", + "sol = solve(prob) # intégration numérique\n", + "pf = plot!(pf, xspan, x -> (f(x, p, t0)-1), label = \"p=$p\") # affichage du second membre\n", + "px = plot!(px, sol, label = \"p=$p\") # affichage de la solution\n", + "\n", + "#\n", + "plot!(pf, xlims=(0, 2), ylims=(0, 4))\n", + "plot!(px, xlims=(t0, tf), ylims=( 0, 100))\n", + "plot(pf, px, size=(900, 400))" + ] + }, + { + "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", + "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, vars=(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, vars=(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, vars=(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, vars=(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, vars=(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=(850, 550))\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", + "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, vars=(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, vars=(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, vars=(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=(850, 550))" + ] + }, + { + "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 (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=(850, 550))" + ] + }, + { + "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.\n", + "\n", + "Remarque : voir la page Wikipedia sur le [phénomène de résonance](https://fr.wikipedia.org/wiki/Résonance#:~:text=Le%20phénomène%20de%20résonance%20n,en%20phase%20»%20avec%20cette%20dernière.) pour plus d'informations." + ] + }, + { + "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", + "ω₀ = ω/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=(850, 550))\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 n'intervient pas explicitement, le système est autonome.\n", + "\"\"\"\n", + "function Lorentz(x, λ, t)\n", + "\n", + " xpoint = similar(x)\n", + " σ, ρ, β = λ\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", + " #\n", + " plot!(xlims = (-20, 20), ylims = (-25, 30), zlims = (0, 50), size=(850, 550))\n", + "\n", + " # \n", + " duration = 10\n", + " fps = 10\n", + " frames = fps*duration\n", + " step = length(sol.t) ÷ frames\n", + "\n", + " # return if there is nothing to compute\n", + " if (step == 0)\n", + " return;\n", + " end\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()" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Flots en dimension 2\n", + "\n", + "On considère le problème de contrôle optimal suivant:\n", + "\n", + "$$ \\frac{1}{2}\\int_0^{1} u^2(t)\\,\\mathrm{d}t \\to \\min, $$\n", + "\n", + "sous les contraintes\n", + "\n", + "$$ \\dot{x}(t) = -x(t) + u(t)$$\n", + "\n", + "$$ x(0)=x_0=-1,\\quad x(1)=0. $$\n", + "\n", + "Le but est ici de tracer les extrémales et le flot associé pour des points initiaux $z(0) = (x_0, p(0))$." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "On note $z = (x, p)$ la paire état, état adoint. On note $F(t, z)$ le système hamiltonien donné par le PMP, c-a-d:\n", + "\n", + "$$\n", + "F(t, z) = \\left(\\frac{\\partial H}{\\partial p}(t, z, u(z)), -\\frac{\\partial H}{\\partial x}(t, z, u(z))\\right)\n", + "$$\n", + "\n", + "où $u(z)$ est le contrôle maximisant. \n", + "\n", + "- Codez ci-dessous la fonction $F$ et visualiser son flot. \n", + "- Visualisez l'extrémale la plus proche de la solution.\n", + "- Qu'observez-vous sur la forme des courbes vertes, c-a-d des fronts d'ondes ? Pourquoi ?\n", + "\n", + "**Remarque.** On rappelle que les extrémales s'écrivent $x(t) = p_0\\, \\mathrm{sh}(t) + x_0\\, e^{-t}$, $p(t) = p_0\\, e^t$." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# système hamiltonien\n", + "function F(z)\n", + " zpoint = similar(z)\n", + " \n", + " # A COMPLETER/MODIFIER\n", + " zpoint = zeros(size(z))\n", + "\n", + " return zpoint\n", + "end\n", + "\n", + "t0 = 0\n", + "tf = 1\n", + "\n", + "# initialisation du plot\n", + "plt = plot()\n", + "ymin = -0.2\n", + "ymax = 2.5\n", + "\n", + "# plot de trajectoires\n", + "z0 = [[-1, p0] for p0 ∈ range(ymin, ymax, length=50)]\n", + "plot_traj!(plt, F, z0, tf)\n", + "\n", + "# plot du flot\n", + "z0 = [[-1, p0] for p0 ∈ range(ymin, ymax, length=50)]\n", + "plot_flow!(plt, F, z0, tf)\n", + "\n", + "# affichages additionels\n", + "plot!(plt, xlims = (-1.2, 2), ylims = (ymin, ymax))\n", + "plot!(plt, [-1, -1], [ymin, ymax], linestyle = :dot, color = :black)\n", + "plot!(plt, [0, 0], [ymin, ymax], linestyle = :dot, color = :black, size=(850, 550), xlabel = \"x\", ylabel = \"p\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "On maintenant considère le problème de contrôle optimal suivant:\n", + "\n", + "$$ \\frac{1}{2}\\int_0^{1} u^2(t)\\,\\mathrm{d}t \\to \\min, $$\n", + "\n", + "sous les contraintes\n", + "\n", + "$$ \\dot{x}(t) = -x(t) + \\alpha x^2(t) + u(t)$$\n", + "\n", + "$$ x(0)=x_0=-1,\\quad x(1)=0. $$\n", + "\n", + "Le but est ici de tracer les extrémales et le flot associé pour des points initiaux $z(0) = (x_0, p(0))$. Visualisez le flot et le tp est terminé." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# paramètre\n", + "α = 1.5\n", + "\n", + "# système hamiltonien\n", + "function F(z)\n", + " zpoint = similar(z)\n", + " zpoint[1] = -z[1] + α*z[1]^2 + z[2]\n", + " zpoint[2] = (1 - 2*α*z[1])*z[2]\n", + " return zpoint\n", + "end\n", + "\n", + "t0 = 0\n", + "tf = 1\n", + "\n", + "# initialisation du plot\n", + "plt = plot()\n", + "ymin = -0.2\n", + "ymax = 2.5\n", + "\n", + "# plot de trajectoires\n", + "z0 = [[-1, p0] for p0 ∈ range(ymin, ymax, length=50)]\n", + "plot_traj!(plt, F, z0, tf)\n", + "\n", + "# plot du flot\n", + "z0 = [[-1, p0] for p0 ∈ range(ymin, ymax, length=100)]\n", + "plot_flow!(plt, F, z0, tf)\n", + "\n", + "# affichages additionels\n", + "plot!(plt, xlims = (-1.2, 2), ylims = (ymin, ymax))\n", + "plot!(plt, [-1, -1], [ymin, ymax], linestyle = :dot, color = :black)\n", + "plot!(plt, [0, 0], [ymin, ymax], linestyle = :dot, color = :black, size=(850, 550), xlabel = \"x\", ylabel = \"p\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Julia 1.10.2", + "language": "julia", + "name": "julia-1.10" + }, + "language_info": { + "file_extension": ".jl", + "mimetype": "application/julia", + "name": "julia", + "version": "1.10.2" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +}