ABACUS develop
Atomic-orbital Based Ab-initio Computation at UStc
Loading...
Searching...
No Matches
exx_rotate_abfs.hpp
Go to the documentation of this file.
1#ifndef EXX_ROTATE_ABFS_HPP
2#define EXX_ROTATE_ABFS_HPP
6#include "exx_rotate_abfs.h"
7
8#include <cmath> // For std::erfc function used in smooth truncation
9#include <vector>
10
11template <typename Tdata>
12void Moment_abfs<Tdata>::cal_multipole(const std::vector<std::vector<std::vector<Numerical_Orbital_Lm>>>& orb_in)
13{
14 ModuleBase::TITLE("Rotate_abfs", "cal_multipole");
15 ModuleBase::timer::start("Rotate_abfs", "cal_multipole");
16
17 this->multipole.resize(orb_in.size());
18 for (size_t T = 0; T != orb_in.size(); ++T)
19 {
20 this->multipole[T].resize(orb_in[T].size());
21 for (size_t L = 0; L != orb_in[T].size(); ++L)
22 {
23 this->multipole[T][L].resize(orb_in[T][L].size());
24 for (size_t N = 0; N != orb_in[T][L].size(); ++N)
25 {
26 const Numerical_Orbital_Lm& orb_lm = orb_in[T][L][N];
27 const int nr = orb_lm.getNr();
28 double* integrated_func = new double[nr];
29 for (size_t ir = 0; ir != nr; ++ir)
30 integrated_func[ir] = orb_lm.getPsi(ir) * std::pow(orb_lm.getRadial(ir), 2 + L) / (2 * L + 1);
31
32 ModuleBase::Integral::Simpson_Integral(nr, integrated_func, orb_lm.getRab(), this->multipole[T][L][N]);
33 }
34 }
35 }
36
37 ModuleBase::timer::end("Rotate_abfs", "cal_multipole");
38}
39
40template <typename Tdata>
41void Moment_abfs<Tdata>::rotate_abfs(std::vector<std::vector<std::vector<Numerical_Orbital_Lm>>>& orb_in)
42{
43 ModuleBase::TITLE("Rotate_abfs", "rotate_abfs");
44 ModuleBase::timer::start("Rotate_abfs", "rotate_abfs");
45
46 // construct tranformation matrix A
47 for (int T = 0; T != orb_in.size(); ++T)
48 {
49 for (int L = 0; L != orb_in[T].size(); ++L)
50 {
51 for (int N = 0; N != orb_in[T][L].size(); ++N)
52 {
53 Numerical_Orbital_Lm& orb_lm_old = orb_in[T][L][N];
54 Numerical_Orbital_Lm orb_lm_mod = orb_lm_old * 0.0;
55 double square = 0.0;
56 for (int N2 = 0; N2 != orb_in[T][L].size(); ++N2)
57 {
58 square += this->multipole[T][L][N2] * this->multipole[T][L][N2];
59 }
60 double norm = std::sqrt(square);
61 // change abfs
62 if (N == 0)
63 {
64 for (int N2 = 0; N2 != orb_in[T][L].size(); ++N2)
65 orb_lm_mod += orb_in[T][L][N2] * this->multipole[T][L][N2] / norm;
66 }
67 else
68 {
69 for (int N2 = 0; N2 != orb_in[T][L].size(); ++N2)
70 {
71 if (N2 == N)
72 {
73 orb_lm_mod += (1.0 - this->multipole[T][L][N] * this->multipole[T][L][N2] / square)
74 * orb_in[T][L][N2];
75 }
76 else
77 {
78 orb_lm_mod
79 += (-this->multipole[T][L][N] * this->multipole[T][L][N2] / square) * orb_in[T][L][N2];
80 }
81 }
82 }
83 orb_lm_old = orb_lm_mod;
84 // change moment
85 if (N == 0)
86 {
87 this->multipole[T][L][N] = norm;
88 std::cout << "Atom type " << T << ", L " << L << ", N " << N
89 << ", multipole after rotation: " << this->multipole[T][L][N] << std::endl;
90 }
91 else
92 {
93 this->multipole[T][L][N] = 0.0;
94 }
95 }
96 }
97 }
98
99 ModuleBase::timer::end("Rotate_abfs", "rotate_abfs");
100}
101
102template <typename Tdata>
103double Moment_abfs<Tdata>::dfact(const int& l) const
104{
105 double result = 1;
106 for (int i = l; i > 1; i -= 2)
107 {
108 result *= i;
109 }
110 return result;
111}
112
113template <typename Tdata>
114int Moment_abfs<Tdata>::factorial(const int& n) const
115{
116 if (n == 0)
117 {
118 return 1;
119 }
120 else if (n > 0)
121 {
122 return n * this->factorial(n - 1);
123 }
124 else
125 {
126 ModuleBase::WARNING_QUIT("Moment_abfs::factorial", "n is out of range");
127 return 0;
128 }
129}
130
131template <typename Tdata>
133{
134 double res = 0.0;
135 for (int i = 2; i <= n; ++i)
136 res += std::log(i);
137 return res;
138}
139
140template <typename Tdata>
141double Moment_abfs<Tdata>::cal_cl1l2(int l1, int l2) const
142{
143 double result = 0.0;
144 // int overflow
145 result = ModuleBase::FOUR_PI * std::sqrt(1.0 / ModuleBase::PI_HALF) * dfact(2 * l1 + 2 * l2 - 1) / dfact(2 * l1 - 1)
146 / dfact(2 * l2 - 1);
147
148 return result;
149}
150
151template <typename Tdata>
153 int m1, // real m1, not index
154 int l2,
155 int m2, // real m2, not index
156 const std::vector<double>& rly, // real Y_LM(R)
157 const ORB_gaunt_table& MGT,
158 const double distance)
159{
160 double sum = 0.0;
161 const double tiny2 = 1e-10;
162 const int L = l1 + l2;
163 const int idx1 = MGT.get_lm_index(l1, m1 + l1);
164 const int idx2 = MGT.get_lm_index(l2, m2 + l2);
165
166 // cyl(m1,m2) = sum_M C(l1,l2,L,m1,m2,M) Y_LM(R)
167 for (int M = -L; M <= L; ++M)
168 {
169 const int idxL = MGT.get_lm_index(L, M + L);
170 const double C = MGT.Gaunt_Coefficients(idx1, idx2, idxL);
171 const double ylm_solid = rly.at(idxL);
172 const double ylm_real = (distance > tiny2) ? ylm_solid / pow(distance, l1 + l2) : ylm_solid;
173
174 if (std::abs(C) > 1e-14)
175 {
176 sum += C * ylm_real;
177 }
178 }
179
180 return sum;
181}
182
183template <typename Tdata>
185 const UnitCell& ucell,
186 const std::vector<std::vector<std::vector<Numerical_Orbital_Lm>>>& orb_in,
187 const std::pair<std::vector<TA>, std::vector<std::vector<std::pair<TA, std::array<Tcell, Ndim>>>>>& list_r,
188 const std::vector<double>& orb_cutoff,
189 const double Rc,
190 LRI_CV<Tdata>& cv,
191 std::map<TA, std::map<TAC, RI::Tensor<Tdata>>>& Vs_cut)
192{
193 ModuleBase::TITLE("Rotate_abfs", "cal_VR");
194 ModuleBase::timer::start("Rotate_abfs", "cal_VR");
195 // copy in source\module_hamilt_lcao\hamilt_lcaodft\center2_orb-orb11.cpp
196 const double tiny1 = 1e-12;
198 // index: T: type, L: angular momentum, N: radial index, M: magnetic moment
200
201 ORB_gaunt_table MGT0;
202 int Lmax = 0;
203 for (size_t T = 0; T != orb_in.size(); ++T)
204 {
205 Lmax = std::max(Lmax, static_cast<int>(orb_in[T].size()) - 1);
206 }
207
208 ModuleBase::TITLE("cal_Gaunt_before");
209 MGT0.init_Gaunt_CH(Lmax);
210 MGT0.init_Gaunt(Lmax);
211 ModuleBase::TITLE("cal_Gaunt_after");
212
213 const auto list_A0 = list_r.first;
214 const auto list_A1 = list_r.second[0];
215
216 auto& Vws = cv.Vws;
217 for (size_t i0 = 0; i0 < list_A0.size(); ++i0)
218 {
219 const TA iat0 = list_A0[i0];
220 const int T1 = ucell.iat2it[iat0];
221 const size_t I1 = ucell.iat2ia[iat0];
222 const auto& tauA = ucell.atoms[T1].tau[I1];
223 const size_t sizeA = index[T1].count_size;
224 for (size_t i1 = 0; i1 < list_A1.size(); ++i1)
225 {
226 const TA iat1 = list_A1[i1].first;
227 const int T2 = ucell.iat2it[iat1];
228 const size_t I2 = ucell.iat2ia[iat1];
229 const auto& tauB = ucell.atoms[T2].tau[I2];
230 const size_t sizeB = index[T2].count_size;
231 const auto R = list_A1[i1].second;
232 // delta_R: Angstrom
233 const auto delta_R = tauB - tauA + (RI_Util::array3_to_Vector3(R) * ucell.latvec);
234 // bohr
235 const double distance_true = (delta_R).norm() * ucell.lat0;
236 // bohr
237 const double distance = (distance_true >= tiny1) ? distance_true : distance_true + tiny1;
238 // Rcut_lcao: bohr, ucell.lat0 = 1.8897 transform angstrom to bohr
239 double Rcut_lcao = orb_cutoff[T1] + orb_cutoff[T2];
240 // Rcut_coul: bohr
241 double Rcut_coul = std::min(cv.cal_V_Rcut(T1, T2), cv.cal_V_Rcut(T2, T2));
242 if (distance < Rcut_lcao || distance >= Rcut_coul)
243 continue;
244 const auto JR = std::make_pair(iat1, R);
245 auto tmp_tensor = RI::Tensor<Tdata>({sizeA, sizeB});
246 for (int L1 = 0; L1 != orb_in[T1].size(); ++L1)
247 {
248 for (int L2 = 0; L2 != orb_in[T2].size(); ++L2)
249 {
250 std::vector<double> rly;
251 // keep bohr
253 (delta_R * ucell.lat0).x,
254 (delta_R * ucell.lat0).y,
255 (delta_R * ucell.lat0).z,
256 rly);
257 const double prefactor1 = std::pow(distance, L1 + L2 + 1);
258 for (int M1 = -L1; M1 <= L1; ++M1)
259 {
260 const int index_M1 = M1 + L1;
261 for (int M2 = -L2; M2 <= L2; ++M2)
262 {
263 const int index_M2 = M2 + L2;
264 const double prefactor = std::pow(-1, L2) * std::pow(ModuleBase::TWO_PI, 1.5) / prefactor1;
265 const double clmlm = this->cal_cl1l2(L1, L2);
266 // For real spherical harmonics, m order is: 0, 0, 1, -1, 0, 1, -1, 2, -2, ...
267 const double ylm = sum_triple_Y_YLM_real(L1, M1, L2, M2, rly, MGT0, distance);
268
269 // Determine N1 and N2 loop ranges based on rotate_abfs
270 // When rotate_abfs=true: only N=0 has non-zero moment, calculate only N1=0 and N2=0
271 // When rotate_abfs=false: all moments are non-zero, calculate all N1, N2
272 const int N1_max = GlobalC::exx_info.info_ri.rotate_abfs ? 1 : orb_in[T1][L1].size();
273 const int N2_max = GlobalC::exx_info.info_ri.rotate_abfs ? 1 : orb_in[T2][L2].size();
274
275 for (int N1 = 0; N1 != N1_max; ++N1)
276 {
277 for (int N2 = 0; N2 != N2_max; ++N2)
278 {
279 double mom1 = this->multipole[T1][L1][N1];
280 const double mom2 = this->multipole[T2][L2][N2];
281 // every L has only one moment!=0 after rotation (N=0)
282 const size_t iA = index[T1][L1][N1][index_M1];
283 const size_t iB = index[T2][L2][N2][index_M2];
284
285 const double value = prefactor * mom1 * mom2 * clmlm * ylm;
286
287 // Apply smooth truncation using erfc function in log space,
288 // exactly as implemented in FHI-aims to ensure consistency
289 // with k-space 1-cos(qRc) truncation scheme.
290 //
291 // FHI-aims formula (cut_coulomb_operator.f90 lines 205, 220):
292 // damp = 0.5 * erfc( (ln(r) - ln(Rc)) / ln(width) )
293 //
294 // This gives:
295 // - r = Rc : damp = 0.5
296 // - r = Rc/width : damp = 0.5 * erfc(-1) ≈ 0.921
297 // - r = Rc*width : damp = 0.5 * erfc(1) ≈ 0.079
298 //
299 // The log-space erfc truncation and 1-cos(qRc) form a Fourier
300 // transform pair, eliminating high-frequency oscillations
301 // that cause aliasing in coarse k-grids.
302 //
303 // Reference: Spencer & Alavi, PRB 77, 193110 (2008)
304 // Reference: FHI-aims/src/cut_coulomb_operator.f90
305 // - lines 71-78: analytic expression
306 // - lines 205, 220: implementation in log space
307 // - runtime_choices.f90 line 2701: width_factor = 8.0
308 //
309 // Default width parameter from FHI-aims (can be adjusted).
310 // Smaller width = sharper truncation (better for coarse k-grids)
311 // For high-lying states, stronger truncation is often needed.
312 // width = 1.05: r = Rc*1.2 gives ~1.5% contribution
313 // width = 1.03: r = Rc*1.1 gives ~0.5% contribution
314 // width = 1.02: r = Rc*1.05 gives ~0.08% contribution (nearly hard)
315 // width = 1.01: essentially hard cutoff at Rc
316 const double width = 0.9; // Width factor - tune this for high states!
317
318 double cutoff_factor = 1.0;
319 // Uncomment to test hard cutoff (for debugging)
320 // cutoff_factor = (distance < Rc) ? 1.0 : 0.0;
321 // tmp_tensor(iA, iB) = value * cutoff_factor;
322 // continue; // Skip the erfc truncation below
323
324 if (distance > 0.0 && width > 1.0)
325 {
326 // Log-space erfc truncation (FHI-aims implementation)
327 cutoff_factor = 0.5 * std::erfc(std::log(distance / Rc) / std::log(width));
328
329 // Debug output for high states (check if truncation is working)
330 static int debug_count = 0;
331 if (debug_count < 10 && distance > Rc * 0.9 && distance < Rc * 1.2)
332 {
333 std::cout << "DEBUG: distance=" << distance << " Rc=" << Rc
334 << " cutoff_factor=" << cutoff_factor << " value=" << value
335 << std::endl;
336 debug_count++;
337 }
338 }
339 else if (distance <= 0.0)
340 {
341 // At r = 0, no truncation
342 cutoff_factor = 1.0;
343 }
344 else
345 {
346 // width <= 1.0: no smooth truncation, use hard cutoff
347 cutoff_factor = (distance < Rc) ? 1.0 : 0.0;
348 // const double gamma = 5.0 / Rc;
349 // double x = gamma * distance;
350 // cutoff_factor = std::erfc(x);
351 // cutoff_factor = (cutoff_factor > 0) ? cutoff_factor : 0.0;
352 }
353
354 tmp_tensor(iA, iB) = value * cutoff_factor;
355 }
356 }
357 // if (iat0 == 0 && iat0 == 0 && R[0] == 2 && R[1] == 2 && R[2] == 1 && iat0 == 0 &&
358 // iat1 == 0)
359 // {
360 // std::cout << "iA: " << iA << ", iB: " << iB << ", L2: " << L2 << ", M2: " << M2
361 // << ", V= " << value << ", prefactor:" << prefactor << ",mom1: " << mom1
362 // << ", mom2: " << mom2 << ", clmlm: " << clmlm << ", ylm: " << ylm
363 // << std::endl;
364 // }
365
366 // if (R[0] == 2 && R[1] == 2 && R[2] == 1 && iat0 == 0 && iat1 == 0)
367 // {
368 // out_pure_ri_tensor("Vs_tensor.txt", tmp_tensor, 0.0);
369 // }
370 // debug
371 // std::cout << "T1: " << T1 << ", L1: " << L1 << ", T2: " << T2 << ", L2: " << L2
372 // << ", delta_R: " << delta_R[0] << ", " << delta_R[1] << ", " << delta_R[2]
373 // << ", distance: " << distance << ", outside V= " << value
374 // << ", prefactor:" << prefactor << ",mom1: " << mom1 << ", mom2: " << mom2
375 // << ", clmlm: " << clmlm << ", ylm_real: " << ylm_real << std::endl;
376 }
377 }
378 }
379 }
380 Vws[T1][T2][delta_R] = tmp_tensor;
381 // I must contain all atoms in unit cell
382 auto& target_inner = Vs_cut.at(iat0);
383 if (target_inner.find(JR) == target_inner.end())
384 {
385 target_inner.emplace(JR, tmp_tensor);
386 }
387 // otherwise, warning
388 else
389 {
390 target_inner[JR] = tmp_tensor;
391 const auto J = JR.first;
392 const auto R = JR.second;
393 // std::cout << "J=" << J << ", R= " << R[0] << ", " << R[1] << ", " << R[2] << std::endl;
394 ModuleBase::WARNING_QUIT("merge_VR", "JR already exists in Vs_cut[I], which is unexpected.");
395 }
396 }
397 }
398 ModuleBase::timer::end("Rotate_abfs", "cal_VR");
399}
400
401template <typename Tdata>
403 const UnitCell& ucell,
404 const std::vector<std::vector<std::vector<Numerical_Orbital_Lm>>>& orb_in,
405 const std::pair<std::vector<TA>, std::vector<std::vector<std::pair<TA, std::array<Tcell, Ndim>>>>>& list_r,
406 const std::vector<double>& orb_cutoff,
407 const double Rc,
408 LRI_CV<Tdata>& cv,
409 std::map<TA, std::map<TAC, RI::Tensor<Tdata>>>& Vs_cut)
410{
411 ModuleBase::TITLE("Rotate_abfs", "discard0_VR");
412 ModuleBase::timer::start("Rotate_abfs", "discard0_VR");
413
414 const double tiny1 = 1e-12;
417
418 const auto list_A0 = list_r.first;
419 const auto list_A1 = list_r.second[0];
420 auto& Vws = cv.Vws;
421
422 // Process cv.Vws - only modify tensors in the moment method range
423 for (size_t i0 = 0; i0 < list_A0.size(); ++i0)
424 {
425 const TA iat0 = list_A0[i0];
426 const int T1 = ucell.iat2it[iat0];
427 const size_t I1 = ucell.iat2ia[iat0];
428 const auto& tauA = ucell.atoms[T1].tau[I1];
429
430 for (size_t i1 = 0; i1 < list_A1.size(); ++i1)
431 {
432 const TA iat1 = list_A1[i1].first;
433 const int T2 = ucell.iat2it[iat1];
434 const size_t I2 = ucell.iat2ia[iat1];
435 const auto& tauB = ucell.atoms[T2].tau[I2];
436 const auto R = list_A1[i1].second;
437
438 // delta_R: Angstrom
439 const auto delta_R = tauB - tauA + (RI_Util::array3_to_Vector3(R) * ucell.latvec);
440 // bohr
441 const double distance_true = (delta_R).norm() * ucell.lat0;
442 const double distance = (distance_true >= tiny1) ? distance_true : distance_true + tiny1;
443
444 double Rcut_lcao = orb_cutoff[T1] + orb_cutoff[T2];
445 double Rcut_coul = std::min(cv.cal_V_Rcut(T1, T2), cv.cal_V_Rcut(T2, T2));
446
447 // Skip if not in moment method range
448 if (distance < Rcut_lcao || distance >= Rcut_coul)
449 continue;
450
451 // Check if this tensor exists in Vws
452 if (Vws.find(T1) != Vws.end() && Vws[T1].find(T2) != Vws[T1].end())
453 {
454 auto& delta_R_map = Vws[T1][T2];
455 if (delta_R_map.find(delta_R) != delta_R_map.end())
456 {
457 RI::Tensor<Tdata>& tensor = delta_R_map[delta_R];
458
459 // Zero out elements where N1 != 0 or N2 != 0
460 for (int L1 = 0; L1 != orb_in[T1].size(); ++L1)
461 {
462 for (int L2 = 0; L2 != orb_in[T2].size(); ++L2)
463 {
464 for (int M1 = -L1; M1 <= L1; ++M1)
465 {
466 const int index_M1 = M1 + L1;
467 for (int M2 = -L2; M2 <= L2; ++M2)
468 {
469 const int index_M2 = M2 + L2;
470
471 // Set all N1 != 0 or N2 != 0 elements to zero
472 for (int N1 = 1; N1 != orb_in[T1][L1].size(); ++N1)
473 {
474 const size_t iA = index[T1][L1][N1][index_M1];
475 for (int N2 = 0; N2 != orb_in[T2][L2].size(); ++N2)
476 {
477 const size_t iB = index[T2][L2][N2][index_M2];
478 tensor(iA, iB) = static_cast<Tdata>(0);
479 }
480 }
481 for (int N2 = 1; N2 != orb_in[T2][L2].size(); ++N2)
482 {
483 const size_t iB = index[T2][L2][N2][index_M2];
484 for (int N1 = 0; N1 != orb_in[T1][L1].size(); ++N1)
485 {
486 const size_t iA = index[T1][L1][N1][index_M1];
487 tensor(iA, iB) = static_cast<Tdata>(0);
488 }
489 }
490 }
491 }
492 }
493 }
494 }
495 }
496 }
497 }
498
499 // Process Vs_cut - only modify tensors in the moment method range
500 for (auto& iat_inner_map : Vs_cut)
501 {
502 const TA iat0 = iat_inner_map.first;
503 const int T1 = ucell.iat2it[iat0];
504 const size_t I1 = ucell.iat2ia[iat0];
505 const auto& tauA = ucell.atoms[T1].tau[I1];
506
507 for (auto& JR_tensor : iat_inner_map.second)
508 {
509 const TA iat1 = JR_tensor.first.first;
510 const int T2 = ucell.iat2it[iat1];
511 const size_t I2 = ucell.iat2ia[iat1];
512 const auto& tauB = ucell.atoms[T2].tau[I2];
513 const auto& R = JR_tensor.first.second;
514
515 // delta_R: Angstrom
516 const auto delta_R = tauB - tauA + (RI_Util::array3_to_Vector3(R) * ucell.latvec);
517 // bohr
518 const double distance_true = (delta_R).norm() * ucell.lat0;
519 const double distance = (distance_true >= tiny1) ? distance_true : distance_true + tiny1;
520
521 double Rcut_lcao = orb_cutoff[T1] + orb_cutoff[T2];
522 double Rcut_coul = std::min(cv.cal_V_Rcut(T1, T2), cv.cal_V_Rcut(T2, T2));
523
524 // Skip if not in moment method range
525 if (distance < Rcut_lcao || distance >= Rcut_coul)
526 continue;
527
528 RI::Tensor<Tdata>& tensor = JR_tensor.second;
529
530 // Zero out elements where N1 != 0 or N2 != 0
531 for (int L1 = 0; L1 != orb_in[T1].size(); ++L1)
532 {
533 for (int L2 = 0; L2 != orb_in[T2].size(); ++L2)
534 {
535 for (int M1 = -L1; M1 <= L1; ++M1)
536 {
537 const int index_M1 = M1 + L1;
538 for (int M2 = -L2; M2 <= L2; ++M2)
539 {
540 const int index_M2 = M2 + L2;
541
542 // Set all N1 != 0 or N2 != 0 elements to zero
543 for (int N1 = 1; N1 != orb_in[T1][L1].size(); ++N1)
544 {
545 const size_t iA = index[T1][L1][N1][index_M1];
546 for (int N2 = 0; N2 != orb_in[T2][L2].size(); ++N2)
547 {
548 const size_t iB = index[T2][L2][N2][index_M2];
549 tensor(iA, iB) = static_cast<Tdata>(0);
550 }
551 }
552 for (int N2 = 1; N2 != orb_in[T2][L2].size(); ++N2)
553 {
554 const size_t iB = index[T2][L2][N2][index_M2];
555 for (int N1 = 0; N1 != orb_in[T1][L1].size(); ++N1)
556 {
557 const size_t iA = index[T1][L1][N1][index_M1];
558 tensor(iA, iB) = static_cast<Tdata>(0);
559 }
560 }
561 }
562 }
563 }
564 }
565 }
566 }
567
568 ModuleBase::timer::end("Rotate_abfs", "discard0_VR");
569}
570
571template <typename Tdata>
572void Moment_abfs<Tdata>::out_pure_ri_tensor(const std::string fn, RI::Tensor<double>& olp, const double threshold)
573{
574 std::ofstream fs;
575 auto format = std::scientific;
576 int prec = 15;
577 fs.open(fn);
578 int nr = olp.shape[0];
579 int nc = olp.shape[1];
580 size_t nnz = nr * nc;
581 fs << "%%MatrixMarket matrix coordinate complex general" << std::endl;
582 fs << "%" << std::endl;
583
584 fs << nr << " " << nc << " " << nnz << std::endl;
585
586 for (int i = 0; i < nr; i++)
587 {
588 for (int j = 0; j < nc; j++)
589 {
590 auto v = olp(i, j);
591 if (fabs(v) > threshold)
592 fs << i + 1 << " " << j + 1 << " " << std::showpoint << format << std::setprecision(prec) << v << "\n";
593 }
594 }
595
596 fs.close();
597}
598
599template <typename Tdata>
601 RI::Tensor<std::complex<double>>& olp,
602 const double threshold)
603{
604 std::ofstream fs;
605 auto format = std::scientific;
606 int prec = 15;
607 fs.open(fn);
608 int nr = olp.shape[0];
609 int nc = olp.shape[1];
610 size_t nnz = nr * nc;
611 fs << "%%MatrixMarket matrix coordinate complex general" << std::endl;
612 fs << "%" << std::endl;
613
614 fs << nr << " " << nc << " " << nnz << std::endl;
615
616 for (int j = 0; j < nc; j++)
617 {
618 for (int i = 0; i < nr; i++)
619 {
620 auto v = olp(i, j);
621 if (fabs(v.real()) > threshold || fabs(v.imag()) > threshold)
622 fs << i + 1 << " " << j + 1 << " " << std::showpoint << format << std::setprecision(prec) << v.real()
623 << " " << std::showpoint << format << std::setprecision(prec) << v.imag() << "\n";
624 }
625 }
626
627 fs.close();
628}
629// template <typename Tdata>
630// void Moment_abfs<Tdata>::diverge_list(
631// const std::pair<std::vector<TA>, std::vector<std::vector<std::pair<TA, std::array<Tcell, Ndim>>>>>&
632// list_As_Vs, std::pair<std::vector<TA>, std::vector<std::vector<std::pair<TA, std::array<Tcell, Ndim>>>>>&
633// list_k, std::pair<std::vector<TA>, std::vector<std::vector<std::pair<TA, std::array<Tcell, Ndim>>>>>& list_r,
634// const UnitCell& ucell,
635// const std::vector<double>& orb_cutoff)
636// {
637// ModuleBase::TITLE("Rotate_abfs", "diverge_list");
638// ModuleBase::timer::start("Rotate_abfs", "diverge_list");
639
640// double Rcut_max = 0;
641// for (int T = 0; T < ucell.ntype; ++T)
642// Rcut_max = std::max(Rcut_max, orb_cutoff[T]);
643
644// list_k.first.clear();
645// list_k.second.clear();
646// list_r.first.clear();
647// list_r.second.clear();
648// list_k.second.resize(1);
649// list_r.second.resize(1);
650// int flag_k = 0;
651// int flag_r = 0;
652// for (size_t iA = 0; iA < list_As_Vs.first.size(); ++iA)
653// {
654// const auto& A = list_As_Vs.first[iA];
655// const size_t TA = ucell.iat2it[A];
656// const size_t IA = ucell.iat2ia[A];
657// const auto& tauA = ucell.atoms[TA].tau[IA];
658// for (const auto& BR: list_As_Vs.second[0])
659// {
660// const auto& B = BR.first;
661// const size_t TB = ucell.iat2it[B];
662// const size_t IB = ucell.iat2ia[B];
663// const auto& tauB = ucell.atoms[TB].tau[IB];
664// const auto& R = BR.second;
665
666// const ModuleBase::Vector3<double> tauB_shift = tauB + (RI_Util::array3_to_Vector3(R) * ucell.latvec);
667// const ModuleBase::Vector3<double> tau_delta = (tauB_shift - tauA) * ucell.lat0;
668// const double distance = tau_delta.norm();
669// if (distance <= Rcut_max)
670// {
671// if (std::find(list_k.first.begin(), list_k.first.end(), A) == list_k.first.end())
672// {
673// list_k.first.emplace_back(A);
674// }
675// if (std::find(list_k.second[0].begin(), list_k.second[0].end(), BR) == list_k.second[0].end())
676// {
677// list_k.second[0].emplace_back(BR);
678// }
679// }
680// else
681// {
682// if (std::find(list_r.first.begin(), list_r.first.end(), A) == list_r.first.end())
683// {
684// list_r.first.emplace_back(A);
685// }
686// if (std::find(list_r.second[0].begin(), list_r.second[0].end(), BR) == list_r.second[0].end())
687// {
688// list_r.second[0].emplace_back(BR);
689// }
690// }
691// }
692// }
693// for (const auto& I: list_r.first)
694// {
695// for (const auto& JR: list_r.second[0])
696// flag_r += 1;
697// }
698// for (const auto& I: list_k.first)
699// {
700// for (const auto& JR: list_k.second[0])
701// flag_k += 1;
702// }
703// std::cout << "All No.(atom pairs)=" << flag_k + flag_r << ", " << flag_k << " inside Rcut, " << flag_r
704// << " outside Rcut" << std::endl;
705// ModuleBase::timer::end("Rotate_abfs", "diverge_list");
706// }
707
708// template <typename Tdata>
709// void Moment_abfs<Tdata>::merge_list(std::map<TA, std::map<TAC, RI::Tensor<Tdata>>>& Vs_cut)
710// {
711// ModuleBase::TITLE("Rotate_abfs", "merge_list");
712// ModuleBase::timer::start("Rotate_abfs", "merge_list");
713
714// for (const auto& IJRc: this->VR)
715// {
716// const TA& I = IJRc.first;
717// const auto& JRc = IJRc.second;
718
719// // if Vs_cut[I] does not exist, then create an empty inner map
720// auto& target_inner = Vs_cut[I];
721
722// for (const auto& JRc_tensor: JRc)
723// {
724// const TAC& JR = JRc_tensor.first;
725// const RI::Tensor<Tdata>& tensor = JRc_tensor.second;
726
727// // if JR does not exist in Vs_cut[I], then insert it
728// if (target_inner.find(JR) == target_inner.end())
729// {
730// target_inner.emplace(JR, tensor);
731// }
732// // otherwise, warning
733// else
734// {
735// target_inner[JR] = tensor;
736// const auto J = JR.first;
737// const auto R = JR.second;
738// std::cout << "J=" << J << ", R= " << R[0] << ", " << R[1] << ", " << R[2] << std::endl;
739// // ModuleBase::WARNING_QUIT("merge_VR", "JR already exists in Vs_cut[I], which is unexpected.");
740// }
741// }
742// }
743// ModuleBase::timer::end("Rotate_abfs", "merge_list");
744// }
745
746#endif
const std::complex< double > i
Definition cal_pLpR.cpp:46
std::vector< ModuleBase::Vector3< double > > tau
Definition atom_spec.h:35
Definition LRI_CV.h:25
std::map< int, std::map< int, std::map< Abfs::Vector3_Order< double >, RI::Tensor< Tdata > > > > Vws
Definition LRI_CV.h:77
double cal_V_Rcut(const int it0, const int it1)
Definition LRI_CV.hpp:86
static void Simpson_Integral(const int mesh, const double *const func, const double *const rab, double &asum)
simpson integral.
Definition math_integral.cpp:66
static void rl_sph_harm(const int Lmax, const double x, const double y, const double z, std::vector< double > &rly)
Get the ylm real object (used in getting overlap)
Definition ylm.cpp:632
static void start(void)
Start total time calculation.
Definition timer.cpp:44
static void end(const std::string &class_name_in, const std::string &name_in)
Definition timer.cpp:109
void out_pure_ri_tensor(const std::string fn, RI::Tensor< std::complex< double > > &olp, const double threshold)
Definition exx_rotate_abfs.hpp:600
double ln_factorial(int n) const
Definition exx_rotate_abfs.hpp:132
double sum_triple_Y_YLM_real(int l1, int m1, int l2, int m2, const std::vector< double > &rly, const ORB_gaunt_table &MGT, const double distance)
Definition exx_rotate_abfs.hpp:152
double dfact(const int &l) const
double factorial
Definition exx_rotate_abfs.hpp:103
std::pair< TA, TC > TAC
Definition exx_rotate_abfs.h:26
double cal_cl1l2(int l1, int l2) const
Definition exx_rotate_abfs.hpp:141
int TA
Definition exx_rotate_abfs.h:21
void cal_VR(const UnitCell &ucell, const std::vector< std::vector< std::vector< Numerical_Orbital_Lm > > > &orb_in, const std::pair< std::vector< TA >, std::vector< std::vector< std::pair< TA, std::array< Tcell, Ndim > > > > > &list_r, const std::vector< double > &orb_cutoff, const double Rc, LRI_CV< Tdata > &cv, std::map< TA, std::map< TAC, RI::Tensor< Tdata > > > &Vs_cut)
Definition exx_rotate_abfs.hpp:184
void rotate_abfs(std::vector< std::vector< std::vector< Numerical_Orbital_Lm > > > &orb_in)
Definition exx_rotate_abfs.hpp:41
void discard0_VR(const UnitCell &ucell, const std::vector< std::vector< std::vector< Numerical_Orbital_Lm > > > &orb_in, const std::pair< std::vector< TA >, std::vector< std::vector< std::pair< TA, std::array< Tcell, Ndim > > > > > &list_r, const std::vector< double > &orb_cutoff, const double Rc, LRI_CV< Tdata > &cv, std::map< TA, std::map< TAC, RI::Tensor< Tdata > > > &Vs_cut)
Definition exx_rotate_abfs.hpp:402
void cal_multipole(const std::vector< std::vector< std::vector< Numerical_Orbital_Lm > > > &orb_in)
Definition exx_rotate_abfs.hpp:12
int factorial(const int &n) const
Definition exx_rotate_abfs.hpp:114
Definition ORB_atomic_lm.h:21
const double * getPsi() const
Definition ORB_atomic_lm.h:137
const double * getRadial() const
Definition ORB_atomic_lm.h:124
const int & getNr() const
Definition ORB_atomic_lm.h:118
const double * getRab() const
Definition ORB_atomic_lm.h:128
Definition ORB_gaunt_table.h:9
void init_Gaunt(const int &lmax)
Definition ORB_gaunt_table.cpp:15
ModuleBase::realArray Gaunt_Coefficients
Definition ORB_gaunt_table.h:56
static int get_lm_index(const int l, const int m)
Definition ORB_gaunt_table.h:89
void init_Gaunt_CH(const int &Lmax)
Definition ORB_gaunt_table.cpp:183
Definition unitcell.h:15
int *& iat2it
Definition unitcell.h:75
Atom * atoms
Definition unitcell.h:45
double & lat0
Definition unitcell.h:56
ModuleBase::Matrix3 & latvec
Definition unitcell.h:63
int *& iat2ia
Definition unitcell.h:76
#define N
Definition exp.cpp:24
#define T
Definition exp.cpp:237
Exx_Info exx_info
Definition exx_info.cpp:8
Range construct_range(const LCAO_Orbitals &orb)
Definition element_basis_index-ORB.cpp:10
IndexLNM construct_index(const Range &range)
Definition element_basis_index.cpp:12
std::vector< Index_T > IndexLNM
Definition element_basis_index.h:42
std::vector< std::vector< NM > > Range
Definition element_basis_index.h:41
void WARNING_QUIT(const std::string &, const std::string &)
Combine the functions of WARNING and QUIT.
Definition test_delley.cpp:14
const double TWO_PI
Definition constants.h:21
const double PI_HALF
Definition constants.h:20
const double FOUR_PI
Definition constants.h:22
void TITLE(const std::string &class_name, const std::string &function_name, const bool disable)
Definition tool_title.cpp:18
ModuleBase::Vector3< Tcell > array3_to_Vector3(const std::array< Tcell, 3 > &v)
Definition RI_Util.h:38
#define threshold
Definition sph_bessel_recursive_test.cpp:4
bool rotate_abfs
Definition exx_info.h:57
Exx_Info_RI info_ri
Definition exx_info.h:86
double norm(const Vec3 &v)
Definition test_partition.cpp:25