Skip to content

Add a native-xtb engine with implicit solvation for open-shell species - #70

Merged
galjos merged 1 commit into
mainfrom
xtb-cli-backend
Jul 6, 2026
Merged

Add a native-xtb engine with implicit solvation for open-shell species#70
galjos merged 1 commit into
mainfrom
xtb-cli-backend

Conversation

@galjos

@galjos galjos commented Jul 5, 2026

Copy link
Copy Markdown
Member

Closes the gap the last two discussions surfaced: neither prior xTB path can do open-shell + solvation together.

The native xtb binary does all of it, so this adds it as the xtb-cli engine — covering charged radicals in solution with method-consistent parameters.

Usage

thermo screen mols/ --engine xtb-cli --solvent water          # radical anions in solvent

What changed

  • calculator/xtb_cli.py (new) — runs xtb --ohess --gfn <n> --chrg <c> --uhf <2S> [--alpb <solvent>], then parses the energy (xtbopt.xyz), optimised geometry, and frequencies (vibspectrum, wavenumber = 3rd-from-last token). The executable is found via $XTB_COMMAND or PATH; nothing is imported from xtb, so the package still imports without it.
  • thermo/api.pyxtb_cli_thermo, resolving the electron-count spin guess to --uhf (radicals open-shell automatically) and solvent--alpb.
  • thermo/screening.py, cli/thermo.pyscreen(engine="xtb-cli") / --engine xtb-cli; solvent now applies to both dftb+ and xtb-cli.

Validation

Real xtb 6.7.1: gas-phase water S = 45.05 cal/mol/K (experiment ~45.1); an OH radical runs open-shell and is stabilised by ~6.5 kcal/mol in water (--alpb) — ΔG_solv on an open-shell radical, the exact case that motivated this. Energy/frequencies match the tblite path.

Offline suite 223 passed / 6 skipped; real DFTB+ + xtb integration 45 passed. CI-safe tests cover parsing, command construction (mocked subprocess), dispatch, and the missing-binary error; a real end-to-end test runs when xtb is present and skips otherwise. Patch coverage verified without the xtb binary (0 uncovered).

Dependency

xtb-cli needs the native xtb binary (optional): conda install -c conda-forge xtb. Without it, the other engines work unchanged and the xtb-cli tests skip.

The tblite xTB engine (in-process) can't do solvation (tblite's ASE calculator
exposes no ALPB/GBSA), and running xTB through DFTB+ can't do open-shell (a known
DFTB+ limitation). The native xtb binary does all of it, so add it as the
"xtb-cli" engine -- covering charged radicals in solution with method-consistent
parameters.

- calculator/xtb_cli.py: run `xtb --ohess --gfn <n> --chrg <c> --uhf <2S>
  [--alpb <solvent>]`, then parse the energy (xtbopt.xyz), optimised geometry,
  and frequencies (vibspectrum), feeding them into run_thermo like the other
  engines. The xtb executable is found via $XTB_COMMAND or PATH; nothing is
  imported from xtb, so the package still imports without it.
- thermo/api.py: `xtb_cli_thermo`, resolving spin to --uhf so radicals run
  open-shell automatically; solvent -> --alpb.
- thermo/screening.py, cli/thermo.py: `screen(engine="xtb-cli")` /
  `--engine xtb-cli`; solvent now applies to dftb+ and xtb-cli.

Validated against the real xtb 6.7.1: gas-phase water S = 45.05 cal/mol/K
(experiment ~45.1); an OH radical runs open-shell and is stabilised by
~6.5 kcal/mol in water (--alpb). Frequencies/energy match the tblite path.
@codecov

codecov Bot commented Jul 5, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.59155% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 96.66%. Comparing base (fd6cac2) to head (2c9630d).

Files with missing lines Patch % Lines
ThermoScreening/calculator/xtb_cli.py 98.21% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main      #70      +/-   ##
==========================================
+ Coverage   96.57%   96.66%   +0.08%     
==========================================
  Files          23       24       +1     
  Lines        1459     1527      +68     
==========================================
+ Hits         1409     1476      +67     
- Misses         50       51       +1     
Flag Coverage Δ
unittests 96.66% <98.59%> (+0.08%) ⬆️

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 b87b46c into main Jul 6, 2026
3 checks passed
@galjos

galjos commented Jul 6, 2026

Copy link
Copy Markdown
Member Author

Added a second commit: thermo doctor now reports the xTB toolchain — the native xtb binary (for --engine xtb-cli, via $XTB_COMMAND or PATH) and the tblite package (for --engine xtb). Both are optional: shown as informational, marked (optional), and they don't change the doctor exit code (which still fails only on a missing required DFTB+ backend). So a DFTB+-only user is unaffected.

galjos added a commit that referenced this pull request Jul 6, 2026
Follow-up to the xtb engines (#68, #70): `thermo doctor` only checked
the DFTB+ toolchain. Now it also reports the xTB backends, so `doctor`
reflects all three engines.

## What it reports
- **`xtb`** — the native binary for `--engine xtb-cli` (resolved via
`$XTB_COMMAND`, then PATH).
- **`tblite`** — the Python package for `--engine xtb`.

```
dftb+        found    /.../bin/dftb+
modes        found    /.../bin/modes
DFTB_PREFIX  found    /.../3ob/skfiles
C-C.skf      found    /.../3ob/skfiles/C-C.skf
xtb          found    /.../xtbcli/bin/xtb
tblite       found    importable
```
When missing, the detail line gives the fix:
```
xtb     missing  not found (set XTB_COMMAND or `conda install -c conda-forge xtb`; needed for --engine xtb-cli)  (optional)
tblite  missing  not importable (`conda install -c conda-forge tblite-python`; needed for --engine xtb)  (optional)
```

## Design: optional, so DFTB+-only users are unaffected
- The xTB checks are marked `(optional)` and **do not change the doctor
exit code** — it still fails only on a missing *required* DFTB+ backend
(`dftb+`/`modes`/`DFTB_PREFIX`/`C-C.skf`).
- `Diagnostic` gains an `optional` flag; `run_doctor` filters optional
items from the pass/fail decision.

This is a small step toward the "helpful doctor" idea — the detail now
includes the exact `conda install` command for whatever's missing.

## Note
This was originally committed onto the #70 branch, but #70 merged before
its CI picked up the extra commit — so it's re-based here as its own PR
off the current main. Offline suite: 252 passed / 11 skipped.
galjos added a commit that referenced this pull request Jul 6, 2026
`environment.yml` already installed DFTB+ but predates the xTB engines
(#68, #70). Add the xTB backends so `conda env create -f
environment.yml` provisions **every** calculation engine in one command.

```yaml
dependencies:
  - python>=3.12
  - dftbplus        # DFTB+ engine: `dftb+` and `modes`
  - xtb             # native xtb binary, for --engine xtb-cli
  - tblite-python   # GFN-xTB via tblite, for --engine xtb
  - pip
  - pip:
      - "-e .[test,lint]"
```

After `conda env create -f environment.yml && conda activate
thermoscreening`, `thermo doctor` reports every backend as found (pairs
with #71). README updated to say the env covers all backends.

Verified the three backends resolve on conda-forge (dftbplus-25.1 nompi,
xtb-6.6.1, tblite-python-0.3.0); YAML validated.

This is the "installable through the project" follow-up: the compiled
backends (DFTB+/modes/xtb/tblite) can't be pip-installed, so the conda
env is how the project bundles them, while `thermo setup-dftb` handles
the Slater-Koster and GBSA parameter files.
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.

1 participant