pyEQL 1.2.0__py3-none-any.whl → 1.3.1__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/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 Solution
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'{bare_el}({int(float(el.split("(")[-1].split(")")[0]))})'
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 [may]_ is used.
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: [stumm]_.
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 [rbs]_
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. [mistry]_. In this model, the activity coefficient
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
- .. [may] May, P. M., Rowland, D., Hefter, G., & Königsberger, E. (2011).
302
- A Generic and Updatable Pitzer Characterization of Aqueous Binary Electrolyte Solutions at 1 bar and 25 °C.
303
- *Journal of Chemical & Engineering Data*, 56(12), 5066-5077. doi:10.1021/je2009329
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
- .. [rbs] Robinson, R. A.; Stokes, R. H. Electrolyte Solutions: Second Revised
309
- Edition; Butterworths: London, 1968, p.32.
304
+ .. [stumm96] Stumm, Werner and Morgan, James J. *Aquatic Chemistry*, 3rd ed,
305
+ pp 165. Wiley Interscience, 1996.
310
306
 
311
- .. [mistry] Mistry, K. H.; Hunter, H. a.; Lienhard V, J. H. Effect of composition and nonideal solution behavior on
312
- desalination calculations for mixed electrolyte solutions with comparison to seawater. Desalination 2013, 318, 34-47.
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 v in solution.get_salt_dict().values():
325
- if v == "HOH":
326
- continue
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.nu_cation >= 2 and salt.nu_anion <= -2:
348
- if salt.nu_cation >= 3 or salt.nu_anion <= -3:
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. [may]_ If appropriate parameters for
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 [rbs]_
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. [mstry]_. In this approach, the osmotic coefficient of
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 = Salt(d["cation"], d["anion"])
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.nu_cation >= 2 and salt.nu_anion >= 2:
600
- if salt.nu_cation >= 3 or salt.nu_anion >= 3:
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{K2}{K1}) = \frac{E_a}{R} ( \frac{1}{T_{1}} - {\frac{1}{T_2}} )
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
- http://chemwiki.ucdavis.edu/Physical_Chemistry/Kinetics/Reaction_Rates/Temperature_Dependence_of_Reaction_Rates/Arrhenius_Equation
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
@@ -97,17 +97,17 @@ def entropy_mix(solution1: Solution, solution2: Solution):
97
97
 
98
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}
99
99
 
100
- Where :math:`n` is the number of moles of substance, :math:`T` is the temperature in kelvin, :math:`x` is the mole fraction of solute :math:`i`,
101
- and subscripts :math:`b`, :math:`c`, and :math:`d` refer to the concentrated, dilute, and blended
102
- 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.
103
103
 
104
104
  Note that dissociated ions must be counted as separate components,
105
105
  so a simple salt dissolved in water is a three component solution (cation,
106
106
  anion, and water).
107
107
 
108
108
  References:
109
- Koga, Yoshikata, 2007. *Solution Thermodynamics and its Application to Aqueous Solutions:
110
- A differential approach.* Elsevier, 2007, pp. 23-37.
109
+ Koga, Yoshikata, 2007. *Solution Thermodynamics and its Application to Aqueous Solutions: *
110
+ *A differential approach.* Elsevier, 2007, pp. 23-37.
111
111
 
112
112
  """
113
113
  concentrate = solution1
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 [mistry]_.
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
- .. [mistry] Mistry, K. H.; Hunter, H. a.; Lienhard V, J. H. Effect of composition and nonideal solution behavior
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
  """