pyEQL 1.1.2__py3-none-any.whl → 1.1.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pyEQL/engines.py +2 -14
- pyEQL/solution.py +51 -12
- {pyEQL-1.1.2.dist-info → pyEQL-1.1.4.dist-info}/METADATA +1 -1
- {pyEQL-1.1.2.dist-info → pyEQL-1.1.4.dist-info}/RECORD +9 -9
- {pyEQL-1.1.2.dist-info → pyEQL-1.1.4.dist-info}/AUTHORS.md +0 -0
- {pyEQL-1.1.2.dist-info → pyEQL-1.1.4.dist-info}/COPYING +0 -0
- {pyEQL-1.1.2.dist-info → pyEQL-1.1.4.dist-info}/LICENSE.txt +0 -0
- {pyEQL-1.1.2.dist-info → pyEQL-1.1.4.dist-info}/WHEEL +0 -0
- {pyEQL-1.1.2.dist-info → pyEQL-1.1.4.dist-info}/top_level.txt +0 -0
pyEQL/engines.py
CHANGED
|
@@ -687,20 +687,8 @@ class NativeEOS(EOS):
|
|
|
687
687
|
)
|
|
688
688
|
|
|
689
689
|
# re-adjust charge balance for any missing species
|
|
690
|
-
# note that if balance_charge is set, it will have been passed to PHREEQC, so
|
|
691
|
-
|
|
692
|
-
charge_adjust = 0
|
|
693
|
-
for s in missing_species:
|
|
694
|
-
charge_adjust += -1 * solution.get_amount(s, "eq").magnitude
|
|
695
|
-
if charge_adjust != 0:
|
|
696
|
-
logger.warning(
|
|
697
|
-
"After equilibration, the charge balance of the solution was not electroneutral."
|
|
698
|
-
f" {charge_adjust} eq of charge were added via {solution._cb_species}"
|
|
699
|
-
)
|
|
700
|
-
|
|
701
|
-
if solution.balance_charge is not None:
|
|
702
|
-
z = solution.get_property(solution._cb_species, "charge")
|
|
703
|
-
solution.add_amount(solution._cb_species, f"{charge_adjust/z} mol")
|
|
690
|
+
# note that if balance_charge is set, it will have been passed to PHREEQC, so the only reason to re-adjust charge balance here is to account for any missing species.
|
|
691
|
+
solution._adjust_charge_balance()
|
|
704
692
|
|
|
705
693
|
# rescale the solvent mass to ensure the total mass of solution does not change
|
|
706
694
|
# this is important because PHREEQC and the pyEQL database may use slightly different molecular
|
pyEQL/solution.py
CHANGED
|
@@ -35,6 +35,7 @@ from pyEQL.utils import FormulaDict, create_water_substance, interpret_units, st
|
|
|
35
35
|
EQUIV_WT_CACO3 = ureg.Quantity(100.09 / 2, "g/mol")
|
|
36
36
|
# string to denote unknown oxidation states
|
|
37
37
|
UNKNOWN_OXI_STATE = "unk"
|
|
38
|
+
K_W = 1e-14 # ion product of water at 25 degC
|
|
38
39
|
|
|
39
40
|
|
|
40
41
|
class Solution(MSONable):
|
|
@@ -242,7 +243,7 @@ class Solution(MSONable):
|
|
|
242
243
|
|
|
243
244
|
# set the pH with H+ and OH-
|
|
244
245
|
self.add_solute("H+", str(10 ** (-1 * pH)) + "mol/L")
|
|
245
|
-
self.add_solute("OH-", str(10 ** (-1 *
|
|
246
|
+
self.add_solute("OH-", str(K_W / (10 ** (-1 * pH))) + "mol/L")
|
|
246
247
|
|
|
247
248
|
# populate the other solutes
|
|
248
249
|
self._solutes = solutes
|
|
@@ -288,17 +289,7 @@ class Solution(MSONable):
|
|
|
288
289
|
)
|
|
289
290
|
|
|
290
291
|
# adjust charge balance, if necessary
|
|
291
|
-
|
|
292
|
-
balanced = False
|
|
293
|
-
self.logger.info(
|
|
294
|
-
f"Solution is not electroneutral (C.B. = {cb} eq/L). Adding {self._cb_species} to compensate."
|
|
295
|
-
)
|
|
296
|
-
z = self.get_property(self._cb_species, "charge")
|
|
297
|
-
self.components[self._cb_species] += -1 * cb / z * self.volume.to("L").magnitude
|
|
298
|
-
if np.isclose(self.charge_balance, 0, atol=1e-8):
|
|
299
|
-
balanced = True
|
|
300
|
-
if not balanced:
|
|
301
|
-
warnings.warn(f"Unable to balance charge using species {self._cb_species}")
|
|
292
|
+
self._adjust_charge_balance()
|
|
302
293
|
|
|
303
294
|
@property
|
|
304
295
|
def mass(self) -> Quantity:
|
|
@@ -2293,6 +2284,54 @@ class Solution(MSONable):
|
|
|
2293
2284
|
|
|
2294
2285
|
return distance.to("nm")
|
|
2295
2286
|
|
|
2287
|
+
def _adjust_charge_balance(self, atol=1e-8) -> None:
|
|
2288
|
+
"""Helper method to adjust the charge balance of the Solution."""
|
|
2289
|
+
cb = self.charge_balance
|
|
2290
|
+
if not np.isclose(cb, 0, atol=atol):
|
|
2291
|
+
self.logger.info(f"Solution is not electroneutral (C.B. = {cb} eq/L).")
|
|
2292
|
+
if self.balance_charge is None:
|
|
2293
|
+
# Nothing to do.
|
|
2294
|
+
self.logger.info("balance_charge is None, so no charge balancing will be performed.")
|
|
2295
|
+
return
|
|
2296
|
+
|
|
2297
|
+
self.logger.info(
|
|
2298
|
+
f"Solution is not electroneutral (C.B. = {cb} eq/L). Adjusting {self._cb_species} to compensate."
|
|
2299
|
+
)
|
|
2300
|
+
|
|
2301
|
+
if self.balance_charge == "pH":
|
|
2302
|
+
# the charge imbalance associated with the H+ / OH- system can be expressed
|
|
2303
|
+
# as ([H+] - [OH-]) or ([H+] - K_W/[H+]). If we adjust H+, we also have to
|
|
2304
|
+
# adjust OH- to maintain water equilibrium.
|
|
2305
|
+
C_hplus = self.get_amount("H+", "mol/L").magnitude
|
|
2306
|
+
start_imbalance = C_hplus - K_W / C_hplus
|
|
2307
|
+
new_imbalance = start_imbalance - cb
|
|
2308
|
+
# calculate the new concentration of H+ that will balance the charge
|
|
2309
|
+
# solve H^2 - new_imbalance H - K_W = 0, so a=1, b=-new_imbalance, c=-K_W. Note that this is guaranteed to have real roots as
|
|
2310
|
+
# b^2-4ac > 0
|
|
2311
|
+
new_hplus = max(
|
|
2312
|
+
[
|
|
2313
|
+
(new_imbalance + np.sqrt(new_imbalance**2 + 4 * 1 * K_W)) / 2,
|
|
2314
|
+
(new_imbalance - np.sqrt(new_imbalance**2 + 4 * 1 * K_W)) / 2,
|
|
2315
|
+
]
|
|
2316
|
+
)
|
|
2317
|
+
self.set_amount("H+", f"{new_hplus} mol/L")
|
|
2318
|
+
self.set_amount("OH-", f"{K_W/new_hplus} mol/L")
|
|
2319
|
+
assert np.isclose(self.charge_balance, 0, atol=atol), f"{self.charge_balance}"
|
|
2320
|
+
return
|
|
2321
|
+
|
|
2322
|
+
z = self.get_property(self._cb_species, "charge")
|
|
2323
|
+
try:
|
|
2324
|
+
self.add_amount(self._cb_species, f"{-1*cb/z} mol")
|
|
2325
|
+
return
|
|
2326
|
+
except ValueError:
|
|
2327
|
+
# if the concentration is negative, it must mean there is not enough present.
|
|
2328
|
+
# remove everything that's present and log an error.
|
|
2329
|
+
self.components[self._cb_species] = 0
|
|
2330
|
+
self.logger.error(
|
|
2331
|
+
f"There is not enough {self._cb_species} present to balance the charge. Try a different species."
|
|
2332
|
+
)
|
|
2333
|
+
return
|
|
2334
|
+
|
|
2296
2335
|
def _update_volume(self):
|
|
2297
2336
|
"""Recalculate the solution volume based on composition."""
|
|
2298
2337
|
self._volume = self._get_solvent_volume() + self._get_solute_volume()
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
pyEQL/__init__.py,sha256=OCp_PiQEPyVoi1VX0ursBzHJWN6nDS1Id6bTBOgqCYs,1999
|
|
2
2
|
pyEQL/activity_correction.py,sha256=eOixjgTd5hTrTRD5s6aPCCG12lAIH7-lRN0Z1qHu678,37151
|
|
3
|
-
pyEQL/engines.py,sha256=
|
|
3
|
+
pyEQL/engines.py,sha256=VbdQSPKlNehW96U1XxWYwjTy6k6WDpZZEx_Y4l3qZv4,34686
|
|
4
4
|
pyEQL/equilibrium.py,sha256=YCtoAJSgn1WC9NJnc3H4FTJdKQvogsvCuj7HqlKMtww,8307
|
|
5
5
|
pyEQL/functions.py,sha256=nc-Hc61MmW-ELBR1PByJvQnELxM7PZexMHbU_O5-Bnw,10584
|
|
6
6
|
pyEQL/salt_ion_match.py,sha256=0nCZXmeo67VqcyYWQpPx-81hjSvnsg8HFB3fIyfjW_k,4070
|
|
7
7
|
pyEQL/solute.py,sha256=no00Rc3tRfHmyht4wm2UXA1KZhKC45tWMO5QEkZY6yg,5140
|
|
8
|
-
pyEQL/solution.py,sha256=
|
|
8
|
+
pyEQL/solution.py,sha256=dktH1abijuORNw5YkTjC5CMqzD2Y9DF_cZPuwOA1-dY,115853
|
|
9
9
|
pyEQL/utils.py,sha256=DWLtNm71qw5j4-jqBp5v3LssEjWgJnVvI6a_H60c5ic,6670
|
|
10
10
|
pyEQL/database/geothermal.dat,sha256=kksnfcBtWdOTpNn4CLXU1Mz16cwas2WuVKpuMU8CaVI,234230
|
|
11
11
|
pyEQL/database/llnl.dat,sha256=jN-a0kfUFbQlYMn2shTVRg1JX_ZhLa-tJ0lLw2YSpLU,751462
|
|
@@ -17,10 +17,10 @@ pyEQL/presets/rainwater.yaml,sha256=S0WHZNDfCJyjSSFxNFdkypjn2s3P0jJGCiYIxvi1ibA,
|
|
|
17
17
|
pyEQL/presets/seawater.yaml,sha256=oryc1CkhRz20RpWE6uiGiT93HoZnqlB0s-0PmBWr3-U,843
|
|
18
18
|
pyEQL/presets/urine.yaml,sha256=0Njtc-H1fFRo7UhquHdiSTT4z-8VZJ1utDCk02qk28M,679
|
|
19
19
|
pyEQL/presets/wastewater.yaml,sha256=jTTFBpmKxczaEtkCZb0xUULIPZt7wfC8eAJ6rthGnmw,502
|
|
20
|
-
pyEQL-1.1.
|
|
21
|
-
pyEQL-1.1.
|
|
22
|
-
pyEQL-1.1.
|
|
23
|
-
pyEQL-1.1.
|
|
24
|
-
pyEQL-1.1.
|
|
25
|
-
pyEQL-1.1.
|
|
26
|
-
pyEQL-1.1.
|
|
20
|
+
pyEQL-1.1.4.dist-info/AUTHORS.md,sha256=K9ZLhKFwZ2zLlFXwN62VuUYCpr5T6n4mOUCUHlytTUs,415
|
|
21
|
+
pyEQL-1.1.4.dist-info/COPYING,sha256=Ww2oUywfFTn242v9ksCgQdIVSpcMXJiKKePn0GFm25E,7649
|
|
22
|
+
pyEQL-1.1.4.dist-info/LICENSE.txt,sha256=2Zf1F7RzbpeposgIxUydpurqNCMoMgDi2gAB65_GjwQ,969
|
|
23
|
+
pyEQL-1.1.4.dist-info/METADATA,sha256=VT4Z5yWuLsahV2Ed9pnCGTqZ4vc10vE5LLwHZHOyAwE,6096
|
|
24
|
+
pyEQL-1.1.4.dist-info/WHEEL,sha256=Wyh-_nZ0DJYolHNn1_hMa4lM7uDedD_RGVwbmTjyItk,91
|
|
25
|
+
pyEQL-1.1.4.dist-info/top_level.txt,sha256=QMOaZjCAm_lS4Njsjh4L0B5aWnJFGQMYKhuH88CG1co,6
|
|
26
|
+
pyEQL-1.1.4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|