@@ -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