Skip to content

Commit 84ca04b

Browse files
authored
refactor(pw): optimize bspline structure factor grid (#7508)
1 parent 698e187 commit 84ca04b

1 file changed

Lines changed: 50 additions & 79 deletions

File tree

source/source_pw/module_pwdft/structure_factor.cpp

Lines changed: 50 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
#include "source_base/global_function.h"
2-
#include "source_base/global_variable.h"
32
#include "source_io/module_parameter/parameter.h"
43
#include "structure_factor.h"
54
#include "source_base/constants.h"
@@ -8,6 +7,7 @@
87
#include "source_base/timer.h"
98
#include "source_base/libm/libm.h"
109

10+
#include <vector>
1111

1212
#ifdef _OPENMP
1313
#include <omp.h>
@@ -203,38 +203,38 @@ void Structure_Factor::setup(const UnitCell* Ucell, const Parallel_Grid& pgrid,
203203
// norder: the order of Cardinal B-spline base functions
204204
//FURTHER OPTIMIZATION:
205205
// 1. Use "r2c" fft
206-
// 2. Add parallel algorithm for fftw or na loop
207206
//
208207
void Structure_Factor::bspline_sf(const int norder,
209208
const UnitCell* Ucell,
210209
const Parallel_Grid& pgrid,
211210
const ModulePW::PW_Basis* rho_basis)
212211
{
213-
double *r = new double [rho_basis->nxyz];
214-
double *tmpr = new double[rho_basis->nrxx];
215-
double *zpiece = new double[rho_basis->nxy];
216-
std::complex<double> *b1 = new std::complex<double> [rho_basis->nx];
217-
std::complex<double> *b2 = new std::complex<double> [rho_basis->ny];
218-
std::complex<double> *b3 = new std::complex<double> [rho_basis->nz];
212+
(void)pgrid;
213+
std::vector<double> tmpr(rho_basis->nrxx);
214+
std::vector<std::complex<double>> b1(rho_basis->nx);
215+
std::vector<std::complex<double>> b2(rho_basis->ny);
216+
std::vector<std::complex<double>> b3(rho_basis->nz);
217+
const int nplane = rho_basis->nplane;
218+
const int startz = rho_basis->startz_current;
219219

220-
for (int it=0; it<Ucell->ntype; it++)
220+
// Each rank owns the same atoms; populate only its local FFT z slab.
221+
for (int it = 0; it < Ucell->ntype; it++)
221222
{
222-
const int na = Ucell->atoms[it].na;
223-
const ModuleBase::Vector3<double> * const taud = Ucell->atoms[it].taud.data();
224-
ModuleBase::GlobalFunc::ZEROS(r,rho_basis->nxyz);
223+
const int na = Ucell->atoms[it].na;
224+
const ModuleBase::Vector3<double>* const taud = Ucell->atoms[it].taud.data();
225+
ModuleBase::GlobalFunc::ZEROS(tmpr.data(), rho_basis->nrxx);
225226

226-
//A parallel algorithm can be added in the future.
227227
#ifdef _OPENMP
228-
#pragma omp parallel for
228+
#pragma omp parallel for
229229
#endif
230-
for(int ia = 0 ; ia < na ; ++ia)
230+
for (int ia = 0; ia < na; ++ia)
231231
{
232-
double gridx = taud[ia].x * rho_basis->nx;
233-
double gridy = taud[ia].y * rho_basis->ny;
234-
double gridz = taud[ia].z * rho_basis->nz;
235-
double dx = gridx - floor(gridx);
236-
double dy = gridy - floor(gridy);
237-
double dz = gridz - floor(gridz);
232+
const double gridx = taud[ia].x * rho_basis->nx;
233+
const double gridy = taud[ia].y * rho_basis->ny;
234+
const double gridz = taud[ia].z * rho_basis->nz;
235+
const double dx = gridx - floor(gridx);
236+
const double dy = gridy - floor(gridy);
237+
const double dz = gridz - floor(gridz);
238238
//I'm not sure if there is a mod function for double data
239239

240240
ModuleBase::Bspline bsx, bsy, bsz;
@@ -245,79 +245,50 @@ void Structure_Factor::bspline_sf(const int norder,
245245
bsy.getbspline(dy);
246246
bsz.getbspline(dz);
247247

248-
for(int iz = 0 ; iz <= norder ; ++iz)
248+
for (int iz = 0; iz <= norder; ++iz)
249249
{
250-
int icz = int(rho_basis->nz*10-iz+floor(gridz))%rho_basis->nz;
251-
for(int iy = 0 ; iy <= norder ; ++iy)
250+
const int icz = int(rho_basis->nz * 10 - iz + floor(gridz)) % rho_basis->nz;
251+
if (icz < startz || icz >= startz + nplane)
252252
{
253-
int icy = int(rho_basis->ny*10-iy+floor(gridy))%rho_basis->ny;
254-
for(int ix = 0 ; ix <= norder ; ++ix )
253+
continue;
254+
}
255+
const int local_z = icz - startz;
256+
for (int iy = 0; iy <= norder; ++iy)
257+
{
258+
const int icy = int(rho_basis->ny * 10 - iy + floor(gridy)) % rho_basis->ny;
259+
for (int ix = 0; ix <= norder; ++ix)
255260
{
256-
int icx = int(rho_basis->nx*10-ix+floor(gridx))%rho_basis->nx;
261+
const int icx = int(rho_basis->nx * 10 - ix + floor(gridx)) % rho_basis->nx;
257262
#ifdef _OPENMP
258-
#pragma omp atomic
263+
#pragma omp atomic
259264
#endif
260-
r[icz*rho_basis->ny*rho_basis->nx + icx*rho_basis->ny + icy] += bsz.bezier_ele(iz)
261-
* bsy.bezier_ele(iy)
262-
* bsx.bezier_ele(ix);
265+
tmpr[(icx * rho_basis->ny + icy) * nplane + local_z]
266+
+= bsz.bezier_ele(iz) * bsy.bezier_ele(iy) * bsx.bezier_ele(ix);
263267
}
264268
}
265269
}
266270
}
267-
268-
//distribute data to different processors for UFFT
269-
//---------------------------------------------------
270-
for(int iz = 0; iz < rho_basis->nz; iz++)
271-
{
272-
if(GlobalV::MY_RANK==0)
273-
{
274-
#ifdef _OPENMP
275-
#pragma omp parallel for schedule(static, 512)
276-
#endif
277-
for(int ir = 0; ir < rho_basis->nxy; ir++)
278-
{
279-
zpiece[ir] = r[iz*rho_basis->nxy + ir];
280-
}
281-
}
282-
283-
#ifdef __MPI
284-
pgrid.zpiece_to_all(zpiece, iz, tmpr);
285-
#else
286-
// Serial build: the whole real-space grid is local, so there is no
287-
// pool to scatter to. zpiece_to_all() is MPI-only, which otherwise
288-
// leaves tmpr uninitialized -> garbage structure factor and a wrong
289-
// total energy. Fill tmpr directly, using the SAME real-space layout
290-
// as zpiece_to_all's serial path: rho[ir*nczp + znow], i.e. xy index
291-
// outer and z innermost (nczp == nz, znow == iz when serial).
292-
for(int ir = 0; ir < rho_basis->nxy; ir++)
293-
{
294-
tmpr[ir*rho_basis->nz + iz] = zpiece[ir];
295-
}
296-
#endif
297-
298-
}
299-
//---------------------------------------------------
300271

301272
//It should be optimized with r2c
302-
rho_basis->real2recip(tmpr, &strucFac(it,0));
303-
this->bsplinecoef(b1,b2,b3,rho_basis->nx, rho_basis->ny, rho_basis->nz, norder);
273+
rho_basis->real2recip(tmpr.data(), &strucFac(it, 0));
274+
this->bsplinecoef(b1.data(),
275+
b2.data(),
276+
b3.data(),
277+
rho_basis->nx,
278+
rho_basis->ny,
279+
rho_basis->nz,
280+
norder);
304281
#ifdef _OPENMP
305-
#pragma omp parallel for schedule(static, 128)
282+
#pragma omp parallel for schedule(static, 128)
306283
#endif
307-
for(int ig = 0 ; ig < rho_basis->npw ; ++ig)
284+
for (int ig = 0; ig < rho_basis->npw; ++ig)
308285
{
309-
int idx = int(rho_basis->gdirect[ig].x+0.1+rho_basis->nx)%rho_basis->nx;
310-
int idy = int(rho_basis->gdirect[ig].y+0.1+rho_basis->ny)%rho_basis->ny;
311-
int idz = int(rho_basis->gdirect[ig].z+0.1+rho_basis->nz)%rho_basis->nz;
312-
strucFac(it,ig) *= ( b1[idx] * b2[idy] * b3[idz] * double(rho_basis->nxyz) );
286+
const int idx = int(rho_basis->gdirect[ig].x + 0.1 + rho_basis->nx) % rho_basis->nx;
287+
const int idy = int(rho_basis->gdirect[ig].y + 0.1 + rho_basis->ny) % rho_basis->ny;
288+
const int idz = int(rho_basis->gdirect[ig].z + 0.1 + rho_basis->nz) % rho_basis->nz;
289+
strucFac(it, ig) *= (b1[idx] * b2[idy] * b3[idz] * double(rho_basis->nxyz));
313290
}
314-
}
315-
delete[] r;
316-
delete[] tmpr;
317-
delete[] zpiece;
318-
delete[] b1;
319-
delete[] b2;
320-
delete[] b3;
291+
}
321292

322293
return;
323294
}

0 commit comments

Comments
 (0)