pyEQL 0.12.2__py2.py3-none-any.whl → 0.14.0__py2.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 +318 -451
- pyEQL/engines.py +40 -40
- pyEQL/equilibrium.py +94 -160
- pyEQL/functions.py +15 -13
- pyEQL/logging_system.py +1 -1
- pyEQL/salt_ion_match.py +19 -27
- pyEQL/solute.py +8 -4
- pyEQL/solution.py +378 -439
- pyEQL/utils.py +11 -5
- {pyEQL-0.12.2.dist-info → pyEQL-0.14.0.dist-info}/METADATA +1 -1
- pyEQL-0.14.0.dist-info/RECORD +28 -0
- pyEQL-0.12.2.dist-info/RECORD +0 -28
- {pyEQL-0.12.2.dist-info → pyEQL-0.14.0.dist-info}/AUTHORS.md +0 -0
- {pyEQL-0.12.2.dist-info → pyEQL-0.14.0.dist-info}/COPYING +0 -0
- {pyEQL-0.12.2.dist-info → pyEQL-0.14.0.dist-info}/LICENSE.txt +0 -0
- {pyEQL-0.12.2.dist-info → pyEQL-0.14.0.dist-info}/WHEEL +0 -0
- {pyEQL-0.12.2.dist-info → pyEQL-0.14.0.dist-info}/top_level.txt +0 -0
pyEQL/solution.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""
|
|
2
2
|
pyEQL Solution Class.
|
|
3
3
|
|
|
4
|
-
:copyright: 2013-
|
|
4
|
+
:copyright: 2013-2024 by Ryan S. Kingsbury
|
|
5
5
|
:license: LGPL, see LICENSE for more details.
|
|
6
6
|
|
|
7
7
|
"""
|
|
@@ -61,50 +61,55 @@ class Solution(MSONable):
|
|
|
61
61
|
Instantiate a Solution from a composition.
|
|
62
62
|
|
|
63
63
|
Args:
|
|
64
|
-
solutes
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
volume
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
temperature
|
|
81
|
-
|
|
82
|
-
pressure
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
pH
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
64
|
+
solutes: dict, optional. Keys must be the chemical formula, while values must be
|
|
65
|
+
str Quantity representing the amount. For example:
|
|
66
|
+
|
|
67
|
+
{"Na+": "0.1 mol/L", "Cl-": "0.1 mol/L"}
|
|
68
|
+
|
|
69
|
+
Note that an older "list of lists" syntax is also supported; however this
|
|
70
|
+
will be deprecated in the future and is no longer recommended. The equivalent
|
|
71
|
+
list syntax for the above example is
|
|
72
|
+
|
|
73
|
+
[["Na+", "0.1 mol/L"], ["Cl-", "0.1 mol/L"]]
|
|
74
|
+
|
|
75
|
+
Defaults to empty (pure solvent) if omitted
|
|
76
|
+
volume: str, optional
|
|
77
|
+
Volume of the solvent, including the unit. Defaults to '1 L' if omitted.
|
|
78
|
+
Note that the total solution volume will be computed using partial molar
|
|
79
|
+
volumes of the respective solutes as they are added to the solution.
|
|
80
|
+
temperature: str, optional
|
|
81
|
+
The solution temperature, including the ureg. Defaults to '25 degC' if omitted.
|
|
82
|
+
pressure: Quantity, optional
|
|
83
|
+
The ambient pressure of the solution, including the unit.
|
|
84
|
+
Defaults to '1 atm' if omitted.
|
|
85
|
+
pH: number, optional
|
|
86
|
+
Negative log of H+ activity. If omitted, the solution will be
|
|
87
|
+
initialized to pH 7 (neutral) with appropriate quantities of
|
|
88
|
+
H+ and OH- ions
|
|
89
|
+
pE: the pE value (redox potential) of the solution. Lower values = more reducing,
|
|
90
90
|
higher values = more oxidizing. At pH 7, water is stable between approximately
|
|
91
91
|
-7 to +14. The default value corresponds to a pE value typical of natural
|
|
92
92
|
waters in equilibrium with the atmosphere.
|
|
93
|
-
balance_charge: The strategy for balancing charge during init and equilibrium calculations. Valid options
|
|
94
|
-
'pH', which will adjust the solution pH to balance charge, 'pE' which will adjust the
|
|
95
|
-
redox equilibrium to balance charge, or the name of a dissolved species e.g. 'Ca+2' or 'Cl-'
|
|
96
|
-
added/subtracted to balance charge. If set to None, no charge balancing will be
|
|
97
|
-
or when equilibrate() is called. Note that in this case, equilibrate()
|
|
98
|
-
|
|
99
|
-
|
|
93
|
+
balance_charge: The strategy for balancing charge during init and equilibrium calculations. Valid options
|
|
94
|
+
are 'pH', which will adjust the solution pH to balance charge, 'pE' which will adjust the
|
|
95
|
+
redox equilibrium to balance charge, or the name of a dissolved species e.g. 'Ca+2' or 'Cl-'
|
|
96
|
+
that will be added/subtracted to balance charge. If set to None, no charge balancing will be
|
|
97
|
+
performed either on init or when equilibrate() is called. Note that in this case, equilibrate()
|
|
98
|
+
can distort the charge balance!
|
|
99
|
+
solvent: Formula of the solvent. Solvents other than water are not supported at this time.
|
|
100
100
|
engine: Electrolyte modeling engine to use. See documentation for details on the available engines.
|
|
101
101
|
database: path to a .json file (str or Path) or maggma Store instance that
|
|
102
102
|
contains serialized SoluteDocs. `None` (default) will use the built-in pyEQL database.
|
|
103
103
|
default_diffusion_coeff: Diffusion coefficient value in m^2/s to use in
|
|
104
|
-
calculations when there is no diffusion coefficient for a species in the database. This affects several
|
|
104
|
+
calculations when there is no diffusion coefficient for a species in the database. This affects several
|
|
105
|
+
important property calculations including conductivity and transport number, which are related to the
|
|
106
|
+
weighted sums of diffusion coefficients of all species. Setting this argument to zero will exclude any
|
|
107
|
+
species that does not have a tabulated diffusion coefficient from these calculations, possibly resulting
|
|
108
|
+
in underestimation of the conductivity and/or inaccurate transport numbers.
|
|
105
109
|
|
|
106
|
-
Missing diffusion coefficients are especially likely in complex electrolytes containing, for example,
|
|
107
|
-
|
|
110
|
+
Missing diffusion coefficients are especially likely in complex electrolytes containing, for example,
|
|
111
|
+
complexes or paired species such as NaSO4[-1]. In such cases, setting default_diffusion_coeff to zero
|
|
112
|
+
is likely to result in the above errors.
|
|
108
113
|
|
|
109
114
|
By default, this argument is set to the diffusion coefficient of NaCl salt, 1.61x10^-9 m2/s.
|
|
110
115
|
|
|
@@ -149,25 +154,28 @@ class Solution(MSONable):
|
|
|
149
154
|
if isinstance(balance_charge, str) and balance_charge not in ["pH", "pE"]:
|
|
150
155
|
self.balance_charge = standardize_formula(balance_charge)
|
|
151
156
|
else:
|
|
152
|
-
self.balance_charge = balance_charge
|
|
157
|
+
self.balance_charge = balance_charge #: Standardized formula of the species used for charge balancing.
|
|
153
158
|
|
|
154
159
|
# instantiate a water substance for property retrieval
|
|
155
160
|
self.water_substance = create_water_substance(self.temperature, self.pressure)
|
|
161
|
+
"""IAPWS instance describing water properties."""
|
|
156
162
|
|
|
157
163
|
# create an empty dictionary of components. This dict comprises {formula: moles}
|
|
158
164
|
# where moles is the number of moles in the solution.
|
|
159
165
|
self.components = FormulaDict({})
|
|
166
|
+
"""Special dictionary where keys are standardized formula and values are the moles present in Solution."""
|
|
160
167
|
|
|
161
168
|
# connect to the desired property database
|
|
162
169
|
if database is None:
|
|
163
170
|
# load the default database, which is a JSONStore
|
|
164
171
|
db_store = IonDB
|
|
165
|
-
elif isinstance(database, str
|
|
172
|
+
elif isinstance(database, (str, Path)):
|
|
166
173
|
db_store = JSONStore(str(database), key="formula")
|
|
167
174
|
logger.info(f"Created maggma JSONStore from .json file {database}")
|
|
168
175
|
else:
|
|
169
176
|
db_store = database
|
|
170
177
|
self.database = db_store
|
|
178
|
+
"""`Store` instance containing the solute property database."""
|
|
171
179
|
self.database.connect()
|
|
172
180
|
logger.info(f"Connected to property database {self.database!s}")
|
|
173
181
|
|
|
@@ -193,6 +201,7 @@ class Solution(MSONable):
|
|
|
193
201
|
if solvent[0] not in ["H2O", "H2O(aq)", "water", "Water", "HOH"]:
|
|
194
202
|
raise ValueError("Non-aqueous solvent detected. These are not yet supported!")
|
|
195
203
|
self.solvent = standardize_formula(solvent[0])
|
|
204
|
+
"""Formula of the component that is set as the solvent (currently only H2O(aq) is supported)."""
|
|
196
205
|
|
|
197
206
|
# TODO - do I need the ability to specify the solvent mass?
|
|
198
207
|
# # raise an error if the solvent volume has also been given
|
|
@@ -220,7 +229,8 @@ class Solution(MSONable):
|
|
|
220
229
|
self.add_solute(k, v)
|
|
221
230
|
elif isinstance(self._solutes, list):
|
|
222
231
|
logger.warning(
|
|
223
|
-
'List input of solutes (e.g., [["Na+", "0.5 mol/L]]) is deprecated! Use dictionary formatted input
|
|
232
|
+
'List input of solutes (e.g., [["Na+", "0.5 mol/L]]) is deprecated! Use dictionary formatted input '
|
|
233
|
+
'(e.g., {"Na+":"0.5 mol/L"} instead.)'
|
|
224
234
|
)
|
|
225
235
|
for item in self._solutes:
|
|
226
236
|
self.add_solute(*item)
|
|
@@ -241,7 +251,8 @@ class Solution(MSONable):
|
|
|
241
251
|
ions = set().union(*[self.cations, self.anions]) # all ions
|
|
242
252
|
if self.balance_charge not in ions:
|
|
243
253
|
raise ValueError(
|
|
244
|
-
f"Charge balancing species {self.balance_charge} was not found in the solution!.
|
|
254
|
+
f"Charge balancing species {self.balance_charge} was not found in the solution!. "
|
|
255
|
+
f"Species {ions} were found."
|
|
245
256
|
)
|
|
246
257
|
z = self.get_property(balance_charge, "charge")
|
|
247
258
|
self.components[balance_charge] += -1 * cb / z * self.volume.to("L").magnitude
|
|
@@ -256,13 +267,8 @@ class Solution(MSONable):
|
|
|
256
267
|
Return the total mass of the solution.
|
|
257
268
|
|
|
258
269
|
The mass is calculated each time this method is called.
|
|
259
|
-
Parameters
|
|
260
|
-
----------
|
|
261
|
-
None
|
|
262
270
|
|
|
263
|
-
Returns:
|
|
264
|
-
-------
|
|
265
|
-
Quantity: the mass of the solution, in kg
|
|
271
|
+
Returns: The mass of the solution, in kg
|
|
266
272
|
|
|
267
273
|
"""
|
|
268
274
|
mass = np.sum([self.get_amount(item, "kg").magnitude for item in self.components])
|
|
@@ -280,8 +286,7 @@ class Solution(MSONable):
|
|
|
280
286
|
The mass of the solvent, in kg
|
|
281
287
|
|
|
282
288
|
See Also:
|
|
283
|
-
|
|
284
|
-
:py:meth:`get_amount()`
|
|
289
|
+
:py:meth:`get_amount()`
|
|
285
290
|
"""
|
|
286
291
|
return self.get_amount(self.solvent, "kg")
|
|
287
292
|
|
|
@@ -291,8 +296,7 @@ class Solution(MSONable):
|
|
|
291
296
|
Return the volume of the solution.
|
|
292
297
|
|
|
293
298
|
Returns:
|
|
294
|
-
|
|
295
|
-
Quantity: the volume of the solution, in L
|
|
299
|
+
Quantity: the volume of the solution, in L
|
|
296
300
|
"""
|
|
297
301
|
# if the composition has changed, recalculate the volume first
|
|
298
302
|
if self.volume_update_required is True:
|
|
@@ -310,17 +314,16 @@ class Solution(MSONable):
|
|
|
310
314
|
volume : Total volume of the solution, including the unit, e.g. '1 L'
|
|
311
315
|
|
|
312
316
|
Examples:
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
{'H2O': '55.50843506179199 mol/kg', 'Cl-': '0.00992937605907076 mol/kg', 'Na+': '2.0059345573880325 mol/kg'}
|
|
317
|
+
>>> mysol = Solution([['Na+','2 mol/L'],['Cl-','0.01 mol/L']],volume='500 mL')
|
|
318
|
+
>>> print(mysol.volume)
|
|
319
|
+
0.5000883925072983 l
|
|
320
|
+
>>> mysol.list_concentrations()
|
|
321
|
+
{'H2O': '55.508435061791985 mol/kg', 'Cl-': '0.00992937605907076 mol/kg', 'Na+': '2.0059345573880325 mol/kg'}
|
|
322
|
+
>>> mysol.volume = '200 mL')
|
|
323
|
+
>>> print(mysol.volume)
|
|
324
|
+
0.2 l
|
|
325
|
+
>>> mysol.list_concentrations()
|
|
326
|
+
{'H2O': '55.50843506179199 mol/kg', 'Cl-': '0.00992937605907076 mol/kg', 'Na+': '2.0059345573880325 mol/kg'}
|
|
324
327
|
|
|
325
328
|
"""
|
|
326
329
|
# figure out the factor to multiply the old concentrations by
|
|
@@ -392,19 +395,17 @@ class Solution(MSONable):
|
|
|
392
395
|
|
|
393
396
|
Generally used for expressing concentration of hydrogen ions (pH)
|
|
394
397
|
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
than the activity to calculate p. Defaults to True.
|
|
398
|
+
Args:
|
|
399
|
+
solute : str
|
|
400
|
+
String representing the formula of the solute
|
|
401
|
+
activity: bool, optional
|
|
402
|
+
If False, the function will use the molar concentration rather
|
|
403
|
+
than the activity to calculate p. Defaults to True.
|
|
402
404
|
|
|
403
405
|
Returns:
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
activity = False) of the solute.
|
|
406
|
+
Quantity
|
|
407
|
+
The negative log10 of the activity (or molar concentration if
|
|
408
|
+
activity = False) of the solute.
|
|
408
409
|
"""
|
|
409
410
|
try:
|
|
410
411
|
if activity is True:
|
|
@@ -422,40 +423,35 @@ class Solution(MSONable):
|
|
|
422
423
|
Density is calculated from the mass and volume each time this method is called.
|
|
423
424
|
|
|
424
425
|
Returns:
|
|
425
|
-
|
|
426
|
-
Quantity: The density of the solution.
|
|
426
|
+
Quantity: The density of the solution.
|
|
427
427
|
"""
|
|
428
428
|
return self.mass / self.volume
|
|
429
429
|
|
|
430
430
|
@property
|
|
431
431
|
def dielectric_constant(self) -> Quantity:
|
|
432
|
-
"""
|
|
432
|
+
r"""
|
|
433
433
|
Returns the dielectric constant of the solution.
|
|
434
434
|
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
None
|
|
435
|
+
Args:
|
|
436
|
+
None
|
|
438
437
|
|
|
439
438
|
Returns:
|
|
440
|
-
|
|
441
|
-
Quantity: the dielectric constant of the solution, dimensionless.
|
|
439
|
+
Quantity: the dielectric constant of the solution, dimensionless.
|
|
442
440
|
|
|
443
441
|
Notes:
|
|
444
|
-
|
|
445
|
-
Implements the following equation as given by Zuber et al.
|
|
442
|
+
Implements the following equation as given by Zuber et al.
|
|
446
443
|
|
|
447
|
-
|
|
444
|
+
.. math:: \epsilon = \epsilon_{solvent} \over 1 + \sum_i \alpha_i x_i
|
|
448
445
|
|
|
449
|
-
|
|
450
|
-
|
|
446
|
+
where :math:`\alpha_i` is a coefficient specific to the solvent and ion, and :math:`x_i`
|
|
447
|
+
is the mole fraction of the ion in solution.
|
|
451
448
|
|
|
452
449
|
|
|
453
450
|
References:
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
doi:10.1016/j.fluid.2014.05.037.
|
|
451
|
+
A. Zuber, L. Cardozo-Filho, V.F. Cabral, R.F. Checoni, M. Castier,
|
|
452
|
+
An empirical equation for the dielectric constant in aqueous and nonaqueous
|
|
453
|
+
electrolyte mixtures, Fluid Phase Equilib. 376 (2014) 116-123.
|
|
454
|
+
doi:10.1016/j.fluid.2014.05.037.
|
|
459
455
|
"""
|
|
460
456
|
di_water = self.water_substance.epsilon
|
|
461
457
|
|
|
@@ -486,8 +482,9 @@ class Solution(MSONable):
|
|
|
486
482
|
@property
|
|
487
483
|
def elements(self) -> list:
|
|
488
484
|
"""
|
|
489
|
-
Return a list of elements that are present in the solution.
|
|
490
|
-
|
|
485
|
+
Return a list of elements that are present in the solution.
|
|
486
|
+
|
|
487
|
+
For example, a solution containing CaCO3 would return ["C", "Ca", "H", "O"]
|
|
491
488
|
"""
|
|
492
489
|
els = []
|
|
493
490
|
for s in self.components:
|
|
@@ -497,24 +494,27 @@ class Solution(MSONable):
|
|
|
497
494
|
@property
|
|
498
495
|
def cations(self) -> dict[str, float]:
|
|
499
496
|
"""
|
|
500
|
-
Returns the subset of `components`
|
|
501
|
-
|
|
497
|
+
Returns the subset of `components` that are cations.
|
|
498
|
+
|
|
499
|
+
The returned dict is sorted by amount in descending order.
|
|
502
500
|
"""
|
|
503
501
|
return {k: v for k, v in self.components.items() if self.get_property(k, "charge") > 0}
|
|
504
502
|
|
|
505
503
|
@property
|
|
506
504
|
def anions(self) -> dict[str, float]:
|
|
507
505
|
"""
|
|
508
|
-
Returns the subset of `components`
|
|
509
|
-
|
|
506
|
+
Returns the subset of `components` that are anions.
|
|
507
|
+
|
|
508
|
+
The returned dict is sorted by amount in descending order.
|
|
510
509
|
"""
|
|
511
510
|
return {k: v for k, v in self.components.items() if self.get_property(k, "charge") < 0}
|
|
512
511
|
|
|
513
512
|
@property
|
|
514
513
|
def neutrals(self) -> dict[str, float]:
|
|
515
514
|
"""
|
|
516
|
-
Returns the subset of `components`
|
|
517
|
-
|
|
515
|
+
Returns the subset of `components` that are neutral (not charged).
|
|
516
|
+
|
|
517
|
+
The returned dict is sorted by amount in descending order.
|
|
518
518
|
"""
|
|
519
519
|
return {k: v for k, v in self.components.items() if self.get_property(k, "charge") == 0}
|
|
520
520
|
|
|
@@ -527,8 +527,7 @@ class Solution(MSONable):
|
|
|
527
527
|
Calculated from the kinematic viscosity
|
|
528
528
|
|
|
529
529
|
See Also:
|
|
530
|
-
|
|
531
|
-
viscosity_kinematic
|
|
530
|
+
:attr:`viscosity_kinematic`
|
|
532
531
|
"""
|
|
533
532
|
return self.viscosity_kinematic * self.density
|
|
534
533
|
|
|
@@ -555,37 +554,35 @@ class Solution(MSONable):
|
|
|
555
554
|
# )
|
|
556
555
|
@property
|
|
557
556
|
def viscosity_kinematic(self) -> Quantity:
|
|
558
|
-
"""
|
|
557
|
+
r"""
|
|
559
558
|
Return the kinematic viscosity of the solution.
|
|
560
559
|
|
|
561
560
|
Notes:
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
and presented in
|
|
561
|
+
The calculation is based on a model derived from the Eyring equation
|
|
562
|
+
and presented in
|
|
565
563
|
|
|
566
|
-
|
|
564
|
+
.. math::
|
|
567
565
|
|
|
568
|
-
|
|
569
|
-
|
|
566
|
+
\ln \nu = \ln {\nu_w MW_w \over \sum_i x_i MW_i } +
|
|
567
|
+
15 x_+^2 + x_+^3 \delta G^*_{123} + 3 x_+ \delta G^*_{23} (1-0.05x_+)
|
|
570
568
|
|
|
571
|
-
|
|
569
|
+
Where:
|
|
572
570
|
|
|
573
|
-
|
|
574
|
-
|
|
571
|
+
.. math:: \delta G^*_{123} = a_o + a_1 (T)^{0.75}
|
|
572
|
+
.. math:: \delta G^*_{23} = b_o + b_1 (T)^{0.5}
|
|
575
573
|
|
|
576
|
-
|
|
577
|
-
|
|
574
|
+
In which :math:`\nu` is the kinematic viscosity, MW is the molecular weight,
|
|
575
|
+
:math:`x_{+}` is the mole fraction of cations, and :math:`T` is the temperature in degrees C.
|
|
578
576
|
|
|
579
|
-
|
|
580
|
-
|
|
577
|
+
The a and b fitting parameters for a variety of common salts are included in the
|
|
578
|
+
database.
|
|
581
579
|
|
|
582
580
|
References:
|
|
583
|
-
|
|
584
|
-
|
|
581
|
+
Vásquez-Castillo, G.; Iglesias-Silva, G. a.; Hall, K. R. An extension of the McAllister model to correlate
|
|
582
|
+
kinematic viscosity of electrolyte solutions. Fluid Phase Equilib. 2013, 358, 44-49.
|
|
585
583
|
|
|
586
584
|
See Also:
|
|
587
|
-
|
|
588
|
-
:py:meth:`viscosity_dynamic`
|
|
585
|
+
:py:meth:`viscosity_dynamic`
|
|
589
586
|
"""
|
|
590
587
|
# identify the main salt in the solution
|
|
591
588
|
salt = self.get_salt()
|
|
@@ -631,7 +628,7 @@ class Solution(MSONable):
|
|
|
631
628
|
|
|
632
629
|
@property
|
|
633
630
|
def conductivity(self) -> Quantity:
|
|
634
|
-
"""
|
|
631
|
+
r"""
|
|
635
632
|
Compute the electrical conductivity of the solution.
|
|
636
633
|
|
|
637
634
|
Returns:
|
|
@@ -643,13 +640,13 @@ class Solution(MSONable):
|
|
|
643
640
|
|
|
644
641
|
.. math::
|
|
645
642
|
|
|
646
|
-
EC = {F^2
|
|
643
|
+
EC = {F^2 \over R T} \sum_i D_i z_i ^ 2 m_i = \sum_i \lambda_i m_i
|
|
647
644
|
|
|
648
645
|
Where :math:`D_i` is the diffusion coefficient, :math:`m_i` is the molal concentration,
|
|
649
646
|
:math:`z_i` is the charge, and the summation extends over all species in the solution.
|
|
650
|
-
Alternatively, :math
|
|
647
|
+
Alternatively, :math:`\lambda_i` is the molar conductivity of solute i.
|
|
651
648
|
|
|
652
|
-
Diffusion coefficients :math:`D_i` (and molar conductivities :math
|
|
649
|
+
Diffusion coefficients :math:`D_i` (and molar conductivities :math:`\lambda_i`) are
|
|
653
650
|
adjusted for the effects of temperature and ionic strength using the method implemented
|
|
654
651
|
in PHREEQC >= 3.4. [aq]_ [hc]_ See `get_diffusion_coefficient for` further details.
|
|
655
652
|
|
|
@@ -658,9 +655,9 @@ class Solution(MSONable):
|
|
|
658
655
|
.. [hc] http://www.hydrochemistry.eu/exmpls/sc.html
|
|
659
656
|
|
|
660
657
|
See Also:
|
|
661
|
-
:py:attr:`get_diffusion_coefficient`
|
|
662
|
-
:py:meth:`get_molar_conductivity`
|
|
663
658
|
:py:attr:`ionic_strength`
|
|
659
|
+
:py:meth:`get_diffusion_coefficient`
|
|
660
|
+
:py:meth:`get_molar_conductivity`
|
|
664
661
|
"""
|
|
665
662
|
EC = ureg.Quantity(
|
|
666
663
|
np.asarray(
|
|
@@ -675,7 +672,7 @@ class Solution(MSONable):
|
|
|
675
672
|
|
|
676
673
|
@property
|
|
677
674
|
def ionic_strength(self) -> Quantity:
|
|
678
|
-
"""
|
|
675
|
+
r"""
|
|
679
676
|
Return the ionic strength of the solution.
|
|
680
677
|
|
|
681
678
|
Return the ionic strength of the solution, calculated as 1/2 * sum ( molality * charge ^2) over all the ions.
|
|
@@ -683,32 +680,28 @@ class Solution(MSONable):
|
|
|
683
680
|
Molal (mol/kg) scale concentrations are used for compatibility with the activity correction formulas.
|
|
684
681
|
|
|
685
682
|
Returns:
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
The ionic strength of the parent solution, mol/kg.
|
|
683
|
+
Quantity:
|
|
684
|
+
The ionic strength of the parent solution, mol/kg.
|
|
689
685
|
|
|
690
686
|
See Also:
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
:py:meth:`get_water_activity`
|
|
687
|
+
:py:meth:`get_activity`
|
|
688
|
+
:py:meth:`get_water_activity`
|
|
694
689
|
|
|
695
690
|
Notes:
|
|
696
|
-
|
|
697
|
-
The ionic strength is calculated according to:
|
|
691
|
+
The ionic strength is calculated according to:
|
|
698
692
|
|
|
699
|
-
|
|
693
|
+
.. math:: I = \sum_i m_i z_i^2
|
|
700
694
|
|
|
701
|
-
|
|
695
|
+
Where :math:`m_i` is the molal concentration and :math:`z_i` is the charge on species i.
|
|
702
696
|
|
|
703
697
|
Examples:
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
<Quantity(0.20000010029672785, 'mole / kilogram')>
|
|
698
|
+
>>> s1 = pyEQL.Solution([['Na+','0.2 mol/kg'],['Cl-','0.2 mol/kg']])
|
|
699
|
+
>>> s1.ionic_strength
|
|
700
|
+
<Quantity(0.20000010029672785, 'mole / kilogram')>
|
|
708
701
|
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
702
|
+
>>> s1 = pyEQL.Solution([['Mg+2','0.3 mol/kg'],['Na+','0.1 mol/kg'],['Cl-','0.7 mol/kg']],temperature='30 degC')
|
|
703
|
+
>>> s1.ionic_strength
|
|
704
|
+
<Quantity(1.0000001004383303, 'mole / kilogram')>
|
|
712
705
|
"""
|
|
713
706
|
# compute using magnitudes only, for performance reasons
|
|
714
707
|
ionic_strength = np.sum(
|
|
@@ -720,21 +713,20 @@ class Solution(MSONable):
|
|
|
720
713
|
|
|
721
714
|
@property
|
|
722
715
|
def charge_balance(self) -> float:
|
|
723
|
-
"""
|
|
716
|
+
r"""
|
|
724
717
|
Return the charge balance of the solution.
|
|
725
718
|
|
|
726
719
|
Return the charge balance of the solution. The charge balance represents the net electric charge
|
|
727
720
|
on the solution and SHOULD equal zero at all times, but due to numerical errors will usually
|
|
728
721
|
have a small nonzero value. It is calculated according to:
|
|
729
722
|
|
|
730
|
-
.. math:: CB =
|
|
723
|
+
.. math:: CB = \sum_i C_i z_i
|
|
731
724
|
|
|
732
725
|
where :math:`C_i` is the molar concentration, and :math:`z_i` is the charge on species i.
|
|
733
726
|
|
|
734
727
|
Returns:
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
The charge balance of the solution, in equivalents (mol of charge) per L.
|
|
728
|
+
float :
|
|
729
|
+
The charge balance of the solution, in equivalents (mol of charge) per L.
|
|
738
730
|
|
|
739
731
|
"""
|
|
740
732
|
charge_balance = 0
|
|
@@ -746,28 +738,24 @@ class Solution(MSONable):
|
|
|
746
738
|
# TODO - consider adding guard statements to prevent alkalinity from being negative
|
|
747
739
|
@property
|
|
748
740
|
def alkalinity(self) -> Quantity:
|
|
749
|
-
"""
|
|
741
|
+
r"""
|
|
750
742
|
Return the alkalinity or acid neutralizing capacity of a solution.
|
|
751
743
|
|
|
752
744
|
Returns:
|
|
753
|
-
|
|
754
|
-
Quantity :
|
|
755
|
-
The alkalinity of the solution in mg/L as CaCO3
|
|
745
|
+
Quantity: The alkalinity of the solution in mg/L as CaCO3
|
|
756
746
|
|
|
757
747
|
Notes:
|
|
758
|
-
|
|
759
|
-
The alkalinity is calculated according to [stm]_
|
|
748
|
+
The alkalinity is calculated according to [stm]_
|
|
760
749
|
|
|
761
|
-
|
|
750
|
+
.. math:: Alk = \sum_{i} z_{i} C_{B} + \sum_{i} z_{i} C_{A}
|
|
762
751
|
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
752
|
+
Where :math:`C_{B}` and :math:`C_{A}` are conservative cations and anions, respectively
|
|
753
|
+
(i.e. ions that do not participate in acid-base reactions), and :math:`z_{i}` is their signed charge.
|
|
754
|
+
In this method, the set of conservative cations is all Group I and Group II cations, and the
|
|
755
|
+
conservative anions are all the anions of strong acids.
|
|
767
756
|
|
|
768
757
|
References:
|
|
769
|
-
|
|
770
|
-
.. [stm] Stumm, Werner and Morgan, James J. Aquatic Chemistry, 3rd ed, pp 165. Wiley Interscience, 1996.
|
|
758
|
+
.. [stm] Stumm, Werner and Morgan, James J. Aquatic Chemistry, 3rd ed, pp 165. Wiley Interscience, 1996.
|
|
771
759
|
|
|
772
760
|
"""
|
|
773
761
|
alkalinity = ureg.Quantity(0, "mol/L")
|
|
@@ -807,14 +795,9 @@ class Solution(MSONable):
|
|
|
807
795
|
NOTE: at present pyEQL cannot distinguish between mg/L as CaCO3
|
|
808
796
|
and mg/L units. Use with caution.
|
|
809
797
|
|
|
810
|
-
Parameters
|
|
811
|
-
----------
|
|
812
|
-
None
|
|
813
|
-
|
|
814
798
|
Returns:
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
The hardness of the solution in mg/L as CaCO3
|
|
799
|
+
Quantity:
|
|
800
|
+
The hardness of the solution in mg/L as CaCO3
|
|
818
801
|
|
|
819
802
|
"""
|
|
820
803
|
hardness = ureg.Quantity(0, "mol/L")
|
|
@@ -832,7 +815,8 @@ class Solution(MSONable):
|
|
|
832
815
|
"""
|
|
833
816
|
Total dissolved solids in mg/L (equivalent to ppm) including both charged and uncharged species.
|
|
834
817
|
|
|
835
|
-
The TDS is defined as the sum of the concentrations of all aqueous solutes (not including the solvent),
|
|
818
|
+
The TDS is defined as the sum of the concentrations of all aqueous solutes (not including the solvent),
|
|
819
|
+
except for H[+1] and OH[-1]].
|
|
836
820
|
"""
|
|
837
821
|
tds = ureg.Quantity(0, "mg/L")
|
|
838
822
|
for s in self.components:
|
|
@@ -845,23 +829,21 @@ class Solution(MSONable):
|
|
|
845
829
|
|
|
846
830
|
@property
|
|
847
831
|
def TDS(self) -> Quantity:
|
|
848
|
-
"""
|
|
849
|
-
Alias of :py:meth:`total_dissolved_solids`
|
|
850
|
-
"""
|
|
832
|
+
"""Alias of :py:meth:`total_dissolved_solids`."""
|
|
851
833
|
return self.total_dissolved_solids
|
|
852
834
|
|
|
853
835
|
@property
|
|
854
836
|
def debye_length(self) -> Quantity:
|
|
855
|
-
"""
|
|
837
|
+
r"""
|
|
856
838
|
Return the Debye length of a solution.
|
|
857
839
|
|
|
858
840
|
Debye length is calculated as [wk3]_
|
|
859
841
|
|
|
860
842
|
.. math::
|
|
861
843
|
|
|
862
|
-
|
|
844
|
+
\kappa^{-1} = \sqrt({\epsilon_r \epsilon_o k_B T \over (2 N_A e^2 I)})
|
|
863
845
|
|
|
864
|
-
where :math:`I` is the ionic strength, :math
|
|
846
|
+
where :math:`I` is the ionic strength, :math:`\epsilon_r` and :math:`\epsilon_r`
|
|
865
847
|
are the relative permittivity and vacuum permittivity, :math:`k_B` is the
|
|
866
848
|
Boltzmann constant, and :math:`T` is the temperature, :math:`e` is the
|
|
867
849
|
elementary charge, and :math:`N_A` is Avogadro's number.
|
|
@@ -869,7 +851,7 @@ class Solution(MSONable):
|
|
|
869
851
|
Returns The Debye length, in nanometers.
|
|
870
852
|
|
|
871
853
|
References:
|
|
872
|
-
|
|
854
|
+
.. [wk3] https://en.wikipedia.org/wiki/Debye_length#Debye_length_in_an_electrolyte
|
|
873
855
|
|
|
874
856
|
See Also:
|
|
875
857
|
:attr:`ionic_strength`
|
|
@@ -892,43 +874,35 @@ class Solution(MSONable):
|
|
|
892
874
|
|
|
893
875
|
@property
|
|
894
876
|
def bjerrum_length(self) -> Quantity:
|
|
895
|
-
"""
|
|
877
|
+
r"""
|
|
896
878
|
Return the Bjerrum length of a solution.
|
|
897
879
|
|
|
898
880
|
Bjerrum length represents the distance at which electrostatic
|
|
899
881
|
interactions between particles become comparable in magnitude
|
|
900
|
-
to the thermal energy.:math
|
|
882
|
+
to the thermal energy.:math:`\lambda_B` is calculated as
|
|
901
883
|
|
|
902
884
|
.. math::
|
|
903
885
|
|
|
904
|
-
|
|
886
|
+
\lambda_B = {e^2 \over (4 \pi \epsilon_r \epsilon_o k_B T)}
|
|
905
887
|
|
|
906
|
-
where :math:`e` is the fundamental charge, :math
|
|
888
|
+
where :math:`e` is the fundamental charge, :math:`\epsilon_r` and :math:`\epsilon_r`
|
|
907
889
|
are the relative permittivity and vacuum permittivity, :math:`k_B` is the
|
|
908
890
|
Boltzmann constant, and :math:`T` is the temperature.
|
|
909
891
|
|
|
910
|
-
Parameters
|
|
911
|
-
----------
|
|
912
|
-
None
|
|
913
|
-
|
|
914
892
|
Returns:
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
The Bjerrum length, in nanometers.
|
|
893
|
+
Quantity:
|
|
894
|
+
The Bjerrum length, in nanometers.
|
|
918
895
|
|
|
919
896
|
References:
|
|
920
|
-
|
|
921
|
-
https://en.wikipedia.org/wiki/Bjerrum_length
|
|
897
|
+
https://en.wikipedia.org/wiki/Bjerrum_length
|
|
922
898
|
|
|
923
899
|
Examples:
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
<Quantity(0.7152793009386953, 'nanometer')>
|
|
900
|
+
>>> s1 = pyEQL.Solution()
|
|
901
|
+
>>> s1.bjerrum_length
|
|
902
|
+
<Quantity(0.7152793009386953, 'nanometer')>
|
|
928
903
|
|
|
929
904
|
See Also:
|
|
930
|
-
|
|
931
|
-
:attr:`dielectric_constant`
|
|
905
|
+
:attr:`dielectric_constant`
|
|
932
906
|
|
|
933
907
|
"""
|
|
934
908
|
bjerrum_length = ureg.e**2 / (
|
|
@@ -938,23 +912,23 @@ class Solution(MSONable):
|
|
|
938
912
|
|
|
939
913
|
@property
|
|
940
914
|
def osmotic_pressure(self) -> Quantity:
|
|
941
|
-
"""
|
|
915
|
+
r"""
|
|
942
916
|
Return the osmotic pressure of the solution relative to pure water.
|
|
943
917
|
|
|
944
918
|
Returns:
|
|
945
919
|
The osmotic pressure of the solution relative to pure water in Pa
|
|
946
920
|
|
|
947
921
|
See Also:
|
|
948
|
-
get_water_activity
|
|
949
|
-
get_osmotic_coefficient
|
|
950
|
-
get_salt
|
|
922
|
+
:attr:`get_water_activity`
|
|
923
|
+
:attr:`get_osmotic_coefficient`
|
|
924
|
+
:attr:`get_salt`
|
|
951
925
|
|
|
952
926
|
Notes:
|
|
953
927
|
Osmotic pressure is calculated based on the water activity [sata]_ [wk]_
|
|
954
928
|
|
|
955
|
-
.. math::
|
|
929
|
+
.. math:: \Pi = -\frac{RT}{V_{w}} \ln a_{w}
|
|
956
930
|
|
|
957
|
-
Where :math
|
|
931
|
+
Where :math:`\Pi` is the osmotic pressure, :math:`V_{w}` is the partial
|
|
958
932
|
molar volume of water (18.2 cm**3/mol), and :math:`a_{w}` is the water
|
|
959
933
|
activity.
|
|
960
934
|
|
|
@@ -1000,30 +974,26 @@ class Solution(MSONable):
|
|
|
1000
974
|
8. number of molecules ('count')
|
|
1001
975
|
9. "parts-per-x" units, where ppm = mg/L, ppb = ug/L ppt = ng/L
|
|
1002
976
|
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
Use '%' to return the mass percent
|
|
977
|
+
Args:
|
|
978
|
+
solute : str
|
|
979
|
+
String representing the name of the solute of interest
|
|
980
|
+
units : str
|
|
981
|
+
Units desired for the output. Examples of valid units are
|
|
982
|
+
'mol/L','mol/kg','mol', 'kg', and 'g/L'
|
|
983
|
+
Use 'fraction' to return the mole fraction.
|
|
984
|
+
Use '%' to return the mass percent
|
|
1012
985
|
|
|
1013
986
|
Returns:
|
|
1014
|
-
|
|
1015
|
-
The amount of the solute in question, in the specified units
|
|
1016
|
-
|
|
987
|
+
The amount of the solute in question, in the specified units
|
|
1017
988
|
|
|
1018
989
|
See Also:
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
get_total_moles_solute
|
|
990
|
+
:attr:`mass`
|
|
991
|
+
:meth:`add_amount`
|
|
992
|
+
:meth:`set_amount`
|
|
993
|
+
:meth:`get_total_amount`
|
|
994
|
+
:meth:`get_osmolarity`
|
|
995
|
+
:meth:`get_osmolality`
|
|
996
|
+
:meth:`get_total_moles_solute`
|
|
1027
997
|
"""
|
|
1028
998
|
z = 1
|
|
1029
999
|
# sanitized unit to be passed to pint
|
|
@@ -1085,8 +1055,9 @@ class Solution(MSONable):
|
|
|
1085
1055
|
|
|
1086
1056
|
def get_components_by_element(self) -> dict[str, list]:
|
|
1087
1057
|
"""
|
|
1088
|
-
Return a list of all species associated with a given element.
|
|
1089
|
-
|
|
1058
|
+
Return a list of all species associated with a given element.
|
|
1059
|
+
|
|
1060
|
+
Elements (keys) are suffixed with their oxidation state in parentheses, e.g.,
|
|
1090
1061
|
|
|
1091
1062
|
{"Na(1.0)":["Na[+1]", "NaOH(aq)"]}
|
|
1092
1063
|
|
|
@@ -1117,7 +1088,7 @@ class Solution(MSONable):
|
|
|
1117
1088
|
|
|
1118
1089
|
def get_el_amt_dict(self):
|
|
1119
1090
|
"""
|
|
1120
|
-
Return a dict of Element: amount in mol
|
|
1091
|
+
Return a dict of Element: amount in mol.
|
|
1121
1092
|
|
|
1122
1093
|
Elements (keys) are suffixed with their oxidation state in parentheses,
|
|
1123
1094
|
e.g. "Fe(2.0)", "Cl(-1.0)".
|
|
@@ -1153,17 +1124,15 @@ class Solution(MSONable):
|
|
|
1153
1124
|
element: The symbol of the element of interest. The symbol can optionally be followed by the
|
|
1154
1125
|
oxidation state in parentheses, e.g., "Na(1.0)", "Fe(2.0)", or "O(0.0)". If no oxidation state
|
|
1155
1126
|
is given, the total concentration of the element (over all oxidation states) is returned.
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1127
|
+
units : str
|
|
1128
|
+
Units desired for the output. Examples of valid units are
|
|
1129
|
+
'mol/L','mol/kg','mol', 'kg', and 'g/L'
|
|
1159
1130
|
|
|
1160
1131
|
Returns:
|
|
1161
|
-
|
|
1162
|
-
The total amount of the element in the solution, in the specified units
|
|
1132
|
+
The total amount of the element in the solution, in the specified units
|
|
1163
1133
|
|
|
1164
|
-
See Also
|
|
1165
|
-
|
|
1166
|
-
get_amount
|
|
1134
|
+
See Also:
|
|
1135
|
+
:meth:`get_amount`
|
|
1167
1136
|
"""
|
|
1168
1137
|
TOT: Quantity = 0
|
|
1169
1138
|
|
|
@@ -1211,14 +1180,11 @@ class Solution(MSONable):
|
|
|
1211
1180
|
def add_solute(self, formula: str, amount: str):
|
|
1212
1181
|
"""Primary method for adding substances to a pyEQL solution.
|
|
1213
1182
|
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
amount : str
|
|
1220
|
-
The amount of substance in the specified unit system. The string should contain both a quantity and
|
|
1221
|
-
a pint-compatible representation of a ureg. e.g. '5 mol/kg' or '0.1 g/L'
|
|
1183
|
+
Args:
|
|
1184
|
+
formula (str): Chemical formula for the solute. Charged species must contain a + or - and
|
|
1185
|
+
(for polyvalent solutes) a number representing the net charge (e.g. 'SO4-2').
|
|
1186
|
+
amount (str): The amount of substance in the specified unit system. The string should contain
|
|
1187
|
+
both a quantity and a pint-compatible representation of a ureg. e.g. '5 mol/kg' or '0.1 g/L'.
|
|
1222
1188
|
"""
|
|
1223
1189
|
# if units are given on a per-volume basis,
|
|
1224
1190
|
# iteratively solve for the amount of solute that will preserve the
|
|
@@ -1282,21 +1248,19 @@ class Solution(MSONable):
|
|
|
1282
1248
|
"""
|
|
1283
1249
|
Add the amount of 'solute' to the parent solution.
|
|
1284
1250
|
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
based on the new composition
|
|
1251
|
+
Args:
|
|
1252
|
+
solute : str
|
|
1253
|
+
String representing the name of the solute of interest
|
|
1254
|
+
amount : str quantity
|
|
1255
|
+
String representing the concentration desired, e.g. '1 mol/kg'
|
|
1256
|
+
If the units are given on a per-volume basis, the solution
|
|
1257
|
+
volume is not recalculated
|
|
1258
|
+
If the units are given on a mass, substance, per-mass, or
|
|
1259
|
+
per-substance basis, then the solution volume is recalculated
|
|
1260
|
+
based on the new composition
|
|
1296
1261
|
|
|
1297
1262
|
Returns:
|
|
1298
|
-
|
|
1299
|
-
Nothing. The concentration of solute is modified.
|
|
1263
|
+
Nothing. The concentration of solute is modified.
|
|
1300
1264
|
"""
|
|
1301
1265
|
# if units are given on a per-volume basis,
|
|
1302
1266
|
# iteratively solve for the amount of solute that will preserve the
|
|
@@ -1378,26 +1342,24 @@ class Solution(MSONable):
|
|
|
1378
1342
|
"""
|
|
1379
1343
|
Set the amount of 'solute' in the parent solution.
|
|
1380
1344
|
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
are modified.
|
|
1345
|
+
Args:
|
|
1346
|
+
solute : str
|
|
1347
|
+
String representing the name of the solute of interest
|
|
1348
|
+
amount : str Quantity
|
|
1349
|
+
String representing the concentration desired, e.g. '1 mol/kg'
|
|
1350
|
+
If the units are given on a per-volume basis, the solution
|
|
1351
|
+
volume is not recalculated and the molar concentrations of
|
|
1352
|
+
other components in the solution are not altered, while the
|
|
1353
|
+
molal concentrations are modified.
|
|
1354
|
+
|
|
1355
|
+
If the units are given on a mass, substance, per-mass, or
|
|
1356
|
+
per-substance basis, then the solution volume is recalculated
|
|
1357
|
+
based on the new composition and the molal concentrations of
|
|
1358
|
+
other components are not altered, while the molar concentrations
|
|
1359
|
+
are modified.
|
|
1397
1360
|
|
|
1398
1361
|
Returns:
|
|
1399
|
-
|
|
1400
|
-
Nothing. The concentration of solute is modified.
|
|
1362
|
+
Nothing. The concentration of solute is modified.
|
|
1401
1363
|
|
|
1402
1364
|
"""
|
|
1403
1365
|
# raise an error if a negative amount is specified
|
|
@@ -1482,13 +1444,12 @@ class Solution(MSONable):
|
|
|
1482
1444
|
def get_osmolarity(self, activity_correction=False) -> Quantity:
|
|
1483
1445
|
"""Return the osmolarity of the solution in Osm/L.
|
|
1484
1446
|
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
depression. Defaults to FALSE if omitted.
|
|
1447
|
+
Args:
|
|
1448
|
+
activity_correction : bool
|
|
1449
|
+
If TRUE, the osmotic coefficient is used to calculate the
|
|
1450
|
+
osmolarity. This correction is appropriate when trying to predict
|
|
1451
|
+
the osmolarity that would be measured from e.g. freezing point
|
|
1452
|
+
depression. Defaults to FALSE if omitted.
|
|
1492
1453
|
"""
|
|
1493
1454
|
factor = self.get_osmotic_coefficient() if activity_correction is True else 1
|
|
1494
1455
|
return factor * self.get_total_moles_solute() / self.volume.to("L")
|
|
@@ -1496,13 +1457,12 @@ class Solution(MSONable):
|
|
|
1496
1457
|
def get_osmolality(self, activity_correction=False) -> Quantity:
|
|
1497
1458
|
"""Return the osmolality of the solution in Osm/kg.
|
|
1498
1459
|
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
depression. Defaults to FALSE if omitted.
|
|
1460
|
+
Args:
|
|
1461
|
+
activity_correction : bool
|
|
1462
|
+
If TRUE, the osmotic coefficient is used to calculate the
|
|
1463
|
+
osmolarity. This correction is appropriate when trying to predict
|
|
1464
|
+
the osmolarity that would be measured from e.g. freezing point
|
|
1465
|
+
depression. Defaults to FALSE if omitted.
|
|
1506
1466
|
"""
|
|
1507
1467
|
factor = self.get_osmotic_coefficient() if activity_correction is True else 1
|
|
1508
1468
|
return factor * self.get_total_moles_solute() / self.solvent_mass.to("kg")
|
|
@@ -1529,13 +1489,12 @@ class Solution(MSONable):
|
|
|
1529
1489
|
Salt object containing information about the parent salt.
|
|
1530
1490
|
|
|
1531
1491
|
See Also:
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
:py:meth:`get_viscosity_kinematic`
|
|
1492
|
+
:py:meth:`get_activity`
|
|
1493
|
+
:py:meth:`get_activity_coefficient`
|
|
1494
|
+
:py:meth:`get_water_activity`
|
|
1495
|
+
:py:meth:`get_osmotic_coefficient`
|
|
1496
|
+
:py:attr:`osmotic_pressure`
|
|
1497
|
+
:py:attr:`viscosity_kinematic`
|
|
1539
1498
|
|
|
1540
1499
|
Examples:
|
|
1541
1500
|
>>> s1 = Solution([['Na+','0.5 mol/kg'],['Cl-','0.5 mol/kg']])
|
|
@@ -1590,23 +1549,17 @@ class Solution(MSONable):
|
|
|
1590
1549
|
enable its effective concentration to be calculated
|
|
1591
1550
|
(e.g., 1 M MgCl2 yields 1 M Mg+2 and 2 M Cl-).
|
|
1592
1551
|
|
|
1593
|
-
Parameters
|
|
1594
|
-
----------
|
|
1595
|
-
None
|
|
1596
|
-
|
|
1597
1552
|
Returns:
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
A dictionary of Salt objects, keyed to the salt formula
|
|
1553
|
+
dict
|
|
1554
|
+
A dictionary of Salt objects, keyed to the salt formula
|
|
1601
1555
|
|
|
1602
1556
|
See Also:
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
:py:meth:`get_viscosity_kinematic`
|
|
1557
|
+
:py:attr:`osmotic_pressure`
|
|
1558
|
+
:py:attr:`viscosity_kinematic`
|
|
1559
|
+
:py:meth:`get_activity`
|
|
1560
|
+
:py:meth:`get_activity_coefficient`
|
|
1561
|
+
:py:meth:`get_water_activity`
|
|
1562
|
+
:py:meth:`get_osmotic_coefficient`
|
|
1610
1563
|
"""
|
|
1611
1564
|
"""
|
|
1612
1565
|
Returns a dict of salts that approximates the composition of the Solution. Like `components`, the dict is
|
|
@@ -1617,9 +1570,9 @@ class Solution(MSONable):
|
|
|
1617
1570
|
of their respective equivalent amounts.
|
|
1618
1571
|
|
|
1619
1572
|
See Also:
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1573
|
+
:attr:`components`
|
|
1574
|
+
:attr:`cations`
|
|
1575
|
+
:attr:`anions`
|
|
1623
1576
|
"""
|
|
1624
1577
|
salt_dict: dict[str, float] = {}
|
|
1625
1578
|
|
|
@@ -1732,8 +1685,9 @@ class Solution(MSONable):
|
|
|
1732
1685
|
|
|
1733
1686
|
def equilibrate(self, **kwargs) -> None:
|
|
1734
1687
|
"""
|
|
1735
|
-
Update the composition of the Solution using the thermodynamic engine.
|
|
1736
|
-
|
|
1688
|
+
Update the composition of the Solution using the thermodynamic engine.
|
|
1689
|
+
|
|
1690
|
+
Any kwargs specified are passed through to self.engine.equilibrate()
|
|
1737
1691
|
|
|
1738
1692
|
Returns:
|
|
1739
1693
|
Nothing. The .components attribute of the Solution is updated.
|
|
@@ -1820,8 +1774,8 @@ class Solution(MSONable):
|
|
|
1820
1774
|
Edition; Butterworths: London, 1968, p.32.
|
|
1821
1775
|
|
|
1822
1776
|
See Also:
|
|
1823
|
-
:py:meth:`get_activity_coefficient`
|
|
1824
1777
|
:attr:`ionic_strength`
|
|
1778
|
+
:py:meth:`get_activity_coefficient`
|
|
1825
1779
|
:py:meth:`get_salt`
|
|
1826
1780
|
|
|
1827
1781
|
"""
|
|
@@ -1873,42 +1827,37 @@ class Solution(MSONable):
|
|
|
1873
1827
|
raise ValueError("Invalid scale argument. Pass 'molal', 'rational', or 'fugacity'.")
|
|
1874
1828
|
|
|
1875
1829
|
def get_water_activity(self) -> Quantity:
|
|
1876
|
-
"""
|
|
1830
|
+
r"""
|
|
1877
1831
|
Return the water activity.
|
|
1878
1832
|
|
|
1879
1833
|
Returns:
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
The thermodynamic activity of water in the solution.
|
|
1834
|
+
Quantity:
|
|
1835
|
+
The thermodynamic activity of water in the solution.
|
|
1883
1836
|
|
|
1884
1837
|
See Also:
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
:py:meth:`get_salt`
|
|
1838
|
+
:attr:`ionic_strength`
|
|
1839
|
+
:py:meth:`get_activity_coefficient`
|
|
1840
|
+
:py:meth:`get_salt`
|
|
1889
1841
|
|
|
1890
1842
|
Notes:
|
|
1891
|
-
|
|
1892
|
-
Water activity is related to the osmotic coefficient in a solution containing i solutes by:
|
|
1843
|
+
Water activity is related to the osmotic coefficient in a solution containing i solutes by:
|
|
1893
1844
|
|
|
1894
|
-
|
|
1845
|
+
.. math:: \ln a_{w} = - \Phi M_{w} \sum_{i} m_{i}
|
|
1895
1846
|
|
|
1896
|
-
|
|
1897
|
-
|
|
1847
|
+
Where :math:`M_{w}` is the molar mass of water (0.018015 kg/mol) and :math:`m_{i}` is the molal
|
|
1848
|
+
concentration of each species.
|
|
1898
1849
|
|
|
1899
|
-
|
|
1900
|
-
|
|
1850
|
+
If appropriate Pitzer model parameters are not available, the
|
|
1851
|
+
water activity is assumed equal to the mole fraction of water.
|
|
1901
1852
|
|
|
1902
1853
|
References:
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
water in aqueous systems: A frequently neglected property." *Chemical Society Review* 34, 440-458.
|
|
1854
|
+
Blandamer, Mike J., Engberts, Jan B. F. N., Gleeson, Peter T., Reis, Joao Carlos R., 2005. "Activity of
|
|
1855
|
+
water in aqueous systems: A frequently neglected property." *Chemical Society Review* 34, 440-458.
|
|
1906
1856
|
|
|
1907
1857
|
Examples:
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
<Quantity(0.9900944932888518, 'dimensionless')>
|
|
1858
|
+
>>> s1 = pyEQL.Solution([['Na+','0.3 mol/kg'],['Cl-','0.3 mol/kg']])
|
|
1859
|
+
>>> s1.get_water_activity()
|
|
1860
|
+
<Quantity(0.9900944932888518, 'dimensionless')>
|
|
1912
1861
|
"""
|
|
1913
1862
|
osmotic_coefficient = self.get_osmotic_coefficient()
|
|
1914
1863
|
|
|
@@ -1924,44 +1873,41 @@ class Solution(MSONable):
|
|
|
1924
1873
|
return ureg.Quantity(np.exp(-osmotic_coefficient * 0.018015 * concentration_sum), "dimensionless")
|
|
1925
1874
|
|
|
1926
1875
|
def get_chemical_potential_energy(self, activity_correction: bool = True) -> Quantity:
|
|
1927
|
-
"""
|
|
1876
|
+
r"""
|
|
1928
1877
|
Return the total chemical potential energy of a solution (not including
|
|
1929
1878
|
pressure or electric effects).
|
|
1930
1879
|
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
a calculation of the ideal chemical potential.
|
|
1880
|
+
Args:
|
|
1881
|
+
activity_correction : bool, optional
|
|
1882
|
+
If True, activities will be used to calculate the true chemical
|
|
1883
|
+
potential. If False, mole fraction will be used, resulting in
|
|
1884
|
+
a calculation of the ideal chemical potential.
|
|
1937
1885
|
|
|
1938
1886
|
Returns:
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
The actual or ideal chemical potential energy of the solution, in Joules.
|
|
1887
|
+
Quantity
|
|
1888
|
+
The actual or ideal chemical potential energy of the solution, in Joules.
|
|
1942
1889
|
|
|
1943
1890
|
Notes:
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
calculated as follows: [koga]_
|
|
1891
|
+
The chemical potential energy (related to the Gibbs mixing energy) is
|
|
1892
|
+
calculated as follows: [koga]_
|
|
1947
1893
|
|
|
1948
|
-
|
|
1894
|
+
.. math:: E = R T \sum_i n_i \ln a_i
|
|
1949
1895
|
|
|
1950
|
-
|
|
1896
|
+
or
|
|
1951
1897
|
|
|
1952
|
-
|
|
1898
|
+
.. math:: E = R T \sum_i n_i \ln x_i
|
|
1953
1899
|
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1900
|
+
Where :math:`n` is the number of moles of substance, :math:`T` is the temperature in kelvin,
|
|
1901
|
+
:math:`R` the ideal gas constant, :math:`x` the mole fraction, and :math:`a` the activity of
|
|
1902
|
+
each component.
|
|
1957
1903
|
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1904
|
+
Note that dissociated ions must be counted as separate components,
|
|
1905
|
+
so a simple salt dissolved in water is a three component solution (cation,
|
|
1906
|
+
anion, and water).
|
|
1961
1907
|
|
|
1962
1908
|
References:
|
|
1963
|
-
|
|
1964
|
-
|
|
1909
|
+
.. [koga] Koga, Yoshikata, 2007. *Solution Thermodynamics and its Application to Aqueous Solutions:
|
|
1910
|
+
A differential approach.* Elsevier, 2007, pp. 23-37.
|
|
1965
1911
|
|
|
1966
1912
|
"""
|
|
1967
1913
|
E = ureg.Quantity(0, "J")
|
|
@@ -1994,17 +1940,15 @@ class Solution(MSONable):
|
|
|
1994
1940
|
for solute, and adjust it from the reference conditions to the conditions
|
|
1995
1941
|
of the solution.
|
|
1996
1942
|
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
'diffusion coefficient'
|
|
1943
|
+
Args:
|
|
1944
|
+
solute: str
|
|
1945
|
+
String representing the chemical formula of the solute species
|
|
1946
|
+
name: str
|
|
1947
|
+
The name of the property needed, e.g.
|
|
1948
|
+
'diffusion coefficient'
|
|
2004
1949
|
|
|
2005
1950
|
Returns:
|
|
2006
|
-
|
|
2007
|
-
Quantity: The desired parameter or None if not found
|
|
1951
|
+
Quantity: The desired parameter or None if not found
|
|
2008
1952
|
|
|
2009
1953
|
"""
|
|
2010
1954
|
base_temperature = ureg.Quantity(25, "degC")
|
|
@@ -2119,7 +2063,7 @@ class Solution(MSONable):
|
|
|
2119
2063
|
return None
|
|
2120
2064
|
|
|
2121
2065
|
def get_transport_number(self, solute: str) -> Quantity:
|
|
2122
|
-
"""Calculate the transport number of the solute in the solution.
|
|
2066
|
+
r"""Calculate the transport number of the solute in the solution.
|
|
2123
2067
|
|
|
2124
2068
|
Args:
|
|
2125
2069
|
solute: Formula of the solute for which the transport number is
|
|
@@ -2133,7 +2077,7 @@ class Solution(MSONable):
|
|
|
2133
2077
|
|
|
2134
2078
|
.. math::
|
|
2135
2079
|
|
|
2136
|
-
t_i = {D_i z_i^2 C_i
|
|
2080
|
+
t_i = {D_i z_i^2 C_i \over \sum D_i z_i^2 C_i}
|
|
2137
2081
|
|
|
2138
2082
|
Where :math:`C_i` is the concentration in mol/L, :math:`D_i` is the diffusion
|
|
2139
2083
|
coefficient, and :math:`z_i` is the charge, and the summation extends
|
|
@@ -2171,7 +2115,7 @@ class Solution(MSONable):
|
|
|
2171
2115
|
return ureg.Quantity(numerator / denominator, "dimensionless")
|
|
2172
2116
|
|
|
2173
2117
|
def _get_molar_conductivity(self, solute: str) -> Quantity:
|
|
2174
|
-
"""
|
|
2118
|
+
r"""
|
|
2175
2119
|
Calculate the molar (equivalent) conductivity for a solute.
|
|
2176
2120
|
|
|
2177
2121
|
Args:
|
|
@@ -2187,17 +2131,20 @@ class Solution(MSONable):
|
|
|
2187
2131
|
|
|
2188
2132
|
.. math::
|
|
2189
2133
|
|
|
2190
|
-
|
|
2134
|
+
\lambda_i = \frac{F^2}{RT} D_i z_i^2
|
|
2191
2135
|
|
|
2192
2136
|
Diffusion coefficients :math:`D_i` are adjusted for the effects of temperature
|
|
2193
|
-
and ionic strength using the method implemented in PHREEQC >= 3.4. See `get_diffusion_coefficient
|
|
2137
|
+
and ionic strength using the method implemented in PHREEQC >= 3.4. See `get_diffusion_coefficient`
|
|
2138
|
+
for further details.
|
|
2194
2139
|
|
|
2195
2140
|
References:
|
|
2196
2141
|
1. .. [smed] Smedley, Stuart. The Interpretation of Ionic Conductivity in Liquids, pp 1-9. Plenum Press, 1980.
|
|
2197
2142
|
|
|
2198
2143
|
2. https://www.hydrochemistry.eu/exmpls/sc.html
|
|
2199
2144
|
|
|
2200
|
-
3. Appelo, C.A.J. Solute transport solved with the Nernst-Planck equation for concrete pores with `free'
|
|
2145
|
+
3. Appelo, C.A.J. Solute transport solved with the Nernst-Planck equation for concrete pores with `free'
|
|
2146
|
+
water and a double layer. Cement and Concrete Research 101, 2017.
|
|
2147
|
+
https://dx.doi.org/10.1016/j.cemconres.2017.08.030
|
|
2201
2148
|
|
|
2202
2149
|
4. CRC Handbook of Chemistry and Physics
|
|
2203
2150
|
|
|
@@ -2218,7 +2165,7 @@ class Solution(MSONable):
|
|
|
2218
2165
|
return molar_cond.to("mS / cm / (mol/L)")
|
|
2219
2166
|
|
|
2220
2167
|
def _get_diffusion_coefficient(self, solute: str, activity_correction: bool = True) -> Quantity:
|
|
2221
|
-
"""
|
|
2168
|
+
r"""
|
|
2222
2169
|
Get the **temperature-adjusted** diffusion coefficient of a solute.
|
|
2223
2170
|
|
|
2224
2171
|
Args:
|
|
@@ -2231,28 +2178,30 @@ class Solution(MSONable):
|
|
|
2231
2178
|
ONLY when the Solution temperature is the same as the reference temperature for the diffusion coefficient
|
|
2232
2179
|
in the database (usually 25 C).
|
|
2233
2180
|
|
|
2234
|
-
Otherwise, the reference D value is adjusted based on the Solution temperature and (optionally),
|
|
2235
|
-
The adjustments are
|
|
2181
|
+
Otherwise, the reference D value is adjusted based on the Solution temperature and (optionally),
|
|
2182
|
+
ionic strength. The adjustments are
|
|
2236
2183
|
|
|
2237
2184
|
.. math::
|
|
2238
2185
|
|
|
2239
|
-
D_T = D_{298}
|
|
2186
|
+
D_T = D_{298} \exp(\frac{d}{T} - \frac{d}{298}) \frac{\nu_{298}}{\nu_T}
|
|
2240
2187
|
|
|
2241
2188
|
.. math::
|
|
2242
2189
|
|
|
2243
|
-
D_{
|
|
2190
|
+
D_{\gamma} = D^0 \exp(\frac{-a1 A |z_i| \sqrt{I}}{1+\kappa a}
|
|
2244
2191
|
|
|
2245
2192
|
.. math::
|
|
2246
2193
|
|
|
2247
|
-
|
|
2194
|
+
\kappa a = B \sqrt{I} \frac{a2}{1+I^{0.75}}
|
|
2248
2195
|
|
|
2249
|
-
where a1, a2, and d are parameters from Ref. 2, A and B are the parameters used in the Debye Huckel
|
|
2250
|
-
I is the ionic strength. If the model parameters for a particular solute are not available,
|
|
2196
|
+
where a1, a2, and d are parameters from Ref. 2, A and B are the parameters used in the Debye Huckel
|
|
2197
|
+
equation, and I is the ionic strength. If the model parameters for a particular solute are not available,
|
|
2251
2198
|
default values of d=0, a1=1.6, and a2=4.73 (as recommended in Ref. 2) are used instead.
|
|
2252
2199
|
|
|
2253
2200
|
References:
|
|
2254
2201
|
1. https://www.hydrochemistry.eu/exmpls/sc.html
|
|
2255
|
-
2. Appelo, C.A.J. Solute transport solved with the Nernst-Planck equation for concrete pores with `free'
|
|
2202
|
+
2. Appelo, C.A.J. Solute transport solved with the Nernst-Planck equation for concrete pores with `free'
|
|
2203
|
+
water and a double layer. Cement and Concrete Research 101, 2017.
|
|
2204
|
+
https://dx.doi.org/10.1016/j.cemconres.2017.08.030
|
|
2256
2205
|
3. CRC Handbook of Chemistry and Physics
|
|
2257
2206
|
|
|
2258
2207
|
See Also:
|
|
@@ -2264,7 +2213,8 @@ class Solution(MSONable):
|
|
|
2264
2213
|
rform = standardize_formula(solute)
|
|
2265
2214
|
if D is None or D.magnitude == 0:
|
|
2266
2215
|
logger.info(
|
|
2267
|
-
f"Diffusion coefficient not found for species {rform}. Using default value of
|
|
2216
|
+
f"Diffusion coefficient not found for species {rform}. Using default value of "
|
|
2217
|
+
f"{self.default_diffusion_coeff} m**2/s."
|
|
2268
2218
|
)
|
|
2269
2219
|
D = ureg.Quantity(self.default_diffusion_coeff, "m**2/s")
|
|
2270
2220
|
|
|
@@ -2317,33 +2267,24 @@ class Solution(MSONable):
|
|
|
2317
2267
|
return D_final
|
|
2318
2268
|
|
|
2319
2269
|
def _get_mobility(self, solute: str) -> Quantity:
|
|
2320
|
-
"""
|
|
2270
|
+
r"""
|
|
2321
2271
|
Calculate the ionic mobility of the solute.
|
|
2322
2272
|
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
solute : str
|
|
2326
|
-
String identifying the solute for which the mobility is
|
|
2327
|
-
to be calculated.
|
|
2273
|
+
Args:
|
|
2274
|
+
solute (str): String identifying the solute for which the mobility is to be calculated.
|
|
2328
2275
|
|
|
2329
2276
|
Returns:
|
|
2330
|
-
|
|
2331
|
-
float : The ionic mobility. Zero if the solute is not charged.
|
|
2332
|
-
|
|
2277
|
+
float: The ionic mobility. Zero if the solute is not charged.
|
|
2333
2278
|
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
This function uses the Einstein relation to convert a diffusion coefficient
|
|
2337
|
-
into an ionic mobility [smed]_
|
|
2279
|
+
Note:
|
|
2280
|
+
This function uses the Einstein relation to convert a diffusion coefficient into an ionic mobility [smed]_
|
|
2338
2281
|
|
|
2339
|
-
|
|
2282
|
+
.. math::
|
|
2340
2283
|
|
|
2341
|
-
|
|
2284
|
+
\mu_i = {F |z_i| D_i \over RT}
|
|
2342
2285
|
|
|
2343
2286
|
References:
|
|
2344
|
-
|
|
2345
|
-
.. [smed] Smedley, Stuart I. The Interpretation of Ionic Conductivity in Liquids. Plenum Press, 1980.
|
|
2346
|
-
|
|
2287
|
+
Smedley, Stuart I. The Interpretation of Ionic Conductivity in Liquids. Plenum Press, 1980.
|
|
2347
2288
|
"""
|
|
2348
2289
|
D = self.get_diffusion_coefficient(solute)
|
|
2349
2290
|
|
|
@@ -2354,33 +2295,29 @@ class Solution(MSONable):
|
|
|
2354
2295
|
return mobility.to("m**2/V/s")
|
|
2355
2296
|
|
|
2356
2297
|
def get_lattice_distance(self, solute: str) -> Quantity:
|
|
2357
|
-
"""
|
|
2298
|
+
r"""
|
|
2358
2299
|
Calculate the average distance between molecules.
|
|
2359
2300
|
|
|
2360
2301
|
Calculate the average distance between molecules of the given solute,
|
|
2361
2302
|
assuming that the molecules are uniformly distributed throughout the
|
|
2362
2303
|
solution.
|
|
2363
2304
|
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
String representing the name of the solute of interest
|
|
2305
|
+
Args:
|
|
2306
|
+
solute : str
|
|
2307
|
+
String representing the name of the solute of interest
|
|
2368
2308
|
|
|
2369
2309
|
Returns:
|
|
2370
|
-
|
|
2371
|
-
Quantity : The average distance between solute molecules
|
|
2310
|
+
Quantity: The average distance between solute molecules
|
|
2372
2311
|
|
|
2373
2312
|
Examples:
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
1.492964.... nanometer
|
|
2313
|
+
>>> soln = Solution([['Na+','0.5 mol/kg'],['Cl-','0.5 mol/kg']])
|
|
2314
|
+
>>> soln.get_lattice_distance('Na+')
|
|
2315
|
+
1.492964.... nanometer
|
|
2378
2316
|
|
|
2379
2317
|
Notes:
|
|
2380
|
-
|
|
2381
|
-
The lattice distance is related to the molar concentration as follows:
|
|
2318
|
+
The lattice distance is related to the molar concentration as follows:
|
|
2382
2319
|
|
|
2383
|
-
|
|
2320
|
+
.. math:: d = ( C_i N_A ) ^ {-{1 \over 3}}
|
|
2384
2321
|
|
|
2385
2322
|
"""
|
|
2386
2323
|
# calculate the volume per particle as the reciprocal of the molar concentration
|
|
@@ -2563,7 +2500,8 @@ class Solution(MSONable):
|
|
|
2563
2500
|
|
|
2564
2501
|
Args:
|
|
2565
2502
|
mode: Whether to list the amounts of all solutes, or only anions, cations, any ion, or any neutral solute.
|
|
2566
|
-
units: The units to list solute amounts in. "activity" will list dimensionless activities instead of
|
|
2503
|
+
units: The units to list solute amounts in. "activity" will list dimensionless activities instead of
|
|
2504
|
+
concentrations.
|
|
2567
2505
|
places: The number of decimal places to round the solute amounts.
|
|
2568
2506
|
"""
|
|
2569
2507
|
print(self)
|
|
@@ -2832,12 +2770,12 @@ class Solution(MSONable):
|
|
|
2832
2770
|
|
|
2833
2771
|
@deprecated(message="get_viscosity_relative() will be removed in the next release.")
|
|
2834
2772
|
def get_viscosity_relative(self): # pragma: no cover
|
|
2835
|
-
"""
|
|
2773
|
+
r"""
|
|
2836
2774
|
Return the viscosity of the solution relative to that of water.
|
|
2837
2775
|
|
|
2838
2776
|
This is calculated using a simplified form of the Jones-Dole equation:
|
|
2839
2777
|
|
|
2840
|
-
.. math::
|
|
2778
|
+
.. math:: \eta_{rel} = 1 + \sum_i B_i m_i
|
|
2841
2779
|
|
|
2842
2780
|
Where :math:`m` is the molal concentration and :math:`B` is an empirical parameter.
|
|
2843
2781
|
|
|
@@ -2895,7 +2833,7 @@ class Solution(MSONable):
|
|
|
2895
2833
|
|
|
2896
2834
|
.. math::
|
|
2897
2835
|
|
|
2898
|
-
\\ln
|
|
2836
|
+
\\ln \nu = \\ln {\nu_w MW_w \\over \\sum_i x_i MW_i } +
|
|
2899
2837
|
15 x_+^2 + x_+^3 \\delta G^*_{123} + 3 x_+ \\delta G^*_{23} (1-0.05x_+)
|
|
2900
2838
|
|
|
2901
2839
|
Where:
|
|
@@ -2903,7 +2841,7 @@ class Solution(MSONable):
|
|
|
2903
2841
|
.. math:: \\delta G^*_{123} = a_o + a_1 (T)^{0.75}
|
|
2904
2842
|
.. math:: \\delta G^*_{23} = b_o + b_1 (T)^{0.5}
|
|
2905
2843
|
|
|
2906
|
-
In which :math
|
|
2844
|
+
In which :math:`\nu` is the kinematic viscosity, MW is the molecular weight,
|
|
2907
2845
|
`x_+` is the mole fraction of cations, and T is the temperature in degrees C.
|
|
2908
2846
|
|
|
2909
2847
|
The a and b fitting parameters for a variety of common salts are included in the
|
|
@@ -2948,13 +2886,13 @@ class Solution(MSONable):
|
|
|
2948
2886
|
|
|
2949
2887
|
.. math::
|
|
2950
2888
|
|
|
2951
|
-
EC = {F^2 \\over R T} \\sum_i D_i z_i ^ 2 \\gamma_i ^ {
|
|
2889
|
+
EC = {F^2 \\over R T} \\sum_i D_i z_i ^ 2 \\gamma_i ^ {\alpha} m_i
|
|
2952
2890
|
|
|
2953
2891
|
Where:
|
|
2954
2892
|
|
|
2955
2893
|
.. math::
|
|
2956
2894
|
|
|
2957
|
-
|
|
2895
|
+
\alpha = \begin{cases} {0.6 \\over \\sqrt{|z_i|}} & {I < 0.36|z_i|} \\ {\\sqrt{I} \\over |z_i|} & otherwise \\end{cases}
|
|
2958
2896
|
|
|
2959
2897
|
Note: PHREEQC uses the molal rather than molar concentration according to
|
|
2960
2898
|
http://wwwbrr.cr.usgs.gov/projects/GWC_coupled/phreeqc/phreeqc3-html/phreeqc3-43.htm
|
|
@@ -2995,7 +2933,7 @@ class Solution(MSONable):
|
|
|
2995
2933
|
message="get_ionic_strength() will be removed in the next release. Access directly via the property Solution.ionic_strength"
|
|
2996
2934
|
)
|
|
2997
2935
|
def get_ionic_strength(self): # pragma: no cover
|
|
2998
|
-
"""
|
|
2936
|
+
r"""
|
|
2999
2937
|
Return the ionic strength of the solution.
|
|
3000
2938
|
|
|
3001
2939
|
Return the ionic strength of the solution, calculated as 1/2 * sum ( molality * charge ^2) over all the ions.
|
|
@@ -3003,7 +2941,7 @@ class Solution(MSONable):
|
|
|
3003
2941
|
|
|
3004
2942
|
Returns:
|
|
3005
2943
|
-------
|
|
3006
|
-
Quantity
|
|
2944
|
+
Quantity:
|
|
3007
2945
|
The ionic strength of the parent solution, mol/kg.
|
|
3008
2946
|
|
|
3009
2947
|
See Also:
|
|
@@ -3015,7 +2953,7 @@ class Solution(MSONable):
|
|
|
3015
2953
|
-----
|
|
3016
2954
|
The ionic strength is calculated according to:
|
|
3017
2955
|
|
|
3018
|
-
.. math:: I =
|
|
2956
|
+
.. math:: I = \sum_i m_i z_i^2
|
|
3019
2957
|
|
|
3020
2958
|
Where :math:`m_i` is the molal concentration and :math:`z_i` is the charge on species i.
|
|
3021
2959
|
|
|
@@ -3037,7 +2975,7 @@ class Solution(MSONable):
|
|
|
3037
2975
|
message="get_charge_balance() will be removed in the next release. Access directly via the property Solution.charge_balance"
|
|
3038
2976
|
)
|
|
3039
2977
|
def get_charge_balance(self): # pragma: no cover
|
|
3040
|
-
"""
|
|
2978
|
+
r"""
|
|
3041
2979
|
Return the charge balance of the solution.
|
|
3042
2980
|
|
|
3043
2981
|
Return the charge balance of the solution. The charge balance represents the net electric charge
|
|
@@ -3053,7 +2991,7 @@ class Solution(MSONable):
|
|
|
3053
2991
|
-----
|
|
3054
2992
|
The charge balance is calculated according to:
|
|
3055
2993
|
|
|
3056
|
-
.. math:: CB = F
|
|
2994
|
+
.. math:: CB = F \sum_i n_i z_i
|
|
3057
2995
|
|
|
3058
2996
|
Where :math:`n_i` is the number of moles, :math:`z_i` is the charge on species i, and :math:`F` is the Faraday constant.
|
|
3059
2997
|
|
|
@@ -3066,19 +3004,19 @@ class Solution(MSONable):
|
|
|
3066
3004
|
message="get_alkalinity() will be removed in the next release. Access directly via the property Solution.alkalinity"
|
|
3067
3005
|
)
|
|
3068
3006
|
def get_alkalinity(self): # pragma: no cover
|
|
3069
|
-
"""
|
|
3007
|
+
r"""
|
|
3070
3008
|
Return the alkalinity or acid neutralizing capacity of a solution.
|
|
3071
3009
|
|
|
3072
3010
|
Returns:
|
|
3073
3011
|
-------
|
|
3074
|
-
Quantity
|
|
3012
|
+
Quantity:
|
|
3075
3013
|
The alkalinity of the solution in mg/L as CaCO3
|
|
3076
3014
|
|
|
3077
3015
|
Notes:
|
|
3078
3016
|
-----
|
|
3079
3017
|
The alkalinity is calculated according to:
|
|
3080
3018
|
|
|
3081
|
-
.. math:: Alk = F
|
|
3019
|
+
.. math:: Alk = F \sum_i z_i C_B - \sum_i z_i C_A
|
|
3082
3020
|
|
|
3083
3021
|
Where :math:`C_B` and :math:`C_A` are conservative cations and anions, respectively
|
|
3084
3022
|
(i.e. ions that do not participate in acid-base reactions), and :math:`z_i` is their charge.
|
|
@@ -3125,14 +3063,14 @@ class Solution(MSONable):
|
|
|
3125
3063
|
message="get_debye_length() will be removed in the next release. Access directly via the property Solution.debye_length"
|
|
3126
3064
|
)
|
|
3127
3065
|
def get_debye_length(self): # pragma: no cover
|
|
3128
|
-
"""
|
|
3066
|
+
r"""
|
|
3129
3067
|
Return the Debye length of a solution.
|
|
3130
3068
|
|
|
3131
3069
|
Debye length is calculated as
|
|
3132
3070
|
|
|
3133
3071
|
.. math::
|
|
3134
3072
|
|
|
3135
|
-
|
|
3073
|
+
\kappa^{-1} = \sqrt({\epsilon_r \epsilon_o k_B T \over (2 N_A e^2 I)})
|
|
3136
3074
|
|
|
3137
3075
|
where :math:`I` is the ionic strength, :math:`epsilon_r` and :math:`epsilon_r`
|
|
3138
3076
|
are the relative permittivity and vacuum permittivity, :math:`k_B` is the
|
|
@@ -3166,16 +3104,16 @@ class Solution(MSONable):
|
|
|
3166
3104
|
message="get_bjerrum_length() will be removed in the next release. Access directly via the property Solution.bjerrum_length"
|
|
3167
3105
|
)
|
|
3168
3106
|
def get_bjerrum_length(self): # pragma: no cover
|
|
3169
|
-
"""
|
|
3107
|
+
r"""
|
|
3170
3108
|
Return the Bjerrum length of a solution.
|
|
3171
3109
|
|
|
3172
3110
|
Bjerrum length represents the distance at which electrostatic
|
|
3173
3111
|
interactions between particles become comparable in magnitude
|
|
3174
|
-
to the thermal energy.:math
|
|
3112
|
+
to the thermal energy.:math:`\lambda_B` is calculated as
|
|
3175
3113
|
|
|
3176
3114
|
.. math::
|
|
3177
3115
|
|
|
3178
|
-
|
|
3116
|
+
\lambda_B = {e^2 \over (4 \pi \epsilon_r \epsilon_o k_B T)}
|
|
3179
3117
|
|
|
3180
3118
|
where :math:`e` is the fundamental charge, :math:`epsilon_r` and :math:`epsilon_r`
|
|
3181
3119
|
are the relative permittivity and vacuum permittivity, :math:`k_B` is the
|
|
@@ -3228,9 +3166,9 @@ class Solution(MSONable):
|
|
|
3228
3166
|
-----
|
|
3229
3167
|
Implements the following equation as given by [zub]_
|
|
3230
3168
|
|
|
3231
|
-
.. math:: \\epsilon = \\epsilon_solvent \\over 1 + \\sum_i
|
|
3169
|
+
.. math:: \\epsilon = \\epsilon_solvent \\over 1 + \\sum_i \alpha_i x_i
|
|
3232
3170
|
|
|
3233
|
-
where :math
|
|
3171
|
+
where :math:`\alpha_i` is a coefficient specific to the solvent and ion, and :math:`x_i`
|
|
3234
3172
|
is the mole fraction of the ion in solution.
|
|
3235
3173
|
|
|
3236
3174
|
|
|
@@ -3318,10 +3256,10 @@ class Solution(MSONable):
|
|
|
3318
3256
|
|
|
3319
3257
|
References:
|
|
3320
3258
|
.. [1] Millero, Frank J. "The composition of Standard Seawater and the definition of
|
|
3321
|
-
|
|
3259
|
+
the Reference-Composition Salinity Scale." *Deep-sea Research. Part I* 55(1), 2008, 50-72.
|
|
3322
3260
|
|
|
3323
3261
|
.. [2] Metcalf & Eddy, Inc. et al. *Wastewater Engineering: Treatment and Resource Recovery*, 5th Ed.
|
|
3324
|
-
|
|
3262
|
+
McGraw-Hill, 2013.
|
|
3325
3263
|
|
|
3326
3264
|
.. [3] https://en.wikipedia.org/wiki/Saline_(medicine)
|
|
3327
3265
|
|
|
@@ -3362,6 +3300,7 @@ class Solution(MSONable):
|
|
|
3362
3300
|
else:
|
|
3363
3301
|
dumpfn(self, filename)
|
|
3364
3302
|
|
|
3303
|
+
@classmethod
|
|
3365
3304
|
def from_file(self, filename: str | Path) -> Solution:
|
|
3366
3305
|
"""Loading from a .yaml or .json file.
|
|
3367
3306
|
|