# -*- coding: utf-8 -*-
"""TP_2_Titrage_des_ions_carbonate_complété.ipynb

Automatically generated by Colab.

Original file is located at
    https://colab.research.google.com/drive/1bcrxhsMNUYs6ImCmRqvT72gOe5aeIK9C

#**1. Dosage pH - métrique des ions carbonate par l'acide chlorhydrique**

## Description du protocole :
- On procède à l'étalonnage du pH - mètre grâce aux solutions tampon de $pH = 4,0$ et $pH = 7,0$ ,
- On remplit la burette d'une solution d'acide chlorhydrique ($\mathrm {H_{3}O_{(aq)}^{+}, Cl_{(aq)}^{-})}$ à une concentration de $\mathrm {0,1 \ mol.L^{–1}}$
- On prélève $20,0 \ mL$ d'une solution de carbonate de solution $\mathrm {( CO_{3(aq)}^{2-} , 2 Na_{(aq)} ^{+})}$ à l'aide d'une pipette jaugée deux traits de $20,0 \ mL$ dont on cherche la concentration.

## Mesures
On relève le $pH$ en fonction du volume d'acide chlorhydrique versé en faisant très attention aux variations de $pH$. L'ajout s'arrête vers $\mathrm {V_{acide} = 20, 0 \ mL}$ quand on s'aperçoit que le second saut de pH est bien dépassé.

La courbe est tracée au fur et à mesure de la prise des points.

#Scripts Python
On entre les valeurs de pH et de volumes relevées sous deux tableaux "array" disctincts.

L'idée est de :
  - Tracer la courbe pH - métrique,
  - Ecrire une fonction dérivée pour déterminer le ou les volumes à l'équivalence,
  - Calculer la concentration de la dibase,
  - Tracer l'évolution des quantités de matière en fonction du volume de titrant versé, d'une façon générale :
    - la dibase, ici les ions carbonate
    - l'espèce amphotère, ici les ions hydrogénocarbonate
    - le diacide, ici l'acide carbonique
    - le titrant, ici l'acide chlorhydrique
"""

#Importation des bibliothèques
import matplotlib.pyplot as plt
import numpy as np

# Entrée des valeurs expérimentales
Va = np.array([0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.2, 4.4, 4.6, 4.8, 5, 5.2, 5.4, 5.6, 5.8, 6.0, 6.5, 7.0, 7.5, 8, 8.5, 9.0, 9.2, 9.4, 9.6, 9.8, 10.0, 10.2, 10.4, 10.6, 10.8, 11.0, 11.2, 11.4, 11.6, 11.8, 12, 12.5, 13, 13.5, 14, 14.5, 15, 15.5, 16, 16.5, 17, 17.5, 18, 18.5, 19, 19.5, 20])
pH = np.array([10.83, 10.63, 10.45, 10.27, 10.12, 9.93, 9.78, 9.57, 9.27, 9.18, 8.97, 8.74, 8.17, 7.6, 7.35, 7.14, 7.03, 6.9, 6.81, 6.64, 6.47, 6.28, 6.11, 5.87, 5.7, 5.52, 5.42, 5.19, 4.91, 3.98, 3.19, 2.89, 2.69, 2.63, 2.55, 2.45, 2.42, 2.36, 2.32, 2.28, 2.2, 2.12, 2.06, 2.01, 1.96, 1.93, 1.89, 1.86, 1.83, 1.81, 1.78, 1.76, 1.73, 1.72, 1.7, 1.68])

"""#**2. Tracé de la courbe du pH en fonction du volume de solution titrante versé**"""

#Tracé de la courbe pH = f(V)

plt.plot(Va, pH, 'b+')
plt.xlabel('Volume de solution titrante versée / mL')
plt.ylabel('pH')
plt.title('Evolution du pH en fonction de Va versé')
plt.grid()
plt.show()

"""# **3. Évaluation du volume équivalent**

On estime numériquement les valeurs de $\frac{\mathrm{d}pH}{\mathrm{d}V}$ pour divers volumes $V$ de solution titrante versée. Les valeurs de $\frac{\mathrm{d}pH}{\mathrm{d}V}$ sont déterminées à l'aide de la dérivée centrée sur un point d'abscisse $V_i$, c'est à dire :

$$ \left( \dfrac{dpH}{dV} \right)_i =  \dfrac {pH_{i+1}-pH_{i-1}}{V_{i+1}-V_{i-1}}. $$

Ce schéma numérique limite en partie l'influence du bruit et n'induit pas de décalage. Il faut noter qu'on ne peut évaluer ainsi la dérivée sur les points extrèmes — on n'en a de toute façon pas besoin. On crée une fonction `VolEq` qui prend en argument les array `V` et `pH`, et qui retourne :
* un array contenant les dérivées numériques ;
* un array contenant les volumes, privés des deux points extrèmes.

Pour évaluer le volume équivalent, on repère le volume qui maximise la dérivée précédemment calculée.

#Calcul de la dérivée :
- Calcul de la dérivée centrée via numpy qui fait tout le travail : élimination des deux points en amont et en aval pour permettre le calcul sur les vecteurs.
- Numpy balaye automatiquement le tableau pour calculer les valeurs de cette dérivée centrée. Cela permet d'éviter de faire des boucles conditionnelles (type for ou while).

 - Exemple de premiers calculs : (10.45 - 10.83) / (1.0-0.0) = -0.38 et ainsi de suite : (10.27-10.63)/(1.5-0.5) = -0.36

- En Python, avec Numpy, pour sélectionner un sous-ensemble de données dans un `array`, on utilise les crochets []. Par exemple :
  * pour avoir un sous-ensemble des 10 _premiers_ éléments d'un `array` `x`, on fait : `x[:9]` ;
  * pour avoir un sous-ensemble des 10 _derniers_ éléments d'un `array` `x`, on fait : `x[-9:]` ;
  * pour avoir un sous ensemble avec les 2e, 3e et 4 éléments d'un `array` `x`, on fait : `x[1:4]` ;
  * si on écrit `x[:-2]`; on enlève les deux *derniers* éléments d'un `array` `x` ;
  * si on écrit `x[2:]`; on enlève les deux *premiers* éléments d'un `array` `x`.
"""

