- jeu. 01 février 2018
- Cours
- #ipython jupyter
Table des matières
- 1 Base de la programmation
- 2 Erreur sous Python
- 3 Python 3
- 4 Programmation sctructuré
- 5 Exemple: simulation de l’alunissage de Neil Amstrong (Apollo 11)
- 6 FIN
%matplotlib inline
#%autosave 300
import numpy as np
import scipy as sp
import matplotlib.pyplot as plt
from matplotlib import rcParams
rcParams['font.family'] = 'serif'
rcParams['font.size'] = 14
from IPython.core.display import HTML
from IPython.display import display
from matplotlib import animation
css_file = 'style.css'
HTML(open(css_file, "r").read())
# edit metadata   "livereveal": {"scroll": true }
# https://damianavila.github.io/RISE/customize.html"
Base de la programmation¶
Marc BUFFAT, dpt mécanique, Université Claude Bernard Lyon 1
Rappel de programmation Python¶
Python tutor: http://pythontutor.com¶
Outil en ligne permettant de visualiser l’execution d’un programme Python
Variable¶
variable:
- case mémoire pour stocker de l’information
- doit être déclaré (initialisé) avant d’être utilisé
x=1
x=x+1
y=2*x+1
x=y+1
Type de variable¶
fonction du type de l’information (entier, réel, chaine)
x=1
print(type(x))
x=1.0
print(type(x))
x='1'
print(type(x))
Initialisation d’une variable¶
attention on doit définir une variable (sa valeur) avant de l’utiliser !!
# erreur !
Y=X
# modification:  X,Y,x sont 3 variables #
Y=x
X=2
print(X,Y,x)
x=3
print(X,Y,x)
Portée d’une variable¶
Attention: dans une fonction les arguments et les variables dans la fonction sont locales.
Quelles sont les valeurs des variables a,b,c après execution du programme ci-dessous ?
a=3
c=-3
def func1(a,b):
    c=0
    def func2(a,b):
        c = a - b
        return c
    c=func2(b,a)
    return c
a=func1(2,1)
execution du code avec pythontutor¶
%load_ext tutormagic
%%tutor --lang python3 -h 400
a=3
c=-3
def func1(a,b):
    c=0
    def func2(a,b):
        c = a - b
        return c
    c=func2(b,a)
    return c
a=func1(2,1)
argument d’une fonction¶
Lors de l’appel d’une fonction, les arguments peuvent être des expressions, des valeurs ou des variables (si elles sont initialisées)
# exemple d'arguments
func1(x,x+1)
func1(c,2)
a=func1(a,a)
liste et tableau¶
- liste: ensemble ordonné de valeurs - ajout et suppression d’éléments
- la taille et le type peuvent variés
 
- tableau: ensemble ordonné de valeurs de même type - vecteurs, matrices
- taille fixée
 
- indice: on compte à partir de 0 - indice à partir de 0
- [ ] pour sélectionner un élèment
- [0] premier element
- [-1] dernier element
- [n0:n1:p] selection des elements de l’indice n0 (defaut 0) à n1 (exclus) avec un pas p (defaut 1)
 - aliasing attention à la copie- A=B aliasing (A et B sont identiques)
- A=B[:] copie
 
 
#  manipulation de liste
L=[1,2,3]
L1=L[:]
L1[-1]=4
L[0]=5
print(L,L1)
execution du code avec pythontutor¶
%%tutor --lang python3
L=[1,2,3]
L1=L[:]
L1[-1]=4
L[0]=5
# manipulation de tableau (avec aliasing)
X=np.linspace(1,5,5)
Y=X
Z=2*X
Y[0]=0
X[0]=Y[1]
Z[0]=1
print(X,Y,Z)
# decalage a droite: version 1
n = 5
X = np.linspace(1,5,5)
a = X[-1]
for i in range(n-1):
    X[i+1]=X[i]
X[0]=a
# decalage a droite: version 2
n=5
Y=np.linspace(1,n,n)
x=Y[-1]
for i in range(1,n):
    Y[n-i]=Y[n-i-1]
Y[0]=x
# validation
print(X)
print(Y)
exemple 2¶
Calcul de l’expression
  pour i de a N
  fin i
