pyEQL 1.1.5__py3-none-any.whl → 1.1.6__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/functions.py CHANGED
@@ -15,13 +15,17 @@ from pyEQL import Solution, ureg
15
15
  logger = logging.getLogger(__name__)
16
16
 
17
17
 
18
- def gibbs_mix(solution1: Solution, solution2: Solution):
18
+ def gibbs_mix(solution1: Solution, solution2: Solution, activity_correction: bool = True):
19
19
  r"""
20
20
  Return the Gibbs energy change associated with mixing two solutions.
21
21
 
22
22
  Args:
23
23
  solution1: a solution to be mixed.
24
24
  solution2: a solution to be mixed.
25
+ activity_correction : bool, optional
26
+ If True, activities will be used to calculate the true energy of
27
+ mixing. If False, mole fraction will be used, resulting in a
28
+ calculation of the ideal energy of mixing (i.e., :math:`\Delta_{mix} S \times T` )
25
29
 
26
30
  Returns:
27
31
  The change in Gibbs energy associated with complete mixing of the
@@ -32,10 +36,17 @@ def gibbs_mix(solution1: Solution, solution2: Solution):
32
36
 
33
37
  .. math::
34
38
 
35
- \Delta_{mix} G = \sum_i {(n_c + n_d) R T \ln a_b} - \sum_i {n_c R T \ln a_c} - \sum_i {n_d R T \ln a_d}
39
+ \Delta_{mix} G_{true} = \sum_i {(n_c + n_d) R T \ln a_b} - \sum_i {n_c R T \ln a_c} - \sum_i {n_d R T \ln a_d}
36
40
 
37
- Where :math:`n` is the number of moles of substance, :math:`T` is the temperature in kelvin,
38
- and subscripts :math:`b`, :math:`c`, and :math:`d` refer to the concentrated, dilute, and blended
41
+ or
42
+
43
+ .. math::
44
+
45
+ \Delta_{mix} G_{ideal} = \sum_i {(n_c + n_d) R T \ln x_b} - \sum_i {n_c R T \ln x_c} - \sum_i {n_d R T \ln x_d}
46
+
47
+
48
+ Where :math:`n` is the number of moles of substance, :math:`T` is the temperature in kelvin, :math:`a` is the activity of solute :math:`i`,
49
+ :math:`x` is the mole fraction of solute :math:`i`, and subscripts :math:`b`, :math:`c`, and :math:`d` refer to the concentrated, dilute, and blended
39
50
  Solutions, respectively.
40
51
 
41
52
  Note that dissociated ions must be counted as separate components,
@@ -56,7 +67,10 @@ def gibbs_mix(solution1: Solution, solution2: Solution):
56
67
  for solution in term_list:
57
68
  for solute in solution.components:
58
69
  if solution.get_amount(solute, "fraction") != 0:
59
- term_list[solution] += solution.get_amount(solute, "mol") * np.log(solution.get_activity(solute))
70
+ if activity_correction is True:
71
+ term_list[solution] += solution.get_amount(solute, "mol") * np.log(solution.get_activity(solute))
72
+ else:
73
+ term_list[solution] += solution.get_amount(solute, "mol") * np.log(solution.get_amount(solute, "fraction"))
60
74
 
61
75
  return (ureg.R * blend.temperature.to("K") * (term_list[blend] - term_list[concentrate] - term_list[dilute])).to(
62
76
  "J"
@@ -72,16 +86,16 @@ def entropy_mix(solution1: Solution, solution2: Solution):
72
86
 
73
87
  Returns:
74
88
  The ideal mixing entropy associated with complete mixing of the
75
- Solutions, in Joules.
89
+ Solutions, in Joules per Kelvin.
76
90
 
77
91
  Notes:
78
92
  The ideal entropy of mixing is calculated as follows
79
93
 
80
94
  .. math::
81
95
 
82
- \Delta_{mix} S = \sum_i {(n_c + n_d) R T \ln x_b} - \sum_i {n_c R T \ln x_c} - \sum_i {n_d R T \ln x_d}
96
+ \Delta_{mix} S = \sum_i {(n_c + n_d) R \ln x_b} - \sum_i {n_c R \ln x_c} - \sum_i {n_d R \ln x_d}
83
97
 
84
- Where :math:`n` is the number of moles of substance, :math:`T` is the temperature in kelvin,
98
+ Where :math:`n` is the number of moles of substance, :math:`T` is the temperature in kelvin, :math:`x` is the mole fraction of solute :math:`i`,
85
99
  and subscripts :math:`b`, :math:`c`, and :math:`d` refer to the concentrated, dilute, and blended
86
100
  Solutions, respectively.
87
101
 
@@ -107,8 +121,8 @@ def entropy_mix(solution1: Solution, solution2: Solution):
107
121
  solution.get_amount(solute, "fraction")
108
122
  )
109
123
 
110
- return (ureg.R * blend.temperature.to("K") * (term_list[blend] - term_list[concentrate] - term_list[dilute])).to(
111
- "J"
124
+ return (ureg.R * (term_list[blend] - term_list[concentrate] - term_list[dilute])).to(
125
+ "J/K"
112
126
  )
113
127
 
114
128
 
@@ -135,9 +149,9 @@ def donnan_eql(solution: Solution, fixed_charge: str):
135
149
 
136
150
  .. math::
137
151
 
138
- \big(\frac{a_{-}}{\bar a_{-}} \big)^(\frac{1}{z_{-})
139
- \big(\frac{\bar a_{+}}{a_{+}}\big)^(\frac{1}{z_{+})
140
- \exp(\frac{\Delta \pi \bar V}{RT z_{+} \nu_{+}})
152
+ \big(\frac{a_{-}}{\bar a_{-}} \big)^{(\frac{1}{z_{-}})}
153
+ \big(\frac{\bar a_{+}}{a_{+}}\big)^{(\frac{1}{z_{+}})}
154
+ =\exp \big(\frac{\Delta \pi \bar V}{RT z_{+} \nu_{+}}\big)
141
155
 
142
156
  Where subscripts :math:`+` and :math:`-` indicate the cation and anion, respectively,
143
157
  the overbar indicates the membrane phase,
pyEQL/solution.py CHANGED
@@ -1161,7 +1161,8 @@ class Solution(MSONable):
1161
1161
  :meth:`get_amount`
1162
1162
  :func:`pyEQL.utils.interpret_units`
1163
1163
  """
1164
- TOT: Quantity = 0
1164
+ _units = interpret_units(units)
1165
+ TOT: Quantity = ureg.Quantity(0, _units)
1165
1166
 
1166
1167
  # standardize the element formula and units
1167
1168
  el = str(Element(element.split("(")[0]))
@@ -1178,7 +1179,7 @@ class Solution(MSONable):
1178
1179
  else:
1179
1180
  species = []
1180
1181
  for k, v in comp_by_element.items():
1181
- if el in k:
1182
+ if k.split("(")[0] == el:
1182
1183
  species.extend(v)
1183
1184
 
1184
1185
  # loop through the species of interest, adding moles of element
@@ -2294,9 +2295,7 @@ class Solution(MSONable):
2294
2295
  self.logger.info("balance_charge is None, so no charge balancing will be performed.")
2295
2296
  return
2296
2297
 
2297
- self.logger.info(
2298
- f"Solution is not electroneutral (C.B. = {cb} eq/L). Adjusting {self._cb_species} to compensate."
2299
- )
2298
+ self.logger.info(f"Adjusting {self._cb_species} to compensate.")
2300
2299
 
2301
2300
  if self.balance_charge == "pH":
2302
2301
  # the charge imbalance associated with the H+ / OH- system can be expressed
pyEQL/utils.py CHANGED
@@ -137,6 +137,12 @@ def standardize_formula(formula: str):
137
137
  elif sform == "C2I2ClO2[-1]":
138
138
  sform = "CI2ClCOO[-1]"
139
139
 
140
+ # ammonium sulfate salts
141
+ elif sform == "H8S(NO2)2(aq)":
142
+ sform = "(NH4)2SO4(aq)"
143
+ elif sform == "H4SNO4[-1]":
144
+ sform = "NH4SO4[-1]"
145
+
140
146
  # TODO - consider adding recognition of special formulas like MeOH for methanol or Cit for citrate
141
147
  return sform
142
148
 
@@ -5,9 +5,12 @@ developed and maintained by the Kingsbury Lab at Princeton University.
5
5
 
6
6
  Other contributors, listed alphabetically, are:
7
7
 
8
- * Kirill Pushkarev (@kirill-push)
9
- * Dhruv Duseja (@DhruvDuseja)
10
- * Andrew Rosen (@arosen93)
11
- * Hernan Grecco (@hgrecco)
8
+ - Arpit Bhardwaj (@abhardwaj73)
9
+ - Dhruv Duseja (@DhruvDuseja)
10
+ - Hernan Grecco (@hgrecco)
11
+ - Jaebeom Park (@Jaebeom-P)
12
+ - Kirill Pushkarev (@kirill-push)
13
+ - Andrew Rosen (@arosen93)
14
+ - Sui Xiong Tay (@SuixiongTay)
12
15
 
13
16
  (If you think that your name belongs here, please let the maintainer know)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pyEQL
3
- Version: 1.1.5
3
+ Version: 1.1.6
4
4
  Summary: A python interface for solution chemistry
5
5
  Author-email: Ryan Kingsbury <kingsbury@princeton.edu>
6
6
  Project-URL: Docs, https://pyeql.readthedocs.io/
@@ -21,13 +21,13 @@ License-File: LICENSE.txt
21
21
  License-File: COPYING
22
22
  License-File: AUTHORS.md
23
23
  Requires-Dist: pint >=0.19
24
- Requires-Dist: numpy <2
25
- Requires-Dist: scipy
24
+ Requires-Dist: numpy <2,>1.26
25
+ Requires-Dist: scipy >=1.12
26
26
  Requires-Dist: pymatgen ==2024.5.1
27
- Requires-Dist: iapws
27
+ Requires-Dist: iapws >=1.5.3
28
28
  Requires-Dist: monty >=2024.7.12
29
29
  Requires-Dist: maggma >=0.67.0
30
- Requires-Dist: phreeqpython
30
+ Requires-Dist: phreeqpython >=1.5.2
31
31
  Provides-Extra: docs
32
32
  Requires-Dist: sphinx >=3.2.1 ; extra == 'docs'
33
33
  Requires-Dist: sphinx-rtd-theme ; extra == 'docs'
@@ -35,14 +35,14 @@ Requires-Dist: myst-parser[linkify] ; extra == 'docs'
35
35
  Provides-Extra: full
36
36
  Requires-Dist: rich ; extra == 'full'
37
37
  Provides-Extra: testing
38
- Requires-Dist: setuptools ; extra == 'testing'
39
- Requires-Dist: pre-commit ; extra == 'testing'
40
- Requires-Dist: pytest ; extra == 'testing'
41
- Requires-Dist: pytest-cov ; extra == 'testing'
42
- Requires-Dist: pytest-xdist ; extra == 'testing'
38
+ Requires-Dist: setuptools >=68 ; extra == 'testing'
39
+ Requires-Dist: pre-commit >=2 ; extra == 'testing'
40
+ Requires-Dist: pytest >=7 ; extra == 'testing'
41
+ Requires-Dist: pytest-cov >=2.11 ; extra == 'testing'
42
+ Requires-Dist: pytest-xdist >2 ; extra == 'testing'
43
43
  Requires-Dist: black ; extra == 'testing'
44
- Requires-Dist: mypy ; extra == 'testing'
45
- Requires-Dist: ruff ; extra == 'testing'
44
+ Requires-Dist: mypy >1 ; extra == 'testing'
45
+ Requires-Dist: ruff >0.0.100 ; extra == 'testing'
46
46
  Requires-Dist: tox <4 ; extra == 'testing'
47
47
 
