pyEQL 0.5.2__py3-none-any.whl → 1.1.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 +50 -43
- pyEQL/activity_correction.py +481 -707
- pyEQL/database/geothermal.dat +5693 -0
- pyEQL/database/llnl.dat +19305 -0
- pyEQL/database/phreeqc_license.txt +54 -0
- pyEQL/database/pyeql_db.json +35902 -0
- pyEQL/engines.py +793 -0
- pyEQL/equilibrium.py +148 -228
- pyEQL/functions.py +121 -416
- pyEQL/pint_custom_units.txt +2 -2
- pyEQL/presets/Ringers lactate.yaml +20 -0
- pyEQL/presets/normal saline.yaml +17 -0
- pyEQL/presets/rainwater.yaml +17 -0
- pyEQL/presets/seawater.yaml +29 -0
- pyEQL/presets/urine.yaml +26 -0
- pyEQL/presets/wastewater.yaml +21 -0
- pyEQL/salt_ion_match.py +53 -284
- pyEQL/solute.py +126 -191
- pyEQL/solution.py +2163 -2090
- pyEQL/utils.py +165 -0
- pyEQL-1.1.0.dist-info/AUTHORS.md +13 -0
- {pyEQL-0.5.2.dist-info → pyEQL-1.1.0.dist-info}/COPYING +1 -1
- pyEQL-0.5.2.dist-info/LICENSE → pyEQL-1.1.0.dist-info/LICENSE.txt +3 -7
- pyEQL-1.1.0.dist-info/METADATA +129 -0
- pyEQL-1.1.0.dist-info/RECORD +27 -0
- {pyEQL-0.5.2.dist-info → pyEQL-1.1.0.dist-info}/WHEEL +2 -1
- pyEQL/chemical_formula.py +0 -1006
- pyEQL/database/Erying_viscosity.tsv +0 -18
- pyEQL/database/Jones_Dole_B.tsv +0 -32
- pyEQL/database/Jones_Dole_B_inorganic_Jenkins.tsv +0 -75
- pyEQL/database/LICENSE +0 -4
- pyEQL/database/dielectric_parameter.tsv +0 -30
- pyEQL/database/diffusion_coefficient.tsv +0 -116
- pyEQL/database/hydrated_radius.tsv +0 -35
- pyEQL/database/ionic_radius.tsv +0 -35
- pyEQL/database/partial_molar_volume.tsv +0 -22
- pyEQL/database/pitzer_activity.tsv +0 -169
- pyEQL/database/pitzer_volume.tsv +0 -132
- pyEQL/database/template.tsv +0 -14
- pyEQL/database.py +0 -300
- pyEQL/elements.py +0 -4552
- pyEQL/logging_system.py +0 -53
- pyEQL/parameter.py +0 -435
- pyEQL/tests/__init__.py +0 -32
- pyEQL/tests/test_activity.py +0 -578
- pyEQL/tests/test_bulk_properties.py +0 -86
- pyEQL/tests/test_chemical_formula.py +0 -279
- pyEQL/tests/test_debye_length.py +0 -79
- pyEQL/tests/test_density.py +0 -106
- pyEQL/tests/test_dielectric.py +0 -153
- pyEQL/tests/test_effective_pitzer.py +0 -276
- pyEQL/tests/test_mixed_electrolyte_activity.py +0 -154
- pyEQL/tests/test_osmotic_coeff.py +0 -99
- pyEQL/tests/test_pyeql_volume_concentration.py +0 -428
- pyEQL/tests/test_salt_matching.py +0 -337
- pyEQL/tests/test_solute_properties.py +0 -251
- pyEQL/water_properties.py +0 -352
- pyEQL-0.5.2.dist-info/AUTHORS +0 -7
- pyEQL-0.5.2.dist-info/METADATA +0 -72
- pyEQL-0.5.2.dist-info/RECORD +0 -47
- pyEQL-0.5.2.dist-info/entry_points.txt +0 -3
- {pyEQL-0.5.2.dist-info → pyEQL-1.1.0.dist-info}/top_level.txt +0 -0
|
@@ -1,276 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
pyEQL test suite for Effective Pitzer Model
|
|
3
|
-
===========================================
|
|
4
|
-
|
|
5
|
-
This file contains tests for the Effective Pitzer Model
|
|
6
|
-
implemented in pyEQL.
|
|
7
|
-
|
|
8
|
-
The Effective Pitzer Model is described in Mistry et al.
|
|
9
|
-
(DOI: 10.1016/j.desal.2013.03.015). The paper validates
|
|
10
|
-
the model by showing the calculated activity coefficients
|
|
11
|
-
for each component of synthetic seawater (composition
|
|
12
|
-
given in Table 2 of the paper). The mock seawater
|
|
13
|
-
has a mass ratio of NaCl:MgCl2:Na2SO4:CaCl2:KCl
|
|
14
|
-
of 24.53:5.20:4.09:1.16:0.695, and the total
|
|
15
|
-
salinity is varied.
|
|
16
|
-
|
|
17
|
-
MW g/L mol/L
|
|
18
|
-
NaCl 58.44 24.53 0.419746749
|
|
19
|
-
MgCl2 95.2 5.2 0.054621849
|
|
20
|
-
Na2SO4 142 4.09 0.028802817
|
|
21
|
-
CaCl2 110.98 1.16 0.010452334
|
|
22
|
-
KCl 74.55 0.0695 0.00093226
|
|
23
|
-
|
|
24
|
-
The total molality is 0.515 mol salts/kg
|
|
25
|
-
|
|
26
|
-
This test suite replicates that synthetic seawter and then
|
|
27
|
-
confirms that pyEQL's output of activity and fugacity
|
|
28
|
-
coefficients matches that given by the authors.
|
|
29
|
-
|
|
30
|
-
pyEQL probably uses different pitzer parameters than
|
|
31
|
-
the paper, so perfect accuracy is not expected.
|
|
32
|
-
|
|
33
|
-
"""
|
|
34
|
-
|
|
35
|
-
import pyEQL
|
|
36
|
-
import unittest
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
class Test_effective_pitzer(unittest.TestCase, pyEQL.CustomAssertions):
|
|
40
|
-
"""
|
|
41
|
-
test osmotic coefficient based on the Pitzer model
|
|
42
|
-
------------------------------------------------
|
|
43
|
-
|
|
44
|
-
"""
|
|
45
|
-
|
|
46
|
-
def setUp(self):
|
|
47
|
-
# relative error tolerance for assertWithinExperimentalError
|
|
48
|
-
self.tol = 0.15
|
|
49
|
-
|
|
50
|
-
def mock_seawater(self, multiple):
|
|
51
|
-
"""
|
|
52
|
-
Create a solution of mock seawater.
|
|
53
|
-
Multiple is a scale factor by which the base
|
|
54
|
-
composition (regular seawater) is scaled.
|
|
55
|
-
"""
|
|
56
|
-
s1 = pyEQL.Solution(
|
|
57
|
-
[
|
|
58
|
-
["Na+", str(multiple * 0.4197 + multiple * 2 * 0.0288) + "mol/L"],
|
|
59
|
-
[
|
|
60
|
-
"Cl-",
|
|
61
|
-
str(
|
|
62
|
-
multiple * 0.4197
|
|
63
|
-
+ multiple * 2 * 0.0546
|
|
64
|
-
+ multiple * 2 * 0.01045
|
|
65
|
-
+ multiple * 0.00093
|
|
66
|
-
)
|
|
67
|
-
+ "mol/L",
|
|
68
|
-
],
|
|
69
|
-
["Mg+2", str(multiple * 0.0546) + "mol/L"],
|
|
70
|
-
["SO4-2", str(multiple * 0.0288) + "mol/L"],
|
|
71
|
-
["Ca+2", str(multiple * 0.01045) + "mol/L"],
|
|
72
|
-
["K+", str(multiple * 0.00093) + "mol/L"],
|
|
73
|
-
]
|
|
74
|
-
)
|
|
75
|
-
return s1
|
|
76
|
-
|
|
77
|
-
def test_effective_pitzer_nacl_activity(self):
|
|
78
|
-
# test the activity coefficient of NaCl
|
|
79
|
-
# corresponds to 0.515m, 1.03m, 2.58m, and 4.1m
|
|
80
|
-
multiple = [1, 2, 5, 8]
|
|
81
|
-
expected = [0.7, 0.7, 0.8, 1.1]
|
|
82
|
-
|
|
83
|
-
# import the parameters database
|
|
84
|
-
from pyEQL import paramsDB as db
|
|
85
|
-
|
|
86
|
-
for item in range(len(multiple)):
|
|
87
|
-
s1 = self.mock_seawater(multiple[item])
|
|
88
|
-
Salt = pyEQL.salt_ion_match.Salt("Na+", "Cl-")
|
|
89
|
-
db.search_parameters(Salt.formula)
|
|
90
|
-
param = db.get_parameter(Salt.formula, "pitzer_parameters_activity")
|
|
91
|
-
alpha1 = 2
|
|
92
|
-
alpha2 = 0
|
|
93
|
-
molality = Salt.get_effective_molality(s1.get_ionic_strength())
|
|
94
|
-
temperature = str(s1.get_temperature())
|
|
95
|
-
|
|
96
|
-
activity_coefficient = pyEQL.activity_correction.get_activity_coefficient_pitzer(
|
|
97
|
-
s1.get_ionic_strength(),
|
|
98
|
-
molality,
|
|
99
|
-
alpha1,
|
|
100
|
-
alpha2,
|
|
101
|
-
param.get_value()[0],
|
|
102
|
-
param.get_value()[1],
|
|
103
|
-
param.get_value()[2],
|
|
104
|
-
param.get_value()[3],
|
|
105
|
-
Salt.z_cation,
|
|
106
|
-
Salt.z_anion,
|
|
107
|
-
Salt.nu_cation,
|
|
108
|
-
Salt.nu_anion,
|
|
109
|
-
temperature,
|
|
110
|
-
)
|
|
111
|
-
|
|
112
|
-
# convert the result to a rational activity coefficient
|
|
113
|
-
result = activity_coefficient * (
|
|
114
|
-
1
|
|
115
|
-
+ pyEQL.unit("0.018 kg/mol")
|
|
116
|
-
* s1.get_total_moles_solute()
|
|
117
|
-
/ s1.get_solvent_mass()
|
|
118
|
-
)
|
|
119
|
-
# print(result,expected[item])
|
|
120
|
-
self.assertWithinExperimentalError(result, expected[item], self.tol)
|
|
121
|
-
|
|
122
|
-
def test_effective_pitzer_mgcl2_activity(self):
|
|
123
|
-
# test the activity coefficient of MgCl2
|
|
124
|
-
# corresponds to 0.515m, 1.03m, 2.58m, and 4.1m
|
|
125
|
-
multiple = [1, 2, 5, 8]
|
|
126
|
-
expected = [0.5, 0.5, 0.67, 1.15]
|
|
127
|
-
|
|
128
|
-
# import the parameters database
|
|
129
|
-
from pyEQL import paramsDB as db
|
|
130
|
-
|
|
131
|
-
for item in range(len(multiple)):
|
|
132
|
-
s1 = self.mock_seawater(multiple[item])
|
|
133
|
-
Salt = pyEQL.salt_ion_match.Salt("Mg+2", "Cl-")
|
|
134
|
-
db.search_parameters(Salt.formula)
|
|
135
|
-
param = db.get_parameter(Salt.formula, "pitzer_parameters_activity")
|
|
136
|
-
alpha1 = 2
|
|
137
|
-
alpha2 = 0
|
|
138
|
-
molality = Salt.get_effective_molality(s1.get_ionic_strength())
|
|
139
|
-
temperature = str(s1.get_temperature())
|
|
140
|
-
|
|
141
|
-
activity_coefficient = pyEQL.activity_correction.get_activity_coefficient_pitzer(
|
|
142
|
-
s1.get_ionic_strength(),
|
|
143
|
-
molality,
|
|
144
|
-
alpha1,
|
|
145
|
-
alpha2,
|
|
146
|
-
param.get_value()[0],
|
|
147
|
-
param.get_value()[1],
|
|
148
|
-
param.get_value()[2],
|
|
149
|
-
param.get_value()[3],
|
|
150
|
-
Salt.z_cation,
|
|
151
|
-
Salt.z_anion,
|
|
152
|
-
Salt.nu_cation,
|
|
153
|
-
Salt.nu_anion,
|
|
154
|
-
temperature,
|
|
155
|
-
)
|
|
156
|
-
|
|
157
|
-
# convert the result to a rational activity coefficient
|
|
158
|
-
result = activity_coefficient * (
|
|
159
|
-
1
|
|
160
|
-
+ pyEQL.unit("0.018 kg/mol")
|
|
161
|
-
* s1.get_total_moles_solute()
|
|
162
|
-
/ s1.get_solvent_mass()
|
|
163
|
-
)
|
|
164
|
-
# print(result,expected[item])
|
|
165
|
-
self.assertWithinExperimentalError(result, expected[item], self.tol)
|
|
166
|
-
|
|
167
|
-
def test_effective_pitzer_KCl_activity(self):
|
|
168
|
-
# test the activity coefficient of KCl
|
|
169
|
-
# corresponds to 0.515m, 1.03m, 2.58m, and 4.1m
|
|
170
|
-
multiple = [1, 2, 5, 8]
|
|
171
|
-
expected = [0.65, 0.61, 0.65, 0.7]
|
|
172
|
-
|
|
173
|
-
# import the parameters database
|
|
174
|
-
from pyEQL import paramsDB as db
|
|
175
|
-
|
|
176
|
-
for item in range(len(multiple)):
|
|
177
|
-
s1 = self.mock_seawater(multiple[item])
|
|
178
|
-
Salt = pyEQL.salt_ion_match.Salt("K+", "Cl-")
|
|
179
|
-
db.search_parameters(Salt.formula)
|
|
180
|
-
param = db.get_parameter(Salt.formula, "pitzer_parameters_activity")
|
|
181
|
-
alpha1 = 2
|
|
182
|
-
alpha2 = 0
|
|
183
|
-
molality = Salt.get_effective_molality(s1.get_ionic_strength())
|
|
184
|
-
temperature = str(s1.get_temperature())
|
|
185
|
-
|
|
186
|
-
activity_coefficient = pyEQL.activity_correction.get_activity_coefficient_pitzer(
|
|
187
|
-
s1.get_ionic_strength(),
|
|
188
|
-
molality,
|
|
189
|
-
alpha1,
|
|
190
|
-
alpha2,
|
|
191
|
-
param.get_value()[0],
|
|
192
|
-
param.get_value()[1],
|
|
193
|
-
param.get_value()[2],
|
|
194
|
-
param.get_value()[3],
|
|
195
|
-
Salt.z_cation,
|
|
196
|
-
Salt.z_anion,
|
|
197
|
-
Salt.nu_cation,
|
|
198
|
-
Salt.nu_anion,
|
|
199
|
-
temperature,
|
|
200
|
-
)
|
|
201
|
-
|
|
202
|
-
# convert the result to a rational activity coefficient
|
|
203
|
-
result = activity_coefficient * (
|
|
204
|
-
1
|
|
205
|
-
+ pyEQL.unit("0.018 kg/mol")
|
|
206
|
-
* s1.get_total_moles_solute()
|
|
207
|
-
/ s1.get_solvent_mass()
|
|
208
|
-
)
|
|
209
|
-
# print(result,expected[item])
|
|
210
|
-
self.assertWithinExperimentalError(result, expected[item], self.tol)
|
|
211
|
-
|
|
212
|
-
@unittest.expectedFailure
|
|
213
|
-
def test_effective_pitzer_na2so4_activity(self):
|
|
214
|
-
# test the activity coefficient of Na2SO4
|
|
215
|
-
# corresponds to 0.515m, 1.03m, 2.58m, and 4.1m
|
|
216
|
-
multiple = [1, 2, 5, 8]
|
|
217
|
-
expected = [0.38, 0.3, 0.25, 0.2]
|
|
218
|
-
|
|
219
|
-
# import the parameters database
|
|
220
|
-
from pyEQL import paramsDB as db
|
|
221
|
-
|
|
222
|
-
for item in range(len(multiple)):
|
|
223
|
-
s1 = self.mock_seawater(multiple[item])
|
|
224
|
-
Salt = pyEQL.salt_ion_match.Salt("Na+", "SO4-2")
|
|
225
|
-
db.search_parameters(Salt.formula)
|
|
226
|
-
param = db.get_parameter(Salt.formula, "pitzer_parameters_activity")
|
|
227
|
-
alpha1 = 2
|
|
228
|
-
alpha2 = 0
|
|
229
|
-
molality = Salt.get_effective_molality(s1.get_ionic_strength())
|
|
230
|
-
temperature = str(s1.get_temperature())
|
|
231
|
-
|
|
232
|
-
activity_coefficient = pyEQL.activity_correction.get_activity_coefficient_pitzer(
|
|
233
|
-
s1.get_ionic_strength(),
|
|
234
|
-
molality,
|
|
235
|
-
alpha1,
|
|
236
|
-
alpha2,
|
|
237
|
-
param.get_value()[0],
|
|
238
|
-
param.get_value()[1],
|
|
239
|
-
param.get_value()[2],
|
|
240
|
-
param.get_value()[3],
|
|
241
|
-
Salt.z_cation,
|
|
242
|
-
Salt.z_anion,
|
|
243
|
-
Salt.nu_cation,
|
|
244
|
-
Salt.nu_anion,
|
|
245
|
-
temperature,
|
|
246
|
-
)
|
|
247
|
-
|
|
248
|
-
# convert the result to a rational activity coefficient
|
|
249
|
-
result = activity_coefficient * (
|
|
250
|
-
1
|
|
251
|
-
+ pyEQL.unit("0.018 kg/mol")
|
|
252
|
-
* s1.get_total_moles_solute()
|
|
253
|
-
/ s1.get_solvent_mass()
|
|
254
|
-
)
|
|
255
|
-
# print(result,expected[item])
|
|
256
|
-
self.assertWithinExperimentalError(result, expected[item], self.tol)
|
|
257
|
-
|
|
258
|
-
def test_effective_pitzer_fugacity(self):
|
|
259
|
-
# test the fugacity coefficient of mock seawater
|
|
260
|
-
# corresponds to 0.515m, 2.58m, 4.1m, and 5.15 m
|
|
261
|
-
multiple = [1, 5, 8, 10]
|
|
262
|
-
expected = [1, 1, 0.95, 0.95]
|
|
263
|
-
|
|
264
|
-
# import the parameters database
|
|
265
|
-
from pyEQL import paramsDB as db
|
|
266
|
-
|
|
267
|
-
for item in range(len(multiple)):
|
|
268
|
-
s1 = self.mock_seawater(multiple[item])
|
|
269
|
-
result = s1.get_osmotic_coefficient(scale="fugacity")
|
|
270
|
-
|
|
271
|
-
# print(result,expected[item])
|
|
272
|
-
self.assertWithinExperimentalError(result, expected[item], self.tol)
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
if __name__ == "__main__":
|
|
276
|
-
unittest.main()
|
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
pyEQL test suite for mixed electrolyte activity
|
|
3
|
-
===============================================
|
|
4
|
-
|
|
5
|
-
This file contains tests for the Effective Pitzer Model
|
|
6
|
-
implemented in pyEQL.
|
|
7
|
-
|
|
8
|
-
This test suite creates several mixed salt solutions and compares
|
|
9
|
-
pyEQL's calculations with experimental data for activity coefficients
|
|
10
|
-
and/or osmotic coefficients.
|
|
11
|
-
|
|
12
|
-
The Effective Pitzer Model is described in Mistry et al.
|
|
13
|
-
DOI: 10.1016/j.desal.2013.03.015
|
|
14
|
-
|
|
15
|
-
Experimental data for mixed electrolytes is obtained from Rodil et al.
|
|
16
|
-
DOI: 10.1021/je9004432
|
|
17
|
-
|
|
18
|
-
"""
|
|
19
|
-
|
|
20
|
-
import pyEQL
|
|
21
|
-
import unittest
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
class Test_nano3_kno3_activity(unittest.TestCase, pyEQL.CustomAssertions):
|
|
25
|
-
"""
|
|
26
|
-
test mean activity coefficients in a NaNO3 + KNO3 mixture
|
|
27
|
-
---------------------------------------------------------
|
|
28
|
-
Note that the values given in Table 3 of Rodil et al. are single-ion
|
|
29
|
-
activity coefficients that must be averaged (geometrically) to obtained
|
|
30
|
-
the mean values below
|
|
31
|
-
|
|
32
|
-
"""
|
|
33
|
-
|
|
34
|
-
def setUp(self):
|
|
35
|
-
# relative error tolerance for assertWithinExperimentalError
|
|
36
|
-
self.tol = 0.25
|
|
37
|
-
|
|
38
|
-
def test_activity_Na_XNa_75(self):
|
|
39
|
-
# test the activity coefficient of Na+ in mixed NaNO3 and KNO3 when the
|
|
40
|
-
# mole fraction of Na+ is 0.75
|
|
41
|
-
# molality refers to the total nitrate ion molality
|
|
42
|
-
molality = [0.3997, 0.992, 1.584, 2.373]
|
|
43
|
-
expected = [0.613, 0.5039, 0.4448, 0.3928]
|
|
44
|
-
|
|
45
|
-
for item in range(len(molality)):
|
|
46
|
-
s1 = pyEQL.Solution(
|
|
47
|
-
[
|
|
48
|
-
["Na+", str(0.75 * molality[item]) + "mol/kg"],
|
|
49
|
-
["K+", str(0.25 * molality[item]) + "mol/kg"],
|
|
50
|
-
["NO3-", str(molality[item]) + "mol/kg"],
|
|
51
|
-
]
|
|
52
|
-
)
|
|
53
|
-
result = s1.get_activity_coefficient("Na+").magnitude
|
|
54
|
-
# print(result,expected[item])
|
|
55
|
-
self.assertWithinExperimentalError(result, expected[item], self.tol)
|
|
56
|
-
|
|
57
|
-
def test_activity_K_XNa_75(self):
|
|
58
|
-
# test the activity coefficient of Na+ in mixed NaNO3 and KNO3 when the
|
|
59
|
-
# mole fraction of Na+ is 0.75
|
|
60
|
-
# molality refers to the total nitrate ion molality
|
|
61
|
-
molality = [0.3997, 0.992, 1.584, 2.373]
|
|
62
|
-
expected = [0.582, 0.4523, 0.3827, 0.3138]
|
|
63
|
-
|
|
64
|
-
for item in range(len(molality)):
|
|
65
|
-
s1 = pyEQL.Solution(
|
|
66
|
-
[
|
|
67
|
-
["Na+", str(0.75 * molality[item]) + "mol/kg"],
|
|
68
|
-
["K+", str(0.25 * molality[item]) + "mol/kg"],
|
|
69
|
-
["NO3-", str(molality[item]) + "mol/kg"],
|
|
70
|
-
]
|
|
71
|
-
)
|
|
72
|
-
result = s1.get_activity_coefficient("K+").magnitude
|
|
73
|
-
# print(result,expected[item])
|
|
74
|
-
self.assertWithinExperimentalError(result, expected[item], self.tol)
|
|
75
|
-
|
|
76
|
-
def test_activity_Na_XNa_50(self):
|
|
77
|
-
# test the activity coefficient of Na+ in mixed NaNO3 and KNO3 when the
|
|
78
|
-
# mole fraction of Na+ is 0.50
|
|
79
|
-
# molality refers to the total nitrate ion molality
|
|
80
|
-
molality = [0.4005, 0.9926, 1.787, 2.384]
|
|
81
|
-
expected = [0.6211, 0.5181, 0.4481, 0.4132]
|
|
82
|
-
|
|
83
|
-
for item in range(len(molality)):
|
|
84
|
-
s1 = pyEQL.Solution(
|
|
85
|
-
[
|
|
86
|
-
["Na+", str(0.5 * molality[item]) + "mol/kg"],
|
|
87
|
-
["K+", str(0.5 * molality[item]) + "mol/kg"],
|
|
88
|
-
["NO3-", str(molality[item]) + "mol/kg"],
|
|
89
|
-
]
|
|
90
|
-
)
|
|
91
|
-
result = s1.get_activity_coefficient("Na+").magnitude
|
|
92
|
-
# print(result,expected[item])
|
|
93
|
-
self.assertWithinExperimentalError(result, expected[item], self.tol)
|
|
94
|
-
|
|
95
|
-
def test_activity_K_XNa_50(self):
|
|
96
|
-
# test the activity coefficient of Na+ in mixed NaNO3 and KNO3 when the
|
|
97
|
-
# mole fraction of Na+ is 0.50
|
|
98
|
-
# molality refers to the total nitrate ion molality
|
|
99
|
-
molality = [0.4005, 0.9926, 1.787, 2.384]
|
|
100
|
-
expected = [0.582, 0.4529, 0.3635, 0.3133]
|
|
101
|
-
|
|
102
|
-
for item in range(len(molality)):
|
|
103
|
-
s1 = pyEQL.Solution(
|
|
104
|
-
[
|
|
105
|
-
["Na+", str(0.5 * molality[item]) + "mol/kg"],
|
|
106
|
-
["K+", str(0.5 * molality[item]) + "mol/kg"],
|
|
107
|
-
["NO3-", str(molality[item]) + "mol/kg"],
|
|
108
|
-
]
|
|
109
|
-
)
|
|
110
|
-
result = s1.get_activity_coefficient("K+").magnitude
|
|
111
|
-
# print(result,expected[item])
|
|
112
|
-
self.assertWithinExperimentalError(result, expected[item], self.tol)
|
|
113
|
-
|
|
114
|
-
def test_activity_Na_XNa_25(self):
|
|
115
|
-
# test the activity coefficient of Na+ in mixed NaNO3 and KNO3 when the
|
|
116
|
-
# mole fraction of Na+ is 0.25
|
|
117
|
-
# molality refers to the total nitrate ion molality
|
|
118
|
-
molality = [0.4021, 0.9976, 1.794, 2.393]
|
|
119
|
-
expected = [0.6293, 0.5327, 0.4680, 0.4364]
|
|
120
|
-
|
|
121
|
-
for item in range(len(molality)):
|
|
122
|
-
s1 = pyEQL.Solution(
|
|
123
|
-
[
|
|
124
|
-
["Na+", str(0.25 * molality[item]) + "mol/kg"],
|
|
125
|
-
["K+", str(0.75 * molality[item]) + "mol/kg"],
|
|
126
|
-
["NO3-", str(molality[item]) + "mol/kg"],
|
|
127
|
-
]
|
|
128
|
-
)
|
|
129
|
-
result = s1.get_activity_coefficient("Na+").magnitude
|
|
130
|
-
# print(result,expected[item])
|
|
131
|
-
self.assertWithinExperimentalError(result, expected[item], self.tol)
|
|
132
|
-
|
|
133
|
-
def test_activity_K_XNa_25(self):
|
|
134
|
-
# test the activity coefficient of Na+ in mixed NaNO3 and KNO3 when the
|
|
135
|
-
# mole fraction of Na+ is 0.25
|
|
136
|
-
# molality refers to the total nitrate ion molality
|
|
137
|
-
molality = [0.4021, 0.9976, 1.794, 2.393]
|
|
138
|
-
expected = [0.5942, 0.4731, 0.3878, 0.3370]
|
|
139
|
-
|
|
140
|
-
for item in range(len(molality)):
|
|
141
|
-
s1 = pyEQL.Solution(
|
|
142
|
-
[
|
|
143
|
-
["Na+", str(0.25 * molality[item]) + "mol/kg"],
|
|
144
|
-
["K+", str(0.75 * molality[item]) + "mol/kg"],
|
|
145
|
-
["NO3-", str(molality[item]) + "mol/kg"],
|
|
146
|
-
]
|
|
147
|
-
)
|
|
148
|
-
result = s1.get_activity_coefficient("K+").magnitude
|
|
149
|
-
# print(result,expected[item])
|
|
150
|
-
self.assertWithinExperimentalError(result, expected[item], self.tol)
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
if __name__ == "__main__":
|
|
154
|
-
unittest.main()
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
pyEQL osmotic coefficient test suite
|
|
3
|
-
============================================
|
|
4
|
-
|
|
5
|
-
This file contains tests for the osmotic coefficient method
|
|
6
|
-
employed by pyEQL.
|
|
7
|
-
|
|
8
|
-
NOTE: generally, these tests check the module output against experimental
|
|
9
|
-
data rather than the theoretical result of the respective functions.
|
|
10
|
-
"""
|
|
11
|
-
|
|
12
|
-
import pyEQL
|
|
13
|
-
import unittest
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
class Test_osmotic_pitzer(unittest.TestCase, pyEQL.CustomAssertions):
|
|
17
|
-
"""
|
|
18
|
-
test osmotic coefficient based on the Pitzer model
|
|
19
|
-
------------------------------------------------
|
|
20
|
-
|
|
21
|
-
"""
|
|
22
|
-
|
|
23
|
-
def setUp(self):
|
|
24
|
-
self.s1 = pyEQL.Solution([["Na+", "0.1 mol/L"], ["Cl-", "0.1 mol/L"]])
|
|
25
|
-
|
|
26
|
-
# relative error tolerance for assertWithinExperimentalError
|
|
27
|
-
self.tol = 0.05
|
|
28
|
-
|
|
29
|
-
def test_osmotic_pitzer_coeff_units(self):
|
|
30
|
-
# the osmotic coefficient should be dimensionless
|
|
31
|
-
result = self.s1.get_osmotic_coefficient().dimensionality
|
|
32
|
-
self.assertEqual(result, "")
|
|
33
|
-
|
|
34
|
-
def test_activity_pitzer_magnitude(self):
|
|
35
|
-
# the osmotic coefficient should be greater than zero
|
|
36
|
-
result = self.s1.get_osmotic_coefficient()
|
|
37
|
-
self.assertGreaterEqual(result, 0)
|
|
38
|
-
|
|
39
|
-
def test_osmotic_pitzer_ammoniumnitrate(self):
|
|
40
|
-
"""
|
|
41
|
-
calculate the osmotic coefficient at each concentration and compare
|
|
42
|
-
to experimental data for ammonium nitrate
|
|
43
|
-
|
|
44
|
-
References
|
|
45
|
-
----------
|
|
46
|
-
May, P. M., Rowland, D., Hefter, G., & Königsberger, E. (2011).
|
|
47
|
-
A Generic and Updatable Pitzer Characterization of Aqueous Binary Electrolyte Solutions at 1 bar and 25 °C.
|
|
48
|
-
Journal of Chemical & Engineering Data, 56(12), 5066–5077. doi:10.1021/je2009329
|
|
49
|
-
|
|
50
|
-
"""
|
|
51
|
-
# list of concentrations to test, mol/kg
|
|
52
|
-
conc_list = [0.25, 0.5, 0.75, 1, 1.5, 2]
|
|
53
|
-
|
|
54
|
-
# list of published experimental osmotic coefficients
|
|
55
|
-
pub_osmotic_coeff = [0.86, 0.855, 0.83, 0.825, 0.80, 0.78]
|
|
56
|
-
|
|
57
|
-
for i in range(len(conc_list)):
|
|
58
|
-
with self.subTest(conc=conc_list[i]):
|
|
59
|
-
conc = str(conc_list[i]) + "mol/kg"
|
|
60
|
-
sol = pyEQL.Solution()
|
|
61
|
-
sol.add_solute("NH4+", conc)
|
|
62
|
-
sol.add_solute("NO3-", conc)
|
|
63
|
-
result = sol.get_osmotic_coefficient()
|
|
64
|
-
expected = pub_osmotic_coeff[i]
|
|
65
|
-
|
|
66
|
-
self.assertWithinExperimentalError(result, expected, self.tol)
|
|
67
|
-
|
|
68
|
-
def test_osmotic_pitzer_coppersulfate(self):
|
|
69
|
-
"""
|
|
70
|
-
calculate the osmotic coefficient at each concentration and compare
|
|
71
|
-
to experimental data for copper sulate
|
|
72
|
-
|
|
73
|
-
References
|
|
74
|
-
----------
|
|
75
|
-
May, P. M., Rowland, D., Hefter, G., & Königsberger, E. (2011).
|
|
76
|
-
A Generic and Updatable Pitzer Characterization of Aqueous Binary Electrolyte Solutions at 1 bar and 25 °C.
|
|
77
|
-
Journal of Chemical & Engineering Data, 56(12), 5066–5077. doi:10.1021/je2009329
|
|
78
|
-
|
|
79
|
-
"""
|
|
80
|
-
# list of concentrations to test, mol/kg
|
|
81
|
-
conc_list = [0.25, 0.5, 0.75, 1]
|
|
82
|
-
|
|
83
|
-
# list of published experimental osmotic coefficients
|
|
84
|
-
pub_osmotic_coeff = [0.5, 0.485, 0.48, 0.485, 0.5]
|
|
85
|
-
|
|
86
|
-
for i in range(len(conc_list)):
|
|
87
|
-
with self.subTest(conc=conc_list[i]):
|
|
88
|
-
conc = str(conc_list[i]) + "mol/kg"
|
|
89
|
-
sol = pyEQL.Solution()
|
|
90
|
-
sol.add_solute("Cu+2", conc)
|
|
91
|
-
sol.add_solute("SO4-2", conc)
|
|
92
|
-
result = sol.get_osmotic_coefficient()
|
|
93
|
-
expected = pub_osmotic_coeff[i]
|
|
94
|
-
|
|
95
|
-
self.assertWithinExperimentalError(result, expected, self.tol)
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
if __name__ == "__main__":
|
|
99
|
-
unittest.main()
|