@@ -30,93 +30,228 @@ inline RI::Tensor<std::complex<double>> tensor_conj(const RI::Tensor<std::comple
3030}
3131template <typename Tdata, typename Tmatrix>
3232auto RI_2D_Comm::split_m2D_ktoR (const UnitCell& ucell,
33- const K_Vectors & kv,
34- const std::vector<const Tmatrix*>&mks_2D,
35- const Parallel_2D & pv,
36- const int nspin,
33+ const K_Vectors & kv,
34+ const std::vector<const Tmatrix*>&mks_2D,
35+ const Parallel_2D & pv,
36+ const int nspin,
3737 const bool spgsym)
3838-> std::vector<std::map<TA,std::map<TAC,RI::Tensor<Tdata>>>>
3939{
4040 ModuleBase::TITLE (" RI_2D_Comm" ," split_m2D_ktoR" );
4141 ModuleBase::timer::tick (" RI_2D_Comm" , " split_m2D_ktoR" );
42-
4342 const TC period = RI_Util::get_Born_vonKarmen_period (kv);
43+ std::vector<std::map<TA , std::map<TAC , RI ::Tensor<Tdata>>>> mRs_a2D
44+ = (period == TC {1 , 1 , 1 })
45+ ? RI_2D_Comm::split_m2D_ktoR_gamma<Tdata, Tmatrix>(ucell, mks_2D, pv, nspin)
46+ : RI_2D_Comm::split_m2D_ktoR_k<Tdata, Tmatrix>(ucell, kv, mks_2D, pv, nspin, spgsym);
47+ ModuleBase::timer::tick (" RI_2D_Comm" , " split_m2D_ktoR" );
48+ return mRs_a2D ;
49+ }
50+
51+ template <typename Tdata, typename Tmatrix>
52+ auto RI_2D_Comm::split_m2D_ktoR_gamma (const UnitCell& ucell,
53+ const std::vector<const Tmatrix*>& mks_2D,
54+ const Parallel_2D& pv,
55+ const int nspin)
56+ -> std::vector<std::map<TA, std::map<TAC, RI::Tensor<Tdata>>>>
57+ {
58+ ModuleBase::TITLE (" RI_2D_Comm" ," split_m2D_ktoR_gamma" );
59+ ModuleBase::timer::tick (" RI_2D_Comm" , " split_m2D_ktoR_gamma" );
60+
4461 const std::map<int ,int > nspin_k = {{1 ,1 }, {2 ,2 }, {4 ,1 }};
4562 const double SPIN_multiple = std::map<int , double >{ {1 ,0.5 }, {2 ,1 }, {4 ,1 } }.at (nspin); // why?
63+ const TC cell = {0 , 0 , 0 };
4664
4765 std::vector<std::map<TA , std::map<TAC , RI ::Tensor<Tdata>>>> mRs_a2D (nspin);
66+
67+ #ifdef _OPENMP
68+ // pre-init all outer maps mRs_a2D[is_b][iat] to avoid concurrent std::map rebalancing
69+ for (int is_b = 0 ; is_b < nspin; ++is_b)
70+ for (int iat0 = 0 ; iat0 < ucell.nat ; ++iat0)
71+ mRs_a2D [is_b][iat0];
72+
73+ std::vector<omp_lock_t > locks (ucell.nat );
74+ for (auto & l : locks)
75+ omp_init_lock (&l);
76+ #endif
77+
4878 for (int is_k = 0 ; is_k < nspin_k.at (nspin); ++is_k)
49- {
50- const std::vector<int > ik_list = RI_2D_Comm::get_ik_list (kv, is_k);
51- for (const TC &cell : RI_Util::get_Born_von_Karmen_cells (period))
52- {
53- RI ::Tensor<Tdata> mR_2D ;
54- int ik_full = 0 ;
55- for (const int ik : ik_list)
79+ {
80+ using Tdata_m = typename Tmatrix::value_type;
81+ RI ::Tensor<Tdata_m> mk_2D
82+ = RI_Util::Vector_to_Tensor<Tdata_m>(*mks_2D[is_k], pv.get_col_size (), pv.get_row_size ());
83+ const Tdata_m frac = RI ::Global_Func::convert<Tdata_m>(SPIN_multiple);
84+ RI ::Tensor<Tdata> mR_2D = RI ::Global_Func::convert<Tdata>(mk_2D * frac);
85+
86+ #ifdef _OPENMP
87+ #pragma omp parallel for schedule(dynamic)
88+ #endif
89+ for (int iwt0_2D = 0 ; iwt0_2D != mR_2D .shape [0 ]; ++iwt0_2D)
90+ {
91+ const int iwt0 = ModuleBase::GlobalFunc::IS_COLUMN_MAJOR_KS_SOLVER (PARAM .inp .ks_solver )
92+ ? pv.local2global_col (iwt0_2D)
93+ : pv.local2global_row (iwt0_2D);
94+ int iat0, iw0_b, is0_b;
95+ std::tie (iat0, iw0_b, is0_b) = RI_2D_Comm::get_iat_iw_is_block (ucell, iwt0);
96+ const int it0 = ucell.iat2it [iat0];
97+ for (int iwt1_2D = 0 ; iwt1_2D != mR_2D .shape [1 ]; ++iwt1_2D)
5698 {
57- auto set_mR_2D = [&mR_2D ](auto && mk_frac) {
58- if (mR_2D .empty ()) {
59- mR_2D = RI ::Global_Func::convert<Tdata>(mk_frac);
60- } else {
61- mR_2D
62- = mR_2D + RI ::Global_Func::convert<Tdata>(mk_frac);
63- }
64- };
65- using Tdata_m = typename Tmatrix::value_type;
66- if (!spgsym)
99+ const int iwt1 = ModuleBase::GlobalFunc::IS_COLUMN_MAJOR_KS_SOLVER (PARAM .inp .ks_solver )
100+ ? pv.local2global_row (iwt1_2D)
101+ : pv.local2global_col (iwt1_2D);
102+ int iat1, iw1_b, is1_b;
103+ std::tie (iat1, iw1_b, is1_b) = RI_2D_Comm::get_iat_iw_is_block (ucell, iwt1);
104+ const int it1 = ucell.iat2it [iat1];
105+
106+ const int is_b = RI_2D_Comm::get_is_block (is_k, is0_b, is1_b);
107+ #ifdef _OPENMP
108+ omp_set_lock (&locks[iat0]);
109+ #endif
110+ RI ::Tensor<Tdata>& mR_a2D = mRs_a2D [is_b][iat0][{iat1, cell}];
111+ if (mR_a2D .empty ())
67112 {
68- RI ::Tensor<Tdata_m> mk_2D = RI_Util::Vector_to_Tensor<Tdata_m>(*mks_2D[ik], pv.get_col_size (), pv.get_row_size ());
69- const Tdata_m frac = SPIN_multiple
70- * RI ::Global_Func::convert<Tdata_m>(std::exp (
71- -ModuleBase::TWO_PI * ModuleBase::IMAG_UNIT * (kv.kvec_c [ik] * (RI_Util::array3_to_Vector3 (cell) * ucell.latvec ))));
72- if (static_cast <int >(std::round (SPIN_multiple * kv.wk [ik] * kv.get_nkstot_full ())) == 2 )
73- { set_mR_2D (mk_2D * (frac * 0.5 ) + tensor_conj (mk_2D * (frac * 0.5 ))); }
74- else { set_mR_2D (mk_2D * frac); }
113+ mR_a2D = RI ::Tensor<Tdata>(
114+ {static_cast <size_t >(ucell.atoms [it0].nw ),
115+ static_cast <size_t >(ucell.atoms [it1].nw )});
75116 }
117+ mR_a2D (iw0_b, iw1_b) = mR_2D (iwt0_2D, iwt1_2D);
118+ #ifdef _OPENMP
119+ omp_unset_lock (&locks[iat0]);
120+ #endif
121+ }
122+ }
123+ }
124+
125+ #ifdef _OPENMP
126+ for (auto & l : locks)
127+ omp_destroy_lock (&l);
128+
129+ // prune empty inner maps created by pre-init
130+ for (int is_b = 0 ; is_b < nspin; ++is_b)
131+ for (auto it = mRs_a2D [is_b].begin (); it != mRs_a2D [is_b].end ();)
132+ {
133+ if (it->second .empty ())
134+ it = mRs_a2D [is_b].erase (it);
76135 else
77- { // traverse kstar, ik means ik_ibz
78- for (auto & isym_kvd : kv.kstars [ik % ik_list.size ()])
136+ ++it;
137+ }
138+ #endif
139+
140+ ModuleBase::timer::tick (" RI_2D_Comm" , " split_m2D_ktoR_gamma" );
141+ return mRs_a2D ;
142+ }
143+
144+ template <typename Tdata, typename Tmatrix>
145+ auto RI_2D_Comm::split_m2D_ktoR_k (const UnitCell& ucell,
146+ const K_Vectors& kv,
147+ const std::vector<const Tmatrix*>& mks_2D,
148+ const Parallel_2D& pv,
149+ const int nspin,
150+ const bool spgsym)
151+ -> std::vector<std::map<TA, std::map<TAC, RI::Tensor<Tdata>>>>
152+ {
153+ ModuleBase::TITLE (" RI_2D_Comm" ," split_m2D_ktoR_k" );
154+ ModuleBase::timer::tick (" RI_2D_Comm" , " split_m2D_ktoR_k" );
155+
156+ const TC period = RI_Util::get_Born_vonKarmen_period (kv);
157+ const std::map<int ,int > nspin_k = {{1 ,1 }, {2 ,2 }, {4 ,1 }};
158+ const double SPIN_multiple = std::map<int , double >{ {1 ,0.5 }, {2 ,1 }, {4 ,1 } }.at (nspin); // why?
159+
160+ std::vector<std::map<TA , std::map<TAC , RI ::Tensor<Tdata>>>> mRs_a2D (nspin);
161+ #ifdef _OPENMP
162+ #pragma omp parallel
163+ #endif
164+ {
165+ std::vector<std::map<TA , std::map<TAC , RI ::Tensor<Tdata>>>> mRs_a2D_thread (nspin);
166+ for (int is_k = 0 ; is_k < nspin_k.at (nspin); ++is_k)
167+ {
168+ const std::vector<int > ik_list = RI_2D_Comm::get_ik_list (kv, is_k);
169+ const auto cells = RI_Util::get_Born_von_Karmen_cells (period);
170+ #pragma omp for schedule(dynamic)
171+ for (size_t icell = 0 ; icell < cells.size (); ++icell)
172+ {
173+ const TC & cell = cells[icell];
174+ RI ::Tensor<Tdata> mR_2D ;
175+ int ik_full = 0 ;
176+ for (const int ik : ik_list)
177+ {
178+ using Tdata_m = typename Tmatrix::value_type;
179+ auto set_mR_2D = [&mR_2D ](RI ::Tensor<Tdata_m>&& mk_frac)
180+ {
181+ if (mR_2D .empty ())
182+ { mR_2D = RI ::Global_Func::convert<Tdata>(mk_frac); }
183+ else
184+ { mR_2D = mR_2D + RI ::Global_Func::convert<Tdata>(mk_frac); }
185+ };
186+ if (!spgsym)
79187 {
80- RI ::Tensor<Tdata_m> mk_2D = RI_Util::Vector_to_Tensor<Tdata_m>(*mks_2D[ik_full + is_k * kv. get_nkstot_full () ], pv.get_col_size (), pv.get_row_size ());
188+ RI ::Tensor<Tdata_m> mk_2D = RI_Util::Vector_to_Tensor<Tdata_m>(*mks_2D[ik ], pv.get_col_size (), pv.get_row_size ());
81189 const Tdata_m frac = SPIN_multiple
82190 * RI ::Global_Func::convert<Tdata_m>(std::exp (
83- -ModuleBase::TWO_PI * ModuleBase::IMAG_UNIT * ((isym_kvd.second * ucell.G ) * (RI_Util::array3_to_Vector3 (cell) * ucell.latvec ))));
84- set_mR_2D (mk_2D * frac);
85- ++ik_full;
191+ -ModuleBase::TWO_PI * ModuleBase::IMAG_UNIT * (kv.kvec_c [ik] * (RI_Util::array3_to_Vector3 (cell) * ucell.latvec ))));
192+ if (static_cast <int >(std::round (SPIN_multiple * kv.wk [ik] * kv.get_nkstot_full ())) == 2 )
193+ { set_mR_2D (mk_2D * (frac * 0.5 ) + tensor_conj (mk_2D * (frac * 0.5 ))); }
194+ else
195+ { set_mR_2D (mk_2D * frac); }
86196 }
87- }
88- }
89- for (int iwt0_2D=0 ; iwt0_2D!=mR_2D .shape [0 ]; ++iwt0_2D)
90- {
91- const int iwt0 =ModuleBase::GlobalFunc::IS_COLUMN_MAJOR_KS_SOLVER (PARAM .inp .ks_solver )
92- ? pv.local2global_col (iwt0_2D)
93- : pv.local2global_row (iwt0_2D);
94- int iat0, iw0_b, is0_b;
95- std::tie (iat0,iw0_b,is0_b) = RI_2D_Comm::get_iat_iw_is_block (ucell,iwt0);
96- const int it0 = ucell.iat2it [iat0];
97- for (int iwt1_2D=0 ; iwt1_2D!=mR_2D .shape [1 ]; ++iwt1_2D)
98- {
99- const int iwt1 =ModuleBase::GlobalFunc::IS_COLUMN_MAJOR_KS_SOLVER (PARAM .inp .ks_solver )
100- ? pv.local2global_row (iwt1_2D)
101- : pv.local2global_col (iwt1_2D);
102- int iat1, iw1_b, is1_b;
103- std::tie (iat1,iw1_b,is1_b) = RI_2D_Comm::get_iat_iw_is_block (ucell,iwt1);
104- const int it1 = ucell.iat2it [iat1];
105-
106- const int is_b = RI_2D_Comm::get_is_block (is_k, is0_b, is1_b);
107- RI ::Tensor<Tdata> &mR_a2D = mRs_a2D [is_b][iat0][{iat1,cell}];
108- if (mR_a2D .empty ()) {
109- mR_a2D = RI ::Tensor<Tdata>(
110- {static_cast <size_t >(ucell.atoms [it0].nw ),
111- static_cast <size_t >(
112- ucell.atoms [it1].nw )});
197+ else
198+ { // traverse kstar, ik means ik_ibz
199+ for (auto & isym_kvd : kv.kstars [ik % ik_list.size ()])
200+ {
201+ RI ::Tensor<Tdata_m> mk_2D = RI_Util::Vector_to_Tensor<Tdata_m>(*mks_2D[ik_full + is_k * kv.get_nkstot_full ()], pv.get_col_size (), pv.get_row_size ());
202+ const Tdata_m frac = SPIN_multiple
203+ * RI ::Global_Func::convert<Tdata_m>(std::exp (
204+ -ModuleBase::TWO_PI * ModuleBase::IMAG_UNIT * ((isym_kvd.second * ucell.G ) * (RI_Util::array3_to_Vector3 (cell) * ucell.latvec ))));
205+ set_mR_2D (mk_2D * frac);
206+ ++ik_full;
207+ }
208+ }
209+ } // end for ik
210+ for (int iwt0_2D=0 ; iwt0_2D!=mR_2D .shape [0 ]; ++iwt0_2D)
211+ {
212+ const int iwt0 =ModuleBase::GlobalFunc::IS_COLUMN_MAJOR_KS_SOLVER (PARAM .inp .ks_solver )
213+ ? pv.local2global_col (iwt0_2D)
214+ : pv.local2global_row (iwt0_2D);
215+ int iat0, iw0_b, is0_b;
216+ std::tie (iat0,iw0_b,is0_b) = RI_2D_Comm::get_iat_iw_is_block (ucell,iwt0);
217+ const int it0 = ucell.iat2it [iat0];
218+ for (int iwt1_2D=0 ; iwt1_2D!=mR_2D .shape [1 ]; ++iwt1_2D)
219+ {
220+ const int iwt1 =ModuleBase::GlobalFunc::IS_COLUMN_MAJOR_KS_SOLVER (PARAM .inp .ks_solver )
221+ ? pv.local2global_row (iwt1_2D)
222+ : pv.local2global_col (iwt1_2D);
223+ int iat1, iw1_b, is1_b;
224+ std::tie (iat1,iw1_b,is1_b) = RI_2D_Comm::get_iat_iw_is_block (ucell,iwt1);
225+ const int it1 = ucell.iat2it [iat1];
226+
227+ const int is_b = RI_2D_Comm::get_is_block (is_k, is0_b, is1_b);
228+ RI ::Tensor<Tdata>& mR_a2D = mRs_a2D_thread [is_b][iat0][{iat1, cell}];
229+ if (mR_a2D .empty ())
230+ {
231+ mR_a2D = RI ::Tensor<Tdata>(
232+ {static_cast <size_t >(ucell.atoms [it0].nw ),
233+ static_cast <size_t >(ucell.atoms [it1].nw )});
234+ }
235+ mR_a2D (iw0_b, iw1_b) = mR_2D (iwt0_2D, iwt1_2D);
236+ } // for iwt1_2D
237+ } // end for iwt0_2D
238+ } // end for icell
239+ } // end for is_k
240+
241+ #ifdef _OPENMP
242+ #pragma omp critical
243+ #endif
244+ {
245+ for (int is=0 ; is<nspin; ++is)
246+ for (auto &mRs_A : mRs_a2D_thread [is])
247+ for (auto &mRs_B : mRs_A .second )
248+ {
249+ assert (mRs_a2D [is][mRs_A .first ][mRs_B .first ].empty ());
250+ mRs_a2D [is][mRs_A .first ][mRs_B .first ] = std::move (mRs_B .second );
113251 }
114- mR_a2D (iw0_b,iw1_b) = mR_2D (iwt0_2D, iwt1_2D);
115- }
116- }
117252 }
118- }
119- ModuleBase::timer::tick (" RI_2D_Comm" , " split_m2D_ktoR " );
253+ } // end #pragma omp parallel
254+ ModuleBase::timer::tick (" RI_2D_Comm" , " split_m2D_ktoR_k " );
120255 return mRs_a2D ;
121256}
122257
0 commit comments