Skip to content

Commit 4261f5e

Browse files
authored
fix: preserve PW ordering in WT CUDA convolution (#7763)
Co-authored-by: Jiacheng Xu <169599847+Stardust0831@users.noreply.github.com>
1 parent 0b88142 commit 4261f5e

1 file changed

Lines changed: 19 additions & 14 deletions

File tree

source/source_pw/module_ofdft/kernels/cuda/kedf_wt_gpu.cu

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -47,16 +47,19 @@ __global__ void kedf_wt_rho_power(
4747
/// Element-wise multiply: complex array *= real kernel.
4848
/// Uses double2 (native cuFFT type) instead of thrust::complex.
4949
__global__ void kedf_wt_recip_multiply(
50-
double2* __restrict__ data,
50+
const double2* __restrict__ in,
51+
double2* __restrict__ out,
5152
const double* __restrict__ kernel,
53+
const int* __restrict__ box_index,
5254
int npw)
5355
{
5456
int idx = blockIdx.x * blockDim.x + threadIdx.x;
5557
int stride = blockDim.x * gridDim.x;
5658
for (int i = idx; i < npw; i += stride) {
57-
double2 v = data[i];
59+
const int box = box_index[i];
60+
double2 v = in[box];
5861
double k = kernel[i];
59-
data[i] = make_double2(v.x * k, v.y * k);
62+
out[box] = make_double2(v.x * k, v.y * k);
6063
}
6164
}
6265

@@ -118,15 +121,15 @@ void KEDF_WT::multi_kernel_gpu(
118121

119122
// ── Lazy allocation of persistent GPU buffers ──
120123
if (!gpu_allocated_) {
121-
resmem_dd_op()(d_rho_, nrxx);
124+
resmem_dd_op()(d_rho_, nrxx * 2); // real input or complex work buffer
122125
resmem_dd_op()(d_result_, nrxx * 2); // complex work buffer
123126
resmem_dd_op()(d_kernel_, npw);
124127

125128
syncmem_d2d_h2d_op()(d_kernel_, this->kernel_, npw);
126129

127-
// Create cuFFT plans (3D Z2Z, in-place on d_result_)
128-
CUFFT_CHECK(cufftPlan3d(&cufft_plan_fwd_, nz, ny, nx, CUFFT_Z2Z));
129-
CUFFT_CHECK(cufftPlan3d(&cufft_plan_bwd_, nz, ny, nx, CUFFT_Z2Z));
130+
// Match PW_Basis's full-box FFT layout used by ig2ixyz_gpu.
131+
CUFFT_CHECK(cufftPlan3d(&cufft_plan_fwd_, nx, ny, nz, CUFFT_Z2Z));
132+
CUFFT_CHECK(cufftPlan3d(&cufft_plan_bwd_, nx, ny, nz, CUFFT_Z2Z));
130133

131134
gpu_allocated_ = true;
132135
}
@@ -136,6 +139,7 @@ void KEDF_WT::multi_kernel_gpu(
136139

137140
// d_result_ is double* but aliased as cuFFT complex buffer.
138141
auto* d_fft = reinterpret_cast<double2*>(d_result_);
142+
auto* d_filtered = reinterpret_cast<double2*>(d_rho_);
139143

140144
for (int is = 0; is < nspin; ++is) {
141145
// Step 1: Copy input density H→D
@@ -157,24 +161,25 @@ void KEDF_WT::multi_kernel_gpu(
157161
reinterpret_cast<cufftDoubleComplex*>(d_fft),
158162
CUFFT_FORWARD));
159163

160-
// Step 5: Multiply by WT kernel in G-space (double2)
164+
// Step 5: Multiply selected plane waves and zero the rest of the FFT box.
165+
setmem_dd_op()(d_rho_, 0, nrxx * 2);
161166
kedf_wt_recip_multiply<<<blocks_g, THREADS_PER_BLOCK>>>(
162-
d_fft, d_kernel_, npw);
167+
d_fft, d_filtered, d_kernel_, pw_rho->ig2ixyz_gpu, npw);
163168
CHECK_CUDA_SYNC();
164169

165-
// Step 6: Inverse FFT (in-place on d_fft)
170+
// Step 6: Inverse FFT (in-place on the filtered box)
166171
CUFFT_CHECK(cufftExecZ2Z(cufft_plan_bwd_,
167-
reinterpret_cast<cufftDoubleComplex*>(d_fft),
168-
reinterpret_cast<cufftDoubleComplex*>(d_fft),
172+
reinterpret_cast<cufftDoubleComplex*>(d_filtered),
173+
reinterpret_cast<cufftDoubleComplex*>(d_filtered),
169174
CUFFT_INVERSE));
170175

171176
// Step 7: Complex → Real with 1/N normalization (double2)
172177
kedf_wt_complex_to_real_norm<<<blocks_r, THREADS_PER_BLOCK>>>(
173-
d_fft, d_rho_, inv_nrxx, nrxx);
178+
d_filtered, d_result_, inv_nrxx, nrxx);
174179
CHECK_CUDA_SYNC();
175180

176181
// Step 8: D → H
177-
syncmem_d2d_d2h_op()(rkernel_rho[is], d_rho_, nrxx);
182+
syncmem_d2d_d2h_op()(rkernel_rho[is], d_result_, nrxx);
178183
}
179184
}
180185

0 commit comments

Comments
 (0)