Skip to content

Commit 640e7f5

Browse files
maki49mohanchen
andauthored
fix soc symmetry according to deepmodeling#7664 convention (deepmodeling#7804)
Co-authored-by: Mohan Chen <mohanchen@pku.edu.cn>
1 parent 4ec173c commit 640e7f5

2 files changed

Lines changed: 76 additions & 2 deletions

File tree

source/source_cell/module_symmetry/test/symmetry_rho_soc_test.cpp

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,70 @@ TEST(RhogSymmetrySoc, GroupInvariance)
186186
}
187187
}
188188

189+
// ---------------------------------------------------------------------------
190+
// Coupling test (nonzero m_y): the spin-density rotation W used for the grid
191+
// symmetrization (spin_so3) MUST agree with the SU(2) rotation of the spinor
192+
// density block followed by the Pauli decomposition convention that the rest of
193+
// the code uses (func_xyz_to_updown, #7664):
194+
// rho_0 = Re(uu+dd), rho_x = Re(ud+du),
195+
// rho_y = -Im(ud) + Im(du), rho_z = Re(uu-dd).
196+
// This is the check that the self-referential GroupInvariance test above cannot
197+
// make (it uses the same wspin as oracle). A y-channel handedness mismatch
198+
// between spin_so3 and this sigma_y=[[0,-i],[i,0]] convention shows up here.
199+
// ---------------------------------------------------------------------------
200+
namespace
201+
{
202+
using cd = std::complex<double>;
203+
// spinor block D = r0*I + m.sigma (sigma_y = [[0,-i],[i,0]]); layout {uu,ud,du,dd}
204+
ModuleSymmetry::SpinRotation::Su2 block_from_pauli(double r0, double mx, double my, double mz)
205+
{
206+
return {cd(r0 + mz, 0.0), cd(mx, -my), cd(mx, my), cd(r0 - mz, 0.0)};
207+
}
208+
// func_xyz_to_updown extraction (NEW / #7664 convention); factor of 2 vs. m is harmless.
209+
void pauli_from_block(const ModuleSymmetry::SpinRotation::Su2& D, double& rx, double& ry, double& rz)
210+
{
211+
rx = (D[1] + D[2]).real(); // Re(ud+du)
212+
ry = -D[1].imag() + D[2].imag(); // -Im(ud)+Im(du)
213+
rz = (D[0] - D[3]).real(); // Re(uu-dd)
214+
}
215+
} // namespace
216+
217+
TEST(RhogSymmetrySoc, SpinConventionCoupling)
218+
{
219+
// representative magnetizations, all with a nonzero y-component
220+
const double mtest[4][3] = {{0.4, 0.7, -0.5}, {0.0, 1.0, 0.0}, {-0.3, 0.6, 0.9}, {1.0, -0.8, 0.2}};
221+
222+
for (int g = 0; g < 8; ++g)
223+
{
224+
const ModuleBase::Matrix3 gc = gmatc_of(g);
225+
const ModuleSymmetry::SpinRotation::Su2 U = ModuleSymmetry::SpinRotation::so3_to_su2(gc);
226+
const ModuleBase::Matrix3 Wgrid = ModuleSymmetry::SpinRotation::spin_so3(gc);
227+
const ModuleBase::Matrix3 Wpauli = ModuleSymmetry::SpinRotation::pauli_rotation_matrix(U);
228+
229+
// (1) the geometric grid rotation and the SU(2)-induced Pauli rotation must coincide
230+
EXPECT_NEAR(Wgrid.e11, Wpauli.e11, TOL) << "g=" << g; EXPECT_NEAR(Wgrid.e12, Wpauli.e12, TOL) << "g=" << g;
231+
EXPECT_NEAR(Wgrid.e13, Wpauli.e13, TOL) << "g=" << g; EXPECT_NEAR(Wgrid.e21, Wpauli.e21, TOL) << "g=" << g;
232+
EXPECT_NEAR(Wgrid.e22, Wpauli.e22, TOL) << "g=" << g; EXPECT_NEAR(Wgrid.e23, Wpauli.e23, TOL) << "g=" << g;
233+
EXPECT_NEAR(Wgrid.e31, Wpauli.e31, TOL) << "g=" << g; EXPECT_NEAR(Wgrid.e32, Wpauli.e32, TOL) << "g=" << g;
234+
EXPECT_NEAR(Wgrid.e33, Wpauli.e33, TOL) << "g=" << g;
235+
236+
// (2) rotate the spinor block, extract Pauli comps (new convention), compare to Wgrid*m
237+
for (const auto& m : mtest)
238+
{
239+
const ModuleSymmetry::SpinRotation::Su2 D = block_from_pauli(2.0, m[0], m[1], m[2]);
240+
const ModuleSymmetry::SpinRotation::Su2 Dp = ModuleSymmetry::SpinRotation::rotate_spin_block(D, U);
241+
double rx, ry, rz;
242+
pauli_from_block(Dp, rx, ry, rz);
243+
// Wgrid acts on the physical m; the block carries 2*m, so compare against 2*(Wgrid*m).
244+
const ModuleBase::Vector3<double> mv(m[0], m[1], m[2]);
245+
const ModuleBase::Vector3<double> mrot = Wgrid * mv;
246+
EXPECT_NEAR(rx, 2.0 * mrot.x, TOL) << "g=" << g;
247+
EXPECT_NEAR(ry, 2.0 * mrot.y, TOL) << "g=" << g << " (y-channel handedness)";
248+
EXPECT_NEAR(rz, 2.0 * mrot.z, TOL) << "g=" << g;
249+
}
250+
}
251+
}
252+
189253
int main(int argc, char** argv)
190254
{
191255
testing::InitGoogleTest(&argc, argv);

source/source_estate/module_charge/symmetry_rhog.cpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,16 +90,26 @@ void Symmetry_rho::psymmg_soc(std::complex<double>* rhog_x, std::complex<double>
9090
// index [0,nrotk) unitary, [nrotk, nrotk+nrotk_anti) the spatial parts of the
9191
// antiunitary elements Theta*g -- same layout as density_sym_ops().
9292
const int na = symm.magnetic_nspin4 ? symm.nrotk_anti : 0;
93+
// PR 7664 flipped the spinor->Pauli rho^y sign (func_xyz_to_updown), so the grid
94+
// magnetization rho^y = chr.rho[2] consumed by rhog_symmetry_nspin4 now uses the
95+
// standard sigma_y=[[0,-i],[i,0]] convention. Relative to that convention the
96+
// pseudovector rotation applied to (rho^x,rho^y,rho^z) must be conjugated by
97+
// S=diag(1,-1,1) (i.e. the y-channel handedness is flipped); without this the
98+
// density symmetrization is out of sync only in the transverse y-channel.
99+
// spin_so3() itself is left untouched (it is still the physical pseudovector
100+
// rotation used for magnetic-group detection on the STRU moments).
101+
auto yflip = [](ModuleBase::Matrix3 W) {
102+
W.e12 = -W.e12; W.e21 = -W.e21; W.e23 = -W.e23; W.e32 = -W.e32; return W; };
93103
std::vector<ModuleBase::Matrix3> wspin(symm.nrotk + na);
94104
for (int i = 0; i < symm.nrotk; ++i)
95105
{
96106
const ModuleBase::Matrix3 gmatc = ilatvec * symm.gmatrix[i] * latvec;
97-
wspin[i] = ModuleSymmetry::SpinRotation::spin_so3(gmatc);
107+
wspin[i] = yflip(ModuleSymmetry::SpinRotation::spin_so3(gmatc));
98108
}
99109
for (int j = 0; j < na; ++j)
100110
{
101111
const ModuleBase::Matrix3 gmatc = ilatvec * symm.gmatrix_anti[j] * latvec;
102-
wspin[symm.nrotk + j] = ModuleSymmetry::SpinRotation::spin_so3(gmatc);
112+
wspin[symm.nrotk + j] = yflip(ModuleSymmetry::SpinRotation::spin_so3(gmatc));
103113
}
104114
return wspin;
105115
};

0 commit comments

Comments
 (0)