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,337 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
pyEQL salt matching test suite
|
|
3
|
-
==============================
|
|
4
|
-
|
|
5
|
-
This file contains tests for the salt-matching algorithm used by pyEQL in
|
|
6
|
-
salt_ion_match.py
|
|
7
|
-
"""
|
|
8
|
-
|
|
9
|
-
import pyEQL
|
|
10
|
-
import unittest
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class Test_empty_solution(unittest.TestCase, pyEQL.CustomAssertions):
|
|
14
|
-
"""
|
|
15
|
-
test matching a solution that contains no solutes other than water
|
|
16
|
-
|
|
17
|
-
"""
|
|
18
|
-
|
|
19
|
-
# simple case - single-salt
|
|
20
|
-
def setUp(self):
|
|
21
|
-
self.s1 = pyEQL.Solution()
|
|
22
|
-
|
|
23
|
-
# The return type should be a salt object
|
|
24
|
-
def test_salt_type(self):
|
|
25
|
-
result = self.s1.get_salt()
|
|
26
|
-
expected = pyEQL.salt_ion_match.Salt
|
|
27
|
-
|
|
28
|
-
self.assertIsInstance(result, expected)
|
|
29
|
-
|
|
30
|
-
# The salt should be 'HOH'
|
|
31
|
-
def test_salt_formula(self):
|
|
32
|
-
result = self.s1.get_salt().formula
|
|
33
|
-
expected = "HOH"
|
|
34
|
-
|
|
35
|
-
self.assertEqual(result, expected)
|
|
36
|
-
|
|
37
|
-
# The cation should be 'Na+'
|
|
38
|
-
def test_salt_cation(self):
|
|
39
|
-
result = self.s1.get_salt().cation
|
|
40
|
-
expected = "H+"
|
|
41
|
-
|
|
42
|
-
self.assertEqual(result, expected)
|
|
43
|
-
|
|
44
|
-
# The anion should be 'Cl-'
|
|
45
|
-
def test_salt_anion(self):
|
|
46
|
-
result = self.s1.get_salt().anion
|
|
47
|
-
expected = "OH-"
|
|
48
|
-
|
|
49
|
-
self.assertEqual(result, expected)
|
|
50
|
-
|
|
51
|
-
# The cation coefficient should be 1
|
|
52
|
-
def test_salt_nu_cation(self):
|
|
53
|
-
result = self.s1.get_salt().nu_cation
|
|
54
|
-
expected = 1
|
|
55
|
-
|
|
56
|
-
self.assertEqual(result, expected)
|
|
57
|
-
|
|
58
|
-
# The anion coefficient should be 1
|
|
59
|
-
def test_salt_nu_anion(self):
|
|
60
|
-
result = self.s1.get_salt().nu_anion
|
|
61
|
-
expected = 1
|
|
62
|
-
|
|
63
|
-
self.assertEqual(result, expected)
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
class Test_single_salt_mono(unittest.TestCase, pyEQL.CustomAssertions):
|
|
67
|
-
"""
|
|
68
|
-
test matching a solution with a single monovalent salt
|
|
69
|
-
------------------------------------------------
|
|
70
|
-
|
|
71
|
-
"""
|
|
72
|
-
|
|
73
|
-
# simple case - single-salt
|
|
74
|
-
def setUp(self):
|
|
75
|
-
self.s1 = pyEQL.Solution([["Na+", "2 mol/L"], ["Cl-", "2 mol/L"]])
|
|
76
|
-
|
|
77
|
-
# The return type should be a salt object
|
|
78
|
-
def test_salt_type(self):
|
|
79
|
-
result = self.s1.get_salt()
|
|
80
|
-
expected = pyEQL.salt_ion_match.Salt
|
|
81
|
-
|
|
82
|
-
self.assertIsInstance(result, expected)
|
|
83
|
-
|
|
84
|
-
# The salt should be 'NaCl'
|
|
85
|
-
def test_salt_formula(self):
|
|
86
|
-
result = self.s1.get_salt().formula
|
|
87
|
-
expected = "NaCl"
|
|
88
|
-
|
|
89
|
-
self.assertEqual(result, expected)
|
|
90
|
-
|
|
91
|
-
# The cation should be 'Na+'
|
|
92
|
-
def test_salt_cation(self):
|
|
93
|
-
result = self.s1.get_salt().cation
|
|
94
|
-
expected = "Na+"
|
|
95
|
-
|
|
96
|
-
self.assertEqual(result, expected)
|
|
97
|
-
|
|
98
|
-
# The anion should be 'Cl-'
|
|
99
|
-
def test_salt_anion(self):
|
|
100
|
-
result = self.s1.get_salt().anion
|
|
101
|
-
expected = "Cl-"
|
|
102
|
-
|
|
103
|
-
self.assertEqual(result, expected)
|
|
104
|
-
|
|
105
|
-
# The cation coefficient should be 1
|
|
106
|
-
def test_salt_nu_cation(self):
|
|
107
|
-
result = self.s1.get_salt().nu_cation
|
|
108
|
-
expected = 1
|
|
109
|
-
|
|
110
|
-
self.assertEqual(result, expected)
|
|
111
|
-
|
|
112
|
-
# The anion coefficient should be 1
|
|
113
|
-
def test_salt_nu_anion(self):
|
|
114
|
-
result = self.s1.get_salt().nu_anion
|
|
115
|
-
expected = 1
|
|
116
|
-
|
|
117
|
-
self.assertEqual(result, expected)
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
class Test_single_salt_di(unittest.TestCase, pyEQL.CustomAssertions):
|
|
121
|
-
"""
|
|
122
|
-
test matching a solution with a single divalent salt
|
|
123
|
-
------------------------------------------------
|
|
124
|
-
|
|
125
|
-
"""
|
|
126
|
-
|
|
127
|
-
# simple case - single-salt
|
|
128
|
-
def setUp(self):
|
|
129
|
-
self.s1 = pyEQL.Solution([["Na+", "4 mol/L"], ["SO4-2", "2 mol/L"]])
|
|
130
|
-
|
|
131
|
-
# The return type should be a salt object
|
|
132
|
-
def test_salt_type(self):
|
|
133
|
-
result = self.s1.get_salt()
|
|
134
|
-
expected = pyEQL.salt_ion_match.Salt
|
|
135
|
-
|
|
136
|
-
self.assertIsInstance(result, expected)
|
|
137
|
-
|
|
138
|
-
# The salt should be 'Na2SO4'
|
|
139
|
-
def test_salt_formula(self):
|
|
140
|
-
result = self.s1.get_salt().formula
|
|
141
|
-
expected = "Na2SO4"
|
|
142
|
-
|
|
143
|
-
self.assertEqual(result, expected)
|
|
144
|
-
|
|
145
|
-
# The cation should be 'Na+'
|
|
146
|
-
def test_salt_cation(self):
|
|
147
|
-
result = self.s1.get_salt().cation
|
|
148
|
-
expected = "Na+"
|
|
149
|
-
|
|
150
|
-
self.assertEqual(result, expected)
|
|
151
|
-
|
|
152
|
-
# The anion should be 'SO4-2'
|
|
153
|
-
def test_salt_anion(self):
|
|
154
|
-
result = self.s1.get_salt().anion
|
|
155
|
-
expected = "SO4-2"
|
|
156
|
-
|
|
157
|
-
self.assertEqual(result, expected)
|
|
158
|
-
|
|
159
|
-
# The cation coefficient should be 2
|
|
160
|
-
def test_salt_nu_cation(self):
|
|
161
|
-
result = self.s1.get_salt().nu_cation
|
|
162
|
-
expected = 2
|
|
163
|
-
|
|
164
|
-
self.assertEqual(result, expected)
|
|
165
|
-
|
|
166
|
-
# The anion coefficient should be 1
|
|
167
|
-
def test_salt_nu_anion(self):
|
|
168
|
-
result = self.s1.get_salt().nu_anion
|
|
169
|
-
expected = 1
|
|
170
|
-
|
|
171
|
-
self.assertEqual(result, expected)
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
class Test_single_salt_di2(unittest.TestCase, pyEQL.CustomAssertions):
|
|
175
|
-
"""
|
|
176
|
-
test matching a solution with a single divalent salt
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
"""
|
|
180
|
-
|
|
181
|
-
# simple case - single-salt
|
|
182
|
-
def setUp(self):
|
|
183
|
-
self.s1 = pyEQL.Solution([["Fe+3", "1 mol/L"], ["Cl-", "3 mol/L"]])
|
|
184
|
-
|
|
185
|
-
# The return type should be a salt object
|
|
186
|
-
def test_salt_type(self):
|
|
187
|
-
result = self.s1.get_salt()
|
|
188
|
-
expected = pyEQL.salt_ion_match.Salt
|
|
189
|
-
|
|
190
|
-
self.assertIsInstance(result, expected)
|
|
191
|
-
|
|
192
|
-
# The salt should be 'FeCl3'
|
|
193
|
-
def test_salt_formula(self):
|
|
194
|
-
result = self.s1.get_salt().formula
|
|
195
|
-
expected = "FeCl3"
|
|
196
|
-
|
|
197
|
-
self.assertEqual(result, expected)
|
|
198
|
-
|
|
199
|
-
# The cation should be 'Fe+3+'
|
|
200
|
-
def test_salt_cation(self):
|
|
201
|
-
result = self.s1.get_salt().cation
|
|
202
|
-
expected = "Fe+3"
|
|
203
|
-
|
|
204
|
-
self.assertEqual(result, expected)
|
|
205
|
-
|
|
206
|
-
# The anion should be 'Cl-'
|
|
207
|
-
def test_salt_anion(self):
|
|
208
|
-
result = self.s1.get_salt().anion
|
|
209
|
-
expected = "Cl-"
|
|
210
|
-
|
|
211
|
-
self.assertEqual(result, expected)
|
|
212
|
-
|
|
213
|
-
# The cation coefficient should be 1
|
|
214
|
-
def test_salt_nu_cation(self):
|
|
215
|
-
result = self.s1.get_salt().nu_cation
|
|
216
|
-
expected = 1
|
|
217
|
-
|
|
218
|
-
self.assertEqual(result, expected)
|
|
219
|
-
|
|
220
|
-
# The anion coefficient should be 3
|
|
221
|
-
def test_salt_nu_anion(self):
|
|
222
|
-
result = self.s1.get_salt().nu_anion
|
|
223
|
-
expected = 3
|
|
224
|
-
|
|
225
|
-
self.assertEqual(result, expected)
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
class Test_single_ion(unittest.TestCase, pyEQL.CustomAssertions):
|
|
229
|
-
"""
|
|
230
|
-
test matching a solution containing only a single ion
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
"""
|
|
234
|
-
|
|
235
|
-
# simple case - single-salt
|
|
236
|
-
def setUp(self):
|
|
237
|
-
self.s1 = pyEQL.Solution([["Fe+3", "1 mol/L"]])
|
|
238
|
-
|
|
239
|
-
# The return type should be a salt object
|
|
240
|
-
def test_salt_type(self):
|
|
241
|
-
result = self.s1.get_salt()
|
|
242
|
-
expected = pyEQL.salt_ion_match.Salt
|
|
243
|
-
|
|
244
|
-
self.assertIsInstance(result, expected)
|
|
245
|
-
|
|
246
|
-
# The salt should be 'Fe(OH)3'
|
|
247
|
-
def test_salt_formula(self):
|
|
248
|
-
result = self.s1.get_salt().formula
|
|
249
|
-
expected = "Fe(OH)3"
|
|
250
|
-
|
|
251
|
-
self.assertEqual(result, expected)
|
|
252
|
-
|
|
253
|
-
# The cation should be 'Fe+3'
|
|
254
|
-
def test_salt_cation(self):
|
|
255
|
-
result = self.s1.get_salt().cation
|
|
256
|
-
expected = "Fe+3"
|
|
257
|
-
|
|
258
|
-
self.assertEqual(result, expected)
|
|
259
|
-
|
|
260
|
-
# The anion should be 'OH-'
|
|
261
|
-
def test_salt_anion(self):
|
|
262
|
-
result = self.s1.get_salt().anion
|
|
263
|
-
expected = "OH-"
|
|
264
|
-
|
|
265
|
-
self.assertEqual(result, expected)
|
|
266
|
-
|
|
267
|
-
# The cation coefficient should be 1
|
|
268
|
-
def test_salt_nu_cation(self):
|
|
269
|
-
result = self.s1.get_salt().nu_cation
|
|
270
|
-
expected = 1
|
|
271
|
-
|
|
272
|
-
self.assertEqual(result, expected)
|
|
273
|
-
|
|
274
|
-
# The anion coefficient should be 3
|
|
275
|
-
def test_salt_nu_anion(self):
|
|
276
|
-
result = self.s1.get_salt().nu_anion
|
|
277
|
-
expected = 3
|
|
278
|
-
|
|
279
|
-
self.assertEqual(result, expected)
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
class Test_salt_asymmetric(unittest.TestCase, pyEQL.CustomAssertions):
|
|
283
|
-
"""
|
|
284
|
-
test matching a solution where the cation and anion concentrations
|
|
285
|
-
are not equal
|
|
286
|
-
|
|
287
|
-
"""
|
|
288
|
-
|
|
289
|
-
# simple case - single-salt
|
|
290
|
-
def setUp(self):
|
|
291
|
-
self.s1 = pyEQL.Solution([["Na+", "1 mol/kg"], ["Cl-", "4 mol/kg"]])
|
|
292
|
-
|
|
293
|
-
# The return type should be a salt object
|
|
294
|
-
def test_salt_type(self):
|
|
295
|
-
result = self.s1.get_salt()
|
|
296
|
-
expected = pyEQL.salt_ion_match.Salt
|
|
297
|
-
|
|
298
|
-
self.assertIsInstance(result, expected)
|
|
299
|
-
|
|
300
|
-
# The salt should be 'NaCl'
|
|
301
|
-
def test_salt_formula(self):
|
|
302
|
-
result = self.s1.get_salt().formula
|
|
303
|
-
expected = "NaCl"
|
|
304
|
-
|
|
305
|
-
self.assertEqual(result, expected)
|
|
306
|
-
|
|
307
|
-
# The cation should be 'Na+'
|
|
308
|
-
def test_salt_cation(self):
|
|
309
|
-
result = self.s1.get_salt().cation
|
|
310
|
-
expected = "Na+"
|
|
311
|
-
|
|
312
|
-
self.assertEqual(result, expected)
|
|
313
|
-
|
|
314
|
-
# The anion should be 'Cl-'
|
|
315
|
-
def test_salt_anion(self):
|
|
316
|
-
result = self.s1.get_salt().anion
|
|
317
|
-
expected = "Cl-"
|
|
318
|
-
|
|
319
|
-
self.assertEqual(result, expected)
|
|
320
|
-
|
|
321
|
-
# The cation coefficient should be 1
|
|
322
|
-
def test_salt_nu_cation(self):
|
|
323
|
-
result = self.s1.get_salt().nu_cation
|
|
324
|
-
expected = 1
|
|
325
|
-
|
|
326
|
-
self.assertEqual(result, expected)
|
|
327
|
-
|
|
328
|
-
# The anion coefficient should be 1
|
|
329
|
-
def test_salt_nu_anion(self):
|
|
330
|
-
result = self.s1.get_salt().nu_anion
|
|
331
|
-
expected = 1
|
|
332
|
-
|
|
333
|
-
self.assertEqual(result, expected)
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
if __name__ == "__main__":
|
|
337
|
-
unittest.main()
|
|
@@ -1,251 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
pyEQL solute properties test suite
|
|
3
|
-
============================================
|
|
4
|
-
|
|
5
|
-
This file contains tests of the Solution class methods that retrieve or
|
|
6
|
-
calculate properties of individual solutes. Methods currently included
|
|
7
|
-
in the testing are:
|
|
8
|
-
|
|
9
|
-
- get_transport_number()
|
|
10
|
-
- get_molar_conductivity()
|
|
11
|
-
- get_mobility()
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
"""
|
|
15
|
-
|
|
16
|
-
import pyEQL
|
|
17
|
-
import unittest
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
class Test_transport_number(unittest.TestCase, pyEQL.CustomAssertions):
|
|
21
|
-
"""
|
|
22
|
-
test get_transport_number
|
|
23
|
-
------------------------------------------------
|
|
24
|
-
"""
|
|
25
|
-
|
|
26
|
-
# create a test solution
|
|
27
|
-
def setUp(self):
|
|
28
|
-
self.s1 = pyEQL.Solution(
|
|
29
|
-
[["K+", "0.1 mol/L"], ["Cl-", "0.1 mol/L"], ["FeO", "0.2 mol/L"]]
|
|
30
|
-
)
|
|
31
|
-
|
|
32
|
-
# The transport number of any ion should be between 0 and 1
|
|
33
|
-
def test_transport_number_1(self):
|
|
34
|
-
actual = self.s1.get_transport_number("K+")
|
|
35
|
-
|
|
36
|
-
self.assertTrue((0 <= actual) and (actual <= 1))
|
|
37
|
-
|
|
38
|
-
# The transport number of water should be 0
|
|
39
|
-
def test_transport_number_2(self):
|
|
40
|
-
actual = self.s1.get_transport_number("H2O")
|
|
41
|
-
|
|
42
|
-
self.assertEqual(actual.magnitude, 0)
|
|
43
|
-
|
|
44
|
-
# The transport number of any uncharged species should be 0
|
|
45
|
-
def test_transport_number_3(self):
|
|
46
|
-
actual = self.s1.get_transport_number("FeO")
|
|
47
|
-
|
|
48
|
-
self.assertEqual(actual.magnitude, 0)
|
|
49
|
-
|
|
50
|
-
# The transport numbers should add up to 1
|
|
51
|
-
def test_transport_number_4(self):
|
|
52
|
-
total_t = 0
|
|
53
|
-
for item in self.s1.components:
|
|
54
|
-
total_t += self.s1.get_transport_number(item)
|
|
55
|
-
|
|
56
|
-
self.assertAlmostEqual(total_t.magnitude, 1)
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
class Test_molar_conductivity(unittest.TestCase, pyEQL.CustomAssertions):
|
|
60
|
-
"""
|
|
61
|
-
test get_molar_conductivity
|
|
62
|
-
|
|
63
|
-
Published molar conductivity values at 25 degC and infinite dilution
|
|
64
|
-
are found in CRC Handbook of Chemistry and Physics, 92nd ed., 2011.
|
|
65
|
-
|
|
66
|
-
This reference is also the source of diffusion coefficient data
|
|
67
|
-
in the default database, so the values molar conductivity (which
|
|
68
|
-
is calculated from the diffusion coefficient) should match.
|
|
69
|
-
----------------------------------------------------------------
|
|
70
|
-
"""
|
|
71
|
-
|
|
72
|
-
# relative error tolerance for assertWithinExperimentalError
|
|
73
|
-
def setUp(self):
|
|
74
|
-
self.tol = 0.05
|
|
75
|
-
|
|
76
|
-
def test_molar_conductivity_potassium(self):
|
|
77
|
-
# K+ - 73.48 x 10 ** -4 m ** 2 S / mol
|
|
78
|
-
self.s1 = pyEQL.Solution(
|
|
79
|
-
[["K+", "0.001 mol/L"], ["Cl-", "0.001 mol/L"]], temperature="25 degC"
|
|
80
|
-
)
|
|
81
|
-
result = self.s1.get_molar_conductivity("K+").to("m**2*S/mol").magnitude
|
|
82
|
-
expected = pyEQL.unit("73.48e-4 m**2 * S / mol").magnitude
|
|
83
|
-
|
|
84
|
-
self.assertWithinExperimentalError(result, expected, self.tol)
|
|
85
|
-
|
|
86
|
-
def test_molar_conductivity_sodium(self):
|
|
87
|
-
# Na+ - 50.08 x 10 ** -4 m ** 2 S / mol
|
|
88
|
-
self.s1 = pyEQL.Solution(
|
|
89
|
-
[["Na+", "0.001 mol/L"], ["Cl-", "0.001 mol/L"]], temperature="25 degC"
|
|
90
|
-
)
|
|
91
|
-
result = self.s1.get_molar_conductivity("Na+").to("m**2*S/mol").magnitude
|
|
92
|
-
expected = pyEQL.unit("50.08e-4 m**2 * S / mol").magnitude
|
|
93
|
-
|
|
94
|
-
self.assertWithinExperimentalError(result, expected, self.tol)
|
|
95
|
-
|
|
96
|
-
def test_molar_conductivity_magnesium(self):
|
|
97
|
-
# Mg+2 - 106 x 10 ** -4 m ** 2 S / mol
|
|
98
|
-
self.s1 = pyEQL.Solution(
|
|
99
|
-
[["Mg+2", "0.001 mol/L"], ["Cl-", "0.002 mol/L"]], temperature="25 degC"
|
|
100
|
-
)
|
|
101
|
-
result = self.s1.get_molar_conductivity("Mg+2").to("m**2*S/mol").magnitude
|
|
102
|
-
expected = pyEQL.unit("106e-4 m**2 * S / mol").magnitude
|
|
103
|
-
|
|
104
|
-
self.assertWithinExperimentalError(result, expected, self.tol)
|
|
105
|
-
|
|
106
|
-
def test_molar_conductivity_chloride(self):
|
|
107
|
-
# Cl- - 76.31 x 10 ** -4 m ** 2 S / mol
|
|
108
|
-
self.s1 = pyEQL.Solution(
|
|
109
|
-
[["Na+", "0.001 mol/L"], ["Cl-", "0.001 mol/L"]], temperature="25 degC"
|
|
110
|
-
)
|
|
111
|
-
result = self.s1.get_molar_conductivity("Cl-").to("m**2*S/mol").magnitude
|
|
112
|
-
expected = pyEQL.unit("76.31e-4 m**2 * S / mol").magnitude
|
|
113
|
-
|
|
114
|
-
self.assertWithinExperimentalError(result, expected, self.tol)
|
|
115
|
-
|
|
116
|
-
def test_molar_conductivity_fluoride(self):
|
|
117
|
-
# F- - 55.4 x 10 ** -4 m ** 2 S / mol
|
|
118
|
-
self.s1 = pyEQL.Solution(
|
|
119
|
-
[["Na+", "0.001 mol/L"], ["F-", "0.001 mol/L"]], temperature="25 degC"
|
|
120
|
-
)
|
|
121
|
-
result = self.s1.get_molar_conductivity("F-").to("m**2*S/mol").magnitude
|
|
122
|
-
expected = pyEQL.unit("55.4e-4 m**2 * S / mol").magnitude
|
|
123
|
-
|
|
124
|
-
self.assertWithinExperimentalError(result, expected, self.tol)
|
|
125
|
-
|
|
126
|
-
def test_molar_conductivity_sulfate(self):
|
|
127
|
-
# SO4-2 - 160 x 10 ** -4 m ** 2 S / mol
|
|
128
|
-
self.s1 = pyEQL.Solution(
|
|
129
|
-
[["Na+", "0.002 mol/L"], ["SO4-2", "0.001 mol/L"]], temperature="25 degC"
|
|
130
|
-
)
|
|
131
|
-
result = self.s1.get_molar_conductivity("SO4-2").to("m**2*S/mol").magnitude
|
|
132
|
-
expected = pyEQL.unit("160.0e-4 m**2 * S / mol").magnitude
|
|
133
|
-
|
|
134
|
-
self.assertWithinExperimentalError(result, expected, self.tol)
|
|
135
|
-
|
|
136
|
-
def test_molar_conductivity_hydroxide(self):
|
|
137
|
-
# OH- - 198 x 10 ** -4 m ** 2 S / mol
|
|
138
|
-
self.s1 = pyEQL.Solution(temperature="25 degC")
|
|
139
|
-
result = self.s1.get_molar_conductivity("OH-").to("m**2*S/mol").magnitude
|
|
140
|
-
expected = pyEQL.unit("198e-4 m**2 * S / mol").magnitude
|
|
141
|
-
|
|
142
|
-
self.assertWithinExperimentalError(result, expected, self.tol)
|
|
143
|
-
|
|
144
|
-
def test_molar_conductivity_hydrogen(self):
|
|
145
|
-
# H+ - 349.65 x 10 ** -4 m ** 2 S / mol
|
|
146
|
-
self.s1 = pyEQL.Solution(temperature="25 degC")
|
|
147
|
-
result = self.s1.get_molar_conductivity("H+").to("m**2*S/mol").magnitude
|
|
148
|
-
expected = pyEQL.unit("349.65e-4 m**2 * S / mol").magnitude
|
|
149
|
-
|
|
150
|
-
self.assertWithinExperimentalError(result, expected, self.tol)
|
|
151
|
-
|
|
152
|
-
# molar conductivity of a neutral solute should be zero
|
|
153
|
-
def test_molar_conductivity_neutral(self):
|
|
154
|
-
self.s1 = pyEQL.Solution([["FeCl3", "0.001 mol/L"]], temperature="25 degC")
|
|
155
|
-
result = self.s1.get_molar_conductivity("FeCl3").to("m**2*S/mol").magnitude
|
|
156
|
-
expected = pyEQL.unit("0 m**2 * S / mol").magnitude
|
|
157
|
-
|
|
158
|
-
self.assertAlmostEqual(result, expected, 5)
|
|
159
|
-
|
|
160
|
-
# molar conductivity of water should be zero
|
|
161
|
-
def test_molar_conductivity_water(self):
|
|
162
|
-
self.s1 = pyEQL.Solution(temperature="25 degC")
|
|
163
|
-
result = self.s1.get_molar_conductivity("H2O").to("m**2*S/mol").magnitude
|
|
164
|
-
expected = pyEQL.unit("0 m**2 * S / mol").magnitude
|
|
165
|
-
|
|
166
|
-
self.assertAlmostEqual(result, expected, 5)
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
class Test_mobility(unittest.TestCase, pyEQL.CustomAssertions):
|
|
170
|
-
"""
|
|
171
|
-
test get_mobility
|
|
172
|
-
|
|
173
|
-
Since the mobility is simply the molar conductivity divided by
|
|
174
|
-
Faraday's constant and the ion charge, and we have already
|
|
175
|
-
tested get_molar_conductivity, here we only do a couple of tests
|
|
176
|
-
to make sure get_mobility returns a value that is correctly
|
|
177
|
-
scaled related to get_molar_conductivity
|
|
178
|
-
----------------------------------------------------------------
|
|
179
|
-
"""
|
|
180
|
-
|
|
181
|
-
# relative error tolerance for assertWithinExperimentalError
|
|
182
|
-
def setUp(self):
|
|
183
|
-
self.tol = 0.05
|
|
184
|
-
|
|
185
|
-
def test_mobility_potassium(self):
|
|
186
|
-
self.s1 = pyEQL.Solution(
|
|
187
|
-
[["K+", "0.001 mol/L"], ["Cl-", "0.001 mol/L"]], temperature="25 degC"
|
|
188
|
-
)
|
|
189
|
-
molar_conductivity = self.s1.get_molar_conductivity("K+").to("m**2*S/mol")
|
|
190
|
-
expected = self.s1.get_mobility("K+").to("m**2/s/V").magnitude
|
|
191
|
-
charge = self.s1.get_solute("K+").get_formal_charge()
|
|
192
|
-
# calculate the mobility from get_molar_conductivity, then compare with get_mobility
|
|
193
|
-
result = (
|
|
194
|
-
(molar_conductivity / (pyEQL.unit.N_A * pyEQL.unit.e * abs(charge)))
|
|
195
|
-
.to("m**2/s/V")
|
|
196
|
-
.magnitude
|
|
197
|
-
)
|
|
198
|
-
|
|
199
|
-
self.assertWithinExperimentalError(result, expected, self.tol)
|
|
200
|
-
|
|
201
|
-
def test_mobility_chloride(self):
|
|
202
|
-
self.s1 = pyEQL.Solution(
|
|
203
|
-
[["K+", "0.001 mol/L"], ["Cl-", "0.001 mol/L"]], temperature="25 degC"
|
|
204
|
-
)
|
|
205
|
-
molar_conductivity = self.s1.get_molar_conductivity("Cl-").to("m**2*S/mol")
|
|
206
|
-
expected = self.s1.get_mobility("Cl-").to("m**2/s/V").magnitude
|
|
207
|
-
charge = self.s1.get_solute("Cl-").get_formal_charge()
|
|
208
|
-
# calculate the mobility from get_molar_conductivity, then compare with get_mobility
|
|
209
|
-
result = (
|
|
210
|
-
(molar_conductivity / (pyEQL.unit.N_A * pyEQL.unit.e * abs(charge)))
|
|
211
|
-
.to("m**2/s/V")
|
|
212
|
-
.magnitude
|
|
213
|
-
)
|
|
214
|
-
|
|
215
|
-
self.assertWithinExperimentalError(result, expected, self.tol)
|
|
216
|
-
|
|
217
|
-
def test_mobility_magnesium(self):
|
|
218
|
-
self.s1 = pyEQL.Solution(
|
|
219
|
-
[["Mg+2", "0.001 mol/L"], ["Cl-", "0.002 mol/L"]], temperature="25 degC"
|
|
220
|
-
)
|
|
221
|
-
molar_conductivity = self.s1.get_molar_conductivity("Mg+2").to("m**2*S/mol")
|
|
222
|
-
expected = self.s1.get_mobility("Mg+2").to("m**2/s/V").magnitude
|
|
223
|
-
charge = self.s1.get_solute("Mg+2").get_formal_charge()
|
|
224
|
-
# calculate the mobility from get_molar_conductivity, then compare with get_mobility
|
|
225
|
-
result = (
|
|
226
|
-
(molar_conductivity / (pyEQL.unit.N_A * pyEQL.unit.e * abs(charge)))
|
|
227
|
-
.to("m**2/s/V")
|
|
228
|
-
.magnitude
|
|
229
|
-
)
|
|
230
|
-
|
|
231
|
-
self.assertWithinExperimentalError(result, expected, self.tol)
|
|
232
|
-
|
|
233
|
-
def test_mobility_sulfate(self):
|
|
234
|
-
self.s1 = pyEQL.Solution(
|
|
235
|
-
[["K+", "0.002 mol/L"], ["SO4-2", "0.001 mol/L"]], temperature="25 degC"
|
|
236
|
-
)
|
|
237
|
-
molar_conductivity = self.s1.get_molar_conductivity("SO4-2").to("m**2*S/mol")
|
|
238
|
-
expected = self.s1.get_mobility("SO4-2").to("m**2/s/V").magnitude
|
|
239
|
-
charge = self.s1.get_solute("SO4-2").get_formal_charge()
|
|
240
|
-
# calculate the mobility from get_molar_conductivity, then compare with get_mobility
|
|
241
|
-
result = (
|
|
242
|
-
(molar_conductivity / (pyEQL.unit.N_A * pyEQL.unit.e * abs(charge)))
|
|
243
|
-
.to("m**2/s/V")
|
|
244
|
-
.magnitude
|
|
245
|
-
)
|
|
246
|
-
|
|
247
|
-
self.assertWithinExperimentalError(result, expected, self.tol)
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
if __name__ == "__main__":
|
|
251
|
-
unittest.main()
|