pyEQL 1.1.6__py3-none-any.whl → 1.3.0__py3-none-any.whl
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.
- pyEQL/__init__.py +1 -1
- pyEQL/activity_correction.py +9 -9
- pyEQL/database/pyeql_db.json +20799 -21094
- pyEQL/engines.py +61 -66
- pyEQL/equilibrium.py +2 -2
- pyEQL/functions.py +12 -12
- pyEQL/presets/Ringers lactate.yaml +3 -3
- pyEQL/presets/normal saline.yaml +3 -3
- pyEQL/presets/rainwater.yaml +3 -3
- pyEQL/presets/seawater.yaml +3 -3
- pyEQL/presets/urine.yaml +3 -3
- pyEQL/presets/wastewater.yaml +3 -3
- pyEQL/py.typed +0 -0
- pyEQL/salt_ion_match.py +2 -2
- pyEQL/solution.py +199 -293
- pyEQL/utils.py +22 -9
- {pyEQL-1.1.6.dist-info → pyeql-1.3.0.dist-info}/METADATA +29 -29
- pyeql-1.3.0.dist-info/RECORD +26 -0
- {pyEQL-1.1.6.dist-info → pyeql-1.3.0.dist-info}/WHEEL +1 -1
- {pyEQL-1.1.6.dist-info → pyeql-1.3.0.dist-info/licenses}/AUTHORS.md +5 -0
- pyEQL-1.1.6.dist-info/COPYING +0 -165
- pyEQL-1.1.6.dist-info/RECORD +0 -26
- {pyEQL-1.1.6.dist-info → pyeql-1.3.0.dist-info/licenses}/LICENSE.txt +0 -0
- {pyEQL-1.1.6.dist-info → pyeql-1.3.0.dist-info}/top_level.txt +0 -0
pyEQL/engines.py
CHANGED
|
@@ -6,6 +6,7 @@ pyEQL engines for computing aqueous equilibria (e.g., speciation, redox, etc.).
|
|
|
6
6
|
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
|
+
import copy
|
|
9
10
|
import logging
|
|
10
11
|
import os
|
|
11
12
|
import warnings
|
|
@@ -17,7 +18,6 @@ from phreeqpython import PhreeqPython
|
|
|
17
18
|
|
|
18
19
|
import pyEQL.activity_correction as ac
|
|
19
20
|
from pyEQL import ureg
|
|
20
|
-
from pyEQL.salt_ion_match import Salt
|
|
21
21
|
from pyEQL.utils import standardize_formula
|
|
22
22
|
|
|
23
23
|
# These are the only elements that are allowed to have parenthetical oxidation states
|
|
@@ -27,7 +27,7 @@ SPECIAL_ELEMENTS = ["S", "C", "N", "Cu", "Fe", "Mn"]
|
|
|
27
27
|
logger = logging.getLogger(__name__)
|
|
28
28
|
|
|
29
29
|
if TYPE_CHECKING:
|
|
30
|
-
from pyEQL import
|
|
30
|
+
from pyEQL import solution
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
class EOS(ABC):
|
|
@@ -41,7 +41,7 @@ class EOS(ABC):
|
|
|
41
41
|
"""
|
|
42
42
|
|
|
43
43
|
@abstractmethod
|
|
44
|
-
def get_activity_coefficient(self, solution: "Solution", solute: str) -> ureg.Quantity:
|
|
44
|
+
def get_activity_coefficient(self, solution: "solution.Solution", solute: str) -> ureg.Quantity:
|
|
45
45
|
"""
|
|
46
46
|
Return the *molal scale* activity coefficient of solute, given a Solution
|
|
47
47
|
object.
|
|
@@ -58,7 +58,7 @@ class EOS(ABC):
|
|
|
58
58
|
"""
|
|
59
59
|
|
|
60
60
|
@abstractmethod
|
|
61
|
-
def get_osmotic_coefficient(self, solution: "Solution") -> ureg.Quantity:
|
|
61
|
+
def get_osmotic_coefficient(self, solution: "solution.Solution") -> ureg.Quantity:
|
|
62
62
|
"""
|
|
63
63
|
Return the *molal scale* osmotic coefficient of a Solution.
|
|
64
64
|
|
|
@@ -73,7 +73,7 @@ class EOS(ABC):
|
|
|
73
73
|
"""
|
|
74
74
|
|
|
75
75
|
@abstractmethod
|
|
76
|
-
def get_solute_volume(self, solution: "Solution") -> ureg.Quantity:
|
|
76
|
+
def get_solute_volume(self, solution: "solution.Solution") -> ureg.Quantity:
|
|
77
77
|
"""
|
|
78
78
|
Return the volume of only the solutes.
|
|
79
79
|
|
|
@@ -88,7 +88,7 @@ class EOS(ABC):
|
|
|
88
88
|
"""
|
|
89
89
|
|
|
90
90
|
@abstractmethod
|
|
91
|
-
def equilibrate(self, solution: "Solution") -> None:
|
|
91
|
+
def equilibrate(self, solution: "solution.Solution") -> None:
|
|
92
92
|
"""
|
|
93
93
|
Adjust the speciation and pH of a Solution object to achieve chemical equilibrium.
|
|
94
94
|
|
|
@@ -108,25 +108,25 @@ class EOS(ABC):
|
|
|
108
108
|
class IdealEOS(EOS):
|
|
109
109
|
"""Ideal solution equation of state engine."""
|
|
110
110
|
|
|
111
|
-
def get_activity_coefficient(self, solution: "Solution", solute: str) -> ureg.Quantity:
|
|
111
|
+
def get_activity_coefficient(self, solution: "solution.Solution", solute: str) -> ureg.Quantity:
|
|
112
112
|
"""
|
|
113
113
|
Return the *molal scale* activity coefficient of solute, given a Solution
|
|
114
114
|
object.
|
|
115
115
|
"""
|
|
116
116
|
return ureg.Quantity(1, "dimensionless")
|
|
117
117
|
|
|
118
|
-
def get_osmotic_coefficient(self, solution: "Solution") -> ureg.Quantity:
|
|
118
|
+
def get_osmotic_coefficient(self, solution: "solution.Solution") -> ureg.Quantity:
|
|
119
119
|
"""
|
|
120
120
|
Return the *molal scale* osmotic coefficient of solute, given a Solution
|
|
121
121
|
object.
|
|
122
122
|
"""
|
|
123
123
|
return ureg.Quantity(1, "dimensionless")
|
|
124
124
|
|
|
125
|
-
def get_solute_volume(self, solution: "Solution") -> ureg.Quantity:
|
|
125
|
+
def get_solute_volume(self, solution: "solution.Solution") -> ureg.Quantity:
|
|
126
126
|
"""Return the volume of the solutes."""
|
|
127
127
|
return ureg.Quantity(0, "L")
|
|
128
128
|
|
|
129
|
-
def equilibrate(self, solution: "Solution") -> None:
|
|
129
|
+
def equilibrate(self, solution: "solution.Solution") -> None:
|
|
130
130
|
"""Adjust the speciation of a Solution object to achieve chemical equilibrium."""
|
|
131
131
|
warnings.warn("equilibrate() has no effect in IdealEOS!")
|
|
132
132
|
return
|
|
@@ -177,7 +177,7 @@ class NativeEOS(EOS):
|
|
|
177
177
|
# store the solution composition to see whether we need to re-instantiate the solution
|
|
178
178
|
self._stored_comp = None
|
|
179
179
|
|
|
180
|
-
def _setup_ppsol(self, solution: "Solution") -> None:
|
|
180
|
+
def _setup_ppsol(self, solution: "solution.Solution") -> None:
|
|
181
181
|
"""Helper method to set up a PhreeqPython solution for subsequent analysis."""
|
|
182
182
|
self._stored_comp = solution.components.copy()
|
|
183
183
|
solv_mass = solution.solvent_mass.to("kg").magnitude
|
|
@@ -215,7 +215,7 @@ class NativeEOS(EOS):
|
|
|
215
215
|
if bare_el in SPECIAL_ELEMENTS:
|
|
216
216
|
# PHREEQC will ignore float-formatted oxi states. Need to make sure we are
|
|
217
217
|
# passing, e.g. 'C(4)' and not 'C(4.0)'
|
|
218
|
-
key = f
|
|
218
|
+
key = f"{bare_el}({int(float(el.split('(')[-1].split(')')[0]))})"
|
|
219
219
|
elif bare_el in ["H", "O"]:
|
|
220
220
|
continue
|
|
221
221
|
else:
|
|
@@ -252,11 +252,11 @@ class NativeEOS(EOS):
|
|
|
252
252
|
self.ppsol.forget()
|
|
253
253
|
self.ppsol = None
|
|
254
254
|
|
|
255
|
-
def get_activity_coefficient(self, solution: "Solution", solute: str):
|
|
255
|
+
def get_activity_coefficient(self, solution: "solution.Solution", solute: str):
|
|
256
256
|
r"""
|
|
257
|
-
Whenever the appropriate parameters are available, the Pitzer model [
|
|
257
|
+
Whenever the appropriate parameters are available, the Pitzer model [may11]_ is used.
|
|
258
258
|
If no Pitzer parameters are available, then the appropriate equations are selected
|
|
259
|
-
according to the following logic: [
|
|
259
|
+
according to the following logic: [stumm96]_.
|
|
260
260
|
|
|
261
261
|
I <= 0.0005: Debye-Huckel equation
|
|
262
262
|
0.005 < I <= 0.1: Guntelberg approximation
|
|
@@ -266,7 +266,7 @@ class NativeEOS(EOS):
|
|
|
266
266
|
The ionic strength, activity coefficients, and activities are all
|
|
267
267
|
calculated based on the molal (mol/kg) concentration scale. If a different
|
|
268
268
|
scale is given as input, then the molal-scale activity coefficient :math:`\gamma_\pm` is
|
|
269
|
-
converted according to [
|
|
269
|
+
converted according to [rbs68]_
|
|
270
270
|
|
|
271
271
|
.. math:: f_\pm = \gamma_\pm * (1 + M_w \sum_i \nu_i m_i)
|
|
272
272
|
|
|
@@ -287,10 +287,9 @@ class NativeEOS(EOS):
|
|
|
287
287
|
Returns:
|
|
288
288
|
The mean ion activity coefficient of the solute in question on the selected scale.
|
|
289
289
|
|
|
290
|
-
|
|
291
290
|
Notes:
|
|
292
291
|
For multicomponent mixtures, pyEQL implements the "effective Pitzer model"
|
|
293
|
-
presented by Mistry et al. [
|
|
292
|
+
presented by Mistry et al. [mistry13]_. In this model, the activity coefficient
|
|
294
293
|
of a salt in a multicomponent mixture is calculated using an "effective
|
|
295
294
|
molality," which is the molality that would result in a single-salt
|
|
296
295
|
mixture with the same total ionic strength as the multicomponent solution.
|
|
@@ -298,18 +297,15 @@ class NativeEOS(EOS):
|
|
|
298
297
|
.. math:: m_{effective} = \frac{2 I}{(\nu_{+} z_{+}^2 + \nu_{-}- z_{-}^2)}
|
|
299
298
|
|
|
300
299
|
References:
|
|
301
|
-
.. [
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
.. [stumm] Stumm, Werner and Morgan, James J. *Aquatic Chemistry*, 3rd ed,
|
|
306
|
-
pp 165. Wiley Interscience, 1996.
|
|
300
|
+
.. [may11] May, P. M., Rowland, D., Hefter, G., & Königsberger, E. (2011).
|
|
301
|
+
A Generic and Updatable Pitzer Characterization of Aqueous Binary Electrolyte Solutions at 1 bar
|
|
302
|
+
and 25 °C. *Journal of Chemical & Engineering Data*, 56(12), 5066-5077. doi:10.1021/je2009329
|
|
307
303
|
|
|
308
|
-
|
|
309
|
-
|
|
304
|
+
.. [stumm96] Stumm, Werner and Morgan, James J. *Aquatic Chemistry*, 3rd ed,
|
|
305
|
+
pp 165. Wiley Interscience, 1996.
|
|
310
306
|
|
|
311
|
-
|
|
312
|
-
|
|
307
|
+
.. [rbs68] Robinson, R. A.; Stokes, R. H. Electrolyte Solutions: Second Revised
|
|
308
|
+
Edition; Butterworths: London, 1968, p.32.
|
|
313
309
|
|
|
314
310
|
See Also:
|
|
315
311
|
:attr:`pyEQL.solution.Solution.ionic_strength`
|
|
@@ -321,12 +317,9 @@ class NativeEOS(EOS):
|
|
|
321
317
|
# identify the predominant salt that this ion is a member of
|
|
322
318
|
salt = None
|
|
323
319
|
rform = standardize_formula(solute)
|
|
324
|
-
for
|
|
325
|
-
if
|
|
326
|
-
|
|
327
|
-
if rform == v["cation"] or rform == v["anion"]:
|
|
328
|
-
del v["mol"]
|
|
329
|
-
salt = Salt.from_dict(v)
|
|
320
|
+
for d in solution.get_salt_dict().values():
|
|
321
|
+
if rform == d["salt"].cation or rform == d["salt"].anion:
|
|
322
|
+
salt = d["salt"]
|
|
330
323
|
break
|
|
331
324
|
|
|
332
325
|
# show an error if no salt can be found that contains the solute
|
|
@@ -344,8 +337,8 @@ class NativeEOS(EOS):
|
|
|
344
337
|
# determine alpha1 and alpha2 based on the type of salt
|
|
345
338
|
# see the May reference for the rules used to determine
|
|
346
339
|
# alpha1 and alpha2 based on charge
|
|
347
|
-
if salt.
|
|
348
|
-
if salt.
|
|
340
|
+
if salt.z_cation >= 2 and salt.z_anion <= -2:
|
|
341
|
+
if salt.z_cation >= 3 or salt.z_anion <= -3:
|
|
349
342
|
alpha1 = 2.0
|
|
350
343
|
alpha2 = 50.0
|
|
351
344
|
else:
|
|
@@ -429,17 +422,17 @@ class NativeEOS(EOS):
|
|
|
429
422
|
|
|
430
423
|
return molal
|
|
431
424
|
|
|
432
|
-
def get_osmotic_coefficient(self, solution: "Solution") -> ureg.Quantity:
|
|
425
|
+
def get_osmotic_coefficient(self, solution: "solution.Solution") -> ureg.Quantity:
|
|
433
426
|
r"""
|
|
434
427
|
Return the *molal scale* osmotic coefficient of solute, given a Solution
|
|
435
428
|
object.
|
|
436
429
|
|
|
437
|
-
Osmotic coefficient is calculated using the Pitzer model. [
|
|
430
|
+
Osmotic coefficient is calculated using the Pitzer model. [may11]_ If appropriate parameters for
|
|
438
431
|
the model are not available, then pyEQL raises a WARNING and returns an osmotic
|
|
439
432
|
coefficient of 1.
|
|
440
433
|
|
|
441
434
|
If the 'rational' scale is given as input, then the molal-scale osmotic
|
|
442
|
-
coefficient :math:`\phi` is converted according to [
|
|
435
|
+
coefficient :math:`\phi` is converted according to [rbs68]_
|
|
443
436
|
|
|
444
437
|
.. math:: g = - \phi M_{w} \frac{\sum_{i} \nu_{i} m_{i}}{\ln x_{w}}
|
|
445
438
|
|
|
@@ -463,7 +456,7 @@ class NativeEOS(EOS):
|
|
|
463
456
|
|
|
464
457
|
Notes:
|
|
465
458
|
For multicomponent mixtures, pyEQL adopts the "effective Pitzer model"
|
|
466
|
-
presented by Mistry et al. [
|
|
459
|
+
presented by Mistry et al. [mistry13]_. In this approach, the osmotic coefficient of
|
|
467
460
|
each individual salt is calculated using the normal Pitzer model based
|
|
468
461
|
on its respective concentration. Then, an effective osmotic coefficient
|
|
469
462
|
is calculated as the concentration-weighted average of the individual
|
|
@@ -480,17 +473,6 @@ class NativeEOS(EOS):
|
|
|
480
473
|
the author confirmed that the weight factor should be the true molality, and that is what is implemented
|
|
481
474
|
in pyEQL.)
|
|
482
475
|
|
|
483
|
-
References:
|
|
484
|
-
.. [may] May, P. M., Rowland, D., Hefter, G., & Königsberger, E. (2011).
|
|
485
|
-
A Generic and Updatable Pitzer Characterization of Aqueous Binary Electrolyte Solutions at 1 bar and
|
|
486
|
-
25 °C. Journal of Chemical & Engineering Data, 56(12), 5066-5077. doi:10.1021/je2009329
|
|
487
|
-
|
|
488
|
-
.. [rbs] Robinson, R. A.; Stokes, R. H. Electrolyte Solutions: Second Revised
|
|
489
|
-
Edition; Butterworths: London, 1968, p.32.
|
|
490
|
-
|
|
491
|
-
.. [mstry] Mistry, K. H.; Hunter, H. a.; Lienhard V, J. H. Effect of composition and nonideal solution
|
|
492
|
-
behavior on desalination calculations for mixed electrolyte solutions with comparison to seawater. Desalination 2013, 318, 34-47.
|
|
493
|
-
|
|
494
476
|
Examples:
|
|
495
477
|
>>> s1 = pyEQL.Solution({'Na+': '0.2 mol/kg', 'Cl-': '0.2 mol/kg'})
|
|
496
478
|
>>> s1.get_osmotic_coefficient()
|
|
@@ -500,6 +482,24 @@ class NativeEOS(EOS):
|
|
|
500
482
|
>>> s1.get_osmotic_coefficient()
|
|
501
483
|
<Quantity(0.891409618, 'dimensionless')>
|
|
502
484
|
|
|
485
|
+
References:
|
|
486
|
+
[may11]
|
|
487
|
+
|
|
488
|
+
May, P. M., Rowland, D., Hefter, G., & Königsberger, E. (2011).
|
|
489
|
+
A Generic and Updatable Pitzer Characterization of Aqueous Binary Electrolyte Solutions at 1 bar
|
|
490
|
+
and 25 °C. Journal of Chemical & Engineering Data, 56(12), 5066-5077. doi:10.1021/je2009329
|
|
491
|
+
|
|
492
|
+
[rbs68]
|
|
493
|
+
|
|
494
|
+
Robinson, R. A.; Stokes, R. H. Electrolyte Solutions: Second Revised Edition; Butterworths: London, 1968,
|
|
495
|
+
p.32.
|
|
496
|
+
|
|
497
|
+
[mistry13]
|
|
498
|
+
|
|
499
|
+
Mistry, K. H.; Hunter, H. a.; Lienhard V, J. H. Effect of composition and nonideal solution
|
|
500
|
+
behavior on desalination calculations for mixed electrolyte solutions with comparison to
|
|
501
|
+
seawater. Desalination 2013, 318, 34-47.
|
|
502
|
+
|
|
503
503
|
"""
|
|
504
504
|
ionic_strength = solution.ionic_strength
|
|
505
505
|
|
|
@@ -510,11 +510,7 @@ class NativeEOS(EOS):
|
|
|
510
510
|
# coefficint for each, and average them into an effective osmotic
|
|
511
511
|
# coefficient
|
|
512
512
|
for d in solution.get_salt_dict().values():
|
|
513
|
-
item =
|
|
514
|
-
# ignore HOH in the salt list
|
|
515
|
-
if item.formula == "HOH":
|
|
516
|
-
continue
|
|
517
|
-
|
|
513
|
+
item = d["salt"]
|
|
518
514
|
# determine alpha1 and alpha2 based on the type of salt
|
|
519
515
|
# see the May reference for the rules used to determine
|
|
520
516
|
# alpha1 and alpha2 based on charge
|
|
@@ -574,9 +570,9 @@ class NativeEOS(EOS):
|
|
|
574
570
|
return effective_osmotic_sum / molality_sum
|
|
575
571
|
except ZeroDivisionError:
|
|
576
572
|
# this means the solution is empty
|
|
577
|
-
return 1
|
|
573
|
+
return ureg.Quantity(1.0)
|
|
578
574
|
|
|
579
|
-
def get_solute_volume(self, solution: "Solution") -> ureg.Quantity:
|
|
575
|
+
def get_solute_volume(self, solution: "solution.Solution") -> ureg.Quantity:
|
|
580
576
|
"""Return the volume of the solutes."""
|
|
581
577
|
# identify the predominant salt in the solution
|
|
582
578
|
salt = solution.get_salt()
|
|
@@ -584,8 +580,8 @@ class NativeEOS(EOS):
|
|
|
584
580
|
|
|
585
581
|
# use the pitzer approach if parameters are available
|
|
586
582
|
pitzer_calc = False
|
|
583
|
+
param = None if salt is None else solution.get_property(salt.formula, "model_parameters.molar_volume_pitzer")
|
|
587
584
|
|
|
588
|
-
param = solution.get_property(salt.formula, "model_parameters.molar_volume_pitzer")
|
|
589
585
|
if param is not None:
|
|
590
586
|
# determine the average molality of the salt
|
|
591
587
|
# this is necessary for solutions inside e.g. an ion exchange
|
|
@@ -596,8 +592,8 @@ class NativeEOS(EOS):
|
|
|
596
592
|
# determine alpha1 and alpha2 based on the type of salt
|
|
597
593
|
# see the May reference for the rules used to determine
|
|
598
594
|
# alpha1 and alpha2 based on charge
|
|
599
|
-
if salt.
|
|
600
|
-
if salt.
|
|
595
|
+
if salt.z_cation >= 2 and salt.z_anion <= -2:
|
|
596
|
+
if salt.z_cation >= 3 or salt.z_anion <= -3:
|
|
601
597
|
alpha1 = 2.0
|
|
602
598
|
alpha2 = 50.0
|
|
603
599
|
else:
|
|
@@ -660,7 +656,7 @@ class NativeEOS(EOS):
|
|
|
660
656
|
|
|
661
657
|
return solute_vol.to("L")
|
|
662
658
|
|
|
663
|
-
def equilibrate(self, solution: "Solution") -> None:
|
|
659
|
+
def equilibrate(self, solution: "solution.Solution") -> None:
|
|
664
660
|
"""Adjust the speciation of a Solution object to achieve chemical equilibrium."""
|
|
665
661
|
if self.ppsol is not None:
|
|
666
662
|
self.ppsol.forget()
|
|
@@ -699,7 +695,6 @@ class NativeEOS(EOS):
|
|
|
699
695
|
def __deepcopy__(self, memo) -> "NativeEOS":
|
|
700
696
|
# custom deepcopy required because the PhreeqPython instance used by the Native and Phreeqc engines
|
|
701
697
|
# is not pickle-able.
|
|
702
|
-
import copy
|
|
703
698
|
|
|
704
699
|
cls = self.__class__
|
|
705
700
|
result = cls.__new__(cls)
|
|
@@ -735,7 +730,7 @@ class PhreeqcEOS(NativeEOS):
|
|
|
735
730
|
"""
|
|
736
731
|
super().__init__(phreeqc_db=phreeqc_db)
|
|
737
732
|
|
|
738
|
-
def get_activity_coefficient(self, solution: "Solution", solute: str) -> ureg.Quantity:
|
|
733
|
+
def get_activity_coefficient(self, solution: "solution.Solution", solute: str) -> ureg.Quantity:
|
|
739
734
|
"""
|
|
740
735
|
Return the *molal scale* activity coefficient of solute, given a Solution
|
|
741
736
|
object.
|
|
@@ -759,7 +754,7 @@ class PhreeqcEOS(NativeEOS):
|
|
|
759
754
|
|
|
760
755
|
return ureg.Quantity(act, "dimensionless")
|
|
761
756
|
|
|
762
|
-
def get_osmotic_coefficient(self, solution: "Solution") -> ureg.Quantity:
|
|
757
|
+
def get_osmotic_coefficient(self, solution: "solution.Solution") -> ureg.Quantity:
|
|
763
758
|
"""
|
|
764
759
|
Return the *molal scale* osmotic coefficient of solute, given a Solution
|
|
765
760
|
object.
|
|
@@ -771,7 +766,7 @@ class PhreeqcEOS(NativeEOS):
|
|
|
771
766
|
# TODO - find a way to access or calculate osmotic coefficient
|
|
772
767
|
return ureg.Quantity(1, "dimensionless")
|
|
773
768
|
|
|
774
|
-
def get_solute_volume(self, solution: "Solution") -> ureg.Quantity:
|
|
769
|
+
def get_solute_volume(self, solution: "solution.Solution") -> ureg.Quantity:
|
|
775
770
|
"""Return the volume of the solutes."""
|
|
776
771
|
# TODO - phreeqc seems to have no concept of volume, but it does calculate density
|
|
777
772
|
return ureg.Quantity(0, "L")
|
pyEQL/equilibrium.py
CHANGED
|
@@ -129,10 +129,10 @@ def adjust_temp_arrhenius(
|
|
|
129
129
|
TODO - add better reference
|
|
130
130
|
|
|
131
131
|
.. math::
|
|
132
|
-
ln(\frac{
|
|
132
|
+
\ln\left((\frac{K_2}{K_1}\right) = \frac{E_a}{R} \left( \frac{1}{T_{1}} - {\frac{1}{T_2}} \right)
|
|
133
133
|
|
|
134
134
|
References:
|
|
135
|
-
|
|
135
|
+
https://chem.libretexts.org/Bookshelves/Physical_and_Theoretical_Chemistry_Textbook_Maps/Physical_Chemistry_(LibreTexts)/28%3A_Chemical_Kinetics_I_-_Rate_Laws/28.07%3A_Rate_Constants_Are_Usually_Strongly_Temperature_Dependent
|
|
136
136
|
|
|
137
137
|
Examples:
|
|
138
138
|
>>> adjust_temp_arrhenius(7,900*ureg.Quantity('kJ/mol'),37*ureg.Quantity('degC'),97*ureg.Quantity('degC')) #doctest: +ELLIPSIS
|
pyEQL/functions.py
CHANGED
|
@@ -40,8 +40,8 @@ def gibbs_mix(solution1: Solution, solution2: Solution, activity_correction: boo
|
|
|
40
40
|
|
|
41
41
|
or
|
|
42
42
|
|
|
43
|
-
.. math::
|
|
44
|
-
|
|
43
|
+
.. math::
|
|
44
|
+
|
|
45
45
|
\Delta_{mix} G_{ideal} = \sum_i {(n_c + n_d) R T \ln x_b} - \sum_i {n_c R T \ln x_c} - \sum_i {n_d R T \ln x_d}
|
|
46
46
|
|
|
47
47
|
|
|
@@ -70,7 +70,9 @@ def gibbs_mix(solution1: Solution, solution2: Solution, activity_correction: boo
|
|
|
70
70
|
if activity_correction is True:
|
|
71
71
|
term_list[solution] += solution.get_amount(solute, "mol") * np.log(solution.get_activity(solute))
|
|
72
72
|
else:
|
|
73
|
-
term_list[solution] += solution.get_amount(solute, "mol") * np.log(
|
|
73
|
+
term_list[solution] += solution.get_amount(solute, "mol") * np.log(
|
|
74
|
+
solution.get_amount(solute, "fraction")
|
|
75
|
+
)
|
|
74
76
|
|
|
75
77
|
return (ureg.R * blend.temperature.to("K") * (term_list[blend] - term_list[concentrate] - term_list[dilute])).to(
|
|
76
78
|
"J"
|
|
@@ -95,17 +97,17 @@ def entropy_mix(solution1: Solution, solution2: Solution):
|
|
|
95
97
|
|
|
96
98
|
\Delta_{mix} S = \sum_i {(n_c + n_d) R \ln x_b} - \sum_i {n_c R \ln x_c} - \sum_i {n_d R \ln x_d}
|
|
97
99
|
|
|
98
|
-
Where :math:`n` is the number of moles of substance, :math:`T` is the temperature in kelvin, :math:`x` is the
|
|
99
|
-
and subscripts :math:`b`, :math:`c`, and :math:`d` refer to the
|
|
100
|
-
Solutions, respectively.
|
|
100
|
+
Where :math:`n` is the number of moles of substance, :math:`T` is the temperature in kelvin, :math:`x` is the
|
|
101
|
+
mole fraction of solute :math:`i`, and subscripts :math:`b`, :math:`c`, and :math:`d` refer to the
|
|
102
|
+
concentrated, dilute, and blended Solutions, respectively.
|
|
101
103
|
|
|
102
104
|
Note that dissociated ions must be counted as separate components,
|
|
103
105
|
so a simple salt dissolved in water is a three component solution (cation,
|
|
104
106
|
anion, and water).
|
|
105
107
|
|
|
106
108
|
References:
|
|
107
|
-
Koga, Yoshikata, 2007. *Solution Thermodynamics and its Application to Aqueous Solutions:
|
|
108
|
-
|
|
109
|
+
Koga, Yoshikata, 2007. *Solution Thermodynamics and its Application to Aqueous Solutions: *
|
|
110
|
+
*A differential approach.* Elsevier, 2007, pp. 23-37.
|
|
109
111
|
|
|
110
112
|
"""
|
|
111
113
|
concentrate = solution1
|
|
@@ -121,9 +123,7 @@ def entropy_mix(solution1: Solution, solution2: Solution):
|
|
|
121
123
|
solution.get_amount(solute, "fraction")
|
|
122
124
|
)
|
|
123
125
|
|
|
124
|
-
return (ureg.R * (term_list[blend] - term_list[concentrate] - term_list[dilute])).to(
|
|
125
|
-
"J/K"
|
|
126
|
-
)
|
|
126
|
+
return (ureg.R * (term_list[blend] - term_list[concentrate] - term_list[dilute])).to("J/K")
|
|
127
127
|
|
|
128
128
|
|
|
129
129
|
def donnan_eql(solution: Solution, fixed_charge: str):
|
|
@@ -149,7 +149,7 @@ def donnan_eql(solution: Solution, fixed_charge: str):
|
|
|
149
149
|
|
|
150
150
|
.. math::
|
|
151
151
|
|
|
152
|
-
\big(\frac{a_{-}}{\bar a_{-}} \big)^{(\frac{1}{z_{-}})}
|
|
152
|
+
\big(\frac{a_{-}}{\bar a_{-}} \big)^{(\frac{1}{z_{-}})}
|
|
153
153
|
\big(\frac{\bar a_{+}}{a_{+}}\big)^{(\frac{1}{z_{+}})}
|
|
154
154
|
=\exp \big(\frac{\Delta \pi \bar V}{RT z_{+} \nu_{+}}\big)
|
|
155
155
|
|
pyEQL/presets/normal saline.yaml
CHANGED
pyEQL/presets/rainwater.yaml
CHANGED
pyEQL/presets/seawater.yaml
CHANGED
pyEQL/presets/urine.yaml
CHANGED
pyEQL/presets/wastewater.yaml
CHANGED
pyEQL/py.typed
ADDED
|
File without changes
|
pyEQL/salt_ion_match.py
CHANGED
|
@@ -91,7 +91,7 @@ class Salt(MSONable):
|
|
|
91
91
|
# Mg+2 is converted to monovalent complexes like MgOH+. Hence, the activity coefficients deviate a bit from
|
|
92
92
|
# the published values.
|
|
93
93
|
def get_effective_molality(self, ionic_strength):
|
|
94
|
-
r"""Calculate the effective molality according to [
|
|
94
|
+
r"""Calculate the effective molality according to [mistry13]_.
|
|
95
95
|
|
|
96
96
|
.. math:: 2 I \over (\nu_+ z_+^2 + \nu_- z_- ^2)
|
|
97
97
|
|
|
@@ -103,7 +103,7 @@ class Salt(MSONable):
|
|
|
103
103
|
Quantity: the effective molality of the salt in the parent solution
|
|
104
104
|
|
|
105
105
|
References:
|
|
106
|
-
.. [
|
|
106
|
+
.. [mistry13] Mistry, K. H.; Hunter, H. a.; Lienhard V, J. H. Effect of composition and nonideal solution behavior
|
|
107
107
|
on desalination calculations for mixed electrolyte solutions with comparison to seawater. Desalination
|
|
108
108
|
2013, 318, 34-47.
|
|
109
109
|
"""
|