48
48
  [![Read the Docs](https://img.shields.io/readthedocs/pyeql)](https://pyeql.readthedocs.io/en/latest/)
@@ -2,11 +2,11 @@ pyEQL/__init__.py,sha256=OCp_PiQEPyVoi1VX0ursBzHJWN6nDS1Id6bTBOgqCYs,1999
2
2
  pyEQL/activity_correction.py,sha256=eOixjgTd5hTrTRD5s6aPCCG12lAIH7-lRN0Z1qHu678,37151
3
3
  pyEQL/engines.py,sha256=VbdQSPKlNehW96U1XxWYwjTy6k6WDpZZEx_Y4l3qZv4,34686
4
4
  pyEQL/equilibrium.py,sha256=YCtoAJSgn1WC9NJnc3H4FTJdKQvogsvCuj7HqlKMtww,8307
5
- pyEQL/functions.py,sha256=nc-Hc61MmW-ELBR1PByJvQnELxM7PZexMHbU_O5-Bnw,10584
5
+ pyEQL/functions.py,sha256=BZXkiNJWuo4ZMQSVdFQkwqQmzbSkwi-vg1DFFQuFsos,11435
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=0eaPmI3bm_ipGyXtZCcQQ5kuA8Bv_0DBYZeZZ3eWXYk,115758
9
- pyEQL/utils.py,sha256=DWLtNm71qw5j4-jqBp5v3LssEjWgJnVvI6a_H60c5ic,6670
8
+ pyEQL/solution.py,sha256=3hvtqeu5KzfFKzeOdKlzS_aIFPTNgUfhjIwBurfuGJw,115754
9
+ pyEQL/utils.py,sha256=zOXqg89jTqD1mPVAtlBbRxkpP9-IdHfJpK_1VDOywIQ,6828
10
10
  pyEQL/database/geothermal.dat,sha256=kksnfcBtWdOTpNn4CLXU1Mz16cwas2WuVKpuMU8CaVI,234230
11
11
  pyEQL/database/llnl.dat,sha256=jN-a0kfUFbQlYMn2shTVRg1JX_ZhLa-tJ0lLw2YSpLU,751462
12
12
  pyEQL/database/phreeqc_license.txt,sha256=8W1r8VxC2kVptIMSU9sDFNASYqN7MdwKEtIWWfjTQuM,2906
@@ -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.5.dist-info/AUTHORS.md,sha256=K9ZLhKFwZ2zLlFXwN62VuUYCpr5T6n4mOUCUHlytTUs,415
21
- pyEQL-1.1.5.dist-info/COPYING,sha256=Ww2oUywfFTn242v9ksCgQdIVSpcMXJiKKePn0GFm25E,7649
22
- pyEQL-1.1.5.dist-info/LICENSE.txt,sha256=2Zf1F7RzbpeposgIxUydpurqNCMoMgDi2gAB65_GjwQ,969
23
- pyEQL-1.1.5.dist-info/METADATA,sha256=TXDkdGyqFqh4LJfyOFtcqlbRnNh87kySnIPAKzUE1k8,6096
24
- pyEQL-1.1.5.dist-info/WHEEL,sha256=Rp8gFpivVLXx-k3U95ozHnQw8yDcPxmhOpn_Gx8d5nc,91
25
- pyEQL-1.1.5.dist-info/top_level.txt,sha256=QMOaZjCAm_lS4Njsjh4L0B5aWnJFGQMYKhuH88CG1co,6
26
- pyEQL-1.1.5.dist-info/RECORD,,
20
+ pyEQL-1.1.6.dist-info/AUTHORS.md,sha256=Ukdh6f3jO6jdgl2k_r_xdNOuzmjXcISMQqUTSH39QVw,506
21
+ pyEQL-1.1.6.dist-info/COPYING,sha256=Ww2oUywfFTn242v9ksCgQdIVSpcMXJiKKePn0GFm25E,7649
22
+ pyEQL-1.1.6.dist-info/LICENSE.txt,sha256=2Zf1F7RzbpeposgIxUydpurqNCMoMgDi2gAB65_GjwQ,969
23
+ pyEQL-1.1.6.dist-info/METADATA,sha256=zV5ynllRkS-BEc8prG7c-e_7O7tR4MOvAgX2altqT08,6160
24
+ pyEQL-1.1.6.dist-info/WHEEL,sha256=UvcQYKBHoFqaQd6LKyqHw9fxEolWLQnlzP0h_LgJAfI,91
25
+ pyEQL-1.1.6.dist-info/top_level.txt,sha256=QMOaZjCAm_lS4Njsjh4L0B5aWnJFGQMYKhuH88CG1co,6
26
+ pyEQL-1.1.6.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (72.0.0)
2
+ Generator: setuptools (74.0.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
File without changes