Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
85 commits
Select commit Hold shift + click to select a range
3ed21da
Reconcile type hints
ugognw Jun 23, 2025
b161b22
Resolve mypy errors
ugognw Jun 23, 2025
8b8acf6
Update docstring
ugognw Jun 23, 2025
42707e0
Add regr. tests for Solution.component value types
ugognw Jun 27, 2025
5697b98
Store Salt in output of Solution.get_salt_dict
ugognw Jun 27, 2025
6c10fc7
Update changelog
ugognw Jun 27, 2025
4d57419
Clarify docstring
ugognw Jun 27, 2025
a093ba7
Make pyEQL compatible with Solution.get_salt_dict
ugognw Jun 27, 2025
07906e1
Remove conditional expression
ugognw Jun 28, 2025
5fa5a31
Refactor type tests; make test cond stricter
ugognw Jun 29, 2025
4dd8b1d
Remove components unit tests; loosen type check
ugognw Jun 29, 2025
32333ae
Add name to AUTHORS.md
ugognw Jun 29, 2025
2b56014
Iterate over dict values view
ugognw Jun 29, 2025
223b00b
Remove list_salts
ugognw Jun 29, 2025
0e05603
Update CHANGELOG
ugognw Jun 29, 2025
a3ee990
Add test case for first if branch in while loop
ugognw Jun 29, 2025
f6de3eb
Remove unnecessary test case
ugognw Jun 29, 2025
b994bf9
Revert "Remove conditional expression"
ugognw Jun 30, 2025
ae6bfd4
Fix docstring
ugognw Jun 30, 2025
9be76c0
Consolidate/expand get_salt_dict tests
ugognw Jul 1, 2025
149982c
Refactor/document/augment unit tests
ugognw Jul 2, 2025
15275ab
module-level vars for params; refactor fixtures
ugognw Jul 2, 2025
d9ff03f
Annotate salt_ratio fixture
ugognw Jul 2, 2025
2f6871e
Clarify parametrization note; add new cutoff
ugognw Jul 2, 2025
fce8599
Only test for salt order in multisalt solution
ugognw Jul 2, 2025
a5cd97b
Update requested fixtures and parametrizations
ugognw Jul 2, 2025
d3ee331
Permit small error in concentration (abstol=1e-16)
ugognw Jul 2, 2025
3d937ed
Reduce parametrization for multisalt solutions
ugognw Jul 2, 2025
3fdbd80
Move test setup for logging message to fixture
ugognw Jul 2, 2025
5c3d530
Fix salt concentration bug with polyvalent ions
ugognw Jul 2, 2025
d146010
Update changelog
ugognw Jul 2, 2025
2a46439
Add more fixtures; fix tests; adjust salt_ratio
ugognw Jul 2, 2025
2da5c51
Parametrize test_should_order_salts_by_amount
ugognw Jul 2, 2025
5c428aa
Consolidate fixture
ugognw Jul 2, 2025
ebc3e45
Reduce cation/anion_scale
ugognw Jul 2, 2025
d305d8a
Expand test suite for cutoff parameter
ugognw Jul 2, 2025
a1933df
Refactor get_salt_dict
ugognw Jul 2, 2025
6544abb
Edit get_salt to return None if water is only salt
ugognw Jul 2, 2025
d7ab2cc
Fix StreamHandler type hints
ugognw Jul 2, 2025
5b68c96
Update changelog
ugognw Jul 2, 2025
73b1261
NativeEOS/Solution.get_salt edits: .get_salt_dict
ugognw Jul 2, 2025
1671d1e
Implement cutoff in units of moles
ugognw Jul 2, 2025
1cdc3dd
Remove test corresponding to undesired behaviour
ugognw Jul 2, 2025
f26679a
Improve fixture documentation
ugognw Jul 2, 2025
385468a
Wrap type hint in string to appease python3.10
ugognw Jul 2, 2025
2dbc0d7
temp: hack abs tolerance
ugognw Jul 2, 2025
490415e
Add parametrization for salt_conc == cutoff
ugognw Jul 2, 2025
292ff37
Merge branch 'main' into fix-get-salt-dict-type
ugognw Jul 3, 2025
1f63b79
Refactor tests
ugognw Jul 3, 2025
41b026b
Tests: refactoring, (de-)parametrization
ugognw Jul 4, 2025
7018785
Set salt dict values at once; suppress ruff errors
ugognw Jul 4, 2025
de7cd82
Consolidate fixtures in conftest.py
ugognw Jul 4, 2025
44e5d46
Implement cutoff in mol/kg
ugognw Jul 4, 2025
1668cbe
Add salt_conc_units fixture
ugognw Jul 4, 2025
3c88806
Adapt test for mol/kg cutoff
ugognw Jul 4, 2025
5fd50d9
Merge branch 'main' into fix-get-salt-dict-type
ugognw Jul 4, 2025
3fb4687
Expand and test doctest
ugognw Jul 4, 2025
06e8982
Move salt_dict fixtures to salt matching tests
ugognw Jul 4, 2025
735c0ae
Reduce default cutoff to 1e-3
ugognw Jul 4, 2025
d1755c6
Calculate concentration using solvent mass
ugognw Jul 4, 2025
6bd5ffa
Update docstring
ugognw Jul 4, 2025
922e511
Fix bug related to adding solutions + unit tests
ugognw Jul 4, 2025
2408158
Remove atol hack
ugognw Jul 4, 2025
dee5e5a
Concretize new NativeEOS method behaviour w/ tests
ugognw Jul 9, 2025
64df541
Use correct log level
ugognw Jul 9, 2025
4feaab0
Temporarily upd. test values; solute vol. note
ugognw Jul 9, 2025
39f73e0
Exclude HOH from solute pairs
ugognw Jul 10, 2025
5cc5f6f
Remove test logic excluding tests with HOH salt
ugognw Jul 10, 2025
e4d03a9
Fix activity coefficient bug
ugognw Jul 10, 2025
6a8a0ed
Add missing alphas fixture
ugognw Jul 10, 2025
b33712a
Clean up signature
ugognw Jul 10, 2025
d4a9da9
Add unit tests for NativeEOS.get_solute_volume
ugognw Jul 10, 2025
584ed7b
Fix type hints
ugognw Jul 10, 2025
cc5c565
Fix solute volume bug for divalent salts
ugognw Jul 10, 2025
cf8a3e9
Update changelog
ugognw Jul 10, 2025
48cb2a3
Fix typo
ugognw Jul 11, 2025
482f1db
Update doctest to clearly illustrate functionality
ugognw Jul 11, 2025
00b809f
Add tests for salt matching 2:3 and 3:2 valent salts
ugognw Jul 12, 2025
58e2245
Consolidate changelog edits
ugognw Jul 15, 2025
7fac892
Fix typo; link PR
ugognw Jul 15, 2025
5345e73
Merge branch 'main' into fix-get-salt-dict-type
rkingsbury Jul 15, 2025
b496133
Implement internal cutoff to avoid rounding errors
ugognw Jul 15, 2025
37439e5
Test that element oxi states are treated different
ugognw Jul 15, 2025
a0cc4c1
Merge branch 'main' into fix-get-salt-dict-type
rkingsbury Aug 1, 2025
8eef992
Merge branch 'main' into fix-get-salt-dict-type
rkingsbury Aug 8, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions AUTHORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@ Other contributors, listed alphabetically, are:
- Arpit Bhardwaj (@abhardwaj73)
- Nikhil Dhruv (@NikhilDhruv)
- Dhruv Duseja (@DhruvDuseja)
- Hernan Grecco (@hgrecco)
- @githubalexliu
- Hernan Grecco (@hgrecco)
- @Ouriel Ndalamba (@Ouriel-N)
- Ugo Nwosu (@ugognw)
- Yitong Pan (@YitongPan1)
- Jaebeom Park (@Jaebeom-P)
- Kirill Pushkarev (@kirill-push)
- Andrew Rosen (@arosen93)
- Sui Xiong Tay (@SuixiongTay)
- @ugognw


(If you think that your name belongs here, please let the maintainer know)
27 changes: 22 additions & 5 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## Unreleased

### Added

- Docs/CI: sphinx linkcheck job and tox environment/command (`tox -e links`) (#255, @ugognw)
- Docs: add carbonate system tutorial (#204, @NikhilDhruv)

### Fixed

- `Solution` engine, solvent, database were not inherited by the sum of `Solution` objects (#258, ugognw)
- Bugs where incorrect $\alpha_1$ and $\alpha_2$ parameters were used to calculate activity
coefficients and solute molar volumes for salts with divalent (or greater) ions (#258, ugognw)
- calculation of salt concentrations in `Solution.get_salt_dict` for salts containing polyvalent cations (#258, ugognw)
- `Solution.get_salt_dict` now respects the `cutoff` parameter (#258, ugognw)
- Note that `cutoff` is interpreted in units of moles per kilogram of solution (#258, ugognw)
- `Solution.get_salt_dict` always returns a salt dictionary sorted in order of decreasing salt concentration (#258, ugognw)
- `Solution.__init__`: Raise `ValueError` if a user sets inconsistent `H[+1]` in `solutes` and
`pH` keyword arguments (#270, @gnuhpdiem, @rkingsbury). Previously, if the user set `H[+1]` in `solutes`, it's value would silently override the `pH` kwarg. Now, you will get a `ValueError`
if the two are inconsistent, unless the `pH` kwarg is kept at the default value. In that case,
Expand All @@ -29,8 +31,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Docs: Minor fixes for private / cached methods (#197, @githubalexliu)
- Docs: Edit documentation of `debye_parameter_B` (#196, @YitongPan1)

### Added

- Docs/CI: sphinx linkcheck job and tox environment/command (`tox -e links`) (#255, @ugognw)
- Docs: add carbonate system tutorial (#204, @NikhilDhruv)

### Changed

- **BREAKING** - the return value of `Solution.get_salt_dict` now includes `Salt` objects instead of keys corresponding
to `cation` and `anion`. See the example in the docstring for how to adapt existing code to accommodate this
change. (#258, @ugognw)
- **BREAKING** - `Solution.get_salt_dict` no longer returns an entry for water (#258)
- **BREAKING** - `Solution.get_salt` will not return water and may return `None` if no salt is present.
Previously, `Solution.get_salt` would have returned a `Salt` representing water. (#258)
- Ensure more consistent column formatting in `Solution.print()` (#269, @rkingsbury)
- Switch `math.log10` to `np.log10` in `Solution.p()` (#269, @rkingsbury)
- update pre-commit configuration (#269, @rkingsbury)
Expand All @@ -43,12 +56,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Docs: `tox -e docs` command configured to fail on warning (#255, ugognw)
- Docs: ReadTheDocs built with Python 3.11 (#255, ugognw)
- Use `importlib` to locate test files (#241, @SuixiongTay)
- Support `numpy>2.0`
- Bump `pint` to `0.24.4` for `numpy` `v2.0` compatibility and to mitigate CI issues (#239, @SuixiongTay, @rkingsbury)
- CI: add `python` `v3.13` to post-merge unit tests
- bump `pymatgen` to `v2025.1.9`
- bump `maggma` to `v0.71.4`

### Removed

- Python 3.9 version classifier in pyproject.toml (#247, @ugognw)
- `Solution.list_salts` (use `Solution.get_salt_dict()` instead) (#258)

## [1.2.0] - 2024-09-24

Expand Down
32 changes: 12 additions & 20 deletions src/pyEQL/engines.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

"""

import copy
import logging
import os
import warnings
Expand All @@ -17,7 +18,6 @@

import pyEQL.activity_correction as ac
from pyEQL import ureg
from pyEQL.salt_ion_match import Salt
from pyEQL.utils import standardize_formula

# These are the only elements that are allowed to have parenthetical oxidation states
Expand Down Expand Up @@ -215,7 +215,7 @@ def _setup_ppsol(self, solution: "solution.Solution") -> None:
if bare_el in SPECIAL_ELEMENTS:
# PHREEQC will ignore float-formatted oxi states. Need to make sure we are
# passing, e.g. 'C(4)' and not 'C(4.0)'
key = f'{bare_el}({int(float(el.split("(")[-1].split(")")[0]))})'
key = f"{bare_el}({int(float(el.split('(')[-1].split(')')[0]))})"
elif bare_el in ["H", "O"]:
continue
else:
Expand Down Expand Up @@ -317,12 +317,9 @@ def get_activity_coefficient(self, solution: "solution.Solution", solute: str):
# identify the predominant salt that this ion is a member of
salt = None
rform = standardize_formula(solute)
for v in solution.get_salt_dict().values():
if v == "HOH":
continue
if rform == v["cation"] or rform == v["anion"]:
del v["mol"]
salt = Salt.from_dict(v)
for d in solution.get_salt_dict().values():
if rform == d["salt"].cation or rform == d["salt"].anion:
salt = d["salt"]
break

# show an error if no salt can be found that contains the solute
Expand All @@ -340,8 +337,8 @@ def get_activity_coefficient(self, solution: "solution.Solution", solute: str):
# determine alpha1 and alpha2 based on the type of salt
# see the May reference for the rules used to determine
# alpha1 and alpha2 based on charge
if salt.nu_cation >= 2 and salt.nu_anion <= -2:
if salt.nu_cation >= 3 or salt.nu_anion <= -3:
if salt.z_cation >= 2 and salt.z_anion <= -2:
if salt.z_cation >= 3 or salt.z_anion <= -3:
alpha1 = 2.0
alpha2 = 50.0
else:
Expand Down Expand Up @@ -513,11 +510,7 @@ def get_osmotic_coefficient(self, solution: "solution.Solution") -> ureg.Quantit
# coefficint for each, and average them into an effective osmotic
# coefficient
for d in solution.get_salt_dict().values():
item = Salt(d["cation"], d["anion"])
# ignore HOH in the salt list
if item.formula == "HOH":
continue

item = d["salt"]
# determine alpha1 and alpha2 based on the type of salt
# see the May reference for the rules used to determine
# alpha1 and alpha2 based on charge
Expand Down Expand Up @@ -577,7 +570,7 @@ def get_osmotic_coefficient(self, solution: "solution.Solution") -> ureg.Quantit
return effective_osmotic_sum / molality_sum
except ZeroDivisionError:
# this means the solution is empty
return 1
return ureg.Quantity(1.0)

def get_solute_volume(self, solution: "solution.Solution") -> ureg.Quantity:
"""Return the volume of the solutes."""
Expand All @@ -587,8 +580,8 @@ def get_solute_volume(self, solution: "solution.Solution") -> ureg.Quantity:

# use the pitzer approach if parameters are available
pitzer_calc = False
param = None if salt is None else solution.get_property(salt.formula, "model_parameters.molar_volume_pitzer")

param = solution.get_property(salt.formula, "model_parameters.molar_volume_pitzer")
if param is not None:
# determine the average molality of the salt
# this is necessary for solutions inside e.g. an ion exchange
Expand All @@ -599,8 +592,8 @@ def get_solute_volume(self, solution: "solution.Solution") -> ureg.Quantity:
# determine alpha1 and alpha2 based on the type of salt
# see the May reference for the rules used to determine
# alpha1 and alpha2 based on charge
if salt.nu_cation >= 2 and salt.nu_anion >= 2:
if salt.nu_cation >= 3 or salt.nu_anion >= 3:
if salt.z_cation >= 2 and salt.z_anion <= -2:
if salt.z_cation >= 3 or salt.z_anion <= -3:
alpha1 = 2.0
alpha2 = 50.0
else:
Expand Down Expand Up @@ -702,7 +695,6 @@ def equilibrate(self, solution: "solution.Solution") -> None:
def __deepcopy__(self, memo) -> "NativeEOS":
# custom deepcopy required because the PhreeqPython instance used by the Native and Phreeqc engines
# is not pickle-able.
import copy

cls = self.__class__
result = cls.__new__(cls)
Expand Down
Loading
Loading