Repository navigation
[test] Add spin-orbit + spin-polarized Wien2k converter test (CaOs2) - #4
Conversation
1c2001d to
830cb84
Compare
…CaOs2) dftkit's Wien2k converter is only covered by the non-SOC SrVO3 case. This adds a SOC + spin-polarized golden test: CaOs2, a cubic fluorite cell with two symmetry-equivalent correlated Os atoms whose magnetic point group has 16 operations, 8 of them time-reversal. It exercises the combined-spin 'ud' block and the time-reversal symmetry path of dmftproj + the converter on a small 8-k-point fixture, validated by h5diff against a reference produced by this converter.
the-hampel
left a comment
There was a problem hiding this comment.
Reviewed as the first step of the #7 stack (#4 → #5 → #8 → #9 → #10 → #11 → #12 → #15 → #16 → #13/#19). Thanks for laying the harness down first — locking convert_dft_input before touching fortran/dmftproj is the right order, and the SOC/spin-polarized gap in the test suite is real.
Verification done locally
Rebased port/dmftproj-soc-harness onto current origin/unstable (20e6373) — conflict-free, delta unchanged at +1497 over 9 files. Configured and built in a fresh build directory and ran the full suite:
20/20 tests passed
2/20 Test #2: Py_wien2k_soc_convert ... Passed 0.85 sec
(For anyone reproducing this: an existing build/ that has previously been configured on another branch can leave stray test_*.py in test/python/vasp/converter/, which run_suite.py then picks up and fails on. That is a stale-build-dir artifact, not this PR.)
Substantive: the fixture's projectors are not orthonormal
This is the one I'd like to resolve before the stack builds on it.
The fixture declares two correlated Os shells of dim = 10 each — 20 spin-orbitals — but the band window is bands 60–76, i.e. 17 bands, at a single k-point. 20 > 17, so the correlated subspace cannot fit in the window and dmftproj's Löwdin orthonormalization cannot succeed. Reading the shipped reference back:
per shell: max |P P† − 1| = 4.98e-01
stacked 20x17 block: eig(P P†) = {0 x5, 1 x15} -> rank 15
trace(P P†) = 15.000
For contrast, the same quantity on the existing SrVO3 reference is 2e-8 at every one of its 10 k-points, rank-full at each.
So five of the twenty correlated directions are exactly null. As a pure converter characterization test that is survivable — the converter is reshaping and I/O, and it will reshape a rank-deficient block as faithfully as a good one. But the PR sells this as the harness that proves the port "leaves the result unchanged", and #7 itself says the .ctqmcout orthonormalization "fixes the numerical contract for everything downstream". Pinning that contract on a singular overlap matrix is the worst place to pin it: eigenvector choice in the null space is arbitrary, so a Python Löwdin can legitimately differ from the Fortran one there for reasons that say nothing about correctness — and conversely a genuine regression in the well-conditioned part can hide behind it.
Concretely I'd suggest either widening the energy window in case.indmftpr until the window holds at least 20 bands and regenerating the fixture, or dropping to one correlated Os atom if the two-atom permutation symmetry is not what you're after. Ideally the test then also asserts orthonormality directly, so the harness fails loudly rather than silently locking a degenerate case:
P = ar['dft_input']['proj_mat'][ik, 0, icrsh, :dim, :n_orb]
assert np.abs(P @ P.conj().T - np.eye(dim)).max() < 1e-6Also worth fixing
n_k = 1, not 8. The description says "a small (8 k-point) dmftproj output fixture". CaOs2.ctqmcout line 2 is 1, and the reference has n_k = 1, bz_weights = [1.0]. So no k-dependence is locked at all, which matters for a harness meant to catch a per-k projector regression. (The other half of the claim is accurate: 16 symmetry operations with time_inv = [0]*8 + [1]*8, and 48 rot_symmetries from .outputs.) Either fix the sentence or, better, ship a few k-points.
Reference provenance is undocumented. The fixture cannot be regenerated from what is in the tree: case.indmftpr and case.almblm* only arrive in #5 and later. Since this reference governs the whole port, a short header comment or README recording the Wien2k version, the init_lapw / x lapw1 -so / x lapwso / dmftproj invocations, the k-mesh and the window would pay for itself many times over.
h5diff tolerance is loose. h5diff(a, b) defaults to precision=1e-6. For a characterization test whose whole job is to show a reimplementation is a no-op — reading the same fixture bytes, so cross-platform drift is at 1e-15 — that is about six orders of magnitude of slack. Please pass an explicit tight tolerance.
CaOs2.oubwindn is dead. It is byte-identical to CaOs2.oubwinup (same blob), and for SP == 1 and SO == 1 convert_misc_input takes up and never looks at dn. Drop it, or make it non-identical if the intent is to cover the dn fallback.
Nits
wien2k_soc_convert.ref.h5in thefile(COPY …)list is redundant:test/python/CMakeLists.txtalreadyGLOB_RECURSE-copies every*.h5into the binary tree. The SrVO3 block right above correctly omits its own reference — worth matching.- The 2011 GPL boilerplate header on a new 2026 file is copied from
wien2k_convert.py; recently added tests in this repo (e.g.test/python/vasp/converter/test_converter_svo_bands.py) carry none. from h5 import *is unused inwien2k_soc_convert.py.- Fixtures are shipped uncompressed here while the later PRs in the stack gzip them; consistency would be nice, though 630 KB is not a problem on its own.
Note for the rest of the stack
The test only calls convert_dft_input. convert_parproj_input and convert_transport_input are never exercised, so dft_parproj_input and dft_symmpar_input stay unlocked for the SOC path — which is exactly what #10 and #11 port. Worth extending the harness here (it needs CaOs2.sympar / CaOs2.parproj fixtures) rather than leaving those two PRs to validate themselves.
None of the "also" or "nits" items block; the orthonormality question does, in the sense that fixing it later means regenerating the reference and rebasing everything above.
Attribution: this review was produced by Claude (Opus 5) running in Claude Code, driven by @the-hampel.
830cb84 to
12dbb9b
Compare
|
Heads-up: I force-pushed the rebase onto current Note this rebases only #4; #5 and everything above still carry the old Attribution: this note was produced by Claude (Opus 5) running in Claude Code, driven by @the-hampel. |
|
Hi @krystophny , First of all sorry for the delay working on this. I simply did not get to this until now. I reviewed the code work now with Claude and would be happy to work through all PR's if you are still available. Please let me know if you have any questions. Best, |
|
Hi @the-hampel , thanks for that! I will be back from holiday beginning of October, so will take a bit more time also. Then let's check the details. Best, Chris |
|
Merged the current PR target Added independent overlap, shell-permutation and symmetry-unitarity checks, tightened the golden comparison to Fresh native CMake build: 21/21 CTest tests passed. The original 17-band fixture fails the new gate. Exactly one Pi and one Claude Opus review completed without blockers; their relevant findings are addressed. Chris&AI |
triqs.utility.h5diff forwards its precision argument to Green's functions only; numpy arrays are compared with the 1e-6 default of assert_arrays_are_close. h5diff(..., precision=1e-12) therefore checked proj_mat and the symmetry matrices at 1e-6, and a 1e-10 change in CaOs2.ctqmcout went undetected. Compare the archive recursively with an explicit absolute tolerance instead. A 1e-10 perturbation of one ctqmcout projector entry now fails at /dft_input/proj_mat.
The SOC + spin-polarized path of convert_parproj_input and the sympar symmetry reader had no reference, while the dmftproj port replaces the Fortran producers of exactly these files (case.parproj, case.sympar). CaOs2.parproj comes from the native dmftproj run documented in the README; the same run reproduces the shipped ctqmcout to 2e-15 and symqmc/oubwinup byte for byte. dmftproj writes CaOs2.sympar byte-identical to CaOs2.symqmc here, because the partial shells are the correlated shells, so CMake copies symqmc instead of shipping a duplicate. The reference gains dft_parproj_input and dft_symmpar_input; all existing datasets are unchanged bit for bit. Transport is not covered: case.pmat needs Wien2k optic and cannot be produced from the retained inputs.
|
Thanks @krystophny, this addresses everything from the review. We approve the PR in its current form. We pushed two small commits on top:
Fresh build, 21/21 tests pass locally. If you're happy with the two commits, we'll go ahead with a squash-merge. The PRs above #4 will need a rebase onto the new fixtures afterwards. Attribution: this comment was produced by Claude (Opus 5.5) running in Claude Code, driven by @the-hampel. |
|
@the-hampel I am happy after one final check and fix. Thank you! |
Part of #7 (dmftproj Fortran-to-Python port).
Adds a spin-orbit + spin-polarized Wien2k converter test for CaOs2, with two equivalent correlated Os d shells and sixteen magnetic symmetry operations, eight containing time reversal. The fixture retains one k-point and covers the combined-spin block and the two-shell subspace. Local time-reversal rotation matrices are trivial in this fixture; the eight antiunitary operations are covered through their flags and symmetry matrices.
The native Fortran producer uses the original retained Wien2k projector inputs with a widened -2.0 to 3.0 Ry window, selecting bands 43–92 (50 bands) for twenty correlated spin orbitals. The test checks the stacked projector overlap against the identity independently of the reference archive, then compares conversion of the same fixture bytes at an explicit
1e-12tolerance. The regenerated stacked overlap error is about3.1e-8.test/python/wien2k/CaOs2.README.mdrecords the retained producer inputs and native regeneration commands. Compressedalmblmup/almblmdn,indmftpr,dmftsymand the retained cubic-basis template are included. The original Wien2k version, initialization commands and parent k-mesh were not retained; the documented reproduction starts from those projector inputs.Merged the current PR target
unstable(43435dc); upstream has no branch namedmain. The PR base remainsunstable.Verification: fresh native CMake build with TRIQS 4.0.2, all 21 registered CTest tests passed. The new invariant rejects the original 17-band fixture. One Pi review and one Claude Opus review were performed against the frozen candidate.
Chris&AI