Bonsoir,
On m'a fait remarquer que mon script Basic permettait de calculer HClO à partir de pH, CyA et Chole disponible mais pas "l’inverse".
Voici donc une nouvelle version de ce script qui créée deux fonctions dans LibreOffice Calc :
- hoclcalc(pH;CyA;CD) qui retourne HClO pour les valeurs de pH, CyA et chlore disponible
- totckcalc(pH;CyA;HClO) qui retourne le chlore disponible pour ....
REM ***** BASIC *****
'=========================================================
' hoclcalc v3.3 - jph 2026 avec TotClCalc
' EPA HOCl / CYA MODEL 5.0
' - coefficients H/Cy precalcules une seule fois par cellule
' - Newton-Raphson securise (repli bissection)
'=========================================================
Option Explicit
Private Const MWCL2 As Double = 71000
Private Const MWCYA As Double = 129070
Private Const K1a As Double = 10^(-1.80)
Private Const K2 As Double = 10^(-3.75)
Private Const K4 As Double = 10^(-5.33)
Private Const K6 As Double = 10^(-6.88)
Private Const K7a As Double = 10^(-4.51)
Private Const K8 As Double = 10^(-10.12)
Private Const K10 As Double = 10^(-11.40)
Private Const K11a As Double = 10^(-6.90)
Private Const K12 As Double = 10^(-13.50)
Private Const KHOCl As Double = 10^(-7.54)
Private Const INV_K1211 As Double = 1# / (K12 * K11a)
Private Const INV_K12118 As Double = 1# / (K12 * K11a * K8)
Private Const INV_K121187 As Double = 1# / (K12 * K11a * K8 * K7a)
Private Const INV_K1211872 As Double = 1# / (K12 * K11a * K8 * K7a * K2)
Private Const INV_K12118721 As Double = 1# / (K12 * K11a * K8 * K7a * K2 * K1a)
Private Const INV_K121184 As Double = 1# / (K12 * K11a * K8 * K4)
Private Const INV_K12106 As Double = 1# / (K12 * K10 * K6)
Private Const INV_K1210 As Double = 1# / (K12 * K10)
Private Const INV_K12 As Double = 1# / K12
Private Type TCoefs
a3 As Double
a2 As Double
a1 As Double
D As Double
E As Double
F As Double
G As Double
K As Double
End Type
Private Function Cl2ToMol(ByVal x As Double) As Double
Cl2ToMol = x / MWCL2
End Function
Private Function CyToMol(ByVal x As Double) As Double
CyToMol = x / MWCYA
End Function
Private Function MolToCl2(ByVal x As Double) As Double
MolToCl2 = x * MWCL2
End Function
Public Function HOClCalc( _
ByVal pH As Double, _
ByVal TOTCy As Double, _
ByVal TOTCl As Double) As Double
Dim H As Double
Dim Cy As Double
Dim Cl As Double
Dim x As Double
H = 10 ^ (-pH)
Cy = CyToMol(TOTCy)
Cl = Cl2ToMol(TOTCl)
x = SolveHOCl(H, Cy, Cl)
If x < 0# Then
HOClCalc = 0#
Exit Function
End If
HOClCalc = MolToCl2(x)
End Function
Private Sub BuildCoefs(ByVal H As Double, ByVal Cy As Double, ByRef co As TCoefs)
Dim H2 As Double
Dim H3 As Double
Dim A As Double, B As Double, C As Double
H2 = H * H
H3 = H2 * H
A = 3# * H3 * INV_K12118721
B = 2# * H3 * INV_K1211872 _
+ 2# * H2 * INV_K121187
C = H3 * INV_K121184 _
+ H2 * INV_K12118 _
+ H * INV_K1211
co.a3 = Cy * A
co.a2 = Cy * B
co.a1 = Cy * C
co.D = H3 * INV_K12118721
co.E = H3 * INV_K1211872 _
+ H2 * INV_K121187
co.F = C
co.G = H3 * INV_K12106 _
+ H2 * INV_K1210 _
+ H * INV_K12 _
+ 1#
co.K = 1# + KHOCl / H
End Sub
Private Sub EvalFast(ByVal x As Double, ByRef co As TCoefs, _
ByRef f As Double, ByRef df As Double)
Dim Num As Double, Den As Double
Dim dNum As Double, dDen As Double
Dim x2 As Double
x2 = x * x
Num = co.a3 * x2 * x + co.a2 * x2 + co.a1 * x
Den = co.D * x2 * x + co.E * x2 + co.F * x + co.G
dNum = 3# * co.a3 * x2 + 2# * co.a2 * x + co.a1
dDen = 3# * co.D * x2 + 2# * co.E * x + co.F
f = Num / Den + co.K * x
df = (dNum * Den - Num * dDen) / (Den * Den) + co.K
End Sub
Private Function Equation15Fast(ByVal x As Double, ByRef co As TCoefs) As Double
Dim f As Double, df As Double
EvalFast x, co, f, df
Equation15Fast = f
End Function
Private Function SolveHOCl( _
ByVal H As Double, _
ByVal Cy As Double, _
ByVal TotCl As Double) As Double
Const MAXITER As Integer = 60
Const EPSX As Double = 1E-13
Const EPSF As Double = 1E-13
Dim co As TCoefs
Dim a As Double, b As Double, x As Double
Dim fa As Double, fb As Double, fx As Double, dfx As Double
Dim i As Integer
Dim stp As Double
Dim xNext As Double
If TotCl <= 0# Then
SolveHOCl = 0#
Exit Function
End If
BuildCoefs H, Cy, co
a = 0#
b = TotCl
fa = Equation15Fast(a, co) - TotCl
fb = Equation15Fast(b, co) - TotCl
If Abs(fa) < EPSF Then
SolveHOCl = a
Exit Function
End If
If Abs(fb) < EPSF Then
SolveHOCl = b
Exit Function
End If
If fa * fb > 0# Then
SolveHOCl = -1#
Exit Function
End If
x = TotCl / (1# + KHOCl / H)
If x <= a Or x >= b Then x = 0.5 * (a + b)
For i = 1 To MAXITER
EvalFast x, co, fx, dfx
fx = fx - TotCl
If Abs(fx) < EPSF Then Exit For
If fa * fx < 0# Then
b = x
fb = fx
Else
a = x
fa = fx
End If
If dfx <> 0# Then
stp = fx / dfx
Else
stp = (b - a)
End If
xNext = x - stp
If xNext <= a Or xNext >= b Then
xNext = 0.5 * (a + b)
End If
If Abs(xNext - x) < EPSX * (1# + Abs(x)) Then
x = xNext
Exit For
End If
x = xNext
Next i
If x < 0# Then x = 0#
If x > TotCl Then x = TotCl
SolveHOCl = x
End Function
Public Function TotClCalc( _
ByVal pH As Double, _
ByVal TOTCy As Double, _
ByVal HOCl As Double) As Double
Dim H As Double
Dim Cy As Double
Dim x As Double
Dim co As TCoefs
Dim f As Double
H = 10 ^ (-pH)
Cy = CyToMol(TOTCy)
x = Cl2ToMol(HOCl) ' HOCl donné, converti en mol/L
BuildCoefs H, Cy, co
f = Equation15Fast(x, co)
TotClCalc = MolToCl2(f) ' reconversion en mg/L (ou unité "Cl2"
End Function
Sub Test()
MsgBox HOClCalc(7.2, 50, 3)
End Sub
Sub TestInverse()
Dim totCl As Double
Dim hocl As Double
' on calcule HOCl à partir de TotCl = 3, puis on retrouve TotCl à partir de ce HOCl
hocl = HOClCalc(7.2, 50, 3)
totCl = TotClCalc(7.2, 50, hocl)
MsgBox "HOCl = " & hocl & Chr(10) & "TotCl retrouvé = " & totCl
End Sub