Skip to content

Commit f7deafc

Browse files
authored
Refactor: simplify snap_psibeta_half_tddft.cpp (#6846)
* simplify snap_psibeta_half_tddft.cpp * fix: use dk_1 instead of inv_dk_1 in Polynomial_Interpolation call The Polynomial_Interpolation function expects table_interval (dk) as the parameter, not its inverse. The function computes position = x / table_interval internally. This fixes the 05_rtTDDFT test failures.
1 parent 3fcf5f7 commit f7deafc

File tree

1 file changed

+60
-88
lines changed

1 file changed

+60
-88
lines changed

source/source_lcao/module_rt/snap_psibeta_half_tddft.cpp

Lines changed: 60 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -5,26 +5,27 @@
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

1213
namespace 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
*/
2324
static 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

Comments
 (0)