pyEQL 0.15.1__py2.py3-none-any.whl → 1.0.1__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 +9 -1
- pyEQL/activity_correction.py +24 -21
- pyEQL/engines.py +56 -42
- pyEQL/equilibrium.py +18 -12
- pyEQL/functions.py +8 -161
- pyEQL/salt_ion_match.py +1 -0
- pyEQL/solute.py +3 -0
- pyEQL/solution.py +189 -763
- pyEQL/utils.py +3 -0
- {pyEQL-0.15.1.dist-info → pyEQL-1.0.1.dist-info}/METADATA +9 -10
- pyEQL-1.0.1.dist-info/RECORD +27 -0
- pyEQL/logging_system.py +0 -78
- pyEQL-0.15.1.dist-info/RECORD +0 -28
- {pyEQL-0.15.1.dist-info → pyEQL-1.0.1.dist-info}/AUTHORS.md +0 -0
- {pyEQL-0.15.1.dist-info → pyEQL-1.0.1.dist-info}/COPYING +0 -0
- {pyEQL-0.15.1.dist-info → pyEQL-1.0.1.dist-info}/LICENSE.txt +0 -0
- {pyEQL-0.15.1.dist-info → pyEQL-1.0.1.dist-info}/WHEEL +0 -0
- {pyEQL-0.15.1.dist-info → pyEQL-1.0.1.dist-info}/top_level.txt +0 -0
pyEQL/functions.py
CHANGED
|
@@ -5,13 +5,14 @@ pyEQL functions that take Solution objects as inputs or return Solution objects.
|
|
|
5
5
|
:license: LGPL, see LICENSE for more details.
|
|
6
6
|
|
|
7
7
|
"""
|
|
8
|
-
import math
|
|
9
|
-
from typing import Literal
|
|
10
8
|
|
|
11
|
-
|
|
9
|
+
import logging
|
|
10
|
+
|
|
11
|
+
import numpy as np
|
|
12
12
|
|
|
13
13
|
from pyEQL import Solution, ureg
|
|
14
|
-
|
|
14
|
+
|
|
15
|
+
logger = logging.getLogger(__name__)
|
|
15
16
|
|
|
16
17
|
|
|
17
18
|
def gibbs_mix(solution1: Solution, solution2: Solution):
|
|
@@ -55,7 +56,7 @@ def gibbs_mix(solution1: Solution, solution2: Solution):
|
|
|
55
56
|
for solution in term_list:
|
|
56
57
|
for solute in solution.components:
|
|
57
58
|
if solution.get_amount(solute, "fraction") != 0:
|
|
58
|
-
term_list[solution] += solution.get_amount(solute, "mol") *
|
|
59
|
+
term_list[solution] += solution.get_amount(solute, "mol") * np.log(solution.get_activity(solute))
|
|
59
60
|
|
|
60
61
|
return (ureg.R * blend.temperature.to("K") * (term_list[blend] - term_list[concentrate] - term_list[dilute])).to(
|
|
61
62
|
"J"
|
|
@@ -102,7 +103,7 @@ def entropy_mix(solution1: Solution, solution2: Solution):
|
|
|
102
103
|
for solution in term_list:
|
|
103
104
|
for solute in solution.components:
|
|
104
105
|
if solution.get_amount(solute, "fraction") != 0:
|
|
105
|
-
term_list[solution] += solution.get_amount(solute, "mol") *
|
|
106
|
+
term_list[solution] += solution.get_amount(solute, "mol") * np.log(
|
|
106
107
|
solution.get_amount(solute, "fraction")
|
|
107
108
|
)
|
|
108
109
|
|
|
@@ -242,7 +243,7 @@ def donnan_eql(solution: Solution, fixed_charge: str):
|
|
|
242
243
|
|
|
243
244
|
return (act_cation_mem / act_cation_soln) ** (1 / z_cation) * (act_anion_soln / act_anion_mem) ** (
|
|
244
245
|
1 / z_anion
|
|
245
|
-
) -
|
|
246
|
+
) - np.exp(delta_pi * exp_term)
|
|
246
247
|
|
|
247
248
|
# solve the function above using one of scipy's nonlinear solvers
|
|
248
249
|
|
|
@@ -264,157 +265,3 @@ def donnan_eql(solution: Solution, fixed_charge: str):
|
|
|
264
265
|
|
|
265
266
|
# return the equilibrated solution
|
|
266
267
|
return donnan_soln
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
@deprecated(
|
|
270
|
-
message="mix() is deprecated and will be removed in the next release! You can now mix solutions using the addition operator, e.g. s_mix = s1 + s2."
|
|
271
|
-
)
|
|
272
|
-
def mix(s1, s2): # pragma: no cover
|
|
273
|
-
"""
|
|
274
|
-
Mix two solutions together.
|
|
275
|
-
|
|
276
|
-
Args:
|
|
277
|
-
s1, s2: The two solutions to be mixed.
|
|
278
|
-
|
|
279
|
-
Returns:
|
|
280
|
-
A Solution object that represents the result of mixing s1 and s2.
|
|
281
|
-
|
|
282
|
-
Notes:
|
|
283
|
-
The initial volume of the mixed solution is set as the sum of the volumes of s1 and s2. The pressure and
|
|
284
|
-
temperature are volume-weighted averages. The pH and pE values are currently APPROXIMATE because they are
|
|
285
|
-
calculated assuming H+ and e- mix conservatively (i.e., the mixing process does not incorporate any
|
|
286
|
-
equilibration reactions or buffering). Such support is planned in a future release.
|
|
287
|
-
"""
|
|
288
|
-
return s1 + s2
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
@deprecated(
|
|
292
|
-
message="autogenerate() is deprecated and will be removed in the next release! Use Solution.from_preset() instead.)"
|
|
293
|
-
)
|
|
294
|
-
def autogenerate(
|
|
295
|
-
solution: Literal["seawater", "rainwater", "wastewater", "urine", "Ringers lactate", "normal saline"]
|
|
296
|
-
): # pragma: no cover
|
|
297
|
-
"""
|
|
298
|
-
This method provides a quick way to create Solution objects representing
|
|
299
|
-
commonly-encountered solutions, such as seawater, rainwater, and wastewater.
|
|
300
|
-
|
|
301
|
-
Parameters
|
|
302
|
-
----------
|
|
303
|
-
solution : str
|
|
304
|
-
String representing the desired solution
|
|
305
|
-
Valid entries are 'seawater', 'rainwater',
|
|
306
|
-
'wastewater',and 'urine'
|
|
307
|
-
|
|
308
|
-
Returns
|
|
309
|
-
-------
|
|
310
|
-
Solution
|
|
311
|
-
A pyEQL Solution object.
|
|
312
|
-
|
|
313
|
-
Notes
|
|
314
|
-
-----
|
|
315
|
-
The following sections explain the different solution options:
|
|
316
|
-
|
|
317
|
-
- '' - empty solution, equivalent to pyEQL.Solution()
|
|
318
|
-
- 'rainwater' - pure water in equilibrium with atmospheric CO2 at pH 6
|
|
319
|
-
- 'seawater' or 'SW'- Standard Seawater. See Table 4 of the Reference for Composition [1]_
|
|
320
|
-
- 'wastewater' or 'WW' - medium strength domestic wastewater. See Table 3-18 of [2]_
|
|
321
|
-
- 'urine' - typical human urine. See Table 3-15 of [2]_
|
|
322
|
-
- 'normal saline' or 'NS' - normal saline solution used in medicine [3]_
|
|
323
|
-
- 'Ringers lacatate' or 'RL' - Ringer's lactate solution used in medicine [4]_
|
|
324
|
-
|
|
325
|
-
References:
|
|
326
|
-
----------
|
|
327
|
-
.. [1] Millero, Frank J. "The composition of Standard Seawater and the definition of
|
|
328
|
-
the Reference-Composition Salinity Scale." *Deep-sea Research. Part I* 55(1), 2008, 50-72.
|
|
329
|
-
|
|
330
|
-
.. [2] Metcalf & Eddy, Inc. et al. *Wastewater Engineering: Treatment and Resource Recovery*, 5th Ed.
|
|
331
|
-
McGraw-Hill, 2013.
|
|
332
|
-
|
|
333
|
-
.. [3] https://en.wikipedia.org/wiki/Saline_(medicine)
|
|
334
|
-
|
|
335
|
-
.. [4] https://en.wikipedia.org/wiki/Ringer%27s_lactate_solution
|
|
336
|
-
|
|
337
|
-
"""
|
|
338
|
-
if solution == "":
|
|
339
|
-
temperature = "25 degC"
|
|
340
|
-
pressure = "1 atm"
|
|
341
|
-
pH = 7
|
|
342
|
-
solutes = []
|
|
343
|
-
elif solution == "seawater" or solution == "SW":
|
|
344
|
-
temperature = "25 degC"
|
|
345
|
-
pressure = "1 atm"
|
|
346
|
-
pH = 8.1
|
|
347
|
-
solutes = [
|
|
348
|
-
["Na+", "10.78145 g/kg"],
|
|
349
|
-
["Mg+2", "1.28372 g/kg"],
|
|
350
|
-
["Ca+2", "0.41208 g/kg"],
|
|
351
|
-
["K+", "0.39910 g/kg"],
|
|
352
|
-
["Sr+2", "0.00795 g/kg"],
|
|
353
|
-
["Cl-", "19.35271 g/kg"],
|
|
354
|
-
["SO4-2", "2.71235 g/kg"],
|
|
355
|
-
["HCO3-", "0.10481 g/kg"],
|
|
356
|
-
["Br-", "0.06728 g/kg"],
|
|
357
|
-
["CO3-2", "0.01434 g/kg"],
|
|
358
|
-
["B(OH)4", "0.00795 g/kg"],
|
|
359
|
-
["F-", "0.00130 g/kg"],
|
|
360
|
-
["OH-", "0.00014 g/kg"],
|
|
361
|
-
["B(OH)3", "0.01944 g/kg"],
|
|
362
|
-
["CO2", "0.00042 g/kg"],
|
|
363
|
-
]
|
|
364
|
-
elif solution == "rainwater":
|
|
365
|
-
temperature = "25 degC"
|
|
366
|
-
pressure = "1 atm"
|
|
367
|
-
pH = 6
|
|
368
|
-
solutes = [["HCO3-", "10^-5.5 mol/L"], ["CO3-2", "10^-9 mol/L"]]
|
|
369
|
-
elif solution == "wastewater" or solution == "WW":
|
|
370
|
-
temperature = "25 degC"
|
|
371
|
-
pressure = "1 atm"
|
|
372
|
-
pH = 7
|
|
373
|
-
solutes = [
|
|
374
|
-
["NH3", "24.3 mg/L"],
|
|
375
|
-
["PO4-3", "7.6 mg/L"],
|
|
376
|
-
["C6H12O6", "410 mg/L"],
|
|
377
|
-
["K+", "16 mg/L"],
|
|
378
|
-
["Cl-", "59 mg/L"],
|
|
379
|
-
["SO4-2", "26 mg/L"],
|
|
380
|
-
]
|
|
381
|
-
logger.warning("Total organic carbon in wastewater is approximated as glucose")
|
|
382
|
-
elif solution == "urine":
|
|
383
|
-
temperature = "25 degC"
|
|
384
|
-
pressure = "1 atm"
|
|
385
|
-
pH = 7
|
|
386
|
-
solutes = [
|
|
387
|
-
["CON2H4", "20,000 mg/L"],
|
|
388
|
-
["C4H7N3O", "1,000 mg/L"],
|
|
389
|
-
["C5H4N4O3", "300 mg/L"],
|
|
390
|
-
["NH4+", "500 mg/L"],
|
|
391
|
-
["HCO3-", "300 mg/L"],
|
|
392
|
-
["NH4+", "500 mg/L"],
|
|
393
|
-
["Mg+2", "100 mg/L"],
|
|
394
|
-
["PO4-3", "1200 mg/L"],
|
|
395
|
-
["Na+", "6000 mg/L"],
|
|
396
|
-
["K+", "1500 mg/L"],
|
|
397
|
-
["Cl-", "1900 mg/L"],
|
|
398
|
-
["SO4-2", "1800 mg/L"],
|
|
399
|
-
]
|
|
400
|
-
elif solution == "normal saline" or solution == "NS":
|
|
401
|
-
temperature = "25 degC"
|
|
402
|
-
pressure = "1 atm"
|
|
403
|
-
pH = 7
|
|
404
|
-
solutes = [["Na+", "154 mmol/L"], ["Cl-", "154 mmol/L"]]
|
|
405
|
-
elif solution == "Ringers lactate" or solution == "RL":
|
|
406
|
-
temperature = "25 degC"
|
|
407
|
-
pressure = "1 atm"
|
|
408
|
-
pH = 6.5
|
|
409
|
-
solutes = [
|
|
410
|
-
["Na+", "130 mmol/L"],
|
|
411
|
-
["Cl-", "109 mmol/L"],
|
|
412
|
-
["K+", "4 mmol/L"],
|
|
413
|
-
["Ca+2", "1.5 mmol/L"],
|
|
414
|
-
["C3H5O3-", "28 mmol/L"],
|
|
415
|
-
]
|
|
416
|
-
else:
|
|
417
|
-
logger.error("Invalid solution entered - %s" % solution)
|
|
418
|
-
return None
|
|
419
|
-
|
|
420
|
-
return Solution(solutes, temperature=temperature, pressure=pressure, pH=pH)
|
pyEQL/salt_ion_match.py
CHANGED
pyEQL/solute.py
CHANGED
|
@@ -14,6 +14,7 @@ that do depend on compsition are accessed via Solution class methods.
|
|
|
14
14
|
|
|
15
15
|
from __future__ import annotations
|
|
16
16
|
|
|
17
|
+
import logging
|
|
17
18
|
import warnings
|
|
18
19
|
from dataclasses import asdict, dataclass, field
|
|
19
20
|
from typing import Literal
|
|
@@ -23,6 +24,8 @@ from pymatgen.core.ion import Ion
|
|
|
23
24
|
|
|
24
25
|
from pyEQL.utils import standardize_formula
|
|
25
26
|
|
|
27
|
+
logger = logging.getLogger(__name__)
|
|
28
|
+
|
|
26
29
|
|
|
27
30
|
@dataclass
|
|
28
31
|
class Datum:
|