def derivee1(x,y):
    return (y[2:]-y[:-2])/(x[2:]-x[:-2])

derpH = derivee1(Va, pH)

Va_sub = Va[1:-1] # on redimensionne les valeurs de Va pour qu'elles soient de même taille que derpH


plt.plot(Va_sub, derpH , '+-', color = 'brown', label="dérivée")
plt.xlabel("Va (mL)")
plt.ylabel("$\dfrac{pH}{dV}$'")
plt.grid(linestyle='-.')
plt.title("détermination d'un volume à l'équivalence")
plt.xlim(0,20)
plt.ylim(-10,0)
plt.legend()
plt.show()

print('Vaeq 2 =', Va_sub[np.argmin(derpH)], 'mL')

"""# Détermination des deux volumes à l'équivalence

Pour l'instant, on a obtenu uniquement le second volume à l'équivalence.
Pour obtenir également le premier, on peut également utiliser des opérateurs booléens pour sélectionner certaines valeurs. Par exemple :
* `Va[Va<14]` sélectionne toutes les valeurs de `Va` qui sont plus petites que 14 ;
* `Va[(Va<14) & (Va>1)]` sélectionne toutes les valeurs de `Va` qui sont plus petites que 14 et plus grandes que 1.

On décide d'afficher les valeurs des volumes pour lesquels la dérivée du pH est inférieure à un seuil qu'on se donne en regardant le graphe précédent. Cela permet d'en déduire les deux volumes équivalents.
"""

print( Va_sub[derpH<-2], "\n", derpH[derpH<-2], sep='' )

"""#Calcul de l'évolution des quantités de matière au cours du dosage


Méthode classique, valeur sûre, qui utilise des boucles conditionnelles et des listes.
"""

#Calcul de la concentration de la dibase
Ca = 0.1  # concentration de la solution titrante de l'acide chlorhydrique
V_0=20.0
Vae1=4.8
Vae2=10

C_b=(Ca*Vae2/(2*V_0))
print ("La concentration de la dibase est : " , round(C_b,3),  "en mol.L^-1")

#création des listes qui seront retransformées en tableaux numpy"
n_carb=[]
n_amph=[]
n_acide=[]
n_acide_carb=[]

def n_avant_eq1(i):
                                            #La commande append permet de remplir une liste au fur et à mesure des itérations
    n_carb.append((C_b*V_0-Ca*i))
    n_amph.append(Ca*i)
    n_acide.append(0)
    n_acide_carb.append(0)

def n_entre_Veq(i):
    n_carb.append(0)
    n_amph.append(C_b*V_0-Ca*(i-Vae1))
    n_acide.append(0)
    n_acide_carb.append(Ca*(i-Vae1))

def n_apres_eq(i):
                                         #La commande append permet de remplir une liste au fur et à mesure des itérations
  n_carb.append(0)
  n_amph.append(0)
  n_acide_carb.append(Ca*(Vae2-Vae1))
  n_acide.append((Ca*i-2*C_b*V_0))


for i in Va:
    if i<=Vae1:
     n_avant_eq1(i)

    elif Vae1 < i < Vae2:

     n_entre_Veq(i)

    else:
     n_apres_eq(i)

#transformation des listes en array
n_carb=np.array(n_carb)
n_acide=np.array(n_acide)
n_amph=np.array(n_amph)
n_acide_carb=np.array(n_acide_carb)

#Affichage graphique
plt.plot(Va,n_carb,'+-', color= "blue", label="n(ions carbonate)")
plt.plot(Va,n_amph,'+-',color= "purple", label="n(ions hydrogénocarbonate)")
plt.plot(Va,n_acide_carb,'+-', color= "green", label="n(acide carbonique)")
plt.plot(Va,n_acide,'+-', color= "red", label="n(acide chlorhydrique)")

plt.xlabel('V en mL')
plt.ylabel('n en mmol')
plt.title('Évolution des quantités de matière au cours du titrage')
plt.legend()
plt.grid(linestyle='-.')
plt.show()