Support for spin-polarized calculations#257
Draft
chselz wants to merge 16 commits into
Draft
Conversation
Signed-off-by: Christian Selzer <s6chselz@uni-bonn.de>
This reverts commit 8f26f7a. was ai try for unrestricted scf
Signed-off-by: Christian Selzer <s6chselz@uni-bonn.de>
Signed-off-by: Christian Selzer <s6chselz@uni-bonn.de>
Signed-off-by: Christian Selzer <s6chselz@uni-bonn.de>
Signed-off-by: Christian Selzer <s6chselz@uni-bonn.de>
Signed-off-by: Christian Selzer <s6chselz@uni-bonn.de>
Signed-off-by: Christian Selzer <s6chselz@uni-bonn.de>
Signed-off-by: Christian Selzer <s6chselz@uni-bonn.de>
Signed-off-by: Christian Selzer <s6chselz@uni-bonn.de>
| from .field import * | ||
| from .list import InteractionList, InteractionListCache | ||
| from .solvation import * | ||
| from .spin import * |
Signed-off-by: Christian Selzer <s6chselz@uni-bonn.de>
There was a problem hiding this comment.
Pull request overview
This PR adds spin-polarized xTB support by introducing a spin-polarisation interaction and enabling an unrestricted (UHF) SCF flow, with CLI/config hooks plus tests and documentation updates.
Changes:
- Add
SpinPolarisationinteraction (with spin-constant data + factory) and expose it viadxtb.components. - Extend SCF to support
nspin=2(UHF) and route interaction potentials/energies by spin channel. - Add CLI flags (
--spinpol,--uhf-mode), documentation, and tblite-based reference tests for energies/gradients.
Reviewed changes
Copilot reviewed 34 out of 34 changed files in this pull request and generated 13 comments.
Show a summary per file
| File | Description |
|---|---|
| test/test_wavefunction/test_spin.py | Adds tests for spin-representation conversion utilities. |
| test/test_spinpol/test_spinconst.py | Validates loading of spin constants and WLL construction. |
| test/test_spinpol/test_gradient.py | Adds spin-polarized gradient/force checks vs tblite references. |
| test/test_spinpol/test_energy.py | Adds spin-polarized energy and spin-shell energy/potential tests. |
| test/test_spinpol/samples.py | Adds tblite reference data for spin-polarized cases/constants. |
| test/test_spinpol/init.py | Introduces new test package for spin polarization. |
| test/test_singlepoint/test_energy.py | Adds RHF vs UHF closed-shell equivalence tests. |
| test/test_cli/test_args.py | Adds CLI/config test to ensure --spinpol implies UHF mode. |
| src/dxtb/components/spinpolarisation.py | Public re-export module for spin-polarisation component. |
| src/dxtb/components/init.py | Registers spinpolarisation in component package/lazy loader. |
| src/dxtb/_src/wavefunction/spin.py | Adds spin basis conversion helpers (charge/mag ↔ up/down). |
| src/dxtb/_src/wavefunction/init.py | Exposes spin utilities from wavefunction package. |
| src/dxtb/_src/scf/base.py | Implements UHF-aware density/charge/potential/H build and nspin inference. |
| src/dxtb/_src/constants/defaults.py | Adds defaults for spin polarization and UHF mode. |
| src/dxtb/_src/components/interactions/spin/spinpolarisation.py | Implements the SpinPolarisation interaction and its cache/WLL build. |
| src/dxtb/_src/components/interactions/spin/factory.py | Factory for creating SpinPolarisation from atomic numbers. |
| src/dxtb/_src/components/interactions/spin/constants.py | Adds spin-constant table used by the interaction. |
| src/dxtb/_src/components/interactions/spin/init.py | Exposes spin interaction APIs from the new subpackage. |
| src/dxtb/_src/components/interactions/list.py | Makes Potential.mono spin-dimensioned when charges.nspin > 1; registers reset/update. |
| src/dxtb/_src/components/interactions/dispersion/d4sc.py | Minor formatting/comment tweak in error message path. |
| src/dxtb/_src/components/interactions/coulomb/secondorder.py | Minor signature formatting/comment tweak. |
| src/dxtb/_src/components/interactions/container.py | Adds nspin to Charges container. |
| src/dxtb/_src/components/interactions/base.py | Adds spin-channel routing logic to Interaction potential/energy evaluation. |
| src/dxtb/_src/components/interactions/init.py | Re-exports the new spin interaction package. |
| src/dxtb/_src/components/classicals/dispersion/d4.py | Normalizes dtype/device handling for D4 inputs. |
| src/dxtb/_src/cli/driver.py | Adds --spinpol wiring to include spin-polarisation interaction. |
| src/dxtb/_src/cli/argparser.py | Adds --uhf-mode and --spinpol CLI options. |
| src/dxtb/_src/calculators/types/energy.py | Normalizes positions dtype/device in singlepoint(). |
| src/dxtb/_src/calculators/config/scf.py | Adds uhf_mode to SCF configuration. |
| src/dxtb/_src/calculators/config/main.py | Plumbs uhf_mode from args into config (incl. spinpol implication). |
| src/dxtb/main.py | Fixes CLI entry import to use ._src.cli. |
| docs/source/02_indepth/components_interactions.rst | Adds spin-polarisation component to interaction docs. |
| docs/source/01_quickstart/getting_started.rst | Documents restricted vs unrestricted and spin-polarisation usage. |
| .vscode/settings.json | Updates editor environment settings. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+186
to
+198
| wll = torch.zeros((ihelp.nsh, ihelp.nsh), **self.dd) | ||
|
|
||
| for atom_idx, number in enumerate(numbers): | ||
| for ishell in range(ihelp.shells_per_atom[atom_idx]): | ||
| for jshell in range(ihelp.shells_per_atom[atom_idx]): | ||
| ishell_idx = ihelp.shell_index[atom_idx] + ishell | ||
| jshell_idx = ihelp.shell_index[atom_idx] + jshell | ||
| l1 = ihelp.angular[jshell_idx] | ||
| l2 = ihelp.angular[ishell_idx] | ||
| wll[jshell_idx, ishell_idx] = self.spinconst[ | ||
| atom_idx, lidx[l1, l2] | ||
| ] | ||
|
|
Comment on lines
+254
to
+255
| "Positions are required for ES2 cache." | ||
| ) # ? why es2 |
| numbers: Tensor, | ||
| device: torch.device | None = None, | ||
| dtype: torch.dtype | None = None, | ||
| ) -> SpinPolarisation | None: |
| action="store_true", | ||
| help=( | ||
| "R|Use unrestricted SCF mode\n" | ||
| "note this takes roughly twice the time than for restricted SCF" |
| self, | ||
| cache: InteractionCache, | ||
| qat: Tensor, | ||
| **_: Any, # ich hätte es qsh genannt |
Comment on lines
+35
to
+55
| @pytest.mark.parametrize("dtype", [torch.float, torch.double]) | ||
| # @pytest.mark.parametrize("name", sample_list) | ||
| def test_updown_to_magnet(dtype: torch.dtype) -> None: | ||
| dd: DD = {"device": DEVICE, "dtype": dtype} | ||
| tol = torch.finfo(dtype).eps ** 0.5 | ||
|
|
||
| qsh_before = torch.tensor( | ||
| [[-0.82824398, -0.33807717, -0.83367885], [0.0, 0.0, 0.0]] | ||
| ) | ||
|
|
||
| qsh_after = spin.updown_to_magnet_2(qsh_before) | ||
|
|
||
| ref_qsh_after = torch.tensor( | ||
| [ | ||
| [-0.82824398, -0.33807717, -0.83367885], | ||
| [-0.82824398, -0.33807717, -0.83367885], | ||
| ] | ||
| ) | ||
| assert ( | ||
| pytest.approx(ref_qsh_after.cpu(), rel=1e-7, abs=tol) == qsh_after.cpu() | ||
| ) |
| return x | ||
|
|
||
|
|
||
| # === General Forumlas === |
| self, | ||
| cache: ES2Cache, | ||
| qat: Tensor, | ||
| **_: Any, # missleading variable name qsh would be better |
| """Gradient of spGFN2-xTB""" | ||
|
|
||
| spconst: Tensor | ||
| """Spin Constants (same forsp GFN1-xTB and spGFN2-xTB)""" |
Comment on lines
+1071
to
+1076
| # Store alpha eigenvalues/vectors (for compatibility) | ||
| self._data.evals = evals_a | ||
| self._data.evecs = evecs_a | ||
|
|
||
| # Combine eigenvalues for Fermi smearing: shape (..., 2, nao) | ||
| emo = torch.stack([evals_a, evals_b], dim=-2) |
Signed-off-by: Christian Selzer <s6chselz@uni-bonn.de>
| @overload | ||
| def get_interaction( | ||
| self, name: Literal["SpinPolarisation"] | ||
| ) -> SpinPolarisation: ... |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #257 +/- ##
==========================================
- Coverage 86.08% 85.53% -0.55%
==========================================
Files 205 210 +5
Lines 10499 10849 +350
Branches 1224 1284 +60
==========================================
+ Hits 9038 9280 +242
- Misses 1099 1177 +78
- Partials 362 392 +30 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Signed-off-by: Christian Selzer <s6chselz@uni-bonn.de>
Signed-off-by: Christian Selzer <s6chselz@uni-bonn.de>
Signed-off-by: Christian Selzer <s6chselz@uni-bonn.de>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR implements spin-polarized xTB calculations. References were generated with tblite 0.5.0.
All new and also all old tests are passing.
I also updated the documentation to let the users know that this feature is now availible.
the spin polaraization can be activated either through the command line or via defining a new interaction via the factory function.
This feature was desired in #163.
I hope that these changes are not to invasive to the rest of the code base, but it necessitated the creation of spin channels to allow for an unrestricted SCF mode. What i did not do is timing tests to check if UHF takes double as long as RHF but there is a test checking that RHF and UHF results without spinpol give the same result for closed shell molecule