@@ -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+
189253int main (int argc, char ** argv)
190254{
191255 testing::InitGoogleTest (&argc, argv);
0 commit comments