66#include < RI/physics/symmetry/Symmetry_Rotation.h>
77namespace ModuleSymmetry
88{
9+ // / Elementwise complex conjugation used by the time-reversal branch of restore_HR_nspin4.
10+ // / Overloaded (not specialized) so a real Tdata compiles to the identity.
11+ inline float conj_elem (const float v) { return v; }
12+ inline double conj_elem (const double v) { return v; }
13+ inline std::complex <float > conj_elem (const std::complex <float >& v) { return std::conj (v); }
14+ inline std::complex <double > conj_elem (const std::complex <double >& v) { return std::conj (v); }
15+
916 template <typename Tdata>
1017 inline void print_tensor (const RI ::Tensor<Tdata>& t, const std::string& name, const double & threshold = 0.0 )
1118 {
@@ -119,14 +126,24 @@ namespace ModuleSymmetry
119126 // which factorizes into the per-channel orbital rotation G^{cd}=T1^dagger H^{cd} T2 followed by the SU(2) spin mixing
120127 // H'^{ab} = sum_{cd} conj(U_{ca}) U_{db} G^{cd} (mode 'H')
121128 // H'^{ab} = sum_{cd} U_{ca} conj(U_{db}) G^{cd} (mode 'D')
122- // Only space-group operations enter the atom-pair reduction, so no time-reversal branch is needed.
129+ //
130+ // (nspin=4 magnetic) The atom-pair reduction may also use the ANTIUNITARY elements Theta*g of
131+ // the Shubnikov group, flagged by isym >= nsym_. In real space time reversal acts as
132+ // H(R) -> sigma_y H^*(R) sigma_y
133+ // with R and the orbital indices untouched (in a real AO basis Theta = -i sigma_y K, and
134+ // H(R) = sum_k H(k) e^{-ikR} turns H(k) -> sigma_y H^*(-k) sigma_y into exactly this).
135+ // So the antiunitary case is the unitary result Y followed by one channel remap:
136+ // H'^{00} = conj(Y^{11}), H'^{01} = -conj(Y^{10})
137+ // H'^{10} = -conj(Y^{01}), H'^{11} = conj(Y^{00})
138+ // The map is an involution (sigma_y^* = -sigma_y, sigma_y^2 = I), so no extra sign is needed
139+ // when it is applied in either direction.
123140 template <typename Tdata>
124- std::array<std::map<int , std::map<std::pair<int , TC >, RI ::Tensor<Tdata>>>, 4 > Symmetry_rotation::restore_HR_soc (
141+ std::array<std::map<int , std::map<std::pair<int , TC >, RI ::Tensor<Tdata>>>, 4 > Symmetry_rotation::restore_HR_nspin4 (
125142 const Symmetry& symm, const Atom* atoms, const Statistics& st, const char mode,
126143 const std::array<std::map<int , std::map<std::pair<int , TC >, RI ::Tensor<Tdata>>>, 4 >& HR_irreducible_soc)const
127144 {
128- ModuleBase::TITLE (" Symmetry_rotation" , " restore_HR_soc " );
129- ModuleBase::timer::start (" Symmetry_rotation" , " restore_HR_soc " );
145+ ModuleBase::TITLE (" Symmetry_rotation" , " restore_HR_nspin4 " );
146+ ModuleBase::timer::start (" Symmetry_rotation" , " restore_HR_nspin4 " );
130147 assert (mode == ' H' || mode == ' D' );
131148 std::array<std::map<int , std::map<std::pair<int , TC >, RI ::Tensor<Tdata>>>, 4 > HR_full;
132149
@@ -181,6 +198,7 @@ namespace ModuleSymmetry
181198 for (int is = 0 ;is < 4 ;++is) { G[is] = this ->rotate_atompair_serial (Hir[is], isym, a1, a2, mode); }
182199 // step 2: SU(2) spin mixing of the 4 rotated channels into the output channels
183200 const SpinRotation::Su2& U = this ->spin_U_ [isym];
201+ std::array<RI ::Tensor<Tdata>, 4 > Hout_ch;
184202 for (int a = 0 ;a < 2 ;++a) {
185203 for (int b = 0 ;b < 2 ;++b)
186204 {
@@ -194,13 +212,39 @@ namespace ModuleSymmetry
194212 Hout += RI ::Global_Func::convert<Tdata>(coeff) * G[c * 2 + d];
195213 }
196214 }
197- HR_full[a * 2 + b][ap1][{ap2, R}] = Hout;
215+ Hout_ch[a * 2 + b] = Hout;
216+ }
217+ }
218+ // step 3 (antiunitary elements of the Shubnikov group): apply time reversal
219+ // sigma_y (.)^* sigma_y, i.e. the channel remap documented above.
220+ if (isym >= this ->nsym_ )
221+ {
222+ // NOTE: antiunitary elements only ever exist for nspin=4 (nrotk_anti is 0 otherwise), where Tdata is complex.
223+ // conj_elem() is the identity for a
224+ // real Tdata, so this branch must not be reached with one -- it would
225+ // silently degrade into a bare channel swap.
226+ static const int src[4 ] = { 3 , 2 , 1 , 0 }; // 00<-11, 01<-10, 10<-01, 11<-00
227+ static const bool neg[4 ] = { false , true , true , false };
228+ std::array<RI ::Tensor<Tdata>, 4 > Y = Hout_ch;
229+ for (int is = 0 ;is < 4 ;++is)
230+ {
231+ const RI ::Tensor<Tdata>& s = Y[src[is]];
232+ RI ::Tensor<Tdata> t ({ static_cast <size_t >(a1.nw ), static_cast <size_t >(a2.nw ) });
233+ for (size_t i = 0 ;i < t.shape [0 ];++i) {
234+ for (size_t j = 0 ;j < t.shape [1 ];++j)
235+ {
236+ const Tdata v = ModuleSymmetry::conj_elem (s (i, j));
237+ t (i, j) = neg[is] ? -v : v;
238+ }
239+ }
240+ Hout_ch[is] = t;
198241 }
199242 }
243+ for (int is = 0 ;is < 4 ;++is) { HR_full[is][ap1][{ap2, R}] = Hout_ch[is]; }
200244 }
201245 }
202246 }
203- ModuleBase::timer::end (" Symmetry_rotation" , " restore_HR_soc " );
247+ ModuleBase::timer::end (" Symmetry_rotation" , " restore_HR_nspin4 " );
204248 return HR_full;
205249 }
206250
0 commit comments