Skip to content

Migrate Pourbaix workflow to pyEQL v1.6.1 - #369

Open
SuixiongTay wants to merge 60 commits into
KingsburyLab:pourbaixfrom
SuixiongTay:pourbaix_pyEQL_v1.5
Open

Migrate Pourbaix workflow to pyEQL v1.6.1#369
SuixiongTay wants to merge 60 commits into
KingsburyLab:pourbaixfrom
SuixiongTay:pourbaix_pyEQL_v1.5

Conversation

@SuixiongTay

@SuixiongTay SuixiongTay commented Apr 1, 2026

Copy link
Copy Markdown
Collaborator

Description

This PR migrates the previous pourbaix to pourbaix_pyEQL_v1.5 branch.

Content

  1. Core modules: Core pourbaix workflow and diagram construction
  • pourbaix_api.py
  • pourbaix_diagram.py
  • compatibility.py
  1. Databases: Reference databases and correction schemes
  • NBS_Tables_Library.xlsx
  • MP2020Compatibility.yaml
  • MITCompatibility.yaml
  • mpr_reference_ion_database.json
  • pourbaix_test_data.json
  1. Tests: Test coverage from pymatgen
  • test_pourbaix_api.py
  • test_pourbaix_diagram.py
  • test_compatibility.py
  1. Tutorials
  • pyeql_tutorial_pourbaix_Ca-Mg-C.ipynb
  • pyeql_tutorial_pourbaix_Na-K-Mg-Cl.ipynb

Note

  • emmet-core uses typing.NotRequired which was introduced in python 3.11.
  • Therefore, pytest.importskip is used to skip through python 3.10 to avoid the error.

Addressing #368

@SuixiongTay

Copy link
Copy Markdown
Collaborator Author

Hi @rkingsbury , I noticed the pourbaix branch is quite old and there were a lot of commits since then.

Should I target this PR against the pourbaix branch, or would you prefer this PR against the current main and let you assign the branching? Thanks!

@SuixiongTay SuixiongTay added this to the v1.5.0 milestone Apr 1, 2026
@SuixiongTay SuixiongTay changed the title Migrate Pourbaix module to pyEQL v1.5.0 Migrate Pourbaix workflow to pyEQL v1.5.0 Apr 1, 2026
@codecov

codecov Bot commented Apr 1, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 75.44910% with 41 lines in your changes missing coverage. Please review.
✅ Project coverage is 87.17%. Comparing base (dbdfbce) to head (77e9098).
⚠️ Report is 892 commits behind head on pourbaix.

Files with missing lines Patch % Lines
src/pyEQL/pourbaix/pourbaix_api.py 74.16% 26 Missing and 5 partials ⚠️
src/pyEQL/pourbaix/compatibility.py 83.87% 3 Missing and 2 partials ⚠️
src/pyEQL/pourbaix/pourbaix_diagram.py 68.75% 5 Missing ⚠️
Additional details and impacted files
@@              Coverage Diff              @@
##           pourbaix     #369       +/-   ##
=============================================
+ Coverage     71.75%   87.17%   +15.42%     
=============================================
  Files            13       17        +4     
  Lines          2687     3112      +425     
  Branches        481      549       +68     
=============================================
+ Hits           1928     2713      +785     
+ Misses          676      290      -386     
- Partials         83      109       +26     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@rkingsbury

Copy link
Copy Markdown
Member

Hi @SuixiongTay , sorry I somehow missed your comment from 4/1. I've rebased your changes in the pourbaix branch to apply on top of main as of today. I'll do it again after #403 is merged, which may have some impact on your code.

@SuixiongTay
SuixiongTay marked this pull request as draft May 29, 2026 16:58
@SuixiongTay SuixiongTay changed the title Migrate Pourbaix workflow to pyEQL v1.5.0 WIP - Migrate Pourbaix workflow to pyEQL v1.5.0 May 29, 2026
@rkingsbury rkingsbury removed this from the v1.5.0 milestone Jun 15, 2026
@SuixiongTay
SuixiongTay force-pushed the pourbaix_pyEQL_v1.5 branch 2 times, most recently from cbb679d to b5c65a1 Compare August 7, 2026 13:51
@SuixiongTay SuixiongTay changed the title [WIP] - Migrate Pourbaix workflow to pyEQL v1.5.0 Migrate Pourbaix workflow to pyEQL v1.5.0 Aug 7, 2026
@SuixiongTay
SuixiongTay marked this pull request as ready for review August 7, 2026 18:32
@SuixiongTay

Copy link
Copy Markdown
Collaborator Author

Hi @rkingsbury, quick question: Regarding rebasing onto pourbaix branch, my understanding is that it would bring in the previous commits from pourbaix branch into this branch. Is that correct? Or should we directly compare this PR against the pourbaix branch instead of main?

@rkingsbury

Copy link
Copy Markdown
Member

Good question - for this PR, please compare against pourbaix rather than main (I think you can change the target branch, if not, I can). That way the diff will show just your changes on top of the previous addition of pourbaix code.

@SuixiongTay

Copy link
Copy Markdown
Collaborator Author

Thanks @rkingsbury! I dont seem to have the option to edit the target branch. Would you mind helping me change it?

@rkingsbury
rkingsbury changed the base branch from main to pourbaix August 7, 2026 19:41
@rkingsbury rkingsbury changed the title Migrate Pourbaix workflow to pyEQL v1.5.0 Migrate Pourbaix workflow to pyEQL v1.6.1 Aug 7, 2026
@SuixiongTay SuixiongTay changed the title Migrate Pourbaix workflow to pyEQL v1.6.1 [WIP] - Migrate Pourbaix workflow to pyEQL v1.6.1 Aug 7, 2026
@SuixiongTay
SuixiongTay marked this pull request as draft August 7, 2026 19:42
@rkingsbury

Copy link
Copy Markdown
Member

Thanks @rkingsbury! I dont seem to have the option to edit the target branch. Would you mind helping me change it?

Done. You'll need to reconcile some merge conflicts it looks like. Lmk if you get stuck!

@SuixiongTay SuixiongTay changed the title [WIP] - Migrate Pourbaix workflow to pyEQL v1.6.1 Migrate Pourbaix workflow to pyEQL v1.6.1 Aug 8, 2026
@SuixiongTay
SuixiongTay marked this pull request as ready for review August 8, 2026 12:56
@SuixiongTay

Copy link
Copy Markdown
Collaborator Author

Hi @rkingsbury , this PR is ready for your review. I have also included two examples: pyeql_tutorial_pourbaix_Ca-Mg-C.ipynb and pyeql_tutorial_pourbaix_Na-K-Mg-Cl.ipynb which are representative of the Pourbaix diagrams in the manuscript.

@rkingsbury rkingsbury left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this @SuixiongTay ! This really helps me understand your methods and changes. Overall looks good. I've made a series of small comments, including some opportunities for refactoring / streamlining that we can tackle separately or at another time.

The biggest / most important things to address before merging this are:

  1. I don't think it's necessary (or advisable) for us to carry any of the solid compatibility classes in pyEQL. All we need to care about is the AqueousCompatibility. We can import all the **Compatibility classes (MP, MP2020, MIT) and associated .yaml files from pymatgen if we need them. Making this change will simplify this PR quite a bit by eliminating some extra files.
  2. Make sure you have added or updated docstrings and references whereever appropriate to be consistent with your changes. (See specific comments). It's easy to copy/paste stuff, forget to update the docstring or reference, and then have a hard time figuring out where a number came from later on.
  3. Clarification: (why) do we need a separate method modified_get_ion_entries_in_chemsys? I understand it might have made sense to develop it side-by-side initially, but is there any reason not to just merge the changes into the regular get_ion_entries_in_chemsys?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please delete the checkpoint file (and/or edit .gitignore to correctly ignore them - this is actually a problem right now.

(btw, the checkpoint file exposed your MP API Key, so you might want to re-generate it)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both notebooks look good! In this one, please add a short explanatory comment near the examples to explain why, in Example 1, you set comp_dict and conc_dict equal to one another, but in Examples 2 and 3, you set comp_dict to correspond to the target phase of interest.

Comment on lines 1356 to +1511
self.cpd_entropies = {
# exp anion entropy
"O2": 0.316731,
"N2": 0.295729,
"F2": 0.313025,
"Cl2": 0.344373,
"Br": 0.235039,
"Hg": 0.234421,
"H2O": 0.071963, # 0.215891 eV/H2O
# exp cation entropy
"C": 0.017737,
"S": 0.098265,
"Na": 0.158245,
"K": 0.181694,
"Ca": 0.127993,
"Mg": 0.100985,
"Li": 0.089984,
"P": 0.126972,
"Al": 0.087543,
# exp solid entropy
# oxides
"Na2O": 0.0773147,
"MgO": 0.04312, # microcrystal #0.0416239 (macrocrystal)
"CaO": 0.0614161,
"KO2": 0.1202056,
"K2O2": 0.0788753,
"Na2O2": 0.0733903,
"Li2O": 0.038699,
"Fe3O4": 0.06463,
"Fe2O3": 0.05402,
"Ca2Fe2O5": 0.06482,
"Mg(FeO2)2": 0.05465,
"Al2O3": 0.031470,
"CaAl2O4": 0.050422,
"CaAl4O7": 0.0457904,
"LiAlO2": 0.041211,
"LiAl5O8": 0.033062,
"SiO2": 0.043097,
"Al2FeO4": 0.04693,
"MgFe2O4": 0.05465,
# chlorides
"NaCl": 0.111445,
"KCl": 0.127606,
"H4NCl": 0.048721,
"MgCl2": 0.092312,
"CaCl2": 0.107742,
"LiCl": 0.0916683,
"FeCl2": 0.0789525,
"FeCl3": 0.074665,
"MgH2Cl2O": 0.0706607, # hydrate
"MgH4(ClO)2": 0.061768, # hydrate
"MgH8(ClO2)2": 0.0543861, # hydrate
"MgH12(ClO3)2": 0.0538711, # hydrate
"LiAl2H6ClO6": 0.039220162, # hydrate, #0.071213, #quacc 406.14803248222813 J/mol.K
# carbonates
"Li2CO3": 0.046542,
"NaHCO3": 0.052377,
"Na2CO3": 0.069517,
"K2CO3": 0.080096,
"CaCO3": 0.057414,
"MgCO3": 0.040604,
"CaMg(CO3)2": 0.047952,
"KHCO3": 0.059485,
"FeCO3": 0.057414,
"Na3H5(CO4)2": 0.051708,
"Na2H20CO13": 0.0483,
"Na2H2CO4": 0.05772,
"Na2H10SO5": 0.04944,
# sulfides
"MgS": 0.0777628,
"CaS": 0.087296,
"Na2S": 0.086214,
"K2S": 0.108154,
"FeS2": 0.0545,
"FeS": 0.09315,
"Na2S2O7": 0.056774, # hydrate
"K2S2O7": 0.071691, # hydrate
# "Na2S5": None,
# sulfates
"CaSO4": 0.054953,
"MgSO4": 0.047176,
"K2SO4": 0.077500,
"Na2SO4": 0.06603,
"KHSO4": 0.060964,
"NaHSO4": 0.049883,
"Li2SO4": 0.0508103,
"FeSO4": 0.05536,
"Al2(SO4)3": 0.043498,
"CaH4SO6": 0.049983, # hydrate
"Ca2H2S2O9": 0.053768, # hydrate
"MgH12SO10": 0.0448196, # hydrate
"MgH12SO9": 0.04328852, # hydrate
"MgH14SO11": 0.042575, # hydrate
"MgH2SO5": 0.0433990, # hydrate
"FeH14SO11": 0.0468325, # hydrate
# nitrates
"Ca(NO3)2": 0.066369,
"NaNO3": 0.072012,
"NaNO2": 0.080189,
"Mg(NO3)2": 0.056309,
"KNO3": 0.082228,
"KNO2": 0.117494,
"MgPH16NO10": 0.03462, # hydrate #0.04192 #struvite
"MgH12(NO6)2": 0.0517309, # hydrate
# phosphates
"P2O5": 0.050515,
"FePH2O5": 0.044098, # hydrate
"Ca2P2O7": 0.05316,
"FeP(H2O3)2": 0.044098, # hydrate
"Mg2P2O7": 0.04351,
"Mg3(PO4)2": 0.044973,
"Ca3(PO4)2": 0.056098,
"CaPHO4": 0.0491682,
"CaPH5O6": 0.0450325, # hydrate
"CaP2(H2O3)3": 0.044601, # hydrate
"Ca5P3HO13": 0.0574393, # hydrate
# nitrogen compounds
"NaN3": 0.074827,
# carbon compounds
"CaC2": 0.072062,
"Fe3C": 0.07177,
# hydroxides
"KHO": 0.081270,
"NaHO": 0.066391,
"Ca(HO)2": 0.051537,
"Mg(HO)2": 0.039047,
"LiHO": 0.044086,
"Li2O2": 0.037785,
"FeHO2": 0.04664,
"LiH3O2": 0.0366745, # hydrate
"Al(HO)3": 0.0302169,
"AlHO2": 0.0374136, # 0.0272973 polymorph
# hydrides
"NaH": 0.0618271,
"NaH2N": 0.0594075,
"LiH": 0.0309135,
"CaH2": 0.043262,
"LiAlH4": 0.0405526,
"Li3AlH6": 0.0317015,
# cyanates
"NaCNO": 0.0747035,
"KCSN": 0.0959945,
# others
"CaMg2": 0.1074022,
"H4CN2O": 0.0461752,
# silicate
"Mg3Si2H4O9": 0.038,
"MgSiO3": 0.041865,
"CaMg(SiO3)2": 0.044167,
"Ca2Mg5Si8(HO12)2": 0.04137,
"Mg3Si4(HO6)2": 0.038362,
"NaAlSi3O8": 0.0493,
# "CaAl2(SiO4)2",
# "NaAlSi2H2O7",
# "KAl3Si3(HO6)2",
# "Al2Si2H4O9",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just a note for the future given the volume of expanded data here it makes most sense to store all the entropies separately in a .json or .yaml file and read it in here.

Can you add a TODO comment in the code about this? (or just do it now, if you prefer)

Comment on lines 1354 to 1355
# Standard state entropy of molecular-like compounds at 298K (-T delta S)
# from Kubaschewski Tables (eV/atom)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update this comment

  1. molecular-like compounds -> pure elements, molecular gases, and reference solids
  2. Add or update the reference - I think most of your entropies come from NIST rather than Kumaschewski, right?

Comment on lines +1304 to +1305
universal_solid_shift_eV_per_atom: float = 0.0,
apply_universal_shift_to: str = "compounds",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add descriptions for these new kwargs to the docstring (Args: section). Remember to include units!



def test_get_pourbaix_entries(monkeypatch):
from pymatgen.analysis.compatibility import MaterialsProjectAqueousCompatibility # noqa: PLC0415

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should import from pyEQL's version

from pymatgen.analysis.pourbaix_diagram import PourbaixDiagram, PourbaixEntry
from pymatgen.core.composition import Composition
from pymatgen.core.ion import Ion
from pymatgen.entries.compatibility import MaterialsProjectAqueousCompatibility

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should import the pyEQL version

from mp_api.client import MPRester
from pymatgen.analysis.phase_diagram import PhaseDiagram
from pymatgen.analysis.pourbaix_diagram import IonEntry, PourbaixDiagram, PourbaixEntry
from pymatgen.analysis.pourbaix_diagram import PourbaixDiagram, PourbaixEntry

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should import the pyEQL version

Comment thread requirements.txt

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please revert this change to whatever the upstream branch has, unless this bump is required to make your changes work (this requirement will be updated separately elsewhere)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pare this file down to ONLY test MPAqueousCompatibility - in keeping with my bigger comment to remove all the **Compatibility classes except the aqueous one from pyEQL.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants