Commit 1457e26
authored
Fix: correct Pauli-to-spinor Hamiltonian conversion for nspin=4 (#7664)
* fix: correct Pauli-to-spinor Hamiltonian conversion for nspin=4
Fix two bugs in LCAO non-collinear Hamiltonian construction:
1. Wrong sign in off-diagonal elements: H_{up,down} = B_x + i*B_y (wrong)
should be B_x - i*B_y (correct), and vice versa for H_{down,up}.
Fixed by correcting clx_j coefficients in merge_hr_part_to_hR().
2. Missing complex conjugate in lower triangle fill: H(-R) used transpose
instead of conjugate transpose, breaking Hermiticity for complex matrices.
Fixed by using std::conj() when filling lower triangle.
These errors caused the non-collinear Hamiltonian to be the complex conjugate
of the correct result, leading to incorrect spin textures in nspin=4 calculations.
The PW code path was not affected.
Add test case and verification script to validate:
- H(R=0) Hermiticity: max|H - H^dagger| < 1e-10
- Off-diagonal phase: Im(H_{up,down}) < 0 for m||+y direction
See tests/03_NAO_multik/verify_hamiltonian_convention/TEST_DESIGN.md for details.
* fix: correct Pauli-to-spinor conversion in DFT+U and DeltaSpin for nspin=4
Fix three critical bugs in non-collinear (nspin=4) LCAO calculations:
1. DFT+U transfer_vu (dftu_lcao.cpp): Fix sign error in Pauli-to-spinor
conversion. The off-diagonal elements had wrong imaginary part sign:
- Before: V_{up,down} = 0.5*(V_x + i*V_y) (wrong)
- After: V_{up,down} = 0.5*(V_x - i*V_y) (correct, from sigma_y)
2. DFT+U force/stress (dftu_force_stress.hpp): Convert VU from Pauli basis
to spinor basis before force calculation. The old code incorrectly mixed
Pauli-basis VU with spinor-basis DM.
3. DeltaSpin force/stress (dspin_force_stress.hpp): Convert lambda from
Pauli basis to spinor basis. The constraint force F = lambda·dM/dR
requires proper Pauli-to-spinor conversion:
- lambda_spinor = (lambda_z, lambda_x, lambda_x, -lambda_z)
for (uu, ud, du, dd) components.
These fixes ensure consistent Pauli-to-spinor conversion across all modules:
- H construction (gint_common.cpp): already fixed
- DFT+U Hamiltonian: fixed in this commit
- DFT+U force/stress: fixed in this commit
- DeltaSpin force/stress: fixed in this commit
Verified by scf_u_spin4 test (nspin=4 + DFT+U): SCF converges correctly.
* chore: remove .py and .md test files from PR
* fix: correct DFT+U force for nspin=4 - DM is stored in Pauli basis, not spinor basis
Two bugs fixed in dftu_force_stress.hpp:
1. Removed incorrect VU Pauli-to-spinor conversion: DM for nspin=4 is stored in
Pauli basis (rho_0, rho_x, rho_y, rho_z) per func_xyz_to_updown(), so VU must
also stay in Pauli basis for the force trace formula F = -Tr(VU * dDM/dR).
2. Removed force *= 2.0 for nspin=4: Pauli basis already includes all spin
channels, unlike nspin=1 where the factor of 2 accounts for spin degeneracy.
Updated scf_u_spin4 result.ref accordingly.
* fix: remove force*=2.0 for nspin=4 in DeltaSpin - Pauli basis already covers all spin channels
* fix: add missing blacs_context to ELPA Constructor 1 for nspin=4 support
Constructor 1 of ELPA_Solver was missing elpa_set_integer("blacs_context", ...)
while Constructor 2 (otherParameter) already had it. Without blacs_context,
ELPA's internal MPI operations (e.g. MPI_Bcast in complex Cholesky and
invert_triangular) can fail with INVALID DATATYPE when using complex eigensolves.
Also update scf_angle_spin4 result.ref with corrected reference energy.
* fix: correct rho_y sign in spinor-to-Pauli DM conversion (func_xyz_to_updown)
For Pauli decomposition: rho = rho_0*I + rho_x*sigma_x + rho_y*sigma_y + rho_z*sigma_z
sigma_y = [[0,-i],[i,0]], so rho_updown = rho_x + i*rho_y, rho_downup = rho_x - i*rho_y
Thus rho_y = Im(rho_updown - rho_downup) = tmp[1].imag() - tmp[2].imag].
Previously the real version had -tmp[1].imag()+tmp[2].imag() = -2*rho_y (wrong sign),
and the complex version had i*(tmp[1].imag()-tmp[2].imag()) = 2i*rho_y (wrong formula).
This broke rotational invariance: mag along y gave wrong energy (~4 eV deviation vs x/z).
* test: update scf_angle_spin4 and scf_u_spin4 result.ref after DM rho_y fix
* chore: revert density_matrix.cpp rho_y fix (wrong branch) and remove verify_hamiltonian_convention test dir
- Revert density_matrix.cpp func_xyz_to_updown rho_y sign fix from
commit 52ee608 (belongs on a separate DM-fix branch)
- Remove tests/03_NAO_multik/verify_hamiltonian_convention/ (debug helper)
- Update result.ref for scf_angle_spin4 and scf_u_spin4 to match
current code (Pauli-to-spinor + ELPA fixes only)
* fix: restore density_matrix.cpp rho_y sign fix (paired with gint_common clx_j fix)
The gint_common.cpp fix corrects Pauli→spinor (H construction) and the
density_matrix.cpp fix corrects spinor→Pauli (DM Fourier transform).
Both must use the same σ_y convention for self-consistency.
Also update result.ref files for both test cases.
* fix: correct DFT+U force/stress reference values and clean up empty nspin=4 block
Both VU (from cal_v_of_u) and DMR are stored in Pauli basis for nspin=4,
so the Pauli-to-spinor conversion in force/stress calculation is NOT needed.
The previous result.ref for scf_u_spin4 (totalforceref=6.562) was incorrect
because it was generated with code that mixed Pauli-basis VU with incorrectly
converted values. The correct force is 11.33, consistent with the physical
Pauli-basis trace Tr(VU * dDM/dR).
Changes:
- Remove empty if(nspin==4) block in dftu_force_stress.hpp (no conversion needed)
- Update scf_u_spin4/result.ref: totalforceref 6.562 -> 11.332 (correct value)
- Update scf_angle_spin4/result.ref: energy/stress to match computed values
- Add scf_angle_spin4/threshold: relax energy threshold to 1e-5 eV for
non-collinear calculation numerical reproducibility
- Update scf_out_dos_spin4/result.ref: force/stress to match computed values
* fix: correct sigma_y sign convention in Pauli-spinor conversions for nspin=4
Fix inconsistent Pauli-to-spinor and spinor-to-Pauli conversion signs
across multiple modules, which broke rotational invariance in
non-collinear (nspin=4) LCAO calculations.
The standard sigma_y = [[0,-i],[i,0]] convention requires:
H_{up,down} = B_x - i*B_y
rho_y = -Im(rho_updown - rho_downup)
Changes:
- density_matrix.cpp: fix rho_y sign in func_xyz_to_updown
(real: restore correct -Im(updown)+Im(downup);
complex: use i*(updown-downup) with full complex values)
- dftu_pw.cpp: fix Pauli-to-spinor sign in DFT+U transfer_vu (PW path)
- spin_constrain.h: fix pauli_to_moment My sign, update comments
- dspin_lcao.cpp: fix cal_coeff_lambda Pauli-to-spinor sign
- deltaspin_core_test.cpp: update unit test for corrected formula
- scf_u_spin4/result.ref: update reference values after correction
* docs: fix My sign in spin_constrain.cpp comment
Correct the comment to match the sigma_y = [[0,-i],[i,0]] convention:
My = -Im(occ[1] - occ[2]) instead of Im(occ[1] - occ[2])
* test: update 099_PW_DJ_SO ref after sigma_y sign fix in dftu_pw
* test: update scf_out_dos_spin4 ref after sigma_y sign fix
* test: update scf_angle_spin4 ref after sigma_y sign fix1 parent 70f7ed6 commit 1457e26
10 files changed
Lines changed: 31 additions & 31 deletions
File tree
- source
- source_estate/module_dm
- source_lcao
- module_deltaspin
- test
- module_dftu
- module_operator_lcao
- tests
- 01_PW/099_PW_DJ_SO
- 03_NAO_multik
- scf_angle_spin4
- scf_out_dos_spin4
- scf_u_spin4
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
655 | 655 | | |
656 | 656 | | |
657 | 657 | | |
658 | | - | |
| 658 | + | |
659 | 659 | | |
660 | 660 | | |
661 | 661 | | |
| |||
664 | 664 | | |
665 | 665 | | |
666 | 666 | | |
667 | | - | |
| 667 | + | |
668 | 668 | | |
669 | 669 | | |
670 | 670 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
142 | 142 | | |
143 | 143 | | |
144 | 144 | | |
145 | | - | |
| 145 | + | |
146 | 146 | | |
147 | 147 | | |
148 | 148 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
63 | 63 | | |
64 | 64 | | |
65 | 65 | | |
66 | | - | |
67 | | - | |
| 66 | + | |
| 67 | + | |
68 | 68 | | |
69 | 69 | | |
70 | | - | |
| 70 | + | |
71 | 71 | | |
72 | 72 | | |
73 | 73 | | |
| |||
79 | 79 | | |
80 | 80 | | |
81 | 81 | | |
82 | | - | |
| 82 | + | |
83 | 83 | | |
84 | 84 | | |
85 | 85 | | |
| |||
Lines changed: 4 additions & 4 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
23 | 23 | | |
24 | 24 | | |
25 | 25 | | |
26 | | - | |
| 26 | + | |
27 | 27 | | |
28 | 28 | | |
29 | 29 | | |
30 | 30 | | |
31 | 31 | | |
32 | 32 | | |
33 | 33 | | |
34 | | - | |
| 34 | + | |
35 | 35 | | |
36 | 36 | | |
37 | 37 | | |
| |||
82 | 82 | | |
83 | 83 | | |
84 | 84 | | |
85 | | - | |
| 85 | + | |
86 | 86 | | |
87 | 87 | | |
88 | | - | |
| 88 | + | |
89 | 89 | | |
90 | 90 | | |
91 | 91 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
309 | 309 | | |
310 | 310 | | |
311 | 311 | | |
312 | | - | |
313 | | - | |
| 312 | + | |
| 313 | + | |
314 | 314 | | |
315 | 315 | | |
316 | 316 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
56 | 56 | | |
57 | 57 | | |
58 | 58 | | |
59 | | - | |
| 59 | + | |
60 | 60 | | |
61 | | - | |
62 | | - | |
| 61 | + | |
| 62 | + | |
63 | 63 | | |
64 | 64 | | |
65 | 65 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | | - | |
2 | | - | |
3 | | - | |
4 | | - | |
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
5 | 5 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | | - | |
2 | | - | |
3 | | - | |
4 | | - | |
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
5 | 5 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | | - | |
| 1 | + | |
2 | 2 | | |
3 | | - | |
4 | | - | |
| 3 | + | |
| 4 | + | |
5 | 5 | | |
6 | 6 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | | - | |
2 | | - | |
3 | | - | |
4 | | - | |
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
5 | 5 | | |
0 commit comments