from math import *
import matplotlib.pyplot as plt

from scipy.integrate import odeint

## Méthode d'Euler pour les équations différentielles d'ordre 1
## On travaille dans tout le TD sur l'équadiff

##    τ y' + y = ...

## Dans le TD, on fixe la constante de temps τ=1
## et on prendra toujours la valeur initiale y0=1

## Liste des dates
# nombre de points
N=20
## Q5
## Créer la variable tList contenant N points de 0 à 5 inclus, régulièrement espacés
pas=5/(N-1)
tList=[i*pas for i in range(N)]

## Q6
## Compléter : c'est la fonction F fondamentale de l'équadiff qui calcule
## la dérivée y'; ici l'équadiff est homogène.
def Fequadiff(y,t):
    return -y

## Q7
## Compléter pour retourner la liste [yk] nommée yList, impérativement de même longueur
## que tList (sinon, une erreur surviendra lors du tracé).
## (c'est une bonne idée de le vérifier après l'appel, grâce à la commande len).
# Construit la liste des estimations des yk : fonction sans argumement car la valeur
# initiale est fixée à 1, et car tList et la fonction de l'équadiff sont des variables
# globales.

def resoutEuler():
    yk=1
    yList=[yk]
    for i in range(N-1): # si N, tList[i] déclenchera une erreur à la fin
        tk=tList[i]
        tkp1=tList[i+1]
        yk=yk+Fequadiff(yk,tk)*(tkp1-tk)
        yList.append(yk)
    return yList

## Q8
## Expliquer les deux premières lignes du code : voir l'aide de odeint
## dans le document d'accompagnement.
def resoutOde():
    res=odeint(Fequadiff,1,tList)
    yList=[r[0] for r in res]
    return yList

# yList=resoutEuler()
# plt.plot(tList,yList,'b-',label='Euler')
# yList=resoutOde()
# plt.plot(tList,yList,'g-',label='ODE(rk4)')
# ## Q9
# ## Coder la fonction vraie, solution de l'équadiff homogène (compléter)
# def fonctionVraie(t):
#     return exp(-t)
#
# yList=[fonctionVraie(t) for t in tList]
# plt.plot(tList,yList,'r.',label='exact')
# plt.legend()
# plt.show()

## Q10
## Copier le code précédent, du premier yList= jusqu'au plt.show(), et le coller en
## dessous, puis placer le code d'origine en commentaires pour le conserver :
## sélection, clic droit, Commenter
## Modifier le code copié pour afficher les deux fonctions εk, d'Euler, en points
## bleus, et de odeint (Runge-Kutta = RK4), en points rouges.
## Commenter ensuite le code d'Euler pour ne visualiser que les erreurs RK4.

def fonctionVraie(t):
    return exp(-t)

# yList=resoutEuler()
# for i in range(N):
#     yList[i]-=fonctionVraie(tList[i])
# plt.plot(tList,yList,'b.',label='erreur Euler')
yList=resoutOde()
for i in range(N):
    yList[i]-=fonctionVraie(tList[i])
plt.plot(tList,yList,'r.',label='erreur ODE(rk4)')

plt.legend()
plt.show()


## Q11
## Modifier la valeur de N (défini au début du fichier) pour voir son influence sur les
## erreurs commises : N = 1000,  N = 10 (une réexécution du fichier complet par
## "Ctrl-E" doit afficher les nouveaux tracés sans erreurs).

## Q12 : voir doc d'accompagnement
