Skip to content

Let pKa/redox helpers consume conformer ensembles via EnsembleThermo - #119

Merged
galjos merged 2 commits into
mainfrom
ensemble-thermo-adapter
Jul 10, 2026
Merged

Let pKa/redox helpers consume conformer ensembles via EnsembleThermo#119
galjos merged 2 commits into
mainfrom
ensemble-thermo-adapter

Conversation

@galjos

@galjos galjos commented Jul 10, 2026

Copy link
Copy Markdown
Member

`pKa`, `calibrate_proton_reference`, `reduction_potential`, and `reaction_free_energy` all duck-type on a single argument's `total_EeGtot()` -- they never inspect the type, just call that one method. `ensemble.py` already has proper Boltzmann-weighting (`boltzmann_weights`, `ensemble_free_energy`, `lowest_gibbs`), but `ensemble_free_energy` returns a bare float, so there was no way to plug a conformer ensemble directly into those helpers -- today's usage docs pick a single conformer (`generate(..., max_conformers=1)`) for exactly that reason.

The fix

`EnsembleThermo(thermos, temperature=298.15)` wraps `ensemble_free_energy` behind a `.total_EeGtot()` method, so it duck-types as a `Thermo` and can be passed anywhere a single `Thermo` is expected today -- no changes needed to pka.py or reactions.py themselves.

Verification

  • Unit tests confirm `EnsembleThermo(...).total_EeGtot()` matches `ensemble_free_energy(..., unit="H")`, and that it drops into `pKa`/`reduction_potential` producing results identical to manually pre-reducing the ensemble.
  • A real end-to-end test runs actual xtb-cli (GFN2-xTB) on 4-hydroxybutanoic acid / its conjugate base. Picked deliberately: smaller/more rigid acids (e.g. glycolic acid) collapse to a single RDKit conformer after RMSD pruning, which wouldn't actually exercise ensemble averaging -- 4-hydroxybutanoic acid's flexible C-C-C-C backbone gives 4-5 genuinely distinct conformers per species, so this is real Boltzmann averaging over real semiempirical energies, not a degenerate case.
  • Full suite: 401 passed, 10 skipped with a real `xtb` binary; 397 passed, 14 skipped without (clean skip). 100% coverage on `ensemble.py`. Docs build clean.

Closes #118

pKa, calibrate_proton_reference, reduction_potential, and
reaction_free_energy all duck-type on total_EeGtot() -- EnsembleThermo
wraps ensemble_free_energy() behind that same method, so a conformer
ensemble can be passed directly instead of picking a single conformer.
Verified end-to-end with real xtb-cli GFN2-xTB calculations on
4-hydroxybutanoic acid, which (unlike smaller/more rigid acids) RDKit
generates several genuinely distinct conformers for.
@codecov

codecov Bot commented Jul 10, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 97.31%. Comparing base (923a4c4) to head (434989d).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #119   +/-   ##
=======================================
  Coverage   97.31%   97.31%           
=======================================
  Files          32       32           
  Lines        1935     1940    +5     
=======================================
+ Hits         1883     1888    +5     
  Misses         52       52           
Flag Coverage Δ
unittests 97.31% <100.00%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ 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.

@galjos
galjos merged commit 0636de4 into main Jul 10, 2026
3 checks passed
@galjos
galjos deleted the ensemble-thermo-adapter branch July 10, 2026 08:50
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.

pKa/redox helpers can't consume conformer ensembles directly

1 participant