Pour calculer cette expression, on utilise l’une des deux fonctions suivantes. L’une est algorithmiquement fausse. Laquelle ?
# version 1
def iteration1(A,B,X):
    n = X.shape[0]
    Y = X[:]
    for i in range(n):
        sum=0.0
        for j in range(n):
            sum = sum + A[i,j]*Y[j]
            Y[i] = Y[i] - (sum - B[i])/A[i,i]
    return Y
# version 2
def iteration2(A,B,X):
    n = X.shape[0]
    Y = X[:]
    for i in range(n):
        sum=0.0
        for j in range(n):
            sum = sum + A[i,j]*Y[j]
        Y[i] = Y[i] - (sum - B[i])/A[i,i]
    return Y
# exemple de validation
n=3
X=np.random.rand(n)
A=np.random.rand(n,n)
B=np.random.rand(n)
# 
X1=iteration1(A,B,X)
print("X1=",X1)
X2=iteration2(A,B,X)
print("X2=",X2)
programmation récursive¶
- la fonction s’appelle elle-même
- calcul factorielle n!- n! = n*(n-1)!
 
Que calcule la fonction récursive suivante ?
def fonc(L):
    print("appel fonc avec ",L)
    if not L:
        return 0
    else:
        return 1 + fonc(L[1:])
# resultat
fonc([1,2,3,4])
Erreur sous Python¶
retour erreur
   Traceback (most recent call last):
    File "test.py", line 6, in <module>
    test()
    File "test.py", line 3, in test
    print table[4]
    IndexError: list index out of range
code d’erreurs
- IndentationError : - expected an indented block
- IndexError: - list index out of range
- SyntaxError : - inconsistent use of tabs and spaces in indentation
- NameError : - name 'X' is not defined
- ImportError : - no module named X
- ZeroDivisionError : - X division or modulo by zero
Python 3¶
- print est une fonction - print("Bonjour")
au lieu de (python 2.7)
  print "Bonjour"
- la division / est une division réelle (entière sous python 2.7) - 4 / 2 = 2.0 4 // 2 = 2
# fonction de formattage 
print("Bonjour {} {}".format("Marc","Buffat"))
# division entière et réelle
print("division : ",4/2, 4//2)
print("division : ",1/2, 1//2)
Programmation sctructuré¶
principe: “Divide and Conquer”
analyse descendante: top-down design¶
- définition des différentes étapes pour résoudre le problème
- on découpe le problème en une série de sous-problèmes plus simples (si possible indépendant)
- on spécifie ce qui doit résolu dans chacun des sous-problèmes sans forcément dire comment
- puis on itère au niveau des sous problèmes.

programmation ascendante: bottom-up programming¶
- on programme d’abord les sous-problèmes(sous forme de fonction)
- on validation les fonctions
- puis on réitère en remontant dans l’arbre jusqu’au programme principal
- on crée une bibliothéque
- on éffectue l’analyse et la validation globale - règles réutiliser les fonctions déjà écrites et validées (bibliothèques): principe du moindre effort ! 
Exemple: simulation de l’alunissage de Neil Amstrong (Apollo 11)¶

On a perdu le pilotage automatique et il faut oser le module lunaire (LEM) sur la lune en arrivant avec une vitesse quasiment nulle. Pour cela on dispose de rétro-fusées permettant de ralentir la chute du LEM.
- On contrôle manuellement ces rétro-fusées en sélectionnant une poussée (de 0 à 9), correspondant à l’éjection de carburant avec un débit $Qe$ variable et une vitesse $Ue$ fixe.
- Mais on dispose d’une quantité limitée de carburant que l’on doit utiliser avec modération pour pouvoir atterrir en douceur.
modèle physique¶
Le LEM, de masse initiale $M0$, est soumis à la gravité $g$ de la lune et à la poussée des rétro-fusées, correspondant à l’éjection d’un débit de fuel $Qe$ à un vitesse $Ve$ . 

modèle mathématique¶
Equation du mouvement: $$ \frac{d^2 Z}{dt^2} = -g + \frac{Qe*Ue}{M0-Qe*t}$$
en intégrant sur la durée d’une commande $T$ $\rightarrow$ vitesse $V$ $$ V = V0 + g*T + Ue * \ln{(1 - \frac{Qe*T}{M0})} $$ La masse du LEM $M$ diminue $$M = M0 -Qe*T$$ Approximation par DL car $X=\frac{Qe*T}{M0} \ll 1$ $$ V = V0 + g*T - Ue*(X + \frac{X^2}{2} + \frac{X^3}{3} + \frac{X^4}{4} + \frac{X^5}{5})$$ d’où l’altitude $Z$ $$ Z = Z0 - V0*T - g \frac{T^2}{2} + Ue*T*(\frac{X}{2} + \frac{X^2}{6} + \frac{X^3}{12} + \frac{X^4}{20} + \frac{X^5}{30})$$ expression utilisée dans les premiers programmes en BASIC.
cas particuliers¶
- Si le fuel est épuisé ($Qe=0$), le LEM atteins la surface lunaire au bout d’un temps $T$ solution de l’équation du 2nd degré: $$ 0 = Z0 - V0*T -g \frac{T^2}{2}$$ soit $T = (-V0 + \sqrt{V0^2 + 2 g Z0})/g$ 
- Près de la surface, $T$ trop grand $\rightarrow$ prédiction $Z0 < 0$ - calcul $T$ donnant l’altitude $Z=0$, solution d’une équation du 6ième degré.
- calcul par approximations successives en utilisant un DL de $Z(t)$ - estimation $T0$ de $T$ $$ T0 = \frac{-V0 + \sqrt{V0^2 + 2 (g-\frac{Ue*Qe}{M0}) Z0}}{g-\frac{Ue*Qe}{M0}} $$
- recalcule $V0$ et $Z0$, puis recommence.
 
 
Algorithme: analyse top-down¶
problème global¶

sous-problème lecture commande¶

sous-problème VitesseAltitude¶
applications des formules mathématiques de l’analyse précédente
$$ V = V0 + g*T - Ue*(X + \frac{X^2}{2} + \frac{X^3}{3} + \frac{X^4}{4} + \frac{X^5}{5})$$$$ Z = Z0 - V0*T - g \frac{T^2}{2} + Ue*T*(\frac{X}{2} + \frac{X^2}{6} + \frac{X^3}{12} + \frac{X^4}{20} + \frac{X^5}{30})$$sous-problème Alunissage¶

Implémentation fonctions python¶
%%bash
cat alunissage.py
programme principale¶
from alunissage import Lecture_Cde, VitesseAltitude, Alunissage
# conditions initiales
#Z0 = 190000. # position
Z0 = 100000
V0 = 1580.   # et vitesse
M0 = 15000.  # masse initiale du LEM
Me = 8000.   # dont une masse de fuel
t  = 0.      # temps simulation
dt = 10.     # pas en temps entre chaque commande
# sauvegarde données
alt=[Z0]
vit=[V0]
tps=[0.]
fuel=[Me]
print("Simulation alunissage")
while np.abs(Z0)>1.e-2 :
    ch = input("commande (0-9):")
    Qe,T = Lecture_Cde(V0,Z0,Me,dt,ch)
    # calcul de la nouvelle position du LEM
    V1,Z1 = VitesseAltitude(V0,Z0,Qe*T/M0,T)
    # test si alunnissage
    if Z1 < 1.e-2 :
        V1,Z1,T = Alunissage(V0,Z0,M0,Qe)
    # mise a jour de la position du LEM
    Z0 = Z1;      V0 = V1
    Me = Me-Qe*T; M0 = M0-Qe*T
    t  = t + T
    print("t=",int(t),"s Z=",int(Z0),"m V=",int(V0),"m/s fuel=",int(Me),"kg")
    # sauvegarde donnérs
    alt.append(Z0)
    vit.append(V0)
    tps.append(t)
    fuel.append(Me)
# fin simulation
print("Alunissage avec une vitesse ",int(V0)," m/s")
if V0<=0.5 :
    print("Alunissage parfait")
elif V0<=5. :
    print("Bon alunissage, mais perfectible")
elif V0<=27.:
    print("Accident à l'alunissage. Attendez les secours en esperant que vous avez assez d'oxygene !!!")
else :
    print("Crash fatal: aucun survivant")
plt.figure(figsize=(16,8))
plt.subplot(1,3,1)
plt.plot(tps,alt,lw=2)
plt.title("altitude")
plt.subplot(1,3,2)
plt.plot(tps,vit,lw=2)
plt.title("vitesse")
plt.subplot(1,3,3)
plt.plot(tps,fuel,lw=2)
plt.title("fuel")
version avec ncurses¶
python lunar_landing.py
FIN¶
 
