From 7a24383cf2c56f2a68c0e741a5c12cd0f89c32ec Mon Sep 17 00:00:00 2001 From: Anthony Debucquoy Date: Sun, 21 May 2023 20:00:59 +0200 Subject: [PATCH] first commit --- complexes_MEDTA.txt | 62 +++++++++ logKf_EDTA.txt | 62 +++++++++ temp.py | 313 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 437 insertions(+) create mode 100644 complexes_MEDTA.txt create mode 100644 logKf_EDTA.txt create mode 100644 temp.py diff --git a/complexes_MEDTA.txt b/complexes_MEDTA.txt new file mode 100644 index 0000000..98a02a5 --- /dev/null +++ b/complexes_MEDTA.txt @@ -0,0 +1,62 @@ +Ag+, [Ag(EDTA)]3- +Al3+, [Al(EDTA)]- +Am3+, [Am(EDTA)]- +Ba2+, [Ba(EDTA)]2- +Be2+, [Be(EDTA)]2- +Bi3+, [Bi(EDTA)]- +Ca2+, [Ca(EDTA)]2- +Cd2+, [Cd(EDTA)]2- +Ce3+, [Ce(EDTA)]- +Cf3+, [Cf(EDTA)]- +Cm3+, [Cm(EDTA)]- +Co2+, [Co(EDTA)]2– +Co3+, [Co(EDTA)]– +Cr2+, [Cr(EDTA)]2- +Cr3+, [Cr(EDTA)]- +Cu2+, [Cu(EDTA)]2- +Dy3+, [Dy(EDTA)]- +Er3+, [Er(EDTA)]- +Eu3+, [Eu(EDTA)]- +Fe2+, [Fe(EDTA)]2- +Fe3+, [Fe(EDTA)]- +Ga3+, [Ga(EDTA)]- +Gd3+, [Gd(EDTA)]- +Hg2+, [Hg(EDTA)]2- +Ho3+, [Ho(EDTA)]- +In3+, [In(EDTA)]- +La3+, [La(EDTA)]- +Li+, [Li(EDTA)]3- +Lu3+, [Lu(EDTA)]- +Mg2+, [Mg(EDTA)]2- +Mn2+, [Mn(EDTA)]2- +Mo5+, [Mo(EDTA)]+ +Na+, [Na(EDTA)]3- +Nd3+, [Nd(EDTA)]- +Ni2+, [Ni(EDTA)]2- +Pb2+, [Pb(EDTA)]2- +Pd2+, [Pd(EDTA)]2- +Pm3+, [Pm(EDTA)]- +Pr3+, [Pr(EDTA)]- +Pu3+, [Pu(EDTA)]- +Pu4+, [Pu(EDTA)] +Pu6+, [Pu(EDTA)]2+ +Ra2+, [Ra(EDTA)]2- +Sc3+, [Sc(EDTA)]- +Sm3+, [Sm(EDTA)]- +Sn2+, [Sn(EDTA)]2- +Sr2+, [Sr(EDTA)]2- +Tb3+, [Tb(EDTA)]- +Th4+, [Th(EDTA)] +Ti3+, [Ti(EDTA)]- +TiO2+, [TiO(EDTA)]2- +Tl3+, [Tl(EDTA)]- +Tm3+, [Tm(EDTA)]- +U4+, [U(EDTA)] +V2+, [V(EDTA)]2- +V3+, [V(EDTA)]- +VO2+, [VO(EDTA)]2- +V5+, [V(EDTA)]+ +Y3+, [Y(EDTA)]- +Yb3+, [Yb(EDTA)]- +Zn2+, [Zn(EDTA)]2- +Zr4+, [Zr(EDTA)] \ No newline at end of file diff --git a/logKf_EDTA.txt b/logKf_EDTA.txt new file mode 100644 index 0000000..6b41def --- /dev/null +++ b/logKf_EDTA.txt @@ -0,0 +1,62 @@ +Ag+, 7.32 +Al3+, 16.11 +Am3+, 18.18 +Ba2+, 7.78 +Be2+, 9.3 +Bi3+, 22.8 +Ca2+, 11.0 +Cd2+, 16.4 +Ce3+, 16.80 +Cf3+, 19.09 +Cm3+, 18.45 +Co2+, 16.31 +Co3+, 36 +Cr2+, 13.6 +Cr3+, 23 +Cu2+, 18.7 +Dy3+, 18.0 +Er3+, 18.15 +Eu3+, 17.99 +Fe2+, 14.33 +Fe3+, 24.23 +Ga3+, 20.25 +Gd3+, 17.2 +Hg2+, 21.80 +Ho3+, 18.1 +In3+, 24.95 +La3+, 16.34 +Li+, 2.79 +Lu3+, 19.83 +Mg2+, 8.64 +Mn2+, 13.8 +Mo5+, 6.36 +Na+, 1.66 +Nd3+, 16.6 +Ni2+, 18.56 +Pb2+, 18.3 +Pd2+, 18.5 +Pm3+, 17.45 +Pr3+, 16.55 +Pu3+, 18.12 +Pu4+, 17.66 +Pu6+, 17.66 +Ra2+, 7.4 +Sc3+, 23.1 +Sm3+, 16.43 +Sn2+, 22.1 +Sr2+, 8.80 +Tb3+, 17.6 +Th4+, 23.2 +Ti3+, 21.3 +TiO2+, 17.3 +Tl3+, 22.5 +Tm3+, 19.49 +U4+, 17.50 +V2+, 12.70 +V3+, 25.9 +VO2+, 18.0 +V5+, 18.05 +Y3+, 18.32 +Yb3+, 18.70 +Zn2+, 16.4 +Zr4+, 19.40 \ No newline at end of file diff --git a/temp.py b/temp.py new file mode 100644 index 0000000..08e221b --- /dev/null +++ b/temp.py @@ -0,0 +1,313 @@ +from math import log10, prod, sqrt # calculs mathematiques +from matplotlib.figure import Figure # mise en graphique matplotlib dans Tkinter +from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg +import csv # recherche des informations dans une mini base de donnees +from chempy import chemistry # affichage d'une reaction chimique +import tkinter as tk # interface du programme +from tkinter import ttk + + +def reaction(cation) : + + """ + Génération de la réaction de complexation + + :cation: cation metallique complexé + + """ + + with open('complexes_MEDTA.txt', newline='') as csvfile: + liste1 = csv.reader(csvfile) + complexes = dict(liste1) # dictionnaire reliant cation et complexe cation-EDTA + + complexation = chemistry.Reaction({'Y4-': 1, cation: 1}, {complexes[cation]: 1}) # reaction + + return complexation + + +def constante_formation(cation): + + """ + Calcul de la constante de formation du complexe + + :cation: cation metallique complexé + + """ + + with open('logKf_EDTA.txt', newline='') as csvfile: + liste2 = csv.reader(csvfile) + constante = dict(liste2) # dictionnaire reliant cation et Kf cation-EDTA + + if cation in constante : + + Kf = 10 ** float(constante[cation]) + + else : + + cation = input("Données manquantes, veuillez introduire un nouveau cation M ou M(X): ") + + Kf = 10 ** float(constante[cation]) + + return Kf + + +def coeff_distri_ligand(pH): + + """ + Calcul du coefficient de distribution alpha ligand + + :pH: acidite de la solution titree + + """ + + Ka_EDTA = [10**-2, 10**-2.7, 10**-6.16, 10**-10.26] # liste des constantes d'acidite de l'EDTA (de Ka1 a Ka4) + parametre = 1 # denominateur definition aplha ligand + + for i in range(1, len(Ka_EDTA)) : + cste_multiplicative = prod(Ka_EDTA[-i:]) + parametre += 10**(i*-pH) / cste_multiplicative # termes en [H3O+] divisee par produits de Ka_EDTA + + alpha_ligand = 1 / parametre + + return alpha_ligand + + +def cste_formation_pH(cation, pH): + + """ + Calcul de la constante d'equilibre de formation du complexe [MEDTA] modulee par le pH + + :Kf: constante de formation du complexe [MEDTA] + :pH: acidite de la solution titree + + """ + + Kf = constante_formation(cation) + alpha_ligand = coeff_distri_ligand(pH) + Kf_pH = Kf * alpha_ligand + + return Kf_pH + + +def volume_eq(conc_init_metal, V_metal, conc_ligand): + + """ + Calcul du volume equivalent + + :conc_init_metal: concentration initial en solution titree + :V_metal: volume initial de solution titree + :conc_ligand: concentration initial en ligand + + """ + volume_eq = (conc_init_metal * V_metal) / conc_ligand + + return volume_eq + + +def volume_ligand(conc_init_metal, V_metal, conc_ligand): + + """ + Calcul de la gamme de volumes d'EDTA ajoutés + + :conc_init_metal: concentration initiale en solution titrée + :V_metal: volume initial de solution titrée + :conc_ligand: concentration initiale en ligand + + """ + + V_ligand_actuel = 0 # debut titrage + V_ligand_step = 0.1 #intervalle de volume titrant entre chaque mesure + V_equivalence = volume_eq(conc_init_metal, V_metal, conc_ligand) + V_ligand_stop = 2 * V_equivalence # fin titrage + V_ligand = [] # liste des volumes titrant utilises + + nbre_V_ligand = round(V_ligand_stop, 1) * 10 # nombre de mesures + + for i in range(int(nbre_V_ligand) + 1): # remplissage liste des volumes titrant utilises + + V_ligand.append(round(V_ligand_actuel, 1)) # on a claqué le round car les valeurs de i n'étaient pas entieres, et la boucle if ne tombait alors jamais sur le cas de l'équivalence + V_ligand_actuel += V_ligand_step + + return V_ligand + + +def _logM(V_ligand, conc_init_metal, V_metal, conc_ligand, cation, pH, Kf): + + """ + Calcul des valeurs de pM = -logM + + + :conc_init_metal: concentration initiale en solution titrée + :V_metal: volume initial de solution titrée + :conc_ligand: concentration initiale en ligand + :cation: cation metallique complexé + :pH: acidite de la solution titree + :Kf: constante de formation du complexe [MEDTA] + + """ + + pM =[] + + V_equivalence = volume_eq(conc_init_metal, V_metal, conc_ligand) + + for i in V_ligand : # calcul titrage + + if i < V_equivalence: # avant equivalence + + M = conc_metal_anteeq(conc_init_metal, V_metal, conc_ligand, i) + pM.append(-log10(M)) + + elif i == V_equivalence: # a equivalence + + M = conc_metal_eq(conc_init_metal, V_metal, conc_ligand, i, cste_formation_pH(cation, pH)) + tk.Label(interface, text="Volume équivalent (mL) = %.2f" % i).grid(row=9, columnspan=2) # affichage du volume équivalent + tk.Label(interface, text="pM = %.2f" % -log10(M)).grid(row=10, columnspan=2) # affichage du pM à l'équivalence + pM.append(-log10(M)) + + elif i > V_equivalence: # apres equivalence jusqu'a 2*volume_eq + + M = conc_metal_posteq(conc_init_metal, V_metal, conc_ligand, i, Kf) + pM.append(-log10(M)) + + return pM + + +def conc_metal_anteeq(conc_init_metal, V_metal, conc_ligand, V_ligand): + + """ + Calcul de la concentration en metal à l'équilibre avant équivalence en considérant la dilution + + :conc_init_metal: concentration initiale en solution titrée + :V_metal: volume initial de solution titrée + :conc_ligand: concentration initiale en ligand + :V_ligand: volume de ligand (titrant) ajouté + + """ + + V_tot = V_metal * 10**-3 + V_ligand * 10**-3 + + M_1 = (conc_init_metal * V_metal * 10**-3 - conc_ligand * V_ligand* 10**-3 ) / V_tot + + return M_1 + + +def conc_metal_eq(conc_init_metal, V_metal, conc_ligand, V_ligand, Kf_pH): + + """ + Calcul de la concentration en métal a l'équilibre à équivalence en considérant la dilution + + :conc_init_metal: concentration initial en solution titree + :V_metal: volume initial de solution titree + :conc_ligand: concentration initial en ligand + :V_ligand: volume de ligand (titrant) ajoute + :Kf_pH: constante d'equilibre de formation du complexe [MEDTA] modulee par le pH + + """ + + V_tot = V_metal * 10**-3 + V_ligand* 10**-3 # volume total de la solution + + M_2 = sqrt((conc_init_metal * V_metal * 10**-3) / (Kf_pH * V_tot)) + + return M_2 + + +def conc_metal_posteq(conc_init_metal, V_metal, conc_ligand, V_ligand, Kf_pH): + + """ + Calcul de la concentration en metal a l'equilibre apres equivalence en considerant la dilution + + :conc_init_metal: concentration initial en solution titree + :V_metal: volume initial de solution titree + :conc_ligand: concentration initial en ligand + :V_ligand: volume de ligand (titrant) ajoute + :Kf_pH: constante d'equilibre de formation du complexe [MEDTA] modulee par le pH + + """ + + M_3 = (conc_init_metal * V_metal * 10**-3) / (Kf_pH * (conc_ligand * V_ligand* 10**-3 - conc_init_metal * V_metal * 10**-3)) + + return M_3 + + +def get_values(): + + """ + Récupération des données introduites par l'utilisateur via l'interface tkinter et création de la courbe de titrage + + """ + + cation = d1.get() + conc_init_metal = float(d2.get()) + conc_ligand = float(d3.get()) + V_metal = float(d4.get()) + pH = float(d5.get()) + + courbe = graphique(cation, conc_init_metal, conc_ligand, V_metal, pH) # courbe de titrage complexométrique + plot = FigureCanvasTkAgg(courbe, master=interface) + plot.draw() + plot.get_tk_widget().grid(row=12, columnspan=2) + + tk.Label(interface, text=reaction(cation)).grid(row=8, columnspan=2) # affichage réaction + + +def graphique(cation, conc_init_metal, conc_ligand, V_metal, pH): + + """ + Mise en graphique + + :cation: cation metallique complexé + :conc_init_metal: concentration initiale en solution titrée + :conc_ligand: concentration initiale en ligand + :V_metal: volume initial de solution titrée + :pH: acidite de la solution titree + + """ + + fig = Figure(figsize=(4,5)) # affichage du graphique + ax = fig.add_subplot() # génération de graphique + + V_ligand = volume_ligand(conc_init_metal, V_metal, conc_ligand) + Kf = constante_formation(cation) + + # caractéristiques du graphique + ax.plot(V_ligand, _logM(V_ligand, conc_init_metal, V_metal, conc_ligand, cation, pH, Kf), "tab:purple") + ax.set_xlabel("Volume EDTA ajouté en mL") + ax.set_ylabel("pM") + ax.set_title("Courbe de titrage complexométrique") + + return fig + + +""" Interface tkinter """ + +interface = tk.Tk() # fenêtre du programme + +interface.title('Complexométrie') + +tk.Label(interface, text="Cation métallique titré noté Xy+ : ").grid(row=0) # donnée 1 (d1) +tk.Label(interface, text="conc. cation (M): ").grid(row=1) # d2 +tk.Label(interface, text="conc. ligand (M): ").grid(row=2) # d3 +tk.Label(interface, text="vol. solution metallique (mL): ").grid(row=3) # d4 +tk.Label(interface, text="pH : ").grid(row=4) # d5 + +d1 = tk.Entry(interface) # entrées des données +d2 = tk.Entry(interface) +d3 = tk.Entry(interface) +d4 = tk.Entry(interface) +d5 = tk.Entry(interface) + +d1.grid(row=0, column=1) # position des entrées +d2.grid(row=1, column=1) +d3.grid(row=2, column=1) +d4.grid(row=3, column=1) +d5.grid(row=4, column=1) + +submit = ttk.Button(interface, text="Titrer", command= get_values) # button de lancement +submit.grid(row=6, columnspan=2) # position du button de lancement +interface.bind("", lambda _: submit.invoke()) # enter pour titrer + +interface.rowconfigure(5, minsize=30) # espaces vides entre en dessou et au dessus des résultats affichés +interface.rowconfigure(7, minsize=30) +interface.rowconfigure(11, minsize=30) + +interface.mainloop() # fin de l'exécution du programme via tkinter \ No newline at end of file