# ***************************************************************************
# TM1. Obtention d'un état final en chimie
# ***************************************************************************

import matplotlib.pyplot as plt#importation des bibliothèques
import numpy as np
import scipy.optimize as spo #pour l'utilisation de bisect (partie 3)


##1. approche graphique

C0 = 0.01#concentration initiale
K0 = 10**(-7.2) #valeur de la constante d'équilibre

def f(x):#calcule la valeur de la fonction en un point
    """calcule f(x)"""
    f = C0**2*(1+x)*(2*x+0.1)**2/(1-x)-K0
    return(f)


les_f=[]#liste vide qui contiendra les valeurs de f(x)
les_x = np.linspace(-0.05,0.999,100)#creation de la liste des x
#la fonction n'est pas définie en x=1

for x in les_x :#on remplit la liste les_f
    les_f.append(f(x))

plt.plot(les_x,les_f, 'g')#on trace la courbe
plt.title('f=Qr-K°')
plt.xlabel('x')
plt.ylabel('f')
plt.grid()
plt.figure()

#On réduit l'intervalle d'étude autour du zéro supposé
les_f=[]
les_x = np.linspace(-0.05,0.85,100)

for x in les_x :
    les_f.append(f(x))


plt.plot(les_x,les_f, 'g')
plt.title('f=Qr-K°')
plt.xlabel('x')
plt.ylabel('f')
plt.grid()
plt.show()

#Graphiquement, on voit que -0.05<x<+0.2

##2. Recherche de zéros par dichotomie

a=-0.05 #définition des bornes de l'intervalle de recherche du zéro
b=0.2

def dichotomie(a, b, epsilon):#définition de la fonction dichotomie
    g = a#définition des bornes gauche et droite de l'intervalle initial
    d = b
    n = 0#initialisation du compteur de boucle
    while d - g > 2 * epsilon:#tant que la largeur de l'intervalle est supérieure à 2epsilon
        m = (g + d)/2#milieu de l'intervalle
        if f(m) * f(g) <= 0:#si f(m) et f(g) sont de signes opposés
            d = m
        else:#sinon
            g = m
        n = n + 1#incrémentation du compteur de boucle
    return((d + g) / 2, n)#renvoie le milieu de l'intervalle trouvé et le nombre d'itérations

zero = dichotomie(a,b, 1e-9)#appel de la fonction dichotomie pour le calcul du zéro
print("zéro obtenu par la méthode de dichotomie, avec le nombre d'itérations :",zero)#affichage du resultat
#retourne (-0.03696737084537745, 27)

##3.fonction prédéfinie bisect de scipy. optimize (notée spo).
#spo.bisect(f,a,b) détermine une racine de f dans [a, b].
racine = spo.bisect(f,a,b)
print("zéro obtenu par bisect de scipy.optimize :",racine)
print("")



