From 4d1454c3e5ee77be70103d621e73fa7090765d1b Mon Sep 17 00:00:00 2001 From: Vineet Bansal Date: Mon, 12 Jan 2026 18:21:35 -0500 Subject: [PATCH 1/3] snippet in code to surface a possible bug --- src/pyEQL/engines.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/pyEQL/engines.py b/src/pyEQL/engines.py index 5eecead5..b096d22f 100644 --- a/src/pyEQL/engines.py +++ b/src/pyEQL/engines.py @@ -737,6 +737,16 @@ def equilibrate( for s, mol in self.ppsol.species_moles.items(): solution.components[s] = mol + # --- Code to demonstrate bug --- + # The standardized formula for (CO2)2 is still CO2, so this amount + # (negligible) ends up overwriting the original CO2 amount. + # We simply get lucky in the loop above that (CO2)2 is encountered + # before CO2 in the old wrapper, but we force surfacing the bug here. + problematic_keys = ("(CO2)2",) + for k in problematic_keys: + if k in self.ppsol.species_moles: + solution.components[k] = self.ppsol.species_moles[k] + # log a message if any components were not touched by PHREEQC # if that was the case, re-adjust the charge balance to account for those species (since PHREEQC did not) missing_species = set(self._stored_comp.keys()) - {standardize_formula(s) for s in self.ppsol.species} From 549296c7c0cab800979e4a4db2e3ca443825df5d Mon Sep 17 00:00:00 2001 From: Vineet Bansal Date: Tue, 13 Jan 2026 12:17:21 -0500 Subject: [PATCH 2/3] possible fix for issue309 --- src/pyEQL/utils.py | 7 +++++++ tests/test_utils.py | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/src/pyEQL/utils.py b/src/pyEQL/utils.py index 2d4dee88..6cff2cf2 100644 --- a/src/pyEQL/utils.py +++ b/src/pyEQL/utils.py @@ -7,6 +7,7 @@ """ import logging +import re from collections import UserDict from functools import lru_cache from typing import Any @@ -76,6 +77,12 @@ def standardize_formula(formula: str): for char in [r"‑", r"‐", r"‒", r"–", r"—", r"−"]: # noqa: RUF001 formula = formula.replace(char, "-") + # Do not modify any dimers etc (Phreeqc reports a small amount of + # "(CO2)2" in a water solution with C(4), for example. + _POLYMER_RE = re.compile(r"^\([A-Za-z0-9+-]+\)\d+$") + if _POLYMER_RE.match(formula): + return formula + sform = Ion.from_formula(formula).reduced_formula # TODO - manual formula adjustments. May be implemented upstream in pymatgen in the future diff --git a/tests/test_utils.py b/tests/test_utils.py index 9a2800e7..8d9ea121 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -62,6 +62,10 @@ def test_standardize_formula(): assert standardize_formula("(NH4)2SO4") == "(NH4)2SO4(aq)" assert standardize_formula("NH4SO4-") == "NH4SO4[-1]" + # Polymers should be left intact + assert standardize_formula("(CO2)2") == "(CO2)2" + assert standardize_formula("(H2O)3") == "(H2O)3" + def test_formula_dict(): """ From 2a0e8d86daa8114240253a91b920439943fdb3c6 Mon Sep 17 00:00:00 2001 From: Vineet Bansal Date: Tue, 13 Jan 2026 12:54:46 -0500 Subject: [PATCH 3/3] removed snippet to demonstrate bug fix --- src/pyEQL/engines.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/pyEQL/engines.py b/src/pyEQL/engines.py index b096d22f..5eecead5 100644 --- a/src/pyEQL/engines.py +++ b/src/pyEQL/engines.py @@ -737,16 +737,6 @@ def equilibrate( for s, mol in self.ppsol.species_moles.items(): solution.components[s] = mol - # --- Code to demonstrate bug --- - # The standardized formula for (CO2)2 is still CO2, so this amount - # (negligible) ends up overwriting the original CO2 amount. - # We simply get lucky in the loop above that (CO2)2 is encountered - # before CO2 in the old wrapper, but we force surfacing the bug here. - problematic_keys = ("(CO2)2",) - for k in problematic_keys: - if k in self.ppsol.species_moles: - solution.components[k] = self.ppsol.species_moles[k] - # log a message if any components were not touched by PHREEQC # if that was the case, re-adjust the charge balance to account for those species (since PHREEQC did not) missing_species = set(self._stored_comp.keys()) - {standardize_formula(s) for s in self.ppsol.species}