Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
3f261db
Fix(hsolver): reset Davidson restart coefficients to identity
dyzheng Oct 22, 2026
5968bab
Fix(elecstate): include G=0 magnetization in nspin=4 mixing
dyzheng Oct 22, 2026
5ea2c23
Fix(hsolver): honor Hermitian upper triangle in genelpa
dyzheng Oct 22, 2026
359f734
Fix(lcao): correct Pauli-to-spinor conversion for nspin=4
dyzheng Oct 22, 2026
d4d0b79
Fix(pw): correct Pauli-y sign in DeltaSpin onsite force/stress kernels
dyzheng Oct 22, 2026
1bfa4cd
Fix(pw): correct nspin=2 DeltaSpin magnetization output and force
dyzheng Oct 22, 2026
8812439
Fix(xc): retain meta-GGA contributions at zero density gradient
dyzheng Oct 22, 2026
8577fc5
Fix(xc): use precision-matched gcar/kvec_c in grad_wfc
dyzheng Oct 22, 2026
f056f01
Fix(xc): cache LibXC functionals per OpenMP thread in gradcorr
dyzheng Oct 22, 2026
a5bdd49
Fix(pw): accumulate PW stress contributions in double precision
dyzheng Oct 22, 2026
e5d4bf8
Fix(pw): reduce single-precision stress accumulation error
dyzheng Oct 22, 2026
9db3ac4
Fix(elecstate): accumulate GPU k-point densities in double precision
dyzheng Oct 22, 2026
f5f86a5
Fix(cuda): bound long single-precision conjugate reductions
dyzheng Oct 22, 2026
4b584d8
Fix(hsolver): use double precision for GPU-single DAV reduced solves
dyzheng Oct 22, 2026
6d1350d
Fix(pw): add missing single-precision GPU instantiations
dyzheng Oct 22, 2026
c78ba66
Fix(pw): copy gcar device-to-host in FS_Nonlocal_tools
dyzheng Oct 22, 2026
0fc1675
Fix(hsolver): use single-precision MPI datatype in Davidson broadcast
dyzheng Oct 22, 2026
8efdacb
Fix(hsolver): skip near-zero residual directions in single precision
dyzheng Oct 22, 2026
cb4c38e
Fix(psi): avoid Psi offset overflow for large basis sets
dyzheng Oct 22, 2026
14f9cfe
Fix(fft): provide host CPU backends for GPU FFT_Bundle
dyzheng Oct 22, 2026
fdeae13
Fix: backport low-risk general fixes from accel
dyzheng Oct 22, 2026
6333810
Fix(pw): defer float GPU onsite-projector instantiations
dyzheng Oct 22, 2026
e135fb7
Fix(hsolver): make GPU-single DAV reduced solve compile for all T
dyzheng Oct 22, 2026
bb1ef96
Docs(backport): record accel sources and numeric differences
dyzheng Oct 22, 2026
1e746d4
Perf(pw): parallelize count_pw_st with OpenMP
dyzheng Oct 22, 2026
2c509ea
Docs(backport): note applied WP6 count_pw_st backport
dyzheng Oct 22, 2026
57c243d
Test(integrate): refresh LCAO DFT+U nspin=4 SOC reference
dyzheng Oct 22, 2026
7299f54
Fix(pw): make gcar/kvec_c accessors inline
dyzheng Oct 22, 2026
7a1c45e
Revert "Fix(pw): copy gcar device-to-host in FS_Nonlocal_tools"
dyzheng Oct 22, 2026
10c259b
Fix(xc): build precision-matched host gcar/kvec buffers in grad_wfc
dyzheng Oct 22, 2026
90a332f
Docs(backport): record validation results and LTS adaptations
dyzheng Oct 22, 2026
a675e97
Docs(backport): correct measured GPU-single stress errors
dyzheng Oct 22, 2026
6f57fb0
Docs(backport): add validation report
dyzheng Oct 22, 2026
c340094
Docs(backport): clarify non-collinear coverage and limitations
dyzheng Oct 22, 2026
1cb7358
Fix(pw): keep double deeq_nc/qq_so for single-precision force/stress
dyzheng Oct 22, 2026
c4d045b
Docs(backport): record single-precision nspin=4 fix and validation
dyzheng Oct 22, 2026
7cd611c
Docs(backport): add LTS vs accel precision and timing comparison
dyzheng Oct 22, 2026
aba0844
Docs(backport): analyze precision deltas and run performance smaller …
dyzheng Oct 22, 2026
ac3f831
Docs(backport): record performance solvers and gint optimization asse…
dyzheng Oct 22, 2026
ff243eb
Chore: remove unnecessary backport documentation
dyzheng Oct 22, 2026
c6e72bf
Test(integrate): refresh references for mGGA and nupdown=0 fixes
dyzheng Oct 26, 2026
37627ac
Test(integrate): refresh PAW reference for Davidson vcc reset
dyzheng Oct 26, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions source/module_base/parallel_reduce.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@

#include <vector>

#ifdef __MPI
const MPI_Datatype Parallel_Reduce::MPI_Type<int>::value = MPI_INT;
const MPI_Datatype Parallel_Reduce::MPI_Type<double>::value = MPI_DOUBLE;
const MPI_Datatype Parallel_Reduce::MPI_Type<float>::value = MPI_FLOAT;
const MPI_Datatype Parallel_Reduce::MPI_Type<std::complex<double>>::value = MPI_DOUBLE_COMPLEX;
const MPI_Datatype Parallel_Reduce::MPI_Type<std::complex<float>>::value = MPI_C_FLOAT_COMPLEX;
const MPI_Datatype Parallel_Reduce::MPI_Type<long long>::value = MPI_LONG_LONG;
#endif

template <>
void Parallel_Reduce::reduce_all<int>(int& object)
{
Expand Down
41 changes: 41 additions & 0 deletions source/module_base/parallel_reduce.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,47 @@ using std::complex;

namespace Parallel_Reduce
{
#ifdef __MPI
template <typename T>
struct MPI_Type;

template <>
struct MPI_Type<int>
{
static const MPI_Datatype value;
};

template <>
struct MPI_Type<double>
{
static const MPI_Datatype value;
};

template <>
struct MPI_Type<float>
{
static const MPI_Datatype value;
};

template <>
struct MPI_Type<std::complex<double>>
{
static const MPI_Datatype value;
};

template <>
struct MPI_Type<std::complex<float>>
{
static const MPI_Datatype value;
};

template <>
struct MPI_Type<long long>
{
static const MPI_Datatype value;
};
#endif

/// reduce in all process
template <typename T>
void reduce_all(T& object);
Expand Down
54 changes: 36 additions & 18 deletions source/module_basis/module_pw/module_fft/fft_bundle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,18 @@ void FFT_Bundle::initfft(int nx_in,
fft_double = make_unique<FFT_CUDA<double>>();
fft_double->initfft(nx_in,ny_in,nz_in);
#endif
// Host-memory interface: always provide a double CPU backend, and a
// float one when float FFTs are enabled. Single precision still needs
// a double host backend for host-only post-processing.
if (float_flag)
{
host_fft_float = make_unique<FFT_CPU<float>>(this->fft_mode);
host_fft_float->initfft(nx_in, ny_in, nz_in, lixy_in, rixy_in, ns_in,
nplane_in, nproc_in, gamma_only_in, xprime_in);
}
host_fft_double = make_unique<FFT_CPU<double>>(this->fft_mode);
host_fft_double->initfft(nx_in, ny_in, nz_in, lixy_in, rixy_in, ns_in,
nplane_in, nproc_in, gamma_only_in, xprime_in);
}

}
Expand All @@ -108,74 +120,80 @@ void FFT_Bundle::setupFFT()
{
if (double_flag){fft_double->setupFFT();}
if (float_flag) {fft_float->setupFFT();}
if (host_fft_double != nullptr) { host_fft_double->setupFFT(); }
if (host_fft_float != nullptr) { host_fft_float->setupFFT(); }
}

void FFT_Bundle::clearFFT()
{
if (double_flag){fft_double->cleanFFT();}
if (float_flag) {fft_float->cleanFFT();}
if (host_fft_double != nullptr) { host_fft_double->cleanFFT(); }
if (host_fft_float != nullptr) { host_fft_float->cleanFFT(); }
}
void FFT_Bundle::clear()
{
this->clearFFT();
if (double_flag){fft_double->clear();}
if (float_flag) {fft_float->clear();}
if (host_fft_double != nullptr) { host_fft_double->clear(); }
if (host_fft_float != nullptr) { host_fft_float->clear(); }
}

template <> void
FFT_Bundle::fftxyfor(std::complex<float>* in,
std::complex<float>* out)
const {fft_float->fftxyfor(in,out);}
const {get_host_fft_float()->fftxyfor(in,out);}
template <> void
FFT_Bundle::fftxyfor(std::complex<double>* in,
std::complex<double>* out)
const {fft_double->fftxyfor(in,out);}
const {get_host_fft_double()->fftxyfor(in,out);}


template <> void
FFT_Bundle::fftzfor(std::complex<float>* in,
std::complex<float>* out)
const {fft_float->fftzfor(in,out);}
const {get_host_fft_float()->fftzfor(in,out);}
template <> void
FFT_Bundle::fftzfor(std::complex<double>* in,
std::complex<double>* out)
const {fft_double->fftzfor(in,out);}
const {get_host_fft_double()->fftzfor(in,out);}

template <> void
FFT_Bundle::fftxybac(std::complex<float>* in,
std::complex<float>* out)
const {fft_float->fftxybac(in,out);}
const {get_host_fft_float()->fftxybac(in,out);}
template <> void
FFT_Bundle::fftxybac(std::complex<double>* in,
std::complex<double>* out)
const {fft_double->fftxybac(in,out);}
const {get_host_fft_double()->fftxybac(in,out);}

template <> void
FFT_Bundle::fftzbac(std::complex<float>* in,
std::complex<float>* out)
const {fft_float->fftzbac(in,out);}
const {get_host_fft_float()->fftzbac(in,out);}
template <> void
FFT_Bundle::fftzbac(std::complex<double>* in,
std::complex<double>* out)
const {fft_double->fftzbac(in,out);}
const {get_host_fft_double()->fftzbac(in,out);}

template <> void
FFT_Bundle::fftxyr2c(float* in,
std::complex<float>* out)
const {fft_float->fftxyr2c(in,out);}
const {get_host_fft_float()->fftxyr2c(in,out);}
template <> void
FFT_Bundle::fftxyr2c(double* in,
std::complex<double>* out)
const {fft_double->fftxyr2c(in,out);}
const {get_host_fft_double()->fftxyr2c(in,out);}

template <> void
FFT_Bundle::fftxyc2r(std::complex<float>* in,
float* out)
const {fft_float->fftxyc2r(in,out);}
const {get_host_fft_float()->fftxyc2r(in,out);}
template <> void
FFT_Bundle::fftxyc2r(std::complex<double>* in,
double* out)
const {fft_double->fftxyc2r(in,out);}
const {get_host_fft_double()->fftxyc2r(in,out);}

template <> void
FFT_Bundle::fft3D_forward(const base_device::DEVICE_GPU* ctx,
Expand All @@ -201,19 +219,19 @@ const {fft_double->fft3D_backward(in, out);}

// access the real space data
template <> float*
FFT_Bundle::get_rspace_data() const {return fft_float->get_rspace_data();}
FFT_Bundle::get_rspace_data() const {return get_host_fft_float()->get_rspace_data();}
template <> double*
FFT_Bundle::get_rspace_data() const {return fft_double->get_rspace_data();}
FFT_Bundle::get_rspace_data() const {return get_host_fft_double()->get_rspace_data();}

template <> std::complex<float>*
FFT_Bundle::get_auxr_data() const {return fft_float->get_auxr_data();}
FFT_Bundle::get_auxr_data() const {return get_host_fft_float()->get_auxr_data();}
template <> std::complex<double>*
FFT_Bundle::get_auxr_data() const {return fft_double->get_auxr_data();}
FFT_Bundle::get_auxr_data() const {return get_host_fft_double()->get_auxr_data();}

template <> std::complex<float>*
FFT_Bundle::get_auxg_data() const {return fft_float->get_auxg_data();}
FFT_Bundle::get_auxg_data() const {return get_host_fft_float()->get_auxg_data();}
template <> std::complex<double>*
FFT_Bundle::get_auxg_data() const {return fft_double->get_auxg_data();}
FFT_Bundle::get_auxg_data() const {return get_host_fft_double()->get_auxg_data();}

template <> std::complex<float>*
FFT_Bundle::get_auxr_3d_data() const {return fft_float->get_auxr_3d_data();}
Expand Down
16 changes: 15 additions & 1 deletion source/module_basis/module_pw/module_fft/fft_bundle.h
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,21 @@ class FFT_Bundle
bool double_flag=false;
std::shared_ptr<FFT_BASE<float>> fft_float=nullptr;
std::shared_ptr<FFT_BASE<double>> fft_double=nullptr;

// Extra CPU backends serving the host-memory ("cpu-like") interface
// when the primary backend is a device FFT. They keep host
// post-processing (e.g. Wannier90/Berry phase) working on GPU runs.
std::shared_ptr<FFT_BASE<float>> host_fft_float=nullptr;
std::shared_ptr<FFT_BASE<double>> host_fft_double=nullptr;

FFT_BASE<float>* get_host_fft_float() const
{
return (this->device == "cpu") ? this->fft_float.get() : this->host_fft_float.get();
}
FFT_BASE<double>* get_host_fft_double() const
{
return (this->device == "cpu") ? this->fft_double.get() : this->host_fft_double.get();
}

std::string device = "cpu";
std::string precision = "double";
};
Expand Down
18 changes: 0 additions & 18 deletions source/module_basis/module_pw/pw_basis_k.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -412,24 +412,6 @@ std::vector<int> PW_Basis_K::get_ig2iz(const int ik) const
return ig_to_iz;
}

template <>
float * PW_Basis_K::get_kvec_c_data() const {
return this->s_kvec_c;
}
template <>
double * PW_Basis_K::get_kvec_c_data() const {
return this->d_kvec_c;
}

template <>
float * PW_Basis_K::get_gcar_data() const {
return this->s_gcar;
}
template <>
double * PW_Basis_K::get_gcar_data() const {
return this->d_gcar;
}

template <>
float * PW_Basis_K::get_gk2_data() const {
return this->s_gk2;
Expand Down
17 changes: 17 additions & 0 deletions source/module_basis/module_pw/pw_basis_k.h
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,23 @@ class PW_Basis_K : public PW_Basis

};

// Trivial accessors are kept inline so that unit tests and other small
// translation units that call grad_wfc do not need to link pw_basis_k.cpp.
template <>
inline float* PW_Basis_K::get_gcar_data() const { return this->s_gcar; }
template <>
inline double* PW_Basis_K::get_gcar_data() const
{
return this->d_gcar != nullptr ? this->d_gcar : reinterpret_cast<double*>(&this->gcar[0][0]);
}
template <>
inline float* PW_Basis_K::get_kvec_c_data() const { return this->s_kvec_c; }
template <>
inline double* PW_Basis_K::get_kvec_c_data() const
{
return this->d_kvec_c != nullptr ? this->d_kvec_c : reinterpret_cast<double*>(&this->kvec_c[0][0]);
}

}
#endif //PlaneWave_K class

Expand Down
59 changes: 41 additions & 18 deletions source/module_basis/module_pw/pw_distributeg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ void PW_Basis::count_pw_st(
{
ModuleBase::GlobalFunc::ZEROS(st_length2D, this->fftnxy);
ModuleBase::GlobalFunc::ZEROS(st_bottom2D, this->fftnxy);
ModuleBase::Vector3<double> f;

// determine the scaning area along x-direct, if gamma-only && xprime, only positive axis is used.
int ix_end = int(this->nx / 2) + 1;
Expand Down Expand Up @@ -86,10 +85,18 @@ void PW_Basis::count_pw_st(
}
}

this->liy = this->riy = 0;
this->lix = this->rix = 0;
this->npwtot = 0;
this->nstot = 0;
int npwtot_local = 0;
int nstot_local = 0;
int lix_local = 0, rix_local = 0;
int liy_local = 0, riy_local = 0;
Comment on lines +90 to +91

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Non-blocking: please split these into one variable declaration per line, as required by rule 8. The OpenMP reduction logic can stay unchanged.


#ifdef _OPENMP
#pragma omp parallel for collapse(1) \
shared(st_length2D, st_bottom2D) \
reduction(+: npwtot_local, nstot_local) \
reduction(min: rix_local, riy_local) \
reduction(max: lix_local, liy_local)
#endif
for (int ix = ix_start; ix <= ix_end; ++ix)
{
for (int iy = iy_start; iy <= iy_end; ++iy)
Expand All @@ -101,37 +108,53 @@ void PW_Basis::count_pw_st(
// so that its index in st_length and st_bottom is 9 * 10 + 2 = 92.
int x = ix;
int y = iy;
if (x < 0) x += this->nx;
if (y < 0) y += this->ny;
if (x < 0) { x += this->nx; }
if (y < 0) { y += this->ny; }
int index = x * this->fftny + y;

int length = 0; // number of planewave on stick (x, y).

ModuleBase::Vector3<double> f;
f.x = ix;
f.y = iy;

for (int iz = iz_start; iz <= iz_end; ++iz)
{
f.x = ix;
f.y = iy;
f.z = iz;
double modulus = f * (this->GGT * f);
if (modulus <= this->ggecut || this->full_pw)
{
if (length == 0) st_bottom2D[index] = iz; // length == 0 means this point is the bottom of stick (x, y).
++this->npwtot;
if (length == 0)
{
st_bottom2D[index] = iz; // length == 0 means this point is the bottom of stick (x, y).
}
++npwtot_local;
++length;
if(iy < this->riy) this->riy = iy;
if(iy > this->liy) this->liy = iy;
if(ix < this->rix) this->rix = ix;
if(ix > this->lix) this->lix = ix;
if(ix > lix_local) { lix_local = ix; }
if(ix < rix_local) { rix_local = ix; }
if(iy > liy_local) { liy_local = iy; }
if(iy < riy_local) { riy_local = iy; }
}
}
if (length > 0)
{
st_length2D[index] = length;
++this->nstot;
++nstot_local;
}
}
}
riy += this->ny;
rix += this->nx;

if (npwtot_local == 0) // no planewave
{
lix_local = rix_local = liy_local = riy_local = 0;
}

this->npwtot = npwtot_local;
this->nstot = nstot_local;
this->lix = lix_local;
this->rix = rix_local + this->nx;
this->liy = liy_local;
this->riy = riy_local + this->ny;
return;
}

Expand Down
Loading
Loading