titrages 0.1.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. titrages-0.1.2/.gitignore +47 -0
  2. titrages-0.1.2/CHANGELOG.md +130 -0
  3. titrages-0.1.2/LICENSE +21 -0
  4. titrages-0.1.2/PKG-INFO +420 -0
  5. titrages-0.1.2/README.md +386 -0
  6. titrages-0.1.2/docs/DOC.md +243 -0
  7. titrages-0.1.2/docs/PROJET-complexation-precipitation.md +129 -0
  8. titrages-0.1.2/examples/01_acide_faible.py +22 -0
  9. titrages-0.1.2/examples/02_polyacides.py +17 -0
  10. titrages-0.1.2/examples/03_melange_titrant_faible.py +16 -0
  11. titrages-0.1.2/examples/04_pgfplots.py +6 -0
  12. titrages-0.1.2/examples/05_conductimetrie.py +18 -0
  13. titrages-0.1.2/examples/06_redox.py +18 -0
  14. titrages-0.1.2/examples/07_fractions_et_pC.py +35 -0
  15. titrages-0.1.2/examples/08_melanges_sans_dilution.py +34 -0
  16. titrages-0.1.2/examples/09_titrage_acide_fort.py +49 -0
  17. titrages-0.1.2/examples/10_titrage_base_faible.py +27 -0
  18. titrages-0.1.2/examples/11_titrage_diacide.py +51 -0
  19. titrages-0.1.2/examples/README.md +19 -0
  20. titrages-0.1.2/pyproject.toml +123 -0
  21. titrages-0.1.2/scripts/ctan.py +66 -0
  22. titrages-0.1.2/src/titrages/__init__.py +94 -0
  23. titrages-0.1.2/src/titrages/__main__.py +146 -0
  24. titrages-0.1.2/src/titrages/base.py +313 -0
  25. titrages-0.1.2/src/titrages/donnees/conductivites.toml +86 -0
  26. titrages-0.1.2/src/titrages/donnees/couples.toml +323 -0
  27. titrages-0.1.2/src/titrages/donnees/indicateurs.toml +76 -0
  28. titrages-0.1.2/src/titrages/donnees/redox.toml +128 -0
  29. titrages-0.1.2/src/titrages/equilibre.py +226 -0
  30. titrages-0.1.2/src/titrages/export.py +31 -0
  31. titrages-0.1.2/src/titrages/modeles.py +440 -0
  32. titrages-0.1.2/src/titrages/py.typed +0 -0
  33. titrages-0.1.2/src/titrages/redox.py +629 -0
  34. titrages-0.1.2/src/titrages/solution.py +251 -0
  35. titrages-0.1.2/src/titrages/titrage.py +333 -0
  36. titrages-0.1.2/src/titrages/trace.py +210 -0
  37. titrages-0.1.2/tests/conftest.py +22 -0
  38. titrages-0.1.2/tests/reference_mpmath.py +133 -0
  39. titrages-0.1.2/tests/test_base.py +78 -0
  40. titrages-0.1.2/tests/test_conductimetrie.py +88 -0
  41. titrages-0.1.2/tests/test_dilution.py +248 -0
  42. titrages-0.1.2/tests/test_doctests.py +33 -0
  43. titrages-0.1.2/tests/test_equilibre.py +79 -0
  44. titrages-0.1.2/tests/test_export.py +16 -0
  45. titrages-0.1.2/tests/test_latex.py +97 -0
  46. titrages-0.1.2/tests/test_lua.py +163 -0
  47. titrages-0.1.2/tests/test_main.py +47 -0
  48. titrages-0.1.2/tests/test_migration_chimie.py +166 -0
  49. titrages-0.1.2/tests/test_modeles.py +57 -0
  50. titrages-0.1.2/tests/test_package.py +10 -0
  51. titrages-0.1.2/tests/test_redox.py +245 -0
  52. titrages-0.1.2/tests/test_solution.py +80 -0
  53. titrages-0.1.2/tests/test_titrage.py +220 -0
  54. titrages-0.1.2/tests/test_trace.py +59 -0
  55. titrages-0.1.2/tests/test_versions.py +25 -0
@@ -0,0 +1,47 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ build/
6
+ dist/
7
+ .venv/
8
+
9
+ # Outils
10
+ .pytest_cache/
11
+ .ruff_cache/
12
+ .mypy_cache/
13
+ .coverage
14
+ htmlcov/
15
+
16
+ # LaTeX : seules les sources sont suivies ; la documentation compilée
17
+ # (titrages-doc.pdf) est jointe à chaque release et à l'artefact de la CI
18
+ latex/titrages-doc.pdf
19
+ latex/*.aux
20
+ latex/*.log
21
+ latex/*.out
22
+ latex/*.toc
23
+ latex/*.synctex.gz
24
+ latex/*.fls
25
+ latex/*.fdb_latexmk
26
+ latex/*.idx
27
+ latex/*.ind
28
+ latex/*.ilg
29
+ latex/*.glo
30
+ latex/*.hd
31
+ latex/*.listing
32
+ latex/tests/*.pdf
33
+ latex/tests/*.aux
34
+ latex/tests/*.log
35
+ latex/tests/*.out
36
+ latex/tests/*.synctex.gz
37
+ latex/tests/*.dat
38
+ latex/ctan/
39
+ examples/*.pdf
40
+ examples/*.png
41
+
42
+ # Systèmes
43
+ .DS_Store
44
+ .vscode/
45
+
46
+ # Réglages locaux de VS Code
47
+ *.code-workspace
@@ -0,0 +1,130 @@
1
+ # Changelog
2
+
3
+ Le format suit [Keep a Changelog](https://keepachangelog.com/fr/1.1.0/) et le
4
+ [versionnage sémantique](https://semver.org/lang/fr/). Le paquet Python et le paquet
5
+ LaTeX partagent un numéro de version.
6
+
7
+ ## [0.1.2] — 2026-10-11
8
+
9
+ ### Modifié
10
+
11
+ - Publié sur PyPI : `pip install titrages`. Le workflow de release y envoie la roue et le sdist par « trusted publishing », sans jeton ; GitHub garde les artefacts joints à la release.
12
+ - Les liens du README sont absolus, pour la page PyPI.
13
+
14
+ ## [0.1.1] — 2026-10-10
15
+
16
+ ### Modifié
17
+
18
+ - La tête du paquet n'exporte plus que ce qui sert couramment (34 noms) :
19
+ `LN10`, `PKE`, `delta`, `log_k`, `LAMBDA_H3O`, `LAMBDA_HO`, `NERNST`,
20
+ `REFERENCES`, `Composant`, `ComposantRedox`, `Fort`, `charge`,
21
+ `conductivite_molaire`, `electrons_cedes` et `normaliser` restent importables
22
+ de `titrages.equilibre`, `titrages.solution`, `titrages.redox`,
23
+ `titrages.modeles` et `titrages.base`.
24
+
25
+ ### Supprimé
26
+
27
+ - `vers_csv` : `numpy.savetxt` sur les colonnes d'une courbe fait la même chose ;
28
+ `vers_pgfplots` et la commande `titrages` restent.
29
+
30
+ ## [0.1.0] — 2026-10-10
31
+
32
+ Première version publiée (GitHub `antnardo/titrages`).
33
+
34
+ ### Ajouté
35
+
36
+ - `SolutionRedox.diluee` et `melangee`, `TitrageRedox.tangentes` et
37
+ `TangentesRedox` : chaque méthode acide-base a sa symétrique rédox ;
38
+ `tracer_sauts`, `tracer_tangentes` et `tracer_derivee` acceptent un titrage
39
+ rédox ; en LaTeX, `\addplottitragetangentes` et `\titragetangentes` s'appliquent
40
+ à un titrage rédox (moteur Lua, `tangentes_redox`).
41
+ - Sous le moteur pgf (pdfLaTeX), les nombres `\titragevolume`, `\titragepH`,
42
+ `\titragepHinitial`, `\titrageE` et `\titrageconductivite`, par l3fp,
43
+ développables ; `latex/tests/titrages-test-nombres.tex` et `tests/test_latex.py`
44
+ confrontent les deux moteurs au paquet Python, courbes de pgfplots comprises.
45
+ - `tests/reference_mpmath.py`, qui régénère à 60 chiffres les points d'inflexion
46
+ de référence sans rien emprunter au paquet (mpmath, dépendance de développement).
47
+ - Vingt-sept conductivités molaires de plus (CRC Handbook, 97e éd. ; dix-sept
48
+ approchées par un ion voisin, marquées ≈) : la conductimétrie couvre 34 couples
49
+ sur 35 au lieu de 14.
50
+ - L'intégration continue à chaque push, et la publication par release GitHub
51
+ (roue, sdist, documentation PDF, archive CTAN joints à la release).
52
+
53
+ ### Modifié
54
+
55
+ - **Règle de sortie** : toute grandeur rend un `float` pour un argument scalaire,
56
+ un tableau numpy pour un tableau (`Titrage.pH(5)` rendait un `ndarray` de
57
+ dimension zéro).
58
+ - **Une seule unité pour la conductivité, le S/m** : la commande `sigma`,
59
+ `tracer_conductimetrie` et la clé LaTeX `unite` ne convertissent plus en mS/cm
60
+ par défaut ; `unite="mS/cm"` reste disponible.
61
+ - `equilibre.changement_de_signe` remplace `titrage._changement_de_signe`.
62
+ - Le README dit vrai : installation depuis GitHub ou par copie ; PyPI et CTAN à
63
+ venir ; `latex/titrages-doc.pdf` n'est plus suivi par git, la release et la CI le
64
+ fournissent.
65
+
66
+ - La documentation du paquet LaTeX est réécrite en `l3doc` : une fiche de syntaxe
67
+ par commande, toutes les clés avec leur défaut, les messages et leur remède,
68
+ l'interface Lua, la comparaison des deux moteurs, un index.
69
+ - Les points d'inflexion (`sauts`) se calculent à la précision de la machine, en
70
+ acide-base comme en rédox : minima de |dV/dpH| ou |dV/dE| sur la courbe directe,
71
+ affinés par le zéro de la dérivée de leur logarithme (`equilibre.minimum_lisse`)
72
+ et non plus par une section dorée ; confrontés à `mpmath` dans les tests. Les
73
+ sauts rédox se cherchaient en V, où celui de Fe²⁺ par MnO₄⁻ tient en 10⁻⁹ mL
74
+ (1,3716 V au lieu de 1,37288 V).
75
+ - La variance des formes s'écrit Σ_{j<k} x_j x_k (k−j)², et Y₁ − q Σ x_j (j−q) :
76
+ plus de soustraction de nombres voisins dans un saut. `derivee_volume` dérive
77
+ V₀R_b + VR_bu = 0, somme de termes positifs.
78
+ - `TitrageRedox.pente` est analytique, couples dimériques compris ; nouvelle
79
+ méthode `TitrageRedox.derivee_volume(E)`.
80
+
81
+ ### Corrigé
82
+
83
+ - `volumes_equivalents` perdait l'équivalence intermédiaire d'un titrage en
84
+ retour, quand le réactif fort du bécher excède les sites faibles :
85
+ `solution({"CH3COOH": 0.05, "NaOH": 0.1})` par HCl 0,1 rendait `(10,)` au lieu
86
+ de `(5, 10)`. L'acide ou la base forts du bécher réagissent maintenant d'abord
87
+ avec les espèces faibles, chaque proton enlevé devenant un site basique au même
88
+ pKa, et réciproquement ; deux sites de même pKa ne font qu'une équivalence. Même
89
+ correction dans le moteur Lua.
90
+ - `charge` lisait la glycine `H3N+CH2COO-` comme un anion : un signe entre deux
91
+ atomes compte pour ±1, le zwitterion est neutre et l'ion glycinium vaut +1.
92
+ - Un saut sur une courbe décroissante (base titrée par un acide, titrant réducteur)
93
+ se rabattait sur un point de la grille : l'ammoniac par l'acide chlorhydrique
94
+ donnait pH 5,2734 au lieu de 5,27558.
95
+ - La fraction oxydée d'un couple dimérique pouvait dépasser 1 d'un ulp, ce qui
96
+ rendait défini le potentiel d'un bécher de diiode pur.
97
+
98
+ ## [0.1.0-dev] — 23 au 27 septembre 2026, non publiée
99
+
100
+ Première version. Le calcul reprend un module privé de 2024
101
+ (`pyphysique/chimie/titrage.py`), réécrit.
102
+
103
+ ### Ajouté
104
+
105
+ - `Solution` : pH, concentrations, pouvoir tampon d'une solution quelconque —
106
+ espèces faibles introduites sous n'importe quelle forme, acide et base forts.
107
+ - `Titrage` : la courbe V(pH) explicite, avec ou sans dilution, pour un bécher et
108
+ une burette quelconques ; pH à volume donné ; points d'inflexion ; équivalences
109
+ stœchiométriques ; méthode des tangentes parallèles.
110
+ - Fractions en échelle logarithmique, sans débordement.
111
+ - Une base de 35 couples et 9 indicateurs, cherchée par nom, sel ou formule.
112
+ - `titrages.trace` (matplotlib), `vers_pgfplots`, `vers_csv`, et la commande
113
+ `titrages`.
114
+ - La conductimétrie : `Solution.conductivite`, `Titrage.conductivite`,
115
+ `Titrage.courbe_conductimetrique` (loi de Kohlrausch, ions spectateurs, correction
116
+ de dilution), une base de conductivités molaires et les contre-ions des sels.
117
+ - L'oxydoréduction : `CoupleRedox`, `SolutionRedox`, `TitrageRedox` — potentiel,
118
+ courbe E(V), sauts, équivalences, électrode de référence ; couples à plusieurs
119
+ étapes, à pH fixé, dimériques ; `volume(E)` explicite (quotient, ou racine d'un
120
+ trinôme pour un seul dimère) ; une base de 15 couples.
121
+ - Des tests de dilution qui confrontent le calcul direct à un calcul indépendant,
122
+ dilution faite à la main et équilibre résolu par force brute.
123
+ - Le paquet LaTeX `titrages` : moteur Lua sous LuaLaTeX (courbes, dérivée, sauts,
124
+ tangentes, fractions, conductivité, potentiel, nombres développables), moteur
125
+ pgfmath ailleurs (courbes pH, σ et E des couples monomères, fractions).
126
+
127
+ ### Corrigé, par rapport au module de 2024
128
+
129
+ - La pente avec dilution multipliait par `n₀` au lieu de `n`, et appelait
130
+ `Y(h, 1)` au lieu de `Y(1, h)`.
titrages-0.1.2/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 antnardo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,420 @@
1
+ Metadata-Version: 2.5
2
+ Name: titrages
3
+ Version: 0.1.2
4
+ Summary: Courbes de titrage acido-basique sans approximation : pH, polyacides, mélanges, dilution, équivalences, méthode des tangentes, et une base de couples.
5
+ Project-URL: Homepage, https://github.com/antnardo/titrages
6
+ Project-URL: Documentation, https://github.com/antnardo/titrages/blob/main/docs/DOC.md
7
+ Project-URL: Repository, https://github.com/antnardo/titrages
8
+ Project-URL: Issues, https://github.com/antnardo/titrages/issues
9
+ Project-URL: Changelog, https://github.com/antnardo/titrages/blob/main/CHANGELOG.md
10
+ Author: Antonin Marchand
11
+ License-Expression: MIT
12
+ License-File: LICENSE
13
+ Keywords: acide-base,chemistry,chimie,enseignement,pH,polyacide,titrage,titration
14
+ Classifier: Development Status :: 4 - Beta
15
+ Classifier: Environment :: Console
16
+ Classifier: Intended Audience :: Education
17
+ Classifier: Intended Audience :: Science/Research
18
+ Classifier: License :: OSI Approved :: MIT License
19
+ Classifier: Natural Language :: French
20
+ Classifier: Operating System :: OS Independent
21
+ Classifier: Programming Language :: Python :: 3
22
+ Classifier: Programming Language :: Python :: 3.11
23
+ Classifier: Programming Language :: Python :: 3.12
24
+ Classifier: Programming Language :: Python :: 3.13
25
+ Classifier: Programming Language :: Python :: 3.14
26
+ Classifier: Topic :: Education
27
+ Classifier: Topic :: Scientific/Engineering :: Chemistry
28
+ Classifier: Typing :: Typed
29
+ Requires-Python: >=3.11
30
+ Requires-Dist: numpy>=1.24
31
+ Provides-Extra: trace
32
+ Requires-Dist: matplotlib>=3.7; extra == 'trace'
33
+ Description-Content-Type: text/markdown
34
+
35
+ # titrages
36
+
37
+ [![CI](https://github.com/antnardo/titrages/actions/workflows/ci.yml/badge.svg)](https://github.com/antnardo/titrages/actions/workflows/ci.yml)
38
+ [![Licence MIT](https://img.shields.io/badge/licence-MIT-blue.svg)](https://github.com/antnardo/titrages/blob/main/LICENSE)
39
+
40
+ Le pH, la conductivité ou le potentiel d'une solution quelconque, et les courbes de
41
+ titrage pH-métrique, conductimétrique et potentiométrique d'un bécher quelconque par
42
+ une burette quelconque — acides et bases forts ou faibles, polyacides, ampholytes,
43
+ mélanges, titrant faible, titrage en retour, couples rédox à plusieurs étapes ou
44
+ dimériques — avec la dilution, **sans aucune approximation**. Un paquet Python, et
45
+ un paquet LaTeX qui calcule la même chose dans `pgfplots`.
46
+
47
+ ```pycon
48
+ >>> from titrages import Titrage, solution
49
+ >>> t = Titrage(solution({"CH3COOH": 0.1}), solution({"NaOH": 0.1}), volume_becher=10)
50
+ >>> t.pH([0, 5, 10]).round(2).tolist()
51
+ [2.88, 4.76, 8.73]
52
+ >>> t.volumes_equivalents()
53
+ (10.0,)
54
+ >>> [(round(s.volume, 2), round(s.pH, 2)) for s in t.sauts(20)]
55
+ [(10.0, 8.73)]
56
+
57
+ ```
58
+
59
+ Le paquet s'installe depuis GitHub (ci-dessous). CTAN : à venir.
60
+
61
+ ## Sommaire
62
+
63
+ - [Ce qu'il fait](#ce-quil-fait)
64
+ - [Installation](#installation)
65
+ - [Prérequis](#prérequis)
66
+ - [Prise en main](#prise-en-main)
67
+ - [La documentation](#la-documentation)
68
+ - [Les modules](#les-modules)
69
+ - [En ligne de commande](#en-ligne-de-commande)
70
+ - [Le paquet LaTeX](#le-paquet-latex)
71
+ - [Avec pychimie](#avec-pychimie)
72
+ - [Tester](#tester)
73
+ - [Antériorité](#antériorité)
74
+ - [Pour plus tard : complexation et précipitation](#pour-plus-tard--complexation-et-précipitation)
75
+ - [Limites](#limites)
76
+ - [Sources](#sources)
77
+ - [Licence](#licence)
78
+
79
+ ## Ce qu'il fait
80
+
81
+ - **Le sens direct.** À pH imposé, tout est explicite : les fractions de chaque forme,
82
+ puis l'électroneutralité, qui donne le volume versé comme une fonction directe du
83
+ pH, `V(pH) = -V0 R_bécher(pH) / R_burette(pH)`. Pas de polynôme à résoudre, pas de
84
+ réaction prépondérante. C'est la méthode de Kalka (2021) et de Brière (2002),
85
+ généralisée à un bécher et une burette quelconques.
86
+ - **Le sens inverse, quand il le faut.** Le pH d'une solution ou le pH à un volume
87
+ donné se trouvent par dichotomie sur une fonction qu'on sait croissante : une
88
+ racine unique, trouvée à la précision de la machine, sans réglage.
89
+ - **La dilution, exactement.** Le résidu du mélange, multiplié par `V0 + V`, se
90
+ sépare en une part du bécher et une part de la burette, chacune calculée avec ses
91
+ concentrations d'origine : la dilution ne demande aucun traitement particulier.
92
+ Tracer `n0 = Y1 + δ/C` comme une courbe de titrage, ainsi que le fait Kalka (2021),
93
+ dont la méthode est tirée, c'est la négliger — jusqu'à 0,48 unité de pH d'erreur.
94
+ Les tests confrontent la formule à un calcul indépendant qui dilue à la main.
95
+ - **Tous les cas d'un seul tenant.** Une base faible est la forme basique d'un
96
+ couple (l'ammoniac est la forme 1 de NH₄⁺/NH₃) ; un sel s'introduit par sa forme,
97
+ ses ions spectateurs se déduisent. Mélanges, ampholytes, titrant faible, titrage
98
+ en retour ne demandent rien de plus.
99
+ - **Les équivalences, des deux façons.** Les volumes stœchiométriques, et les points
100
+ d'inflexion effectivement visibles : l'acide phosphorique a trois équivalences
101
+ stœchiométriques, et deux sauts seulement.
102
+ - **La méthode des tangentes**, construite exactement sur la courbe, pH-métrique ou
103
+ potentiométrique, pour mesurer son erreur plutôt que la supposer.
104
+ - **Une base de couples, d'indicateurs, de conductivités et de couples rédox**,
105
+ cherchée par ce qu'on écrit : `"NH3"`, `"ammoniac"`, `"carbonate de sodium"`,
106
+ `"CO3^2-"`.
107
+ - **Une précision sans débordement.** Les fractions se calculent en échelle
108
+ logarithmique : l'EDTA à pH 14 ne déborde pas. Les points d'inflexion sont
109
+ confrontés à un calcul mpmath à 60 chiffres (`tests/reference_mpmath.py`).
110
+ - **La conductimétrie** par la loi de Kohlrausch, ions spectateurs compris (le Na⁺
111
+ de la soude, celui du carbonate de sodium), avec ou sans correction de dilution,
112
+ pour 34 des 35 couples de la base.
113
+ - **La potentiométrie** : les électrons remplacent les protons, E/s le pH. Couples à
114
+ plusieurs étapes (le vanadium), couples qui échangent des protons (à pH fixé),
115
+ couples dimériques (I₂/I⁻, Cr₂O₇²⁻/Cr³⁺, S₄O₆²⁻/S₂O₃²⁻), électrode de référence.
116
+ - **Le même calcul en LaTeX**, par un moteur Lua sous LuaLaTeX, ou par pgfmath et
117
+ l3fp sous pdfLaTeX. Les tests confrontent les trois implémentations.
118
+
119
+ ## Installation
120
+
121
+ Quatre façons, selon le poste.
122
+
123
+ **Avec pip depuis PyPI**, quand le réseau et pip sont disponibles :
124
+
125
+ ```bash
126
+ pip install titrages
127
+ pip install "titrages[trace]" # avec matplotlib
128
+ ```
129
+
130
+ (ou `uv add titrages`). **Depuis GitHub**, pour la version de développement :
131
+
132
+ ```bash
133
+ pip install git+https://github.com/antnardo/titrages
134
+ pip install "titrages[trace] @ git+https://github.com/antnardo/titrages" # avec matplotlib
135
+ ```
136
+
137
+ **Avec la roue d'une release**, pour un poste qui a pip mais pas git : chaque
138
+ [release](https://github.com/antnardo/titrages/releases) porte
139
+ `titrages-<version>-py3-none-any.whl` (et le sdist `.tar.gz`, avec `docs/`,
140
+ `examples/` et `tests/`), qui s'installe par `pip install titrages-<version>-py3-none-any.whl`.
141
+
142
+ **Copier le dossier**, sans pip ni réseau : le dossier `src/titrages/` se pose à
143
+ côté des scripts, et `from titrages import Titrage, solution` fonctionne, à condition
144
+ d'exécuter le script depuis son dossier. Le paquet ne demande que numpy.
145
+
146
+ **Pour développer**, un clone et [uv](https://docs.astral.sh/uv/) :
147
+
148
+ ```bash
149
+ git clone https://github.com/antnardo/titrages
150
+ cd titrages && uv sync && uv run pytest
151
+ ```
152
+
153
+ CTAN : à venir.
154
+
155
+ ## Prérequis
156
+
157
+ Python 3.11 ou plus récent, avec numpy (1.24 ou plus) ; matplotlib (3.7 ou plus)
158
+ seulement pour `titrages.trace`. Le paquet est testé sous Python 3.11, 3.12, 3.13
159
+ et 3.14. Le paquet LaTeX demande pgfplots, et LuaLaTeX pour tout ce qui n'est pas
160
+ une courbe ou un nombre (voir [Le paquet LaTeX](#le-paquet-latex)).
161
+
162
+ ## Prise en main
163
+
164
+ Deux règles valent partout. **Un `float` pour un scalaire, un tableau numpy pour un
165
+ tableau** : `t.pH(5)` est un `float`, `t.pH([5, 10])` un tableau. **Une seule unité
166
+ pour la conductivité, le S/m** — celle que donnent λ° en mS·m²·mol⁻¹ et *c* en
167
+ mol/L ; un conductimètre affiche des mS/cm, dix fois moins, et `unite="mS/cm"` le
168
+ fait pour un tracé. Les volumes s'écrivent dans l'unité qu'on veut, la même partout ;
169
+ les concentrations en mol/L.
170
+
171
+ Une courbe pH-métrique, son saut, la méthode des tangentes et la zone de virage
172
+ d'un indicateur :
173
+
174
+ ```python
175
+ import matplotlib.pyplot as plt
176
+ from titrages import Titrage, indicateur, solution
177
+ from titrages.trace import tracer_sauts, tracer_tangentes, tracer_titrage, tracer_zone_virage
178
+
179
+ t = Titrage(solution({"H3PO4": 0.1}), solution({"NaOH": 0.1}), volume_becher=10)
180
+ ax = tracer_titrage(t, 35, lw=2)
181
+ tracer_sauts(t, 35, ax)
182
+ tracer_tangentes(t, 7, 35, ax) # depuis 7 mL, avant le premier saut
183
+ tracer_zone_virage(indicateur("phénolphtaléine"), ax)
184
+ plt.show()
185
+ ```
186
+
187
+ La méthode des tangentes, `t.tangentes(volume_avant, volume_max)`, part d'un point
188
+ avant le saut et rend la construction complète (`Tangentes` : les deux points de
189
+ contact, la pente commune, le point trouvé) :
190
+
191
+ ```pycon
192
+ >>> t = Titrage(solution({"CH3COOH": 0.1}), solution({"NaOH": 0.1}), volume_becher=10)
193
+ >>> tg = t.tangentes(7, 20)
194
+ >>> round(tg.volume, 2), round(tg.pH, 2)
195
+ (10.0, 8.65)
196
+
197
+ ```
198
+
199
+ Un mélange par un titrant faible, et un titrage en retour (la soude en excès a déjà
200
+ transformé l'acide éthanoïque en éthanoate, que l'acide chlorhydrique titre après
201
+ l'excès) :
202
+
203
+ ```pycon
204
+ >>> t = Titrage(solution({"HCl": 0.05, "CH3COOH": 0.05}), solution({"NH3": 0.1}), volume_becher=20)
205
+ >>> [round(s.volume, 1) for s in t.sauts(30)]
206
+ [10.0, 20.0]
207
+ >>> Titrage(solution({"CH3COOH": 0.05, "NaOH": 0.1}), solution({"HCl": 0.1}), 10).volumes_equivalents()
208
+ (5.0, 10.0)
209
+
210
+ ```
211
+
212
+ Le pH d'une solution, et ce qu'elle contient :
213
+
214
+ ```pycon
215
+ >>> from titrages import solution
216
+ >>> s = solution({"Na2CO3": 0.1})
217
+ >>> round(s.pH(), 2)
218
+ 11.65
219
+ >>> round(s.concentrations()["HCO3-"], 4)
220
+ 0.0045
221
+
222
+ ```
223
+
224
+ La conductimétrie, en S/m, corrigée ou non de la dilution, et son tracé par
225
+ `tracer_conductimetrie(t, volume_max, ax, corrigee=True, unite="mS/cm")` :
226
+
227
+ ```pycon
228
+ >>> t = Titrage(solution({"HCl": 0.01}), solution({"NaOH": 0.1}), volume_becher=100)
229
+ >>> round(t.conductivite(10), 4)
230
+ 0.1149
231
+ >>> t.courbe_conductimetrique(20, 3, corrigee=True).conductivite.round(4).tolist()
232
+ [0.4261, 0.1264, 0.3751]
233
+
234
+ ```
235
+
236
+ La potentiométrie, mesurée contre une électrode au calomel saturé. Le pH du milieu,
237
+ supposé tamponné, se donne aux **deux** solutions, bécher et burette, puisqu'il décale
238
+ les potentiels standard apparents ; `tracer_titrage_redox(r, volume_max, ax,
239
+ sauts=True)` trace la courbe, et `tracer_sauts`, `tracer_tangentes`, `tracer_derivee`
240
+ acceptent un titrage rédox comme un titrage acide-base :
241
+
242
+ ```pycon
243
+ >>> from titrages import TitrageRedox, solution_redox
244
+ >>> r = TitrageRedox(solution_redox({"Fe2+": 0.1}), solution_redox({"KMnO4": 0.02}), 10, reference="ECS")
245
+ >>> r.volumes_equivalents(), round(r.E(10), 3)
246
+ ((10.0,), 1.143)
247
+ >>> v = TitrageRedox(solution_redox({"V2+": 0.1}, pH=1), solution_redox({"KMnO4": 0.02}, pH=1), 10)
248
+ >>> v.volumes_equivalents()
249
+ (10.0, 20.0, 30.0)
250
+
251
+ ```
252
+
253
+ ## La documentation
254
+
255
+ - [docs/DOC.md](https://github.com/antnardo/titrages/blob/main/docs/DOC.md) : l'API complète, la méthode et ses formules.
256
+ - [examples/](https://github.com/antnardo/titrages/tree/main/examples/) : six scripts à lancer, décrits dans
257
+ [examples/README.md](https://github.com/antnardo/titrages/blob/main/examples/README.md).
258
+ - Le paquet LaTeX : [latex/README.md](https://github.com/antnardo/titrages/blob/main/latex/README.md), et sa documentation
259
+ `titrages-doc.pdf` (index, clés, messages), jointe à chaque
260
+ [release](https://github.com/antnardo/titrages/releases) et à l'artefact de la
261
+ CI ; pour la recompiler, voir [latex/README.md](https://github.com/antnardo/titrages/blob/main/latex/README.md).
262
+ - [CHANGELOG.md](https://github.com/antnardo/titrages/blob/main/CHANGELOG.md).
263
+
264
+ ## Les modules
265
+
266
+ | Module | Rôle |
267
+ | --- | --- |
268
+ | `titrages.base` | la base de couples, d'indicateurs, de conductivités et de couples rédox ; `solution`, `solution_redox`, `espece`, `couple`, `indicateur`, `chercher` |
269
+ | `titrages.solution` | `Solution` : pH, concentrations, pouvoir tampon, conductivité d'une solution quelconque |
270
+ | `titrages.titrage` | `Titrage` : la courbe V(pH), le pH à volume donné, les sauts, les équivalences, les tangentes, la conductimétrie |
271
+ | `titrages.redox` | `SolutionRedox`, `TitrageRedox` : les mêmes, les électrons remplaçant les protons |
272
+ | `titrages.equilibre` | les fractions, les moments, le résidu de l'électroneutralité, les dichotomies |
273
+ | `titrages.modeles` | les objets du domaine : `Couple`, `Espece`, `Courbe`, `Saut`, `Tangentes`, leurs analogues rédox |
274
+ | `titrages.trace` | les tracés matplotlib |
275
+ | `titrages.export` | `vers_pgfplots` |
276
+ | `titrages.__main__` | la commande `titrages` |
277
+
278
+ Tout ce qui sert couramment s'importe de `titrages` directement.
279
+
280
+ ## En ligne de commande
281
+
282
+ ```bash
283
+ titrages pH CH3COOH=0.1 CH3COO-=0.05
284
+ titrages sigma HCl=0.01 # en S/m
285
+ titrages E Fe2+=0.1 Fe3+=0.01
286
+ titrages titrage H3PO4=0.1 --burette NaOH=0.1 --volume 10
287
+ titrages redox V2+=0.1 --burette KMnO4=0.02 --reference ECS
288
+ titrages couples phosph
289
+ titrages indicateurs
290
+ ```
291
+
292
+ ## Le paquet LaTeX
293
+
294
+ Le dossier [`latex/`](https://github.com/antnardo/titrages/tree/main/latex/) contient `titrages.sty` et `titrages.lua`. Ils
295
+ s'installent par copie des deux fichiers dans un dossier que TeX trouve, par exemple
296
+ `TEXMFHOME/tex/latex/titrages/`, ou à côté du document ; chaque release porte
297
+ aussi `titrages-ctan.zip`, l'archive prête pour CTAN, avec la documentation compilée.
298
+ Le paquet demande pgfplots, et `\pgfplotsset{compat=1.18}` dans le préambule :
299
+
300
+ ```latex
301
+ \usepackage{titrages}
302
+ \pgfplotsset{compat=1.18}
303
+ \titragedefinir{ethanoique}{
304
+ volume = 10,
305
+ becher = { espece = { pKa = 4.76, C = 0.1 } },
306
+ burette = { base forte = 0.1 },
307
+ }
308
+ \begin{tikzpicture}
309
+ \begin{axis}[xlabel={$V$ (mL)}, ylabel=pH]
310
+ \addplottitrage[thick]{ethanoique}
311
+ \addplottitragetangentes[red, dashed]{ethanoique}{7}
312
+ \end{axis}
313
+ \end{tikzpicture}
314
+ Le pH à l'équivalence vaut \num{\titragepH{ethanoique}{10}}.
315
+ ```
316
+
317
+ Deux moteurs derrière la même interface. Sous LuaLaTeX, `titrages.lua` calcule tout
318
+ — courbes pH, σ et E, dérivée, sauts, équivalences, tangentes, nombres
319
+ développables —, en une seconde. Sous pdfLaTeX, le moteur pgf trace les courbes par
320
+ pgfmath (quatre à cinq chiffres, invisible au tracé) et donne par l3fp les nombres
321
+ qui ne demandent qu'une évaluation ou une dichotomie : `\titragevolume`,
322
+ `\titragepH`, `\titrageE`, `\titrageconductivite` ; pas d'équivalences, de sauts
323
+ ni de tangentes, ni de couples dimériques. Son coût : 250 lignes d'expl3 à maintenir
324
+ en parallèle du moteur Lua, et une compilation deux à trente fois plus lente (une
325
+ demi-seconde par nombre). `tests/test_latex.py` vérifie que les deux moteurs donnent
326
+ les nombres du paquet Python.
327
+
328
+ ## Avec pychimie
329
+
330
+ `titrages` ne dépend que de numpy et ne connaît que des concentrations en mol/L.
331
+ Pour partir d'une masse pesée, le paquet voisin
332
+ [pychimie](https://github.com/antnardo/pychimie) donne la masse molaire ; le pont
333
+ tient en une ligne, dans le script de l'utilisateur, sans que l'un importe l'autre :
334
+
335
+ ```python
336
+ from pychimie import masse_molaire # un paquet à part, installé à part
337
+ from titrages import Titrage, solution
338
+
339
+ C = 0.384 / masse_molaire("NaHCO3") / 0.100 # 384 mg dans 100 mL, en mol/L
340
+ t = Titrage(solution({"NaHCO3": C}), solution({"HCl": 0.1}), volume_becher=50)
341
+ ```
342
+
343
+ Les deux paquets ont une classe `Solution` de sens différents ; quand les deux
344
+ cohabitent, importer l'une sous un alias (`from titrages import Solution as
345
+ SolutionTitrage`). Le renommage est prévu du côté de pychimie.
346
+
347
+ ## Tester
348
+
349
+ ```bash
350
+ uv run pytest # tout, moteur Lua et paquet LaTeX compris quand TeX est là
351
+ uv run pytest -m "not latex" # sans compiler le paquet LaTeX (une quarantaine de secondes)
352
+ uv run ruff check src tests && uv run ruff format --check src tests && uv run mypy
353
+ cd latex/tests && texlua test_titrages.lua
354
+ ```
355
+
356
+ Les tests marqués `lua` confrontent le moteur Lua au moteur Python par `texlua` (ou
357
+ `lua`) ; ceux marqués `latex` compilent `latex/tests/titrages-test-nombres.tex` par
358
+ `lualatex` et par `pdflatex` et comparent leurs nombres au calcul Python ; les deux
359
+ groupes sont sautés quand TeX manque. Les points d'inflexion de référence se
360
+ régénèrent par `uv run python tests/reference_mpmath.py` (mpmath, dépendance de
361
+ développement). L'intégration continue (`.github/workflows/ci.yml`) rejoue tout
362
+ cela à chaque push, sous Python 3.11 à 3.14, et compile la documentation LaTeX ; à
363
+ chaque release publiée, `publish.yml` joint à la release la roue, le sdist, la
364
+ documentation PDF et l'archive CTAN.
365
+
366
+ ## Antériorité
367
+
368
+ [pHcalc](https://github.com/rnelsonchem/pHcalc) et
369
+ [chempy](https://github.com/bjodah/chempy) calculent le pH d'une composition
370
+ donnée (chempy traite aussi complexation et précipitation) ; ni l'un ni l'autre
371
+ n'a d'objet titrage, de dilution exacte en V(pH), de sauts, de tangentes, de
372
+ conductimétrie ni de rédox. Côté LaTeX, [phtitration](https://ctan.org/pkg/phtitration)
373
+ (CTAN, 2026) trace huit configurations de titrage par un titrant fort, par
374
+ Henderson-Hasselbalch par morceaux pour les monoacides et par le calcul paramétrique
375
+ exact pour les polyacides, sans mélange, sans nombres, ni conductimétrie ni rédox ;
376
+ `titrages` part du même calcul paramétrique et le généralise à un bécher et une
377
+ burette quelconques. Sans équivalent ailleurs : le couple Python + LaTeX à même
378
+ calcul, la conductimétrie avec spectateurs, le rédox dimérique, la base en français.
379
+
380
+ ## Pour plus tard : complexation et précipitation
381
+
382
+ Le paquet ne traite ni la complexation ni la précipitation : un titrage par le
383
+ chlorure de baryum ou par l'EDTA se calcule à la main. L'étude
384
+ [docs/PROJET-complexation-precipitation.md](https://github.com/antnardo/titrages/blob/main/docs/PROJET-complexation-precipitation.md)
385
+ dit ce que coûterait leur ajout, en deux niveaux. Le **niveau 1** garde la méthode
386
+ explicite en paramétrant la courbe par la grandeur mesurée, pM ou pAg : la
387
+ complexométrie en milieu tamponné (EDTA, constante conditionnelle), l'argentimétrie
388
+ (Mohr, Charpentier-Volhard) et les mélanges d'halogénures y entrent, avec des
389
+ courbes à points anguleux là où un solide apparaît ou disparaît ; 800 à 1 200 lignes,
390
+ Lua et LaTeX compris, le moteur pgf pouvant suivre. Le **niveau 2** — ligand basique
391
+ en milieu non tamponné, complexes successifs, hydroxydes — demande un solveur de
392
+ spéciation (Newton sur les logarithmes des concentrations libres, continuation le
393
+ long de la courbe, problème de complémentarité pour les solides) : 2 500 à 4 000
394
+ lignes, sans moteur pgf, et une précision qui n'est plus celle du calcul explicite.
395
+ Les deux demandent une base de constantes (β, Ks) sourcées. Recommandation de
396
+ l'étude : le niveau 1 d'abord, si un TP le demande ; sinon chempy ponctuellement.
397
+
398
+ ## Limites
399
+
400
+ Solutions idéales (activité = concentration, conductivités molaires limites),
401
+ température par le seul `pKe` et la pente de Nernst. Les couples rédox qui échangent
402
+ des protons sont pris à pH fixé ; les métaux et les gaz ne sont pas des couples de
403
+ solution. Les pKa, E° et λ° de la base sont ceux des tables usuelles à 25 °C ; ils
404
+ diffèrent d'une table à l'autre, et la base le signale quand l'écart est notable. Les
405
+ λ° de dix-sept ions, non tabulés dans le CRC, sont approchés par un ion voisin,
406
+ nommé dans `src/titrages/donnees/conductivites.toml` ; ceux de l'EDTA manquent.
407
+
408
+ ## Sources
409
+
410
+ - H. Kalka, *Polyprotic Acids and Beyond — An Algebraic Approach*, Chemistry 2021,
411
+ 3, 454-508, [doi:10.3390/chemistry3020034](https://doi.org/10.3390/chemistry3020034).
412
+ - T. Brière, *Une méthode simple de résolution des problèmes de pH et de titrages
413
+ acido-basiques sans approximations*, BUP 841, 2002.
414
+ - Y. Cortial, *Courbe de dosage acidobasique et méthode des tangentes*, BUP 734, 1991.
415
+ - W. M. Haynes (dir.), *CRC Handbook of Chemistry and Physics*, 97e éd., CRC Press,
416
+ 2016 : constantes d'acidité, potentiels standard, conductivités molaires ioniques.
417
+
418
+ ## Licence
419
+
420
+ MIT.