55#include " source_base/math_polyint.h"
66#include " source_base/timer.h"
77#include " source_base/ylm.h"
8- #include < vector>
9- #include < complex>
8+
109#include < cmath>
10+ #include < complex>
11+ #include < vector>
1112
1213namespace module_rt
1314{
1415
1516/* *
1617 * @brief Initialize Gauss-Legendre grid points and weights.
1718 * Thread-safe initialization using static local variable.
18- *
19+ *
1920 * @param grid_size Number of grid points (140)
2021 * @param gl_x Output: Grid points in [-1, 1]
2122 * @param gl_w Output: Weights
2223 */
2324static void init_gauss_legendre_grid (int grid_size, std::vector<double >& gl_x, std::vector<double >& gl_w)
2425{
2526 static bool init = false ;
26- // Thread-safe initialization
27- #pragma omp critical(init_gauss_legendre)
27+ // Thread-safe initialization
28+ #pragma omp critical(init_gauss_legendre)
2829 {
2930 if (!init)
3031 {
@@ -34,48 +35,17 @@ static void init_gauss_legendre_grid(int grid_size, std::vector<double>& gl_x, s
3435 }
3536}
3637
37- /* *
38- * @brief Interpolate radial function value at a given distance using cubic interpolation.
39- *
40- * @param psi Pointer to radial function array
41- * @param mesh Number of mesh points
42- * @param inv_dk Inverse of grid spacing (1/dk)
43- * @param distance Distance to interpolate at
44- * @return double Interpolated value
45- */
46- inline double interpolate_radial (
47- const double * psi,
48- int mesh,
49- double inv_dk,
50- double distance)
51- {
52- double position = distance * inv_dk;
53- int iq = static_cast <int >(position);
54-
55- // Boundary check safe-guard
56- if (iq > mesh - 4 ) return 0.0 ;
57-
58- const double x0 = position - static_cast <double >(iq);
59- const double x1 = 1.0 - x0;
60- const double x2 = 2.0 - x0;
61- const double x3 = 3.0 - x0;
62-
63- // Cubic interpolation formula
64- return x1*x2*(psi[iq]*x3+psi[iq+3 ]*x0)/6.0
65- + x0*x3*(psi[iq+1 ]*x2-psi[iq+2 ]*x1)/2.0 ;
66- }
67-
6838/* *
6939 * @brief Main function to calculate overlap integrals <phi|exp^{-iAr}|beta>
7040 * and its derivatives (if calc_r is true).
71- *
41+ *
7242 * This function integrates the overlap between a local orbital phi (at R1)
7343 * and a non-local projector beta (at R0), modulated by a plane-wave-like phase factor
7444 * exp^{-iAr}, where A is a vector potential.
75- *
45+ *
7646 * @param orb LCAO Orbitals information
7747 * @param infoNL_ Non-local pseudopotential information
78- * @param nlm Output:
48+ * @param nlm Output:
7949 * nlm[0] : <phi|exp^{-iAr}|beta>
8050 * nlm[1, 2, 3] : <phi|r_a * exp^{-iAr}|beta>, a = x, y, z (if calc_r=true)
8151 * @param R1 Position of atom 1 (orbital phi)
@@ -96,7 +66,7 @@ void snap_psibeta_half_tddft(const LCAO_Orbitals& orb,
9666 const int & L1,
9767 const int & m1,
9868 const int & N1,
99- const ModuleBase::Vector3<double >& R0,
69+ const ModuleBase::Vector3<double >& R0,
10070 const int & T0,
10171 const ModuleBase::Vector3<double >& A,
10272 const bool & calc_r)
@@ -105,27 +75,29 @@ void snap_psibeta_half_tddft(const LCAO_Orbitals& orb,
10575
10676 // 1. Initialization and Early Exits
10777 const int nproj = infoNL_.nproj [T0];
108-
78+
10979 // Resize output vector based on whether position operator matrix elements are needed
11080 int required_size = calc_r ? 4 : 1 ;
111- if (nlm.size () != required_size) nlm.resize (required_size);
112-
113- if (nproj == 0 ) return ;
81+ if (nlm.size () != required_size)
82+ nlm.resize (required_size);
83+
84+ if (nproj == 0 )
85+ return ;
11486
11587 // 2. Determine total number of projectors and identify active ones based on cutoff
11688 int natomwfc = 0 ;
11789 std::vector<bool > calproj (nproj, false );
118-
90+
11991 const double Rcut1 = orb.Phi [T1].getRcut ();
12092 const ModuleBase::Vector3<double > dRa = R0 - R1;
12193 const double distance10 = dRa.norm ();
122-
94+
12395 bool any_active = false ;
12496 for (int ip = 0 ; ip < nproj; ip++)
12597 {
12698 const int L0 = infoNL_.Beta [T0].Proj [ip].getL ();
12799 natomwfc += 2 * L0 + 1 ;
128-
100+
129101 const double Rcut0 = infoNL_.Beta [T0].Proj [ip].getRcut ();
130102 if (distance10 <= (Rcut1 + Rcut0))
131103 {
@@ -135,7 +107,8 @@ void snap_psibeta_half_tddft(const LCAO_Orbitals& orb,
135107 }
136108
137109 // Initialize output values to zero and resize inner vectors
138- for (auto & x : nlm) {
110+ for (auto & x: nlm)
111+ {
139112 x.assign (natomwfc, 0.0 );
140113 }
141114
@@ -150,12 +123,11 @@ void snap_psibeta_half_tddft(const LCAO_Orbitals& orb,
150123 const int mesh_r1 = phi_ln.getNr ();
151124 const double * psi_1 = phi_ln.getPsi ();
152125 const double dk_1 = phi_ln.getDk ();
153- const double inv_dk_1 = 1.0 / dk_1;
154126
155127 // 4. Prepare Integration Grids
156128 const int radial_grid_num = 140 ;
157129 const int angular_grid_num = 110 ;
158-
130+
159131 // Cached standard Gauss-Legendre grid
160132 static std::vector<double > gl_x (radial_grid_num);
161133 static std::vector<double > gl_w (radial_grid_num);
@@ -169,17 +141,17 @@ void snap_psibeta_half_tddft(const LCAO_Orbitals& orb,
169141 std::vector<double > A_dot_lebedev (angular_grid_num);
170142 for (int ian = 0 ; ian < angular_grid_num; ++ian)
171143 {
172- A_dot_lebedev[ian] = A.x * ModuleBase::Integral::Lebedev_Laikov_grid110_x[ian] +
173- A.y * ModuleBase::Integral::Lebedev_Laikov_grid110_y[ian] +
174- A.z * ModuleBase::Integral::Lebedev_Laikov_grid110_z[ian];
144+ A_dot_lebedev[ian] = A.x * ModuleBase::Integral::Lebedev_Laikov_grid110_x[ian]
145+ + A.y * ModuleBase::Integral::Lebedev_Laikov_grid110_y[ian]
146+ + A.z * ModuleBase::Integral::Lebedev_Laikov_grid110_z[ian];
175147 }
176148
177149 // Reuseable buffers for inner loops to avoid allocation
178150 std::vector<std::complex <double >> result_angular; // Accumulator for angular integration
179151 // Accumulators for position operator components
180152 std::vector<std::complex <double >> res_ang_x, res_ang_y, res_ang_z;
181-
182- std::vector<double > rly1 ((L1 + 1 ) * (L1 + 1 )); // Spherical harmonics buffer for L1
153+
154+ std::vector<double > rly1 ((L1 + 1 ) * (L1 + 1 )); // Spherical harmonics buffer for L1
183155 std::vector<std::vector<double >> rly0_cache (angular_grid_num); // Cache for L0 Ylm
184156
185157 // 5. Loop over Projectors (Beta)
@@ -207,8 +179,8 @@ void snap_psibeta_half_tddft(const LCAO_Orbitals& orb,
207179 double r_max = radial0[mesh_r0 - 1 ];
208180 double xl = (r_max - r_min) * 0.5 ;
209181 double xmean = (r_max + r_min) * 0.5 ;
210-
211- for (int i= 0 ; i< radial_grid_num; ++i)
182+
183+ for (int i = 0 ; i < radial_grid_num; ++i)
212184 {
213185 r_radial[i] = xmean + xl * gl_x[i];
214186 w_radial[i] = xl * gl_w[i];
@@ -219,12 +191,13 @@ void snap_psibeta_half_tddft(const LCAO_Orbitals& orb,
219191
220192 // 5.2 Precompute Spherical Harmonics (Ylm) for L0 on angular grid
221193 // Since L0 changes with projector, we compute this per projector loop.
222- for (int ian = 0 ; ian < angular_grid_num; ++ian) {
223- ModuleBase::Ylm::rl_sph_harm (L0,
224- ModuleBase::Integral::Lebedev_Laikov_grid110_x[ian],
225- ModuleBase::Integral::Lebedev_Laikov_grid110_y[ian],
226- ModuleBase::Integral::Lebedev_Laikov_grid110_z[ian],
227- rly0_cache[ian]);
194+ for (int ian = 0 ; ian < angular_grid_num; ++ian)
195+ {
196+ ModuleBase::Ylm::rl_sph_harm (L0,
197+ ModuleBase::Integral::Lebedev_Laikov_grid110_x[ian],
198+ ModuleBase::Integral::Lebedev_Laikov_grid110_y[ian],
199+ ModuleBase::Integral::Lebedev_Laikov_grid110_z[ian],
200+ rly0_cache[ian]);
228201 }
229202
230203 // Resize accumulators if needed
@@ -260,21 +233,22 @@ void snap_psibeta_half_tddft(const LCAO_Orbitals& orb,
260233 const double y = ModuleBase::Integral::Lebedev_Laikov_grid110_y[ian];
261234 const double z = ModuleBase::Integral::Lebedev_Laikov_grid110_z[ian];
262235 const double w_ang = ModuleBase::Integral::Lebedev_Laikov_grid110_w[ian];
263-
236+
264237 // Vector r = r_val * u_angle
265238 double rx = r_val * x;
266239 double ry = r_val * y;
267240 double rz = r_val * z;
268-
241+
269242 // Vector r' = r + R0 - R1 = r + dRa
270243 double tx = rx + dRa.x ;
271244 double ty = ry + dRa.y ;
272245 double tz = rz + dRa.z ;
273-
274- double tnorm = std::sqrt (tx* tx + ty* ty + tz* tz);
275-
246+
247+ double tnorm = std::sqrt (tx * tx + ty * ty + tz * tz);
248+
276249 // If r' is outside the cutoff of Phi(r'), skip
277- if (tnorm > Rcut1) continue ;
250+ if (tnorm > Rcut1)
251+ continue ;
278252
279253 // Compute Ylm for L1 at direction r'
280254 if (tnorm > 1e-10 )
@@ -285,7 +259,7 @@ void snap_psibeta_half_tddft(const LCAO_Orbitals& orb,
285259 else
286260 {
287261 // At origin, only Y_00 is non-zero (if using real spherical harmonics convention)
288- ModuleBase::Ylm::rl_sph_harm (L1, 0.0 , 0.0 , 1.0 , rly1);
262+ ModuleBase::Ylm::rl_sph_harm (L1, 0.0 , 0.0 , 1.0 , rly1);
289263 }
290264
291265 // Calculate common phase and weight factor
@@ -294,11 +268,11 @@ void snap_psibeta_half_tddft(const LCAO_Orbitals& orb,
294268 const std::complex <double > exp_iAr = std::exp (ModuleBase::IMAG_UNIT * phase);
295269
296270 // Interpolate Psi at |r'|
297- double interp_psi = interpolate_radial (psi_1, mesh_r1, inv_dk_1 , tnorm);
298-
271+ double interp_psi = ModuleBase::PolyInt::Polynomial_Interpolation (psi_1, mesh_r1, dk_1 , tnorm);
272+
299273 const int offset_L1 = L1 * L1 + m1;
300274 const double ylm_L1_val = rly1[offset_L1];
301-
275+
302276 // Combined factor: exp(iAr) * Y_L1m1(r') * Psi(|r'|) * weight_angle
303277 const std::complex <double > common_factor = exp_iAr * ylm_L1_val * interp_psi * w_ang;
304278
@@ -319,7 +293,7 @@ void snap_psibeta_half_tddft(const LCAO_Orbitals& orb,
319293 double r_op_x = rx + R0.x ;
320294 double r_op_y = ry + R0.y ;
321295 double r_op_z = rz + R0.z ;
322-
296+
323297 res_ang_x[m0] += term * r_op_x;
324298 res_ang_y[m0] += term * r_op_y;
325299 res_ang_z[m0] += term * r_op_z;
@@ -329,16 +303,14 @@ void snap_psibeta_half_tddft(const LCAO_Orbitals& orb,
329303
330304 // 5.5 Combine Radial and Angular parts
331305 // Interpolate Beta(|r|)
332- // Note: The original code implies beta_r stores values that might need scaling or are just the function values.
333- // Typically radial integration is \int f(r) r^2 dr.
334- // Here we have factor: beta_val * r_radial[ir] * w_radial[ir]
335- // w_radial includes the Jacobian for the change of variable from [-1,1] to [r_min, r_max].
336- // The extra r_radial[ir] suggests either beta is stored as r*beta, or we are doing \int ... r dr (2D?),
337- // or Jacobian r^2 is split. Assuming original logic is correct.
338-
339- double beta_val = ModuleBase::PolyInt::Polynomial_Interpolation (
340- beta_r, mesh_r0, dk_0, r_radial[ir]);
341-
306+ // Note: The original code implies beta_r stores values that might need scaling or are just the function
307+ // values. Typically radial integration is \int f(r) r^2 dr. Here we have factor: beta_val * r_radial[ir] *
308+ // w_radial[ir] w_radial includes the Jacobian for the change of variable from [-1,1] to [r_min, r_max]. The
309+ // extra r_radial[ir] suggests either beta is stored as r*beta, or we are doing \int ... r dr (2D?), or
310+ // Jacobian r^2 is split. Assuming original logic is correct.
311+
312+ double beta_val = ModuleBase::PolyInt::Polynomial_Interpolation (beta_r, mesh_r0, dk_0, r_radial[ir]);
313+
342314 double radial_factor = beta_val * r_radial[ir] * w_radial[ir];
343315
344316 int current_idx = index_offset;
@@ -347,7 +319,7 @@ void snap_psibeta_half_tddft(const LCAO_Orbitals& orb,
347319 // Final accumulation into global nlm array
348320 // Add phase exp(i A * R0)
349321 nlm[0 ][current_idx] += radial_factor * result_angular[m0] * exp_iAR0;
350-
322+
351323 if (calc_r)
352324 {
353325 nlm[1 ][current_idx] += radial_factor * res_ang_x[m0] * exp_iAR0;
@@ -364,11 +336,11 @@ void snap_psibeta_half_tddft(const LCAO_Orbitals& orb,
364336
365337 // 6. Final Conjugation
366338 // Apply conjugation to all elements as per convention <phi|beta> = <beta|phi>*
367- for (int dim = 0 ; dim < nlm.size (); dim++)
339+ for (int dim = 0 ; dim < nlm.size (); dim++)
368340 {
369- for (auto &x : nlm[dim])
341+ for (auto & x : nlm[dim])
370342 {
371- x = std::conj (x);
343+ x = std::conj (x);
372344 }
373345 }
374346
0 commit comments