From 71518d6dc8ded7a5b9657507bc09eb2f682dca97 Mon Sep 17 00:00:00 2001 From: Hongxu Ren Date: Wed, 30 Sep 2026 22:40:55 +0800 Subject: [PATCH 01/25] refactor(pw): separate exchange source and target bases --- source/source_pw/module_pwdft/op_pw_exx.cpp | 59 +++++++++++++++---- source/source_pw/module_pwdft/op_pw_exx.h | 9 +++ .../source_pw/module_pwdft/op_pw_exx_ace.cpp | 2 +- .../source_pw/module_pwdft/op_pw_exx_pot.cpp | 17 ++++-- source/source_pw/module_pwdft/stress_exx.cpp | 4 +- 5 files changed, 72 insertions(+), 19 deletions(-) diff --git a/source/source_pw/module_pwdft/op_pw_exx.cpp b/source/source_pw/module_pwdft/op_pw_exx.cpp index f40649fde60..4612002facd 100644 --- a/source/source_pw/module_pwdft/op_pw_exx.cpp +++ b/source/source_pw/module_pwdft/op_pw_exx.cpp @@ -53,6 +53,8 @@ OperatorEXXPW::OperatorEXXPW(const int* isk_in, { ModuleBase::WARNING_QUIT("OperatorEXXPW", "EXX Calculation does not support k-point parallelism when exxace is set to false"); } + source_basis_ = wfcpw_in; + source_points_ = kv_in; gamma_extrapolation = exx_info.gamma_extrapolation; bool is_mp = kv_in->get_is_mp(); #ifdef __MPI @@ -225,6 +227,24 @@ void OperatorEXXPW::act(const int nbands, } } +template +void OperatorEXXPW::set_source(const ModulePW::PW_Basis_K& source_basis, + const K_Vectors& source_points, + const psi::Psi& source_psi, + const ModuleBase::matrix& source_weights) +{ + if (exxace_ || gamma_extrapolation || exx_sg_init) + { + ModuleBase::WARNING_QUIT("OperatorEXXPW", "Independent EXX sources require direct exchange without gamma extrapolation, before FFT initialization"); + } + source_basis_ = &source_basis; + source_points_ = &source_points; + psi = source_psi; + wg = &source_weights; + q_points.clear(); + first_iter = false; +} + template void OperatorEXXPW::act_op(const int nbands, const int nbasis, @@ -245,7 +265,7 @@ void OperatorEXXPW::act_op(const int nbands, auto q_points = get_q_points(this->ik); int nk_fac = nspin_ == 2 ? 2 : 1; - int nk = wfcpw->nks / nk_fac; + int nk = source_basis_->nks / nk_fac; const Real nqs = q_points.size(); maybe_setup_exx_grid(); @@ -254,7 +274,7 @@ void OperatorEXXPW::act_op(const int nbands, for (int iq: q_points) { - get_exx_potential(kv, wfcpw, rhopw_dev, pot, tpiba, gamma_extrapolation, ucell->omega, this->ik, iq % nk, false, this->coulomb_param); + get_exx_potential(source_points_, wfcpw, source_basis_, rhopw_dev, pot, tpiba, gamma_extrapolation, ucell->omega, this->ik, iq, false, this->coulomb_param); for (int m_iband = 0; m_iband < psi.get_nbands(); m_iband++) { // occupation of the source state (m, iq), not of the target k-point @@ -264,10 +284,18 @@ void OperatorEXXPW::act_op(const int nbands, continue; } - wfc_to_real_exx(get_pw(m_iband, iq), iq, nbasis); + const T* source_band = get_pw(m_iband, iq); + if (source_basis_ == wfcpw) + { + wfc_to_real_exx(source_band, iq, psi.get_nbasis()); + } + else + { + source_basis_->recip_to_real(ctx, source_band, psi_mq_real, iq); + } // full accumulation weight, hybrid_alpha included - const Real factor = this->hybrid_alpha * wg_mqb_real / kv->wk[iq] / nqs; + const Real factor = this->hybrid_alpha * wg_mqb_real / source_points_->wk[iq] / nqs; apply_fock_all_bands(nbands, nbasis, iq, factor, tmhpsi); } // end of m_iband @@ -310,7 +338,7 @@ void OperatorEXXPW::act_op_kpar(const int nbands, for (int iq = 0; iq < nqs; iq++) { // for \psi_nk, get the pw of iq and band m - get_exx_potential(kv, wfcpw, rhopw_dev, pot, tpiba, gamma_extrapolation, ucell->omega, this->ik, iq, false, this->coulomb_param); + get_exx_potential(kv, wfcpw, wfcpw, rhopw_dev, pot, tpiba, gamma_extrapolation, ucell->omega, this->ik, iq, false, this->coulomb_param); // decide which pool does the iq belong to int iq_pool = kv->para_k.whichpool[iq]; @@ -383,6 +411,11 @@ void OperatorEXXPW::maybe_setup_exx_grid() const return; } #endif + if (source_basis_ != wfcpw) + { + exx_sg_init = true; + return; + } setup_exx_small_grid(); if (std::is_same::value && !exx_sg_ok) { @@ -395,6 +428,10 @@ void OperatorEXXPW::maybe_setup_exx_grid() const template bool OperatorEXXPW::exx_grid_active() const { + if (source_basis_ != wfcpw) + { + return false; + } #if !defined(__CUDA) if (!std::is_same::value) { @@ -865,7 +902,7 @@ std::vector OperatorEXXPW::get_q_points(const int ik) const // if () // downsampling { - for (int iq = 0; iq < wfcpw->nks; iq++) + for (int iq = 0; iq < source_basis_->nks; iq++) { if (nspin_ ==1 ) { @@ -874,8 +911,8 @@ std::vector OperatorEXXPW::get_q_points(const int ik) const else if (nspin_ == 2) { int nk_fac = 2; - int nk = wfcpw->nks / nk_fac; - if (iq / nk == ik / nk) + int nk = source_basis_->nks / nk_fac; + if (source_points_->isk[iq] == isk[ik]) { q_points_ik.push_back(iq); } @@ -888,7 +925,7 @@ std::vector OperatorEXXPW::get_q_points(const int ik) const } // else // { - // for (int iq = 0; iq < wfcpw->nks; iq++) + // for (int iq = 0; iq < source_basis_->nks; iq++) // { // kv-> // } @@ -928,6 +965,8 @@ OperatorEXXPW::OperatorEXXPW(const OperatorEXXPW *op // copy all the datas this->isk = op->isk; this->wfcpw = op->wfcpw; + this->source_basis_ = op->source_basis_; + this->source_points_ = op->source_points_; this->rhopw = op->rhopw; this->rhopw_dev = op->rhopw_dev; this->psi = op->psi; @@ -1023,7 +1062,7 @@ double OperatorEXXPW::cal_exx_energy_op(psi::Psi *ppsi_) c for (int iq: q_points_ik) { - get_exx_potential(kv, wfcpw, rhopw_dev, pot, tpiba, gamma_extrapolation, ucell->omega, ik, iq % nk, false, this->coulomb_param); + get_exx_potential(kv, wfcpw, wfcpw, rhopw_dev, pot, tpiba, gamma_extrapolation, ucell->omega, ik, iq % nk, false, this->coulomb_param); for (int m_iband = 0; m_iband < nb; m_iband++) { const double wg_iqb_real = (*wg)(iq, m_iband); diff --git a/source/source_pw/module_pwdft/op_pw_exx.h b/source/source_pw/module_pwdft/op_pw_exx.h index 3f32fd0d0ff..af922e7a91f 100644 --- a/source/source_pw/module_pwdft/op_pw_exx.h +++ b/source/source_pw/module_pwdft/op_pw_exx.h @@ -59,6 +59,12 @@ class OperatorEXXPW : public OperatorPW void set_wg(const ModuleBase::matrix *wg_in) { wg = wg_in; } + // The source orbitals remain fixed while target states are diagonalized. + void set_source(const ModulePW::PW_Basis_K& source_basis, + const K_Vectors& source_points, + const psi::Psi& source_psi, + const ModuleBase::matrix& source_weights); + void construct_ace() const; bool first_iter = true; @@ -71,6 +77,8 @@ class OperatorEXXPW : public OperatorPW private: const int* isk = nullptr; const ModulePW::PW_Basis_K* wfcpw = nullptr; + const ModulePW::PW_Basis_K* source_basis_ = nullptr; + const K_Vectors* source_points_ = nullptr; const ModulePW::PW_Basis* rhopw = nullptr; ModulePW::PW_Basis* rhopw_dev = nullptr; // for device const UnitCell *ucell = nullptr; @@ -345,6 +353,7 @@ extern template class OperatorEXXPW, base_device::DEVICE_GP template void get_exx_potential(const K_Vectors* kv, const ModulePW::PW_Basis_K* wfcpw, + const ModulePW::PW_Basis_K* source_basis, ModulePW::PW_Basis* rhopw_dev, Real* pot, double tpiba, diff --git a/source/source_pw/module_pwdft/op_pw_exx_ace.cpp b/source/source_pw/module_pwdft/op_pw_exx_ace.cpp index 67322bdc493..3e22bfd6e56 100644 --- a/source/source_pw/module_pwdft/op_pw_exx_ace.cpp +++ b/source/source_pw/module_pwdft/op_pw_exx_ace.cpp @@ -159,7 +159,7 @@ void OperatorEXXPW::construct_ace() const iq = iq0 + ispin * nk; // iq in the same spin channel // for \psi_nk, get the pw of iq and band m - get_exx_potential(kv, wfcpw, rhopw_dev, pot, tpiba, gamma_extrapolation, ucell->omega, ik, iq, false, this->coulomb_param); + get_exx_potential(kv, wfcpw, wfcpw, rhopw_dev, pot, tpiba, gamma_extrapolation, ucell->omega, ik, iq, false, this->coulomb_param); // decide which pool does the iq belong to int iq_pool = kv->para_k.whichpool[iq0]; diff --git a/source/source_pw/module_pwdft/op_pw_exx_pot.cpp b/source/source_pw/module_pwdft/op_pw_exx_pot.cpp index a7ee389c67c..c79d050a616 100644 --- a/source/source_pw/module_pwdft/op_pw_exx_pot.cpp +++ b/source/source_pw/module_pwdft/op_pw_exx_pot.cpp @@ -59,6 +59,7 @@ extern template class OperatorEXXPW, base_device::DEVICE_GP template void get_exx_potential(const K_Vectors* kv, const ModulePW::PW_Basis_K* wfcpw, + const ModulePW::PW_Basis_K* source_basis, ModulePW::PW_Basis* rhopw_dev, Real* pot, double tpiba, @@ -137,7 +138,7 @@ void get_exx_potential(const K_Vectors* kv, } } - const int nk_fac = PARAM.inp.nspin == 2 ? 2 : 1; + const int nk_fac = kv->get_spin_mult(); const int nk = nks / nk_fac; Real gg = (k_c - q_c + rhopw_dev->gcar[ig]).norm2() * tpiba2; @@ -171,7 +172,7 @@ void get_exx_potential(const K_Vectors* kv, double exx_div = exx_divergence(Conv_Coulomb_Pot_K::Coulomb_Type::Erfc, erfc_omega, kv, - wfcpw, + source_basis, rhopw_dev, tpiba, gamma_extrapolation, @@ -210,7 +211,7 @@ void get_exx_potential(const K_Vectors* kv, } } - const int nk_fac = PARAM.inp.nspin == 2 ? 2 : 1; + const int nk_fac = kv->get_spin_mult(); const int nk = nks / nk_fac; // const int ig_kq = ik * nks * npw + iq * npw + ig; @@ -329,7 +330,7 @@ void get_exx_stress_potential(const K_Vectors* kv, } } - const int nk_fac = PARAM.inp.nspin == 2 ? 2 : 1; + const int nk_fac = kv->get_spin_mult(); const int nk = nks / nk_fac; // const int ig_kq = ik * nks * npw + iq * npw + ig; @@ -396,7 +397,7 @@ void get_exx_stress_potential(const K_Vectors* kv, } } - const int nk_fac = PARAM.inp.nspin == 2 ? 2 : 1; + const int nk_fac = kv->get_spin_mult(); const int nk = nks / nk_fac; // const int ig_kq = ik * nks * npw + iq * npw + ig; @@ -447,7 +448,7 @@ double exx_divergence(Conv_Coulomb_Pot_K::Coulomb_Type coulomb_type, double nqs_half2 = 0.5 * kv->nmp[1]; double nqs_half3 = 0.5 * kv->nmp[2]; - int nk_fac = PARAM.inp.nspin == 2 ? 2 : 1; + const int nk_fac = kv->get_spin_mult(); // here we follow the exx_divergence subroutine in q-e (PW/src/exx_base.f90) double alpha = 10.0 / wfcpw->gk_ecut; @@ -556,6 +557,7 @@ double exx_divergence(Conv_Coulomb_Pot_K::Coulomb_Type coulomb_type, return exx_div; } template void get_exx_potential(const K_Vectors*, + const ModulePW::PW_Basis_K*, const ModulePW::PW_Basis_K*, ModulePW::PW_Basis*, float*, @@ -567,6 +569,7 @@ template void get_exx_potential(const K_Vectors* bool, const CoulombParam&); template void get_exx_potential(const K_Vectors*, + const ModulePW::PW_Basis_K*, const ModulePW::PW_Basis_K*, ModulePW::PW_Basis*, double*, @@ -599,6 +602,7 @@ template void get_exx_stress_potential(const K_ const CoulombParam&); #if ((defined __CUDA) || (defined __ROCM)) template void get_exx_potential(const K_Vectors*, + const ModulePW::PW_Basis_K*, const ModulePW::PW_Basis_K*, ModulePW::PW_Basis*, float*, @@ -610,6 +614,7 @@ template void get_exx_potential(const K_Vectors* bool, const CoulombParam&); template void get_exx_potential(const K_Vectors*, + const ModulePW::PW_Basis_K*, const ModulePW::PW_Basis_K*, ModulePW::PW_Basis*, double*, diff --git a/source/source_pw/module_pwdft/stress_exx.cpp b/source/source_pw/module_pwdft/stress_exx.cpp index 2fdda85f062..52f05b672b3 100644 --- a/source/source_pw/module_pwdft/stress_exx.cpp +++ b/source/source_pw/module_pwdft/stress_exx.cpp @@ -63,7 +63,7 @@ void Stress_PW::stress_exx(ModuleBase::matrix& sigma, resmem_real_op()(pot, rhopw->npw); resmem_real_op()(pot_stress, rhopw->npw); - // hamilt::get_exx_potential(p_kv, wfcpw, rhopw, pot, tpiba, gamma_extrapolation, omega); + // hamilt::get_exx_potential(p_kv, wfcpw, wfcpw, rhopw, pot, tpiba, gamma_extrapolation, omega); // hamilt::get_exx_stress_potential(p_kv, wfcpw, rhopw, pot_stress, tpiba, gamma_extrapolation, omega); // calculate the stress @@ -81,7 +81,7 @@ void Stress_PW::stress_exx(ModuleBase::matrix& sigma, for (int iq = 0; iq < nqs; iq++) { - hamilt::get_exx_potential(p_kv, wfcpw, rhopw, pot, tpiba, gamma_extrapolation, omega, ik, iq, true, exx_info.coulomb_param); + hamilt::get_exx_potential(p_kv, wfcpw, wfcpw, rhopw, pot, tpiba, gamma_extrapolation, omega, ik, iq, true, exx_info.coulomb_param); hamilt::get_exx_stress_potential(p_kv, wfcpw, rhopw, pot_stress, tpiba, gamma_extrapolation, omega, ik, iq, exx_info.coulomb_param); for (int mband = 0; mband < d_psi_in->get_nbands(); mband++) { From d70d270791a585e67b0c82bdd07c5c5640e3c4bd Mon Sep 17 00:00:00 2001 From: Hongxu Ren Date: Wed, 30 Sep 2026 22:48:12 +0800 Subject: [PATCH 02/25] feat(pw): load a frozen SCF ensemble for screened hybrid NSCF --- source/source_esolver/esolver_ks_pw.cpp | 124 ++++++++++++++++++- source/source_esolver/esolver_ks_pw.h | 8 ++ source/source_io/CMakeLists.txt | 1 + source/source_io/module_wf/exx_source_io.cpp | 113 +++++++++++++++++ source/source_io/module_wf/exx_source_io.h | 35 ++++++ source/source_pw/module_pwdft/exx_helper.cpp | 11 +- source/source_pw/module_pwdft/op_pw_exx.cpp | 3 +- 7 files changed, 290 insertions(+), 5 deletions(-) create mode 100644 source/source_io/module_wf/exx_source_io.cpp create mode 100644 source/source_io/module_wf/exx_source_io.h diff --git a/source/source_esolver/esolver_ks_pw.cpp b/source/source_esolver/esolver_ks_pw.cpp index 0a49659661a..caced83e640 100644 --- a/source/source_esolver/esolver_ks_pw.cpp +++ b/source/source_esolver/esolver_ks_pw.cpp @@ -1,4 +1,12 @@ #include "esolver_ks_pw.h" +#include "source_io/module_wf/exx_source_io.h" +#include "source_io/module_wf/read_wfc_pw.h" +#include "source_base/module_out/filename.h" + +#include +#include +#include +#include #include "source_estate/elecstate_pw.h" #include "source_estate/module_charge/chg_symm.h" @@ -27,6 +35,28 @@ namespace ModuleESolver { +namespace +{ +std::string exx_restart_configuration(const Input_para& inp, const General_Exx_Info& info) +{ + std::ostringstream out; + out << std::setprecision(17) << inp.dft_functional << ':' << inp.ecutwfc << ':' + << info.ecut_exx << ':' << info.hybrid_alpha << ':' << info.gamma_extrapolation; + for (const auto& kernel : info.coulomb_param) + { + out << ':' << static_cast(kernel.first); + for (const auto& term : kernel.second) + { + for (const auto& parameter : term) + { + out << ':' << parameter.first << '=' << parameter.second; + } + } + } + return out.str(); +} +} + template ESolver_KS_PW::ESolver_KS_PW() @@ -81,6 +111,17 @@ void ESolver_KS_PW::before_all_runners(BaseCell& basecell, const Inpu ESolver_KS::before_all_runners(ucell, inp); + if (inp.calculation == "nscf" && this->general_exx_info_.cal_exx) + { + const auto fock = this->general_exx_info_.coulomb_param.find(Conv_Coulomb_Pot_K::Coulomb_Type::Fock); + const bool has_fock = fock != this->general_exx_info_.coulomb_param.end() && !fock->second.empty(); + if (inp.device != "cpu" || inp.kpar != 1 || inp.bndpar != 1 || inp.nspin == 4 || inp.exxace + || inp.exx_gamma_extrapolation || inp.symmetry == "1" || inp.init_wfc == "file" || has_fock) + { + ModuleBase::WARNING_QUIT("ESolver_KS_PW", "Hybrid NSCF currently requires CPU, kpar=1, nspin=1/2, symmetry=-1/0, exxace=false, exx_gamma_extrapolation=false, screened exchange and fresh target wavefunctions"); + } + } + //! setup and allocation for pelec, potentials, etc. elecstate::setup_estate_pw(ucell, this->kv, @@ -189,9 +230,76 @@ void ESolver_KS_PW::before_scf(UnitCell& ucell, const int istep) //! Setup EXX helper for Hamiltonian and psi exx_helper->before_scf(this->p_hamilt, this->stp.template get_psi_t(), *this->inp_, this->general_exx_info_); + if (this->inp_->calculation == "nscf" && this->general_exx_info_.cal_exx) + { + this->prepare_exx_nscf(ucell, PARAM.globalv.global_readin_dir); + } + ModuleBase::timer::end("ESolver_KS_PW", "before_scf"); } +template +void ESolver_KS_PW::prepare_exx_nscf(const UnitCell& ucell, const std::string& readin_dir) +{ + ModuleBase::timer::start("ESolver_KS_PW", "prepare_exx_nscf"); + const Input_para& inp = *this->inp_; + const std::string configuration = exx_restart_configuration(inp, this->general_exx_info_); + const std::string filename = readin_dir + "EXX_SOURCE"; + std::ifstream in(filename); + try + { + ModuleIO::read_exx_source(in, exx_source_points_, exx_source_weights_, inp.nspin, + this->pw_wfc->nx, this->pw_wfc->ny, this->pw_wfc->nz, configuration); + } + catch (const std::exception& error) + { + ModuleBase::WARNING_QUIT("ESolver_KS_PW", error.what()); + } + const int nqs = exx_source_points_.get_nks(); + int nq = exx_source_points_.get_nkstot_nospin(); + exx_source_points_.para_k.kinfo(nq, 1, 0, this->pw_wfc->poolrank, this->pw_wfc->poolnproc, inp.nspin); + exx_source_basis_.reset(new ModulePW::PW_Basis_K(inp.device, inp.precision)); +#ifdef __MPI + exx_source_basis_->initmpi(this->pw_wfc->poolnproc, this->pw_wfc->poolrank, this->pw_wfc->pool_world); +#endif + exx_source_basis_->initgrids(ucell.lat0, ucell.latvec, + this->pw_wfc->nx, this->pw_wfc->ny, this->pw_wfc->nz); + exx_source_basis_->initparameters(false, inp.ecutwfc, nqs, exx_source_points_.kvec_d.data()); + exx_source_basis_->fft_bundle.initfftmode(inp.fft_mode); + exx_source_basis_->setuptransform(); + exx_source_basis_->collect_local_pw(inp.erf_ecut, inp.erf_height, inp.erf_sigma); + for (int iq = 0; iq < nqs; ++iq) + { + exx_source_points_.ngk[iq] = exx_source_basis_->npwk[iq]; + exx_source_points_.kvec_c[iq] = exx_source_points_.kvec_d[iq] * ucell.G; + } + const int nbands = exx_source_weights_.nc; + const int nbasis = exx_source_basis_->npwk_max; + exx_source_psi_.reset(new psi::Psi(nqs, nbands, nbasis, exx_source_points_.ngk, true)); + for (int iq = 0; iq < nqs; ++iq) + { + const std::string wfc_filename = ModuleIO::filename_output(readin_dir, "wf", "pw", iq, + exx_source_points_.ik2iktot, inp.nspin, nqs, 2, false, false, -1); + ModuleBase::ComplexMatrix wfc(nbands, nbasis); + ModuleIO::read_wfc_pw(wfc_filename, exx_source_basis_.get(), this->pw_wfc->poolrank, + this->pw_wfc->poolnproc, nbands, 1, iq, iq, nqs, wfc); + exx_source_psi_->fix_k(iq); + std::vector coefficients(nbands * nbasis); + for (int ib = 0; ib < nbands; ++ib) + { + for (int ig = 0; ig < nbasis; ++ig) + { + coefficients[ib * nbasis + ig] = static_cast(wfc(ib, ig)); + } + } + base_device::memory::synchronize_memory_op()( + exx_source_psi_->get_pointer(), coefficients.data(), coefficients.size()); + } + auto* helper = static_cast*>(this->exx_helper); + helper->op_exx->set_source(*exx_source_basis_, exx_source_points_, *exx_source_psi_, exx_source_weights_); + ModuleBase::timer::end("ESolver_KS_PW", "prepare_exx_nscf"); +} + template void ESolver_KS_PW::iter_init(UnitCell& ucell, const int istep, const int iter) { @@ -298,7 +406,7 @@ void ESolver_KS_PW::iter_finish(UnitCell& ucell, const int istep, int // Related to EXX bool cal_exx = general_exx_info_.cal_exx; double hybrid_alpha = general_exx_info_.hybrid_alpha; - if (cal_exx && !exx_helper->get_op_first_iter()) + if (cal_exx && this->inp_->calculation != "nscf" && !exx_helper->get_op_first_iter()) { this->pelec->set_exx(exx_helper->cal_exx_energy(this->stp.template get_psi_t()), cal_exx, @@ -367,6 +475,20 @@ void ESolver_KS_PW::after_scf(UnitCell& ucell, const int istep, const this->Pgrid, *this->inp_); + if (conv_esolver && this->inp_->calculation == "scf" && this->general_exx_info_.cal_exx + && this->inp_->out_wfc_pw == 2 && this->inp_->out_freq_ion == 0 && this->inp_->kpar == 1 + && this->inp_->nspin != 4 && this->inp_->symmetry != "1") + { + if (this->pw_wfc->poolrank == 0) + { + const std::string filename = PARAM.globalv.global_out_dir + "EXX_SOURCE"; + const std::string configuration = exx_restart_configuration(*this->inp_, this->general_exx_info_); + std::ofstream out(filename); + ModuleIO::write_exx_source(out, this->kv, this->pelec->wg, this->inp_->nspin, + this->pw_wfc->nx, this->pw_wfc->ny, this->pw_wfc->nz, configuration); + } + } + ModuleBase::timer::end("ESolver_KS_PW", "after_scf"); } diff --git a/source/source_esolver/esolver_ks_pw.h b/source/source_esolver/esolver_ks_pw.h index 34e28bd639e..ec6975da919 100644 --- a/source/source_esolver/esolver_ks_pw.h +++ b/source/source_esolver/esolver_ks_pw.h @@ -49,6 +49,14 @@ class ESolver_KS_PW : public ESolver_KS virtual void allocate_hamilt(const UnitCell& ucell); + void prepare_exx_nscf(const UnitCell& ucell, const std::string& readin_dir); + + // Owned SCF ensemble; its lifetime covers every target diagonalization. + std::unique_ptr exx_source_basis_; + K_Vectors exx_source_points_; + ModuleBase::matrix exx_source_weights_; + std::unique_ptr> exx_source_psi_; + // Electronic wave function psi Setup_Psi_pw stp; diff --git a/source/source_io/CMakeLists.txt b/source/source_io/CMakeLists.txt index ea2588f4b8d..ff46b22a52b 100644 --- a/source/source_io/CMakeLists.txt +++ b/source/source_io/CMakeLists.txt @@ -22,6 +22,7 @@ list(APPEND objects module_bessel/numerical_descriptor.cpp module_output/print_info.cpp module_output/read_cube.cpp + module_wf/exx_source_io.cpp module_wf/read_wfc_pw.cpp module_wf/read_wf2rho_pw.cpp module_restart/restart.cpp diff --git a/source/source_io/module_wf/exx_source_io.cpp b/source/source_io/module_wf/exx_source_io.cpp new file mode 100644 index 00000000000..d652970c289 --- /dev/null +++ b/source/source_io/module_wf/exx_source_io.cpp @@ -0,0 +1,113 @@ +#include "exx_source_io.h" + +#include "source_base/matrix.h" +#include "source_cell/klist.h" + +#include +#include +#include +#include +#include + +void ModuleIO::write_exx_source(std::ostream& out, + const K_Vectors& points, + const ModuleBase::matrix& weights, + int nspin, + int nx, + int ny, + int nz, + const std::string& configuration) +{ + out << "ABACUS_EXX_SOURCE_V1\n" << configuration << '\n'; + out << nspin << ' ' << nx << ' ' << ny << ' ' << nz << ' ' << weights.nr << ' ' << weights.nc << '\n'; + out << points.nmp[0] << ' ' << points.nmp[1] << ' ' << points.nmp[2] << '\n'; + out << std::setprecision(17); + for (int iq = 0; iq < weights.nr; ++iq) + { + const auto& q = points.kvec_d[iq]; + out << q.x << ' ' << q.y << ' ' << q.z << ' ' << points.wk[iq] << ' ' << points.isk[iq]; + for (int ib = 0; ib < weights.nc; ++ib) + { + out << ' ' << weights(iq, ib); + } + out << '\n'; + } + if (!out) + { + throw std::runtime_error("Cannot write EXX source checkpoint"); + } +} + +void ModuleIO::read_exx_source(std::istream& in, + K_Vectors& points, + ModuleBase::matrix& weights, + int nspin, + int nx, + int ny, + int nz, + const std::string& configuration) +{ + std::string magic; + std::string saved_configuration; + std::getline(in, magic); + std::getline(in, saved_configuration); + int saved_spin = 0; + int saved_nx = 0; + int saved_ny = 0; + int saved_nz = 0; + int nks = 0; + int nbands = 0; + in >> saved_spin >> saved_nx >> saved_ny >> saved_nz >> nks >> nbands; + if (!in || magic != "ABACUS_EXX_SOURCE_V1" || saved_configuration != configuration + || saved_spin != nspin || saved_nx != nx || saved_ny != ny || saved_nz != nz + || nks <= 0 || nbands <= 0 || nks > 100000 || nbands > 100000 + || static_cast(nks) * nbands > 100000000) + { + throw std::runtime_error("Missing, incompatible or invalid EXX source checkpoint; regenerate with a converged hybrid SCF"); + } + const int spin_mult = nspin == 2 ? 2 : 1; + if (nks % spin_mult != 0) + { + throw std::runtime_error("Invalid EXX source spin dimensions"); + } + in >> points.nmp[0] >> points.nmp[1] >> points.nmp[2]; + points.set_nks(nks); + points.set_nkstot(nks); + const int nq = nks / spin_mult; + points.set_nkstot_nospin(nq); + points.set_spin_mult(spin_mult); + points.kvec_d.resize(nks); + points.kvec_c.resize(nks); + points.wk.resize(nks); + points.isk.resize(nks); + points.ngk.resize(nks); + points.ik2iktot.resize(nks); + weights.create(nks, nbands); + const double expected_weight = nspin == 1 ? 2.0 / nq : 1.0 / nq; + for (int iq = 0; iq < nks; ++iq) + { + auto& q = points.kvec_d[iq]; + in >> q.x >> q.y >> q.z >> points.wk[iq] >> points.isk[iq]; + if (!in || !std::isfinite(q.x) || !std::isfinite(q.y) || !std::isfinite(q.z) + || !std::isfinite(points.wk[iq]) || std::abs(points.wk[iq] - expected_weight) > 1e-10 + || points.isk[iq] != iq / nq) + { + throw std::runtime_error("EXX source requires a complete uniform q mesh with ordered spin channels"); + } + points.ik2iktot[iq] = iq; + for (int ib = 0; ib < nbands; ++ib) + { + in >> weights(iq, ib); + if (!in || !std::isfinite(weights(iq, ib)) || weights(iq, ib) < 0 + || weights(iq, ib) > expected_weight + 1e-10) + { + throw std::runtime_error("Invalid EXX source occupation"); + } + } + } + in >> std::ws; + if (!in.eof()) + { + throw std::runtime_error("Unexpected trailing EXX source checkpoint data"); + } +} diff --git a/source/source_io/module_wf/exx_source_io.h b/source/source_io/module_wf/exx_source_io.h new file mode 100644 index 00000000000..1e8394a31ff --- /dev/null +++ b/source/source_io/module_wf/exx_source_io.h @@ -0,0 +1,35 @@ +#ifndef EXX_SOURCE_IO_H +#define EXX_SOURCE_IO_H + +#include +#include + +class K_Vectors; +namespace ModuleBase +{ +class matrix; +} + +namespace ModuleIO +{ +// A versioned companion to WAVEFUNC*.dat, containing the frozen SCF ensemble. +// Streams keep serialization independent of process ownership and file paths. +void write_exx_source(std::ostream& out, + const K_Vectors& points, + const ModuleBase::matrix& weights, + int nspin, + int nx, + int ny, + int nz, + const std::string& configuration); + +void read_exx_source(std::istream& in, + K_Vectors& points, + ModuleBase::matrix& weights, + int nspin, + int nx, + int ny, + int nz, + const std::string& configuration); +} +#endif diff --git a/source/source_pw/module_pwdft/exx_helper.cpp b/source/source_pw/module_pwdft/exx_helper.cpp index 3f117482540..caa85ac85b6 100644 --- a/source/source_pw/module_pwdft/exx_helper.cpp +++ b/source/source_pw/module_pwdft/exx_helper.cpp @@ -12,7 +12,7 @@ template void Exx_Helper::init(const UnitCell& ucell, const Input_para& inp, const ModuleBase::matrix& wg, const General_Exx_Info& exx_info) { if (inp.calculation != "scf" && inp.calculation != "relax" - && inp.calculation != "cell-relax" && inp.calculation != "md") + && inp.calculation != "cell-relax" && inp.calculation != "md" && inp.calculation != "nscf") { return; } @@ -22,7 +22,7 @@ void Exx_Helper::init(const UnitCell& ucell, const Input_para& inp, c return; } - if (exx_info.separate_loop) + if (exx_info.separate_loop && inp.calculation != "nscf") { XC_Functional::set_xc_first_loop(ucell); this->set_firstiter(); @@ -36,7 +36,7 @@ void Exx_Helper::before_scf(void* p_hamilt, void* psi, const Input_pa { /// Return if not a valid calculation type if (inp.calculation != "scf" && inp.calculation != "relax" - && inp.calculation != "cell-relax" && inp.calculation != "md") + && inp.calculation != "cell-relax" && inp.calculation != "md" && inp.calculation != "nscf") { return; } @@ -60,6 +60,11 @@ bool Exx_Helper::iter_finish(void* p_elec, Charge* p_charge, void* ps UnitCell& ucell, const Input_para& inp, bool& conv_esolver, int& iter) { + if (inp.calculation == "nscf") + { + return false; + } + /// Return if EXX is not enabled if (op_exx == nullptr) { diff --git a/source/source_pw/module_pwdft/op_pw_exx.cpp b/source/source_pw/module_pwdft/op_pw_exx.cpp index 4612002facd..8d47398f92d 100644 --- a/source/source_pw/module_pwdft/op_pw_exx.cpp +++ b/source/source_pw/module_pwdft/op_pw_exx.cpp @@ -274,7 +274,8 @@ void OperatorEXXPW::act_op(const int nbands, for (int iq: q_points) { - get_exx_potential(source_points_, wfcpw, source_basis_, rhopw_dev, pot, tpiba, gamma_extrapolation, ucell->omega, this->ik, iq, false, this->coulomb_param); + const int iq_nospin = iq % nk; + get_exx_potential(source_points_, wfcpw, source_basis_, rhopw_dev, pot, tpiba, gamma_extrapolation, ucell->omega, this->ik, iq_nospin, false, this->coulomb_param); for (int m_iband = 0; m_iband < psi.get_nbands(); m_iband++) { // occupation of the source state (m, iq), not of the target k-point From f3b8efbb8782f797ac6cb8159329a805530bd019 Mon Sep 17 00:00:00 2001 From: Hongxu Ren Date: Wed, 30 Sep 2026 23:07:17 +0800 Subject: [PATCH 03/25] test(pw): verify and document screened hybrid NSCF restarts --- docs/advanced/elec_properties/band.md | 2 + docs/advanced/elec_properties/hybrid_nscf.md | 129 +++++++++++++++ docs/advanced/elec_properties/index.rst | 1 + docs/advanced/input_files/input-main.md | 2 +- docs/parameters.yaml | 2 +- source/source_esolver/esolver_ks_pw.cpp | 22 ++- .../module_parameter/read_inp_sys.cpp | 2 +- source/source_io/test/CMakeLists.txt | 8 + source/source_io/test/test_exx_source_io.cpp | 92 +++++++++++ source/source_pw/module_pwdft/exx_helper.h | 2 + .../source_pw/module_pwdft/exx_helper_base.h | 2 + source/source_pw/module_pwdft/op_pw_exx.cpp | 8 + tests/integrate/CMakeLists.txt | 12 +- tests/integrate/tools/test_hybrid_nscf.py | 156 ++++++++++++++++++ 14 files changed, 432 insertions(+), 8 deletions(-) create mode 100644 docs/advanced/elec_properties/hybrid_nscf.md create mode 100644 source/source_io/test/test_exx_source_io.cpp create mode 100644 tests/integrate/tools/test_hybrid_nscf.py diff --git a/docs/advanced/elec_properties/band.md b/docs/advanced/elec_properties/band.md index 19bcca6ff11..3a88f94dbb2 100644 --- a/docs/advanced/elec_properties/band.md +++ b/docs/advanced/elec_properties/band.md @@ -1,5 +1,7 @@ # Extracting Band Structure +For plane-wave screened hybrid calculations, follow the [hybrid NSCF workflow](hybrid_nscf.md), which additionally requires the frozen SCF orbitals and source q mesh. + In ABACUS, in order to obtain the eigenvalues of Hamiltonian, or generally called band structure, examples can be found in [examples/band](https://github.com/deepmodeling/abacus-develop/tree/develop/examples/12_band). Similar to the [DOS case](https://abacus-rtd.readthedocs.io/en/latest/advanced/elec_properties/dos.html), one first needs to perform a ground-state energy calculation ***with one additional keyword "[out_chg](https://abacus-rtd.readthedocs.io/en/latest/advanced/input_files/input-main.html#out-chg)" in the INPUT file***: diff --git a/docs/advanced/elec_properties/hybrid_nscf.md b/docs/advanced/elec_properties/hybrid_nscf.md new file mode 100644 index 00000000000..116a0036325 --- /dev/null +++ b/docs/advanced/elec_properties/hybrid_nscf.md @@ -0,0 +1,129 @@ +# Screened hybrid NSCF with plane waves + +A hybrid Hamiltonian needs occupied orbitals as well as the charge density. +PW screened hybrid NSCF now reads a **frozen SCF ensemble** on a source q mesh +and diagonalizes the Hamiltonian on an independent target k list. Increasing +`nbands` in NSCF changes the target states, not the source ensemble. + +This first implementation supports CPU calculations, `kpar 1`, `bndpar 1`, +`nspin 1` or `2`, and a complete, uniformly weighted source mesh without symmetry +reduction. Set `symmetry -1`, `exxace false` and +`exx_gamma_extrapolation false` in both calculations. HSE is supported; +unscreened Fock exchange, including PBE0, is rejected pending validation of the +singularity correction for arbitrary target k points. Forces and stress are +also rejected in hybrid NSCF. The LCAO workflow is unchanged. + +## Prepare the source ensemble + +Run a converged hybrid SCF with the normal source `KPT` and these settings: + +```text +calculation scf +basis_type pw +dft_functional HSE +symmetry -1 +kpar 1 +bndpar 1 +exxace false +exx_gamma_extrapolation false +out_chg 1 +out_wfc_pw 2 +out_freq_ion 0 +cal_force 0 +cal_stress 0 +``` + +The output directory contains the charge density, `wfk*_pw.dat` binary +wavefunctions and `EXX_SOURCE`. The versioned companion file records source +q coordinates, spin labels, k weights, actual weighted occupations, source band +count, FFT dimensions and exchange configuration. Fractional occupations are +preserved. Checkpoints from older runs without `EXX_SOURCE` must be regenerated. +An existing companion is invalidated before SCF wavefunctions are overwritten; +an unconverged calculation does not produce a usable new companion. Reaching +the EXX outer iteration limit is conservatively treated as unconverged here. + +## Solve target states + +Keep the same structure, pseudopotentials, functional, cutoffs and FFT dimensions. +Point `read_file_dir` to the SCF output, replace `KPT` with the target mesh or +band path, and use: + +```text +calculation nscf +read_file_dir ../scf/OUT.hybrid +init_wfc random +nbands 20 +pw_diag_thr 1e-10 +out_band 1 +out_wfc_pw 0 +out_chg 0 +``` + +Retain the source SCF settings listed above, except its output and calculation +settings. Use a separate NSCF output directory to preserve the SCF files. +`init_wfc file` is rejected for this initial implementation: binary source +orbitals are read separately, whereas target orbitals start independently. +`nbands` may exceed the SCF band count. A different number of MPI processes +within the single PW pool is supported; binary coefficients are redistributed +by their Miller indices. Use `OMP_NUM_THREADS=1` for runtime tests. + +Missing, truncated or incompatible companion files and invalid occupations +produce an error. The existing wavefunction reader additionally verifies k +coordinates, cell, source band count and plane-wave count. NSCF does not update +the frozen ensemble or run the EXX SCF outer loop. Its target occupations are +used for ordinary output only, and its printed total energy is not a new +self-consistent hybrid total energy. + +## Algorithm and implementation boundaries + +For each target state, exchange uses + +\[ +V_x\psi_{n\mathbf{k}} = -\alpha\sum_{\mathbf{q},m} + w_{\mathbf{q}} f_{m\mathbf{q}}\, + \psi_{m\mathbf{q}}\, + \mathcal{F}^{-1}\!\left[ + v(\mathbf{k}-\mathbf{q}+\mathbf{G}) + \mathcal{F}[\psi^*_{m\mathbf{q}}\psi_{n\mathbf{k}}] + \right]. +\] + +Here the periodic parts of source and target orbitals have separate PW bases. +The uniform source sum uses the same spin and weighted-occupation convention as +ABACUS SCF. The target `KPT` weights never define the exchange quadrature. +`OperatorEXXPW` accepts explicit source basis, points, orbitals and occupations; +the solver owns their lifetime. Coulomb-kernel construction uses target k +coordinates and source q coordinates, with the screened zero-transfer correction +computed from the source mesh. The two-basis path currently uses the full FFT +grid, including for distributed PW transforms. Small-grid and ACE acceleration +remain separate follow-up work. + +The local `../q-e` implementation was used to analyze periodic pair densities, +`k-q+G` convolution, occupation normalization and the finite screened +zero-transfer term (`PW/src/exx.f90`, `exx_base.f90`). Its Fortran module/global +architecture was not adopted. That checkout explicitly rejects hybrid NSCF in +`PW/src/setup.f90`, so it cannot provide a direct NSCF reference. Also, its +built-in HSE screening default is `0.106 bohr^-1`; use +`screening_parameter=0.11` for comparison with ABACUS HSE06. + +## Reproducible verification + +```bash +cmake --build build --target MODULE_IO_exx_source_io -j 8 +OMP_NUM_THREADS=1 ctest --test-dir build -V -R '^MODULE_IO_exx_source_io$' +python3 tests/integrate/tools/test_hybrid_nscf.py ./build/abacus --mpi-ranks 2 +``` + +Supply the actual configured executable and build directory. The integration +script uses the existing H pseudopotential and structure fixture, performs SCF +and NSCF, and checks extra target bands, a different target k list, a shared +Gamma point, MPI redistribution, both collinear spin channels, immutable source +files, and invalid restart/unsupported-option errors. It needs LibXC and MPI. + +On the initial local two-q-point, 10 Ry test, the same-mesh SCF/NSCF maximum +band difference was `3.7e-5 eV`; the shared Gamma point and serial/two-rank NSCF +results agreed to printed precision. Three checkpoint unit tests passed. +A QE SCF comparison at this low cutoff showed band differences up to about +`0.03 eV`; cross-code agreement has **not** been established. In particular, +this evidence does not validate PBE0, symmetry reconstruction, source q pools, +GPU execution or ACE for independent target k points. diff --git a/docs/advanced/elec_properties/index.rst b/docs/advanced/elec_properties/index.rst index d75e28e28c1..b7efcfe731b 100644 --- a/docs/advanced/elec_properties/index.rst +++ b/docs/advanced/elec_properties/index.rst @@ -4,6 +4,7 @@ Electronic Properties and Outputs .. toctree:: band + hybrid_nscf dos Mulliken potential diff --git a/docs/advanced/input_files/input-main.md b/docs/advanced/input_files/input-main.md index 72916e9187e..e0497cdcac3 100644 --- a/docs/advanced/input_files/input-main.md +++ b/docs/advanced/input_files/input-main.md @@ -633,7 +633,7 @@ - **Description**: Specify the type of calculation. - scf: perform self-consistent electronic structure calculations - - nscf: perform non-self-consistent electronic structure calculations. A charge density file is required + - nscf: perform non-self-consistent electronic structure calculations. A charge density file is required. PW screened hybrid NSCF additionally reads EXX_SOURCE and binary SCF wavefunctions from read_file_dir; see the hybrid NSCF workflow documentation. The initial implementation requires CPU, kpar=bndpar=1, nspin=1/2, symmetry=-1/0, exxace=false, exx_gamma_extrapolation=false and cal_force=cal_stress=false. - relax: perform structure relaxation calculations, the relax_nmax parameter depicts the maximal number of ionic iterations - cell-relax: perform cell relaxation calculations - md: perform molecular dynamics simulations diff --git a/docs/parameters.yaml b/docs/parameters.yaml index 8a05075af6a..71e75f9ed9e 100644 --- a/docs/parameters.yaml +++ b/docs/parameters.yaml @@ -32,7 +32,7 @@ parameters: Specify the type of calculation. * scf: perform self-consistent electronic structure calculations - * nscf: perform non-self-consistent electronic structure calculations. A charge density file is required + * nscf: perform non-self-consistent electronic structure calculations. A charge density file is required. PW screened hybrid NSCF additionally reads EXX_SOURCE and binary SCF wavefunctions from read_file_dir; see the hybrid NSCF workflow documentation. The initial implementation requires CPU, kpar=bndpar=1, nspin=1/2, symmetry=-1/0, exxace=false, exx_gamma_extrapolation=false and cal_force=cal_stress=false. * relax: perform structure relaxation calculations, the relax_nmax parameter depicts the maximal number of ionic iterations * cell-relax: perform cell relaxation calculations * md: perform molecular dynamics simulations diff --git a/source/source_esolver/esolver_ks_pw.cpp b/source/source_esolver/esolver_ks_pw.cpp index caced83e640..4af7d6add4b 100644 --- a/source/source_esolver/esolver_ks_pw.cpp +++ b/source/source_esolver/esolver_ks_pw.cpp @@ -3,6 +3,8 @@ #include "source_io/module_wf/read_wfc_pw.h" #include "source_base/module_out/filename.h" +#include +#include #include #include #include @@ -116,9 +118,9 @@ void ESolver_KS_PW::before_all_runners(BaseCell& basecell, const Inpu const auto fock = this->general_exx_info_.coulomb_param.find(Conv_Coulomb_Pot_K::Coulomb_Type::Fock); const bool has_fock = fock != this->general_exx_info_.coulomb_param.end() && !fock->second.empty(); if (inp.device != "cpu" || inp.kpar != 1 || inp.bndpar != 1 || inp.nspin == 4 || inp.exxace - || inp.exx_gamma_extrapolation || inp.symmetry == "1" || inp.init_wfc == "file" || has_fock) + || inp.cal_force || inp.cal_stress || inp.exx_gamma_extrapolation || inp.symmetry == "1" || inp.init_wfc == "file" || has_fock) { - ModuleBase::WARNING_QUIT("ESolver_KS_PW", "Hybrid NSCF currently requires CPU, kpar=1, nspin=1/2, symmetry=-1/0, exxace=false, exx_gamma_extrapolation=false, screened exchange and fresh target wavefunctions"); + ModuleBase::WARNING_QUIT("ESolver_KS_PW", "Hybrid NSCF currently requires CPU, kpar=bndpar=1, nspin=1/2, symmetry=-1/0, exxace=false, exx_gamma_extrapolation=false, screened exchange, cal_force=cal_stress=false and fresh target wavefunctions"); } } @@ -138,6 +140,16 @@ void ESolver_KS_PW::before_all_runners(BaseCell& basecell, const Inpu this->solvent, inp); + if (inp.calculation == "scf" && this->general_exx_info_.cal_exx && inp.out_wfc_pw == 2 + && inp.kpar == 1 && inp.bndpar == 1 && this->pw_wfc->poolrank == 0) + { + const std::string checkpoint = PARAM.globalv.global_out_dir + "EXX_SOURCE"; + if (std::remove(checkpoint.c_str()) != 0 && errno != ENOENT) + { + ModuleBase::WARNING_QUIT("ESolver_KS_PW", "Cannot invalidate the previous EXX source checkpoint"); + } + } + this->stp.before_runner(ucell, this->kv, this->sf, *this->pw_wfc, this->ppcell.lmaxkb, *this->inp_); ModuleBase::GlobalFunc::DONE(GlobalV::ofs_running, "INIT BASIS"); @@ -475,8 +487,10 @@ void ESolver_KS_PW::after_scf(UnitCell& ucell, const int istep, const this->Pgrid, *this->inp_); - if (conv_esolver && this->inp_->calculation == "scf" && this->general_exx_info_.cal_exx - && this->inp_->out_wfc_pw == 2 && this->inp_->out_freq_ion == 0 && this->inp_->kpar == 1 + const bool exchange_converged = !this->exx_helper->get_op_first_iter() + && this->exx_helper->iteration_count() < this->inp_->exx_hybrid_step; + if (conv_esolver && exchange_converged && this->inp_->calculation == "scf" && this->general_exx_info_.cal_exx + && this->inp_->out_wfc_pw == 2 && this->inp_->out_freq_ion == 0 && this->inp_->kpar == 1 && this->inp_->bndpar == 1 && this->inp_->nspin != 4 && this->inp_->symmetry != "1") { if (this->pw_wfc->poolrank == 0) diff --git a/source/source_io/module_parameter/read_inp_sys.cpp b/source/source_io/module_parameter/read_inp_sys.cpp index 97a40123eb8..a6fe0fd5c68 100644 --- a/source/source_io/module_parameter/read_inp_sys.cpp +++ b/source/source_io/module_parameter/read_inp_sys.cpp @@ -151,7 +151,7 @@ void ReadInput::item_system() item.description = R"(Specify the type of calculation. * scf: perform self-consistent electronic structure calculations -* nscf: perform non-self-consistent electronic structure calculations. A charge density file is required +* nscf: perform non-self-consistent electronic structure calculations. A charge density file is required. PW screened hybrid NSCF additionally reads EXX_SOURCE and binary SCF wavefunctions from read_file_dir; see the hybrid NSCF workflow documentation. The initial implementation requires CPU, kpar=bndpar=1, nspin=1/2, symmetry=-1/0, exxace=false, exx_gamma_extrapolation=false and cal_force=cal_stress=false. * relax: perform structure relaxation calculations, the relax_nmax parameter depicts the maximal number of ionic iterations * cell-relax: perform cell relaxation calculations * md: perform molecular dynamics simulations diff --git a/source/source_io/test/CMakeLists.txt b/source/source_io/test/CMakeLists.txt index baa3fd76c12..f0ac19a5e25 100644 --- a/source/source_io/test/CMakeLists.txt +++ b/source/source_io/test/CMakeLists.txt @@ -11,6 +11,14 @@ AddTest( ../../source_cell/parallel_kpoints.cpp ../../source_cell/reciprocal_grid.cpp ) +AddTest( + TARGET MODULE_IO_exx_source_io + LIBS parameter base device symmetry + SOURCES test_exx_source_io.cpp ../module_wf/exx_source_io.cpp + ../../source_cell/klist.cpp ../../source_cell/klist_io.cpp + ../../source_cell/parallel_kpoints.cpp ../../source_cell/reciprocal_grid.cpp +) + if(NOT ENABLE_MPI) return() endif() diff --git a/source/source_io/test/test_exx_source_io.cpp b/source/source_io/test/test_exx_source_io.cpp new file mode 100644 index 00000000000..ffd05a5fccb --- /dev/null +++ b/source/source_io/test/test_exx_source_io.cpp @@ -0,0 +1,92 @@ +#include "source_io/module_wf/exx_source_io.h" +#include "source_base/matrix.h" +#include "source_cell/klist.h" + +#include "gtest/gtest.h" + +#include +#include +#include + +namespace +{ +std::string checkpoint(int nspin) +{ + const int nks = nspin == 2 ? 4 : 2; + K_Vectors points; + points.kvec_d.resize(nks); + points.wk.resize(nks); + points.isk.resize(nks); + points.nmp[0] = 2; + points.nmp[1] = 1; + points.nmp[2] = 1; + ModuleBase::matrix weights(nks, 3); + for (int iq = 0; iq < nks; ++iq) + { + points.kvec_d[iq].x = 0.5 * (iq % 2); + points.wk[iq] = nspin == 1 ? 1.0 : 0.5; + points.isk[iq] = iq / 2; + if (nspin == 1) + { + points.isk[iq] = 0; + } + weights(iq, 0) = points.wk[iq]; + weights(iq, 1) = points.wk[iq] * 0.125; + } + std::ostringstream out; + ModuleIO::write_exx_source(out, points, weights, nspin, 15, 15, 15, "HSE:10:40"); + return out.str(); +} +} + +TEST(ExxSourceIO, PreservesFractionalOccupationsAndSpinOrder) +{ + for (int nspin = 1; nspin <= 2; ++nspin) + { + const std::string saved = checkpoint(nspin); + std::istringstream in(saved); + K_Vectors points; + ModuleBase::matrix weights; + ModuleIO::read_exx_source(in, points, weights, nspin, 15, 15, 15, "HSE:10:40"); + const int nks = nspin == 1 ? 2 : 4; + EXPECT_EQ(points.get_nks(), nks); + EXPECT_EQ(points.get_nkstot_nospin(), 2); + EXPECT_EQ(points.get_spin_mult(), nspin); + EXPECT_EQ(weights.nc, 3); + EXPECT_DOUBLE_EQ(weights(1, 1), points.wk[1] * 0.125); + EXPECT_DOUBLE_EQ(weights(1, 2), 0.0); + EXPECT_DOUBLE_EQ(points.kvec_d[1].x, 0.5); + EXPECT_EQ(points.isk.back(), nspin - 1); + } +} + +TEST(ExxSourceIO, RejectsIncompatibleConfigurationAndGrid) +{ + const std::string saved = checkpoint(1); + K_Vectors points; + ModuleBase::matrix weights; + std::istringstream changed_functional(saved); + EXPECT_THROW(ModuleIO::read_exx_source(changed_functional, points, weights, 1, 15, 15, 15, "PBE0:10:40"), std::runtime_error); + std::istringstream changed_grid(saved); + EXPECT_THROW(ModuleIO::read_exx_source(changed_grid, points, weights, 1, 16, 15, 15, "HSE:10:40"), std::runtime_error); + std::istringstream changed_spin(saved); + EXPECT_THROW(ModuleIO::read_exx_source(changed_spin, points, weights, 2, 15, 15, 15, "HSE:10:40"), std::runtime_error); +} + +TEST(ExxSourceIO, RejectsTruncationInvalidOccupationsAndTrailingData) +{ + const std::string saved = checkpoint(1); + K_Vectors points; + ModuleBase::matrix weights; + const std::string truncated_text = saved.substr(0, saved.size() - 6); + std::istringstream truncated(truncated_text); + EXPECT_THROW(ModuleIO::read_exx_source(truncated, points, weights, 1, 15, 15, 15, "HSE:10:40"), std::runtime_error); + std::istringstream trailing(saved + "unexpected"); + EXPECT_THROW(ModuleIO::read_exx_source(trailing, points, weights, 1, 15, 15, 15, "HSE:10:40"), std::runtime_error); + std::string invalid = saved; + const auto occupation = invalid.find("0.125"); + ASSERT_NE(occupation, std::string::npos); + invalid.replace(occupation, 5, "-0.25"); + std::istringstream negative(invalid); + EXPECT_THROW(ModuleIO::read_exx_source(negative, points, weights, 1, 15, 15, 15, "HSE:10:40"), std::runtime_error); +} diff --git a/source/source_pw/module_pwdft/exx_helper.h b/source/source_pw/module_pwdft/exx_helper.h index 2adb945b8b6..fbb24c47963 100644 --- a/source/source_pw/module_pwdft/exx_helper.h +++ b/source/source_pw/module_pwdft/exx_helper.h @@ -44,6 +44,8 @@ struct Exx_Helper : public Exx_HelperBase double cal_exx_energy(void* psi_) override; + int iteration_count() const override { return exx_iter; } + bool get_op_first_iter() const override { return op_exx ? op_exx->first_iter : false; } void set_op_first_iter(bool flag) override { if (op_exx) op_exx->first_iter = flag; } void set_op_exx(void* op) override { op_exx = reinterpret_cast(op); } diff --git a/source/source_pw/module_pwdft/exx_helper_base.h b/source/source_pw/module_pwdft/exx_helper_base.h index 7ebab443948..8699395ffb3 100644 --- a/source/source_pw/module_pwdft/exx_helper_base.h +++ b/source/source_pw/module_pwdft/exx_helper_base.h @@ -33,6 +33,8 @@ class Exx_HelperBase virtual double cal_exx_energy(void* psi) = 0; + virtual int iteration_count() const = 0; + virtual bool get_op_first_iter() const = 0; virtual void set_op_first_iter(bool flag) = 0; diff --git a/source/source_pw/module_pwdft/op_pw_exx.cpp b/source/source_pw/module_pwdft/op_pw_exx.cpp index 8d47398f92d..222536928b9 100644 --- a/source/source_pw/module_pwdft/op_pw_exx.cpp +++ b/source/source_pw/module_pwdft/op_pw_exx.cpp @@ -237,6 +237,14 @@ void OperatorEXXPW::set_source(const ModulePW::PW_Basis_K& source_bas { ModuleBase::WARNING_QUIT("OperatorEXXPW", "Independent EXX sources require direct exchange without gamma extrapolation, before FFT initialization"); } + if (source_basis.nks != source_points.get_nks() || source_psi.get_nk() != source_basis.nks + || source_weights.nr != source_basis.nks || source_weights.nc != source_psi.get_nbands() + || source_psi.get_nbasis() != source_basis.npwk_max + || source_basis.nx != wfcpw->nx || source_basis.ny != wfcpw->ny || source_basis.nz != wfcpw->nz + || source_basis.nrxx != wfcpw->nrxx || source_basis.poolnproc != wfcpw->poolnproc) + { + ModuleBase::WARNING_QUIT("OperatorEXXPW", "Incompatible EXX source dimensions or FFT distribution"); + } source_basis_ = &source_basis; source_points_ = &source_points; psi = source_psi; diff --git a/tests/integrate/CMakeLists.txt b/tests/integrate/CMakeLists.txt index 9f737798889..d143c3a0e7e 100644 --- a/tests/integrate/CMakeLists.txt +++ b/tests/integrate/CMakeLists.txt @@ -14,4 +14,14 @@ else() COMMAND ${BASH} Autotest.sh -a ${ABACUS_BIN_PATH} -n 4 -j auto WORKING_DIRECTORY ${ABACUS_TEST_DIR}/integrate ) -endif() \ No newline at end of file +endif() +if(ENABLE_LIBXC AND ENABLE_MPI) + add_test( + NAME PW_HYBRID_NSCF + COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/tools/test_hybrid_nscf.py + ${ABACUS_BIN_PATH} --mpi-ranks 2 + ) + set_tests_properties(PW_HYBRID_NSCF PROPERTIES + LABELS "PW;EXX;NSCF" PROCESSORS 2 TIMEOUT 300 + ) +endif() diff --git a/tests/integrate/tools/test_hybrid_nscf.py b/tests/integrate/tools/test_hybrid_nscf.py new file mode 100644 index 00000000000..b35f86535f8 --- /dev/null +++ b/tests/integrate/tools/test_hybrid_nscf.py @@ -0,0 +1,156 @@ +#!/usr/bin/env python3 +"""Exercise a frozen HSE ensemble on independent PW target k points.""" +import argparse +import hashlib +import math +import os +from pathlib import Path +import shutil +import subprocess +import tempfile + +REPO = Path(__file__).resolve().parents[3] +COMMON = """INPUT_PARAMETERS +suffix hybrid +basis_type pw +nbands 3 +ecutwfc 10 +scf_thr 1e-9 +scf_nmax 100 +pw_diag_thr 1e-10 +pw_seed 1 +smearing_method fixed +dft_functional HSE +symmetry -1 +exxace false +exx_gamma_extrapolation false +out_band 1 +cal_force 0 +cal_stress 0 +""" +MESH = "K_POINTS\n0\nGamma\n2 1 1 0 0 0\n" +PATH = "K_POINTS\n3\nDirect\n0 0 0 1\n0.125 0 0 1\n0.25 0 0 1\n" + + +def create_case(root, name, extra, points=MESH): + case = root / name + case.mkdir() + shutil.copy(REPO / "tests/01_PW/097_PW_PBE0/STRU", case / "STRU") + text = COMMON + f"pseudo_dir {REPO / 'tests/PP_ORB'}\n" + extra + (case / "INPUT").write_text(text) + (case / "KPT").write_text(points) + return case + + +def run(executable, case, launcher, expected_error=None): + env = dict(os.environ, OMP_NUM_THREADS="1") + with (case / "run.log").open("w") as log: + result = subprocess.run(launcher + [str(executable)], cwd=case, env=env, + stdout=log, stderr=subprocess.STDOUT, timeout=180) + text = (case / "run.log").read_text() + if expected_error: + assert expected_error in text, text[-4000:] + else: + assert result.returncode == 0 and "TOTAL Time" in text, text[-4000:] + + +def bands(case, spin=0): + filename = "band.txt" if spin == 0 else f"bands{spin}.txt" + lines = (case / "OUT.hybrid" / filename).read_text().splitlines() + return [[float(value) for value in line.split()[2:]] for line in lines if line.strip()] + + +def max_difference(reference, target): + assert len(reference) == len(target) + return max(abs(a - b) for row, other in zip(reference, target) for a, b in zip(row, other)) + + +def digest(directory): + return {p.name: hashlib.sha256(p.read_bytes()).hexdigest() + for p in directory.iterdir() if p.is_file()} + + +def verify(executable, root, mpi_ranks): + scf = create_case(root, "scf", "calculation scf\nout_chg 1\nout_wfc_pw 2\n") + run(executable, scf, []) + source = scf / "OUT.hybrid" + assert (source / "EXX_SOURCE").exists() + original = digest(source) + extra = f"calculation nscf\nread_file_dir {source}\nout_chg 0\nout_wfc_pw 0\n" + # More target bands than source bands, initialized independently. + same = create_case(root, "same", extra) + (same / "INPUT").write_text((same / "INPUT").read_text().replace("nbands 3", "nbands 5")) + run(executable, same, []) + delta = max_difference(bands(scf), bands(same)) + assert delta < 2e-4, f"SCF/NSCF eigenvalue mismatch: {delta} eV" + print(f"same mesh, source 3 bands / target 5 bands: max difference {delta:.3g} eV") + + path = create_case(root, "path", extra, PATH) + run(executable, path, []) + values = bands(path) + assert len(values) == 3 and all(math.isfinite(x) for row in values for x in row) + gamma_delta = max_difference([bands(same)[0]], [values[0]]) + assert gamma_delta < 2e-4 + assert abs(values[1][0] - values[0][0]) > 0.1 + print(f"independent 3-point target / 2-point source: shared Gamma difference {gamma_delta:.3g} eV") + + if mpi_ranks > 1: + parallel = create_case(root, "parallel", extra) + (parallel / "INPUT").write_text((parallel / "INPUT").read_text().replace("nbands 3", "nbands 5")) + run(executable, parallel, ["mpirun", "-np", str(mpi_ranks)]) + delta = max_difference(bands(same), bands(parallel)) + assert delta < 2e-6, delta + print(f"serial SCF restart into {mpi_ranks} MPI ranks: max difference {delta:.3g} eV") + + spin_scf = create_case(root, "spin_scf", "calculation scf\nout_chg 1\nout_wfc_pw 2\nnspin 2\n") + run(executable, spin_scf, []) + spin_source = spin_scf / "OUT.hybrid" + spin = create_case(root, "spin_nscf", f"calculation nscf\nread_file_dir {spin_source}\nnspin 2\n") + run(executable, spin, []) + for channel in (1, 2): + delta = max_difference(bands(spin_scf, channel), bands(spin, channel)) + assert delta < 2e-4, delta + print(f"spin channel {channel}: max difference {delta:.3g} eV") + assert digest(source) == original, "NSCF modified the SCF restart ensemble" + + broken_source = root / "broken_source" + shutil.copytree(source, broken_source) + (broken_source / "EXX_SOURCE").unlink() + broken = create_case(root, "missing", extra.replace(str(source), str(broken_source))) + run(executable, broken, [], "EXX source checkpoint") + (broken_source / "EXX_SOURCE").write_text((source / "EXX_SOURCE").read_text()[:-6]) + truncated = create_case(root, "truncated", extra.replace(str(source), str(broken_source))) + run(executable, truncated, [], "Invalid EXX source occupation") + unsupported = create_case(root, "unsupported_ace", extra) + (unsupported / "INPUT").write_text((unsupported / "INPUT").read_text().replace("exxace false", "exxace true")) + run(executable, unsupported, [], "Hybrid NSCF currently requires") + print("missing/truncated checkpoint and unsupported ACE rejected") + + # A failed SCF must invalidate an older companion before replacing orbitals. + failed = create_case(root, "failed_scf", "calculation scf\nout_chg 1\nout_wfc_pw 2\nexx_hybrid_step 1\n") + shutil.copytree(source, failed / "OUT.hybrid") + text = (failed / "INPUT").read_text().replace("scf_nmax 100", "scf_nmax 1") + (failed / "INPUT").write_text(text) + run(executable, failed, []) + assert not (failed / "OUT.hybrid/EXX_SOURCE").exists(), "Failed SCF left a stale checkpoint" + print("failed SCF invalidates the previous source checkpoint") + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("executable", type=Path) + parser.add_argument("--workdir", type=Path) + parser.add_argument("--mpi-ranks", type=int, default=2) + args = parser.parse_args() + executable = args.executable.resolve() + if args.workdir: + args.workdir.mkdir(parents=True, exist_ok=True) + verify(executable, args.workdir.resolve(), args.mpi_ranks) + else: + with tempfile.TemporaryDirectory(prefix="abacus-hybrid-nscf-") as directory: + verify(executable, Path(directory), args.mpi_ranks) + print("PASS: screened hybrid NSCF regression") + + +if __name__ == "__main__": + main() From cf1aaedf1e91ed8df56762c3809647aac6928fbb Mon Sep 17 00:00:00 2001 From: Hongxu Ren Date: Wed, 30 Sep 2026 23:12:26 +0800 Subject: [PATCH 04/25] refactor(esolver): isolate hybrid NSCF restart orchestration --- source/source_esolver/CMakeLists.txt | 1 + source/source_esolver/esolver_ks_pw.cpp | 129 +--------------- source/source_esolver/pw_hybrid_nscf.cpp | 184 +++++++++++++++++++++++ source/source_esolver/pw_hybrid_nscf.h | 32 ++++ 4 files changed, 223 insertions(+), 123 deletions(-) create mode 100644 source/source_esolver/pw_hybrid_nscf.cpp create mode 100644 source/source_esolver/pw_hybrid_nscf.h diff --git a/source/source_esolver/CMakeLists.txt b/source/source_esolver/CMakeLists.txt index 95488f4be33..32872777e18 100644 --- a/source/source_esolver/CMakeLists.txt +++ b/source/source_esolver/CMakeLists.txt @@ -3,6 +3,7 @@ list(APPEND objects esolver_ks.cpp esolver_fp.cpp esolver_ks_pw.cpp + pw_hybrid_nscf.cpp esolver_ks_pw_tddft.cpp esolver_ks_lcaopw.cpp esolver_sdft_pw.cpp diff --git a/source/source_esolver/esolver_ks_pw.cpp b/source/source_esolver/esolver_ks_pw.cpp index 4af7d6add4b..a994d4139e2 100644 --- a/source/source_esolver/esolver_ks_pw.cpp +++ b/source/source_esolver/esolver_ks_pw.cpp @@ -1,14 +1,5 @@ #include "esolver_ks_pw.h" -#include "source_io/module_wf/exx_source_io.h" -#include "source_io/module_wf/read_wfc_pw.h" -#include "source_base/module_out/filename.h" - -#include -#include -#include -#include -#include -#include +#include "pw_hybrid_nscf.h" #include "source_estate/elecstate_pw.h" #include "source_estate/module_charge/chg_symm.h" @@ -37,27 +28,6 @@ namespace ModuleESolver { -namespace -{ -std::string exx_restart_configuration(const Input_para& inp, const General_Exx_Info& info) -{ - std::ostringstream out; - out << std::setprecision(17) << inp.dft_functional << ':' << inp.ecutwfc << ':' - << info.ecut_exx << ':' << info.hybrid_alpha << ':' << info.gamma_extrapolation; - for (const auto& kernel : info.coulomb_param) - { - out << ':' << static_cast(kernel.first); - for (const auto& term : kernel.second) - { - for (const auto& parameter : term) - { - out << ':' << parameter.first << '=' << parameter.second; - } - } - } - return out.str(); -} -} template @@ -113,16 +83,7 @@ void ESolver_KS_PW::before_all_runners(BaseCell& basecell, const Inpu ESolver_KS::before_all_runners(ucell, inp); - if (inp.calculation == "nscf" && this->general_exx_info_.cal_exx) - { - const auto fock = this->general_exx_info_.coulomb_param.find(Conv_Coulomb_Pot_K::Coulomb_Type::Fock); - const bool has_fock = fock != this->general_exx_info_.coulomb_param.end() && !fock->second.empty(); - if (inp.device != "cpu" || inp.kpar != 1 || inp.bndpar != 1 || inp.nspin == 4 || inp.exxace - || inp.cal_force || inp.cal_stress || inp.exx_gamma_extrapolation || inp.symmetry == "1" || inp.init_wfc == "file" || has_fock) - { - ModuleBase::WARNING_QUIT("ESolver_KS_PW", "Hybrid NSCF currently requires CPU, kpar=bndpar=1, nspin=1/2, symmetry=-1/0, exxace=false, exx_gamma_extrapolation=false, screened exchange, cal_force=cal_stress=false and fresh target wavefunctions"); - } - } + validate_hybrid_nscf(inp, this->general_exx_info_); //! setup and allocation for pelec, potentials, etc. elecstate::setup_estate_pw(ucell, @@ -140,15 +101,7 @@ void ESolver_KS_PW::before_all_runners(BaseCell& basecell, const Inpu this->solvent, inp); - if (inp.calculation == "scf" && this->general_exx_info_.cal_exx && inp.out_wfc_pw == 2 - && inp.kpar == 1 && inp.bndpar == 1 && this->pw_wfc->poolrank == 0) - { - const std::string checkpoint = PARAM.globalv.global_out_dir + "EXX_SOURCE"; - if (std::remove(checkpoint.c_str()) != 0 && errno != ENOENT) - { - ModuleBase::WARNING_QUIT("ESolver_KS_PW", "Cannot invalidate the previous EXX source checkpoint"); - } - } + invalidate_exx_source(inp, this->general_exx_info_, *this->pw_wfc, PARAM.globalv.global_out_dir); this->stp.before_runner(ucell, this->kv, this->sf, *this->pw_wfc, this->ppcell.lmaxkb, *this->inp_); @@ -250,68 +203,6 @@ void ESolver_KS_PW::before_scf(UnitCell& ucell, const int istep) ModuleBase::timer::end("ESolver_KS_PW", "before_scf"); } -template -void ESolver_KS_PW::prepare_exx_nscf(const UnitCell& ucell, const std::string& readin_dir) -{ - ModuleBase::timer::start("ESolver_KS_PW", "prepare_exx_nscf"); - const Input_para& inp = *this->inp_; - const std::string configuration = exx_restart_configuration(inp, this->general_exx_info_); - const std::string filename = readin_dir + "EXX_SOURCE"; - std::ifstream in(filename); - try - { - ModuleIO::read_exx_source(in, exx_source_points_, exx_source_weights_, inp.nspin, - this->pw_wfc->nx, this->pw_wfc->ny, this->pw_wfc->nz, configuration); - } - catch (const std::exception& error) - { - ModuleBase::WARNING_QUIT("ESolver_KS_PW", error.what()); - } - const int nqs = exx_source_points_.get_nks(); - int nq = exx_source_points_.get_nkstot_nospin(); - exx_source_points_.para_k.kinfo(nq, 1, 0, this->pw_wfc->poolrank, this->pw_wfc->poolnproc, inp.nspin); - exx_source_basis_.reset(new ModulePW::PW_Basis_K(inp.device, inp.precision)); -#ifdef __MPI - exx_source_basis_->initmpi(this->pw_wfc->poolnproc, this->pw_wfc->poolrank, this->pw_wfc->pool_world); -#endif - exx_source_basis_->initgrids(ucell.lat0, ucell.latvec, - this->pw_wfc->nx, this->pw_wfc->ny, this->pw_wfc->nz); - exx_source_basis_->initparameters(false, inp.ecutwfc, nqs, exx_source_points_.kvec_d.data()); - exx_source_basis_->fft_bundle.initfftmode(inp.fft_mode); - exx_source_basis_->setuptransform(); - exx_source_basis_->collect_local_pw(inp.erf_ecut, inp.erf_height, inp.erf_sigma); - for (int iq = 0; iq < nqs; ++iq) - { - exx_source_points_.ngk[iq] = exx_source_basis_->npwk[iq]; - exx_source_points_.kvec_c[iq] = exx_source_points_.kvec_d[iq] * ucell.G; - } - const int nbands = exx_source_weights_.nc; - const int nbasis = exx_source_basis_->npwk_max; - exx_source_psi_.reset(new psi::Psi(nqs, nbands, nbasis, exx_source_points_.ngk, true)); - for (int iq = 0; iq < nqs; ++iq) - { - const std::string wfc_filename = ModuleIO::filename_output(readin_dir, "wf", "pw", iq, - exx_source_points_.ik2iktot, inp.nspin, nqs, 2, false, false, -1); - ModuleBase::ComplexMatrix wfc(nbands, nbasis); - ModuleIO::read_wfc_pw(wfc_filename, exx_source_basis_.get(), this->pw_wfc->poolrank, - this->pw_wfc->poolnproc, nbands, 1, iq, iq, nqs, wfc); - exx_source_psi_->fix_k(iq); - std::vector coefficients(nbands * nbasis); - for (int ib = 0; ib < nbands; ++ib) - { - for (int ig = 0; ig < nbasis; ++ig) - { - coefficients[ib * nbasis + ig] = static_cast(wfc(ib, ig)); - } - } - base_device::memory::synchronize_memory_op()( - exx_source_psi_->get_pointer(), coefficients.data(), coefficients.size()); - } - auto* helper = static_cast*>(this->exx_helper); - helper->op_exx->set_source(*exx_source_basis_, exx_source_points_, *exx_source_psi_, exx_source_weights_); - ModuleBase::timer::end("ESolver_KS_PW", "prepare_exx_nscf"); -} - template void ESolver_KS_PW::iter_init(UnitCell& ucell, const int istep, const int iter) { @@ -489,18 +380,10 @@ void ESolver_KS_PW::after_scf(UnitCell& ucell, const int istep, const const bool exchange_converged = !this->exx_helper->get_op_first_iter() && this->exx_helper->iteration_count() < this->inp_->exx_hybrid_step; - if (conv_esolver && exchange_converged && this->inp_->calculation == "scf" && this->general_exx_info_.cal_exx - && this->inp_->out_wfc_pw == 2 && this->inp_->out_freq_ion == 0 && this->inp_->kpar == 1 && this->inp_->bndpar == 1 - && this->inp_->nspin != 4 && this->inp_->symmetry != "1") + if (conv_esolver && exchange_converged) { - if (this->pw_wfc->poolrank == 0) - { - const std::string filename = PARAM.globalv.global_out_dir + "EXX_SOURCE"; - const std::string configuration = exx_restart_configuration(*this->inp_, this->general_exx_info_); - std::ofstream out(filename); - ModuleIO::write_exx_source(out, this->kv, this->pelec->wg, this->inp_->nspin, - this->pw_wfc->nx, this->pw_wfc->ny, this->pw_wfc->nz, configuration); - } + save_exx_source(*this->inp_, this->general_exx_info_, this->kv, this->pelec->wg, + *this->pw_wfc, PARAM.globalv.global_out_dir); } ModuleBase::timer::end("ESolver_KS_PW", "after_scf"); diff --git a/source/source_esolver/pw_hybrid_nscf.cpp b/source/source_esolver/pw_hybrid_nscf.cpp new file mode 100644 index 00000000000..00030d8ff48 --- /dev/null +++ b/source/source_esolver/pw_hybrid_nscf.cpp @@ -0,0 +1,184 @@ +#include "pw_hybrid_nscf.h" +#include "esolver_ks_pw.h" +#include "source_io/module_wf/exx_source_io.h" +#include "source_io/module_wf/read_wfc_pw.h" +#include "source_base/module_out/filename.h" +#include "source_hamilt/module_xc/general_exx_info.h" +#include "source_pw/module_pwdft/exx_helper.h" + +#include +#include +#include +#include +#include +#include + +namespace ModuleESolver +{ +namespace +{ +std::string exx_restart_configuration(const Input_para& inp, const General_Exx_Info& info) +{ + std::ostringstream out; + out << std::setprecision(17) << inp.dft_functional << ':' << inp.ecutwfc << ':' + << info.ecut_exx << ':' << info.hybrid_alpha << ':' << info.gamma_extrapolation; + for (const auto& kernel : info.coulomb_param) + { + out << ':' << static_cast(kernel.first); + for (const auto& term : kernel.second) + { + for (const auto& parameter : term) + { + out << ':' << parameter.first << '=' << parameter.second; + } + } + } + return out.str(); +} +} + +namespace +{ +bool checkpoint_output_enabled(const Input_para& inp) +{ + return inp.out_wfc_pw == 2 && inp.out_freq_ion == 0 && inp.kpar == 1 + && inp.bndpar == 1 && inp.nspin != 4 && inp.symmetry != "1"; +} +} + +void validate_hybrid_nscf(const Input_para& inp, const General_Exx_Info& info) +{ + if (inp.calculation != "nscf" || !info.cal_exx) + { + return; + } + const auto fock = info.coulomb_param.find(Conv_Coulomb_Pot_K::Coulomb_Type::Fock); + const bool has_fock = fock != info.coulomb_param.end() && !fock->second.empty(); + const bool compatible_execution = inp.device == "cpu" && inp.kpar == 1 && inp.bndpar == 1 && inp.nspin != 4; + const bool compatible_exchange = !inp.exxace && !inp.exx_gamma_extrapolation && !has_fock; + const bool compatible_targets = inp.symmetry != "1" && inp.init_wfc != "file" && !inp.cal_force && !inp.cal_stress; + if (!compatible_execution || !compatible_exchange || !compatible_targets) + { + ModuleBase::WARNING_QUIT("ESolver_KS_PW", + "Hybrid NSCF currently requires CPU, kpar=bndpar=1, nspin=1/2, symmetry=-1/0, " + "exxace=false, exx_gamma_extrapolation=false, screened exchange, " + "cal_force=cal_stress=false and fresh target wavefunctions"); + } +} + +void invalidate_exx_source(const Input_para& inp, + const General_Exx_Info& info, + const ModulePW::PW_Basis_K& basis, + const std::string& out_dir) +{ + if (inp.calculation != "scf" || !info.cal_exx || inp.out_wfc_pw != 2 + || inp.kpar != 1 || inp.bndpar != 1 || basis.poolrank != 0) + { + return; + } + const std::string checkpoint = out_dir + "EXX_SOURCE"; + if (std::remove(checkpoint.c_str()) != 0 && errno != ENOENT) + { + ModuleBase::WARNING_QUIT("ESolver_KS_PW", "Cannot invalidate the previous EXX source checkpoint"); + } +} + +void save_exx_source(const Input_para& inp, + const General_Exx_Info& info, + const K_Vectors& points, + const ModuleBase::matrix& weights, + const ModulePW::PW_Basis_K& basis, + const std::string& out_dir) +{ + const bool output_enabled = checkpoint_output_enabled(inp); + if (inp.calculation != "scf" || !info.cal_exx || !output_enabled || basis.poolrank != 0) + { + return; + } + const std::string filename = out_dir + "EXX_SOURCE"; + const std::string configuration = exx_restart_configuration(inp, info); + std::ofstream out(filename); + try + { + ModuleIO::write_exx_source(out, points, weights, inp.nspin, basis.nx, basis.ny, basis.nz, configuration); + } + catch (const std::exception& error) + { + ModuleBase::WARNING_QUIT("ESolver_KS_PW", error.what()); + } +} + +template +void ESolver_KS_PW::prepare_exx_nscf(const UnitCell& ucell, const std::string& readin_dir) +{ + ModuleBase::timer::start("ESolver_KS_PW", "prepare_exx_nscf"); + const Input_para& inp = *this->inp_; + const std::string configuration = exx_restart_configuration(inp, this->general_exx_info_); + const std::string filename = readin_dir + "EXX_SOURCE"; + std::ifstream in(filename); + try + { + ModuleIO::read_exx_source(in, exx_source_points_, exx_source_weights_, inp.nspin, + this->pw_wfc->nx, this->pw_wfc->ny, this->pw_wfc->nz, configuration); + } + catch (const std::exception& error) + { + ModuleBase::WARNING_QUIT("ESolver_KS_PW", error.what()); + } + const int nqs = exx_source_points_.get_nks(); + int nq = exx_source_points_.get_nkstot_nospin(); + exx_source_points_.para_k.kinfo(nq, 1, 0, this->pw_wfc->poolrank, this->pw_wfc->poolnproc, inp.nspin); + exx_source_basis_.reset(new ModulePW::PW_Basis_K(inp.device, inp.precision)); +#ifdef __MPI + exx_source_basis_->initmpi(this->pw_wfc->poolnproc, this->pw_wfc->poolrank, this->pw_wfc->pool_world); +#endif + exx_source_basis_->initgrids(ucell.lat0, ucell.latvec, + this->pw_wfc->nx, this->pw_wfc->ny, this->pw_wfc->nz); + exx_source_basis_->initparameters(false, inp.ecutwfc, nqs, exx_source_points_.kvec_d.data()); + exx_source_basis_->fft_bundle.initfftmode(inp.fft_mode); + exx_source_basis_->setuptransform(); + exx_source_basis_->collect_local_pw(inp.erf_ecut, inp.erf_height, inp.erf_sigma); + for (int iq = 0; iq < nqs; ++iq) + { + exx_source_points_.ngk[iq] = exx_source_basis_->npwk[iq]; + exx_source_points_.kvec_c[iq] = exx_source_points_.kvec_d[iq] * ucell.G; + } + const int nbands = exx_source_weights_.nc; + const int nbasis = exx_source_basis_->npwk_max; + exx_source_psi_.reset(new psi::Psi(nqs, nbands, nbasis, exx_source_points_.ngk, true)); + for (int iq = 0; iq < nqs; ++iq) + { + const std::string wfc_filename = ModuleIO::filename_output(readin_dir, "wf", "pw", iq, + exx_source_points_.ik2iktot, inp.nspin, nqs, 2, false, false, -1); + ModuleBase::ComplexMatrix wfc(nbands, nbasis); + ModuleIO::read_wfc_pw(wfc_filename, exx_source_basis_.get(), this->pw_wfc->poolrank, + this->pw_wfc->poolnproc, nbands, 1, iq, iq, nqs, wfc); + exx_source_psi_->fix_k(iq); + std::vector coefficients(nbands * nbasis); + for (int ib = 0; ib < nbands; ++ib) + { + for (int ig = 0; ig < nbasis; ++ig) + { + coefficients[ib * nbasis + ig] = static_cast(wfc(ib, ig)); + } + } + base_device::memory::synchronize_memory_op()( + exx_source_psi_->get_pointer(), coefficients.data(), coefficients.size()); + } + auto* helper = static_cast*>(this->exx_helper); + helper->op_exx->set_source(*exx_source_basis_, exx_source_points_, *exx_source_psi_, exx_source_weights_); + ModuleBase::timer::end("ESolver_KS_PW", "prepare_exx_nscf"); +} + + +template void ESolver_KS_PW, base_device::DEVICE_CPU>::prepare_exx_nscf( + const UnitCell&, const std::string&); +template void ESolver_KS_PW, base_device::DEVICE_CPU>::prepare_exx_nscf( + const UnitCell&, const std::string&); +#if defined(__CUDA) || defined(__ROCM) +template void ESolver_KS_PW, base_device::DEVICE_GPU>::prepare_exx_nscf( + const UnitCell&, const std::string&); +template void ESolver_KS_PW, base_device::DEVICE_GPU>::prepare_exx_nscf( + const UnitCell&, const std::string&); +#endif +} // namespace ModuleESolver diff --git a/source/source_esolver/pw_hybrid_nscf.h b/source/source_esolver/pw_hybrid_nscf.h new file mode 100644 index 00000000000..db23e72d7e4 --- /dev/null +++ b/source/source_esolver/pw_hybrid_nscf.h @@ -0,0 +1,32 @@ +#ifndef PW_HYBRID_NSCF_H +#define PW_HYBRID_NSCF_H + +#include + +struct Input_para; +struct General_Exx_Info; +class K_Vectors; +namespace ModuleBase +{ +class matrix; +} +namespace ModulePW +{ +class PW_Basis_K; +} + +namespace ModuleESolver +{ +void validate_hybrid_nscf(const Input_para& inp, const General_Exx_Info& info); +void invalidate_exx_source(const Input_para& inp, + const General_Exx_Info& info, + const ModulePW::PW_Basis_K& basis, + const std::string& out_dir); +void save_exx_source(const Input_para& inp, + const General_Exx_Info& info, + const K_Vectors& points, + const ModuleBase::matrix& weights, + const ModulePW::PW_Basis_K& basis, + const std::string& out_dir); +} +#endif From 381ac423d8da15ca65850a3dfc1564168f27dc0c Mon Sep 17 00:00:00 2001 From: Hongxu Ren Date: Wed, 30 Sep 2026 23:29:48 +0800 Subject: [PATCH 05/25] docs(pw): compare hybrid NSCF bands with VASP and retain direct exchange --- docs/advanced/elec_properties/hybrid_nscf.md | 47 +++++++++++++++++--- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/docs/advanced/elec_properties/hybrid_nscf.md b/docs/advanced/elec_properties/hybrid_nscf.md index 116a0036325..c2cdcc43ff3 100644 --- a/docs/advanced/elec_properties/hybrid_nscf.md +++ b/docs/advanced/elec_properties/hybrid_nscf.md @@ -95,8 +95,11 @@ ABACUS SCF. The target `KPT` weights never define the exchange quadrature. the solver owns their lifetime. Coulomb-kernel construction uses target k coordinates and source q coordinates, with the screened zero-transfer correction computed from the source mesh. The two-basis path currently uses the full FFT -grid, including for distributed PW transforms. Small-grid and ACE acceleration -remain separate follow-up work. +grid, including for distributed PW transforms. Small-grid acceleration remains +separate follow-up work. This frozen-source NSCF workflow deliberately uses +direct exchange; ACE is not part of its implementation roadmap. The SCF ACE +projectors are tied to their original target subspace and cannot be reused as a +validated exchange operator on an independent band path. The local `../q-e` implementation was used to analyze periodic pair densities, `k-q+G` convolution, occupation normalization and the finite screened @@ -124,6 +127,40 @@ On the initial local two-q-point, 10 Ry test, the same-mesh SCF/NSCF maximum band difference was `3.7e-5 eV`; the shared Gamma point and serial/two-rank NSCF results agreed to printed precision. Three checkpoint unit tests passed. A QE SCF comparison at this low cutoff showed band differences up to about -`0.03 eV`; cross-code agreement has **not** been established. In particular, -this evidence does not validate PBE0, symmetry reconstruction, source q pools, -GPU execution or ACE for independent target k points. +`0.03 eV`; that H test alone does not establish cross-code agreement. + +A separate Si comparison used the same two-atom primitive cell (`a=10.2 bohr`), +HSE exchange fraction `0.25`, screening `0.11 bohr^-1`, `20 Ry` cutoff, +`2x2x2` source mesh, eight bands and nine L-Gamma-X target points. VASP 6.2.1 +used `HFSCREEN=0.207869873 Angstrom^-1`, `PRECFOCK=Accurate`, `ISYM=-1`, +`ALGO=Damped`, `EDIFF=1e-9` and `NELMIN=40`. Its explicit k list contained the +eight source points and six additional zero-weight points. Target points +already present in the source mesh were included only once. This follows the +[VASP hybrid band workflow](https://vasp.at/wiki/Band-structure_calculation_using_hybrid_functionals). + +After aligning each code's Gamma valence-band top, the comparison gave: + +| Quantity (eV) | ABACUS NSCF | VASP | +| --- | ---: | ---: | +| Gamma direct gap | 3.604645 | 3.619060 | +| Gap on the sampled path | 1.449187 | 1.486063 | +| L direct gap | 3.967258 | 4.005180 | +| X direct gap | 4.655743 | 4.681974 | + +For bands 2-6 across all nine points, the RMS difference was `0.042351 eV` +and the maximum difference was `0.086995 eV`. Both codes placed the lowest +sampled conduction state at fractional `(0.375, 0, 0.375)`. +ABACUS used `Si_ONCV_PBE-1.0.upf`; VASP used `PAW_PBE Si 05Jan2001`. +The coarse mesh, sparse path and different pseudopotentials make this a +qualitative cross-check, not a cutoff or k-grid convergence study. + +An initial VASP reference with duplicate zero-weight Gamma points gave an +inconsistent band-4 eigenvalue: it differed from the weighted source Gamma +by `0.686083 eV`. Raising `NELMIN` to 60 did not remove that discrepancy. +The comparison above is from a fresh calculation with unique k coordinates, +using the weighted mesh result at coincident path points. No eigenvalues were +edited to align the spectra. + +These checks do not validate PBE0, symmetry reconstruction, source q pools +or GPU execution. Direct exchange remains the NSCF method; ACE is not a +planned extension of this workflow. From d7939c5671c6d58b7abfa782c8889bcb27575a09 Mon Sep 17 00:00:00 2001 From: Hongxu Ren Date: Wed, 30 Sep 2026 23:55:24 +0800 Subject: [PATCH 06/25] feat(pw): enable and verify CUDA screened hybrid NSCF --- docs/advanced/elec_properties/hybrid_nscf.md | 31 ++++++++-- docs/advanced/input_files/input-main.md | 2 +- docs/parameters.yaml | 2 +- source/source_esolver/pw_hybrid_nscf.cpp | 8 ++- .../module_parameter/read_inp_sys.cpp | 2 +- tests/integrate/CMakeLists.txt | 11 ++++ tests/integrate/tools/test_hybrid_nscf.py | 58 ++++++++++++++++++- 7 files changed, 103 insertions(+), 11 deletions(-) diff --git a/docs/advanced/elec_properties/hybrid_nscf.md b/docs/advanced/elec_properties/hybrid_nscf.md index c2cdcc43ff3..b49f54ea92c 100644 --- a/docs/advanced/elec_properties/hybrid_nscf.md +++ b/docs/advanced/elec_properties/hybrid_nscf.md @@ -5,7 +5,7 @@ PW screened hybrid NSCF now reads a **frozen SCF ensemble** on a source q mesh and diagonalizes the Hamiltonian on an independent target k list. Increasing `nbands` in NSCF changes the target states, not the source ensemble. -This first implementation supports CPU calculations, `kpar 1`, `bndpar 1`, +This first implementation supports CPU and CUDA GPU calculations, `kpar 1`, `bndpar 1`, `nspin 1` or `2`, and a complete, uniformly weighted source mesh without symmetry reduction. Set `symmetry -1`, `exxace false` and `exx_gamma_extrapolation false` in both calculations. HSE is supported; @@ -64,8 +64,12 @@ settings. Use a separate NSCF output directory to preserve the SCF files. `init_wfc file` is rejected for this initial implementation: binary source orbitals are read separately, whereas target orbitals start independently. `nbands` may exceed the SCF band count. A different number of MPI processes -within the single PW pool is supported; binary coefficients are redistributed -by their Miller indices. Use `OMP_NUM_THREADS=1` for runtime tests. +within the single PW pool is supported on CPU; binary coefficients are redistributed +by their Miller indices. CUDA NSCF currently uses one MPI rank. Select +`device gpu` and `precision double` for the validated CUDA workflow; the source +SCF may run on CPU or GPU. The binary checkpoint format is shared between +these devices. ROCm NSCF remains disabled pending backend verification. +Use `OMP_NUM_THREADS=1` for runtime tests. Missing, truncated or incompatible companion files and invalid occupations produce an error. The existing wavefunction reader additionally verifies k @@ -96,7 +100,8 @@ the solver owns their lifetime. Coulomb-kernel construction uses target k coordinates and source q coordinates, with the screened zero-transfer correction computed from the source mesh. The two-basis path currently uses the full FFT grid, including for distributed PW transforms. Small-grid acceleration remains -separate follow-up work. This frozen-source NSCF workflow deliberately uses +separate follow-up work. CUDA executes the pair-density FFTs and exchange +application on the GPU with separate source and target PW maps. This frozen-source NSCF workflow deliberately uses direct exchange; ACE is not part of its implementation roadmap. The SCF ACE projectors are tied to their original target subspace and cannot be reused as a validated exchange operator on an independent band path. @@ -123,6 +128,24 @@ and NSCF, and checks extra target bands, a different target k list, a shared Gamma point, MPI redistribution, both collinear spin channels, immutable source files, and invalid restart/unsupported-option errors. It needs LibXC and MPI. +For a CUDA build and an available GPU, also run: + +```bash +python3 tests/integrate/tools/test_hybrid_nscf.py ./build/abacus --gpu +``` + +This compares CPU and GPU targets using one frozen CPU source on both a mesh +and an independent path with extra target bands, then checks a GPU-generated +spin-polarized source with CPU and GPU targets. Source files must remain +unchanged. The corresponding CTest is `PW_HYBRID_NSCF_GPU`. + +On a local RTX 3090 with CUDA 13.1, both CTests passed in a CUDA build. +The H CPU/GPU mesh, independent path and both spin-channel eigenvalues agreed +at the printed precision, as did all eight bands at nine Si L-Gamma-X points +using the same frozen CPU source (`20 Ry`, `2x2x2` source mesh). The Si check +compared raw eigenvalues without an energy shift. This validates device +consistency; it does not change the cross-code convergence limits below. + On the initial local two-q-point, 10 Ry test, the same-mesh SCF/NSCF maximum band difference was `3.7e-5 eV`; the shared Gamma point and serial/two-rank NSCF results agreed to printed precision. Three checkpoint unit tests passed. diff --git a/docs/advanced/input_files/input-main.md b/docs/advanced/input_files/input-main.md index e0497cdcac3..ea3f35f1990 100644 --- a/docs/advanced/input_files/input-main.md +++ b/docs/advanced/input_files/input-main.md @@ -633,7 +633,7 @@ - **Description**: Specify the type of calculation. - scf: perform self-consistent electronic structure calculations - - nscf: perform non-self-consistent electronic structure calculations. A charge density file is required. PW screened hybrid NSCF additionally reads EXX_SOURCE and binary SCF wavefunctions from read_file_dir; see the hybrid NSCF workflow documentation. The initial implementation requires CPU, kpar=bndpar=1, nspin=1/2, symmetry=-1/0, exxace=false, exx_gamma_extrapolation=false and cal_force=cal_stress=false. + - nscf: perform non-self-consistent electronic structure calculations. A charge density file is required. PW screened hybrid NSCF additionally reads EXX_SOURCE and binary SCF wavefunctions from read_file_dir; see the hybrid NSCF workflow documentation. The initial implementation supports CPU or CUDA GPU and requires kpar=bndpar=1, nspin=1/2, symmetry=-1/0, exxace=false, exx_gamma_extrapolation=false and cal_force=cal_stress=false. - relax: perform structure relaxation calculations, the relax_nmax parameter depicts the maximal number of ionic iterations - cell-relax: perform cell relaxation calculations - md: perform molecular dynamics simulations diff --git a/docs/parameters.yaml b/docs/parameters.yaml index 71e75f9ed9e..89a2d975d76 100644 --- a/docs/parameters.yaml +++ b/docs/parameters.yaml @@ -32,7 +32,7 @@ parameters: Specify the type of calculation. * scf: perform self-consistent electronic structure calculations - * nscf: perform non-self-consistent electronic structure calculations. A charge density file is required. PW screened hybrid NSCF additionally reads EXX_SOURCE and binary SCF wavefunctions from read_file_dir; see the hybrid NSCF workflow documentation. The initial implementation requires CPU, kpar=bndpar=1, nspin=1/2, symmetry=-1/0, exxace=false, exx_gamma_extrapolation=false and cal_force=cal_stress=false. + * nscf: perform non-self-consistent electronic structure calculations. A charge density file is required. PW screened hybrid NSCF additionally reads EXX_SOURCE and binary SCF wavefunctions from read_file_dir; see the hybrid NSCF workflow documentation. The initial implementation supports CPU or CUDA GPU and requires kpar=bndpar=1, nspin=1/2, symmetry=-1/0, exxace=false, exx_gamma_extrapolation=false and cal_force=cal_stress=false. * relax: perform structure relaxation calculations, the relax_nmax parameter depicts the maximal number of ionic iterations * cell-relax: perform cell relaxation calculations * md: perform molecular dynamics simulations diff --git a/source/source_esolver/pw_hybrid_nscf.cpp b/source/source_esolver/pw_hybrid_nscf.cpp index 00030d8ff48..63271d6a59c 100644 --- a/source/source_esolver/pw_hybrid_nscf.cpp +++ b/source/source_esolver/pw_hybrid_nscf.cpp @@ -54,13 +54,17 @@ void validate_hybrid_nscf(const Input_para& inp, const General_Exx_Info& info) } const auto fock = info.coulomb_param.find(Conv_Coulomb_Pot_K::Coulomb_Type::Fock); const bool has_fock = fock != info.coulomb_param.end() && !fock->second.empty(); - const bool compatible_execution = inp.device == "cpu" && inp.kpar == 1 && inp.bndpar == 1 && inp.nspin != 4; + bool compatible_device = inp.device == "cpu"; +#ifdef __CUDA + compatible_device = compatible_device || inp.device == "gpu"; +#endif + const bool compatible_execution = compatible_device && inp.kpar == 1 && inp.bndpar == 1 && inp.nspin != 4; const bool compatible_exchange = !inp.exxace && !inp.exx_gamma_extrapolation && !has_fock; const bool compatible_targets = inp.symmetry != "1" && inp.init_wfc != "file" && !inp.cal_force && !inp.cal_stress; if (!compatible_execution || !compatible_exchange || !compatible_targets) { ModuleBase::WARNING_QUIT("ESolver_KS_PW", - "Hybrid NSCF currently requires CPU, kpar=bndpar=1, nspin=1/2, symmetry=-1/0, " + "Hybrid NSCF currently requires CPU or CUDA GPU, kpar=bndpar=1, nspin=1/2, symmetry=-1/0, " "exxace=false, exx_gamma_extrapolation=false, screened exchange, " "cal_force=cal_stress=false and fresh target wavefunctions"); } diff --git a/source/source_io/module_parameter/read_inp_sys.cpp b/source/source_io/module_parameter/read_inp_sys.cpp index a6fe0fd5c68..c1d9f51f4dd 100644 --- a/source/source_io/module_parameter/read_inp_sys.cpp +++ b/source/source_io/module_parameter/read_inp_sys.cpp @@ -151,7 +151,7 @@ void ReadInput::item_system() item.description = R"(Specify the type of calculation. * scf: perform self-consistent electronic structure calculations -* nscf: perform non-self-consistent electronic structure calculations. A charge density file is required. PW screened hybrid NSCF additionally reads EXX_SOURCE and binary SCF wavefunctions from read_file_dir; see the hybrid NSCF workflow documentation. The initial implementation requires CPU, kpar=bndpar=1, nspin=1/2, symmetry=-1/0, exxace=false, exx_gamma_extrapolation=false and cal_force=cal_stress=false. +* nscf: perform non-self-consistent electronic structure calculations. A charge density file is required. PW screened hybrid NSCF additionally reads EXX_SOURCE and binary SCF wavefunctions from read_file_dir; see the hybrid NSCF workflow documentation. The initial implementation supports CPU or CUDA GPU and requires kpar=bndpar=1, nspin=1/2, symmetry=-1/0, exxace=false, exx_gamma_extrapolation=false and cal_force=cal_stress=false. * relax: perform structure relaxation calculations, the relax_nmax parameter depicts the maximal number of ionic iterations * cell-relax: perform cell relaxation calculations * md: perform molecular dynamics simulations diff --git a/tests/integrate/CMakeLists.txt b/tests/integrate/CMakeLists.txt index d143c3a0e7e..a75ca159264 100644 --- a/tests/integrate/CMakeLists.txt +++ b/tests/integrate/CMakeLists.txt @@ -25,3 +25,14 @@ if(ENABLE_LIBXC AND ENABLE_MPI) LABELS "PW;EXX;NSCF" PROCESSORS 2 TIMEOUT 300 ) endif() + +if(ENABLE_LIBXC AND ENABLE_MPI AND USE_CUDA) + add_test( + NAME PW_HYBRID_NSCF_GPU + COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/tools/test_hybrid_nscf.py + ${ABACUS_BIN_PATH} --gpu + ) + set_tests_properties(PW_HYBRID_NSCF_GPU PROPERTIES + LABELS "PW;EXX;NSCF;GPU" PROCESSORS 1 TIMEOUT 300 RUN_SERIAL TRUE + ) +endif() diff --git a/tests/integrate/tools/test_hybrid_nscf.py b/tests/integrate/tools/test_hybrid_nscf.py index b35f86535f8..65a8eb24c01 100644 --- a/tests/integrate/tools/test_hybrid_nscf.py +++ b/tests/integrate/tools/test_hybrid_nscf.py @@ -13,6 +13,8 @@ COMMON = """INPUT_PARAMETERS suffix hybrid basis_type pw +device cpu +precision double nbands 3 ecutwfc 10 scf_thr 1e-9 @@ -136,19 +138,71 @@ def verify(executable, root, mpi_ranks): print("failed SCF invalidates the previous source checkpoint") +def verify_gpu(executable, root): + """Compare devices using the same frozen ensemble, then reverse the restart.""" + cpu_scf = create_case(root, "cpu_scf", "calculation scf\nout_chg 1\nout_wfc_pw 2\n") + run(executable, cpu_scf, []) + source = cpu_scf / "OUT.hybrid" + original = digest(source) + extra = f"calculation nscf\nread_file_dir {source}\n" + for name, points in (("same", MESH), ("path", PATH)): + reference = create_case(root, f"cpu_{name}", extra, points) + target = create_case(root, f"gpu_{name}", extra, points) + for case in (reference, target): + text = (case / "INPUT").read_text().replace("nbands 3", "nbands 5") + if case == target: + text = text.replace("device cpu", "device gpu") + (case / "INPUT").write_text(text) + run(executable, case, []) + delta = max_difference(bands(reference), bands(target)) + assert delta < 2e-6, f"CPU/GPU {name} mismatch: {delta} eV" + print(f"CPU source, CPU/GPU {name} targets: max difference {delta:.3g} eV") + assert digest(source) == original, "GPU NSCF modified CPU source files" + + gpu_scf = create_case(root, "gpu_scf", "calculation scf\nout_chg 1\nout_wfc_pw 2\nnspin 2\n") + text = (gpu_scf / "INPUT").read_text().replace("device cpu", "device gpu") + (gpu_scf / "INPUT").write_text(text) + run(executable, gpu_scf, []) + source = gpu_scf / "OUT.hybrid" + assert (source / "EXX_SOURCE").exists() + original = digest(source) + targets = [] + for device in ("cpu", "gpu"): + target = create_case(root, f"{device}_spin", f"calculation nscf\nread_file_dir {source}\nnspin 2\n", PATH) + text = (target / "INPUT").read_text().replace("device cpu", f"device {device}") + (target / "INPUT").write_text(text) + run(executable, target, []) + targets.append(target) + for channel in (1, 2): + delta = max_difference(bands(targets[0], channel), bands(targets[1], channel)) + assert delta < 2e-6, delta + gamma_delta = max_difference([bands(gpu_scf, channel)[0]], [bands(targets[1], channel)[0]]) + assert gamma_delta < 2e-4, gamma_delta + print(f"GPU source, spin {channel}, independent CPU/GPU targets: {delta:.3g} eV") + assert digest(source) == original, "NSCF modified GPU source files" + unsupported = create_case(root, "gpu_unsupported_ace", extra) + text = (unsupported / "INPUT").read_text().replace("device cpu", "device gpu") + text = text.replace("exxace false", "exxace true") + (unsupported / "INPUT").write_text(text) + run(executable, unsupported, [], "Hybrid NSCF currently requires") + print("CUDA NSCF rejects ACE") + + def main(): parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("executable", type=Path) parser.add_argument("--workdir", type=Path) + parser.add_argument("--gpu", action="store_true", help="verify CUDA using one rank and double precision") parser.add_argument("--mpi-ranks", type=int, default=2) args = parser.parse_args() executable = args.executable.resolve() + verify_case = verify_gpu if args.gpu else lambda exe, root: verify(exe, root, args.mpi_ranks) if args.workdir: args.workdir.mkdir(parents=True, exist_ok=True) - verify(executable, args.workdir.resolve(), args.mpi_ranks) + verify_case(executable, args.workdir.resolve()) else: with tempfile.TemporaryDirectory(prefix="abacus-hybrid-nscf-") as directory: - verify(executable, Path(directory), args.mpi_ranks) + verify_case(executable, Path(directory)) print("PASS: screened hybrid NSCF regression") From 78510e3607b3407328f215c014526e3220e67b8b Mon Sep 17 00:00:00 2001 From: Hongxu Ren Date: Wed, 30 Sep 2026 23:59:40 +0800 Subject: [PATCH 07/25] fix(pw): match exchange FFT precision to wavefunctions --- docs/advanced/elec_properties/hybrid_nscf.md | 11 +++++++++-- source/source_pw/module_pwdft/op_pw_exx.cpp | 9 +++++++-- tests/integrate/tools/test_hybrid_nscf.py | 10 ++++++++++ 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/docs/advanced/elec_properties/hybrid_nscf.md b/docs/advanced/elec_properties/hybrid_nscf.md index b49f54ea92c..032b1f5f2b3 100644 --- a/docs/advanced/elec_properties/hybrid_nscf.md +++ b/docs/advanced/elec_properties/hybrid_nscf.md @@ -132,18 +132,25 @@ For a CUDA build and an available GPU, also run: ```bash python3 tests/integrate/tools/test_hybrid_nscf.py ./build/abacus --gpu +OMP_NUM_THREADS=1 ctest --test-dir build -V -R '^PW_HYBRID_NSCF(_GPU)?$' ``` This compares CPU and GPU targets using one frozen CPU source on both a mesh and an independent path with extra target bands, then checks a GPU-generated spin-polarized source with CPU and GPU targets. Source files must remain -unchanged. The corresponding CTest is `PW_HYBRID_NSCF_GPU`. +unchanged. A three-band single-precision GPU path additionally checks conversion +from a double-precision CPU source and the full-grid exchange FFT precision. +Single precision uses the existing looser diagonalization threshold; use +`precision double` for accurate high-energy target bands. The corresponding CTest is `PW_HYBRID_NSCF_GPU`. On a local RTX 3090 with CUDA 13.1, both CTests passed in a CUDA build. The H CPU/GPU mesh, independent path and both spin-channel eigenvalues agreed at the printed precision, as did all eight bands at nine Si L-Gamma-X points using the same frozen CPU source (`20 Ry`, `2x2x2` source mesh). The Si check -compared raw eigenvalues without an energy shift. This validates device +compared raw eigenvalues without an energy shift. The three-band H +single-precision GPU path differed by at most `5.76e-5 eV` from double precision. +The CPU build also passed its checkpoint unit tests and NSCF integration test. +This validates device consistency; it does not change the cross-code convergence limits below. On the initial local two-q-point, 10 Ry test, the same-mesh SCF/NSCF maximum diff --git a/source/source_pw/module_pwdft/op_pw_exx.cpp b/source/source_pw/module_pwdft/op_pw_exx.cpp index 222536928b9..61b156fed19 100644 --- a/source/source_pw/module_pwdft/op_pw_exx.cpp +++ b/source/source_pw/module_pwdft/op_pw_exx.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include namespace hamilt @@ -90,8 +91,12 @@ OperatorEXXPW::OperatorEXXPW(const int* isk_in, Real tpiba2 = tpiba * tpiba; // initialize rhopw_dev on the resolved EXX cutoff - rhopw_dev = new ModulePW::PW_Basis(wfcpw->get_device(), rhopw->get_precision()); - rhopw_dev->fft_bundle.setfft(wfcpw->get_device(), rhopw->get_precision()); + // Pair densities have the wavefunction precision, while the ordinary + // charge density may retain double precision in a single-precision run. + const std::string exchange_device = wfcpw->get_device(); + const std::string exchange_precision = wfcpw->get_precision(); + rhopw_dev = new ModulePW::PW_Basis(exchange_device, exchange_precision); + rhopw_dev->fft_bundle.setfft(exchange_device, exchange_precision); #ifdef __MPI rhopw_dev->initmpi(rhopw->poolnproc, rhopw->poolrank, rhopw->pool_world); #endif diff --git a/tests/integrate/tools/test_hybrid_nscf.py b/tests/integrate/tools/test_hybrid_nscf.py index 65a8eb24c01..8ce0a22ee65 100644 --- a/tests/integrate/tools/test_hybrid_nscf.py +++ b/tests/integrate/tools/test_hybrid_nscf.py @@ -157,6 +157,16 @@ def verify_gpu(executable, root): delta = max_difference(bands(reference), bands(target)) assert delta < 2e-6, f"CPU/GPU {name} mismatch: {delta} eV" print(f"CPU source, CPU/GPU {name} targets: max difference {delta:.3g} eV") + single = create_case(root, "gpu_single", extra, PATH) + text = (single / "INPUT").read_text().replace("device cpu", "device gpu") + text = text.replace("precision double", "precision single") + text = text.replace("pw_diag_thr 1e-10", "pw_diag_thr 1e-6") + (single / "INPUT").write_text(text) + run(executable, single, []) + reference = [row[:3] for row in bands(root / "cpu_path")] + delta = max_difference(reference, bands(single)) + assert delta < 2e-4, f"Single-precision GPU restart mismatch: {delta} eV" + print(f"CPU double source, GPU single 3-band path: max difference {delta:.3g} eV") assert digest(source) == original, "GPU NSCF modified CPU source files" gpu_scf = create_case(root, "gpu_scf", "calculation scf\nout_chg 1\nout_wfc_pw 2\nnspin 2\n") From 99e9c5637d27d265ecda5fbea4e201a77a4bf7a9 Mon Sep 17 00:00:00 2001 From: Hongxu Ren Date: Thu, 8 Oct 2026 01:23:11 +0800 Subject: [PATCH 08/25] feat(pw): share screened zero-transfer limits with LCAO --- docs/advanced/elec_properties/hybrid_nscf.md | 26 +++++++- docs/advanced/input_files/input-main.md | 25 ++++---- docs/parameters.yaml | 15 +++-- source/source_hamilt/module_xc/exx_info.cpp | 3 +- .../module_parameter/read_inp_exx_dftu.cpp | 60 +++++++++++++++++-- .../module_parameter/read_inp_other.cpp | 4 +- .../test_serial/read_input_item_test.cpp | 22 +++++++ source/source_pw/module_pwdft/op_pw_exx.cpp | 45 +++++++++++--- .../source_pw/module_pwdft/op_pw_exx_pot.cpp | 12 +--- tests/integrate/tools/test_hybrid_nscf.py | 59 ++++++++++++++++++ 10 files changed, 229 insertions(+), 42 deletions(-) diff --git a/docs/advanced/elec_properties/hybrid_nscf.md b/docs/advanced/elec_properties/hybrid_nscf.md index 032b1f5f2b3..5638bada47f 100644 --- a/docs/advanced/elec_properties/hybrid_nscf.md +++ b/docs/advanced/elec_properties/hybrid_nscf.md @@ -114,6 +114,29 @@ architecture was not adopted. That checkout explicitly rejects hybrid NSCF in built-in HSE screening default is `0.106 bohr^-1`; use `screening_parameter=0.11` for comparison with ABACUS HSE06. +## Screened zero-transfer treatment + +PW HSE uses the same `exx_singularity_correction limits` default as NAO/LCAO. +For screened exchange the reciprocal kernel has the finite limit +`-pi * e2 / omega^2` at `k-q+G=0`; this scheme retains that limit without adding +an auxiliary-function correction. It uses `exx_gamma_extrapolation false`, +which is selected automatically when omitted. Explicit gamma extrapolation +with `limits`, and unscreened Fock terms with `limits`, are rejected in PW. + +Set `exx_singularity_correction auxiliary` explicitly to retain the historical +PW auxiliary correction (including the existing gamma-extrapolation option). +This is also the default for unscreened PW hybrids; it does not enable +unscreened hybrid NSCF. For screened independent-k targets the auxiliary +correction can cause a jump when a target coincides with a source point. +LCAO-specific `spencer`, `revised_spencer`, `massidda` and `carrier` schemes +are not implemented for PW and are rejected rather than silently ignored. + +SCF and NSCF must use the same scheme. The scheme is part of the `EXX_SOURCE` +configuration, and an incompatible restart is rejected. Regenerate the SCF +source before switching schemes; checkpoints from the earlier implementation +must also be regenerated. The cross-code results below used the historical +auxiliary scheme and do not constitute validation of the new default. + ## Reproducible verification ```bash @@ -191,6 +214,5 @@ The comparison above is from a fresh calculation with unique k coordinates, using the weighted mesh result at coincident path points. No eigenvalues were edited to align the spectra. -These checks do not validate PBE0, symmetry reconstruction, source q pools -or GPU execution. Direct exchange remains the NSCF method; ACE is not a +These checks do not validate PBE0, symmetry reconstruction or source q pools. Direct exchange remains the NSCF method; ACE is not a planned extension of this workflow. diff --git a/docs/advanced/input_files/input-main.md b/docs/advanced/input_files/input-main.md index ea3f35f1990..c0d4c834411 100644 --- a/docs/advanced/input_files/input-main.md +++ b/docs/advanced/input_files/input-main.md @@ -320,6 +320,7 @@ - [exx\_separate\_loop](#exx_separate_loop) - [exx\_hybrid\_step](#exx_hybrid_step) - [exx\_mixing\_beta](#exx_mixing_beta) + - [exx\_singularity\_correction](#exx_singularity_correction) - [Exact Exchange (LCAO in PW)](#exact-exchange-lcao-in-pw) - [exx\_fock\_lambda](#exx_fock_lambda) - [Exact Exchange (LCAO)](#exact-exchange-lcao) @@ -337,7 +338,6 @@ - [exx\_opt\_orb\_ecut](#exx_opt_orb_ecut) - [exx\_opt\_orb\_tolerence](#exx_opt_orb_tolerence) - [exx\_real\_number](#exx_real_number) - - [exx\_singularity\_correction](#exx_singularity_correction) - [rpa\_ccp\_rmesh\_times](#rpa_ccp_rmesh_times) - [exx\_symmetry\_realspace](#exx_symmetry_realspace) - [out\_ri\_cv](#out_ri_cv) @@ -3308,6 +3308,18 @@ - **Description**: Mixing parameter for densty matrix in each iteration of the outer-loop - **Default**: 1.0 +### exx_singularity_correction + +- **Type**: String +- **Description**: Scheme for Coulomb singularity / zero-transfer treatment in exact exchange. + - limits: use the finite screened Coulomb-kernel limit, without an auxiliary correction. Default for HSE and cwp22 in both PW and LCAO. PW requires screened exchange and exx_gamma_extrapolation=false; the latter defaults to false for this scheme. + - auxiliary: retain the historical PW auxiliary-function correction. PW only; default for unscreened PW hybrids. For independent-k screened hybrid NSCF this can cause discontinuities at source k points. + - spencer: LCAO spherical truncation, Phys. Rev. B 77, 193110 (2008). + - revised_spencer: LCAO, Phys. Rev. Mater. 5, 013807 (2021). + - massidda / carrier: LCAO auxiliary singularity corrections. + Use the same scheme for SCF and NSCF. Regenerate the SCF source checkpoint after changing schemes. +- **Default**: default + [back to top](#full-list-of-input-keywords) ## Exact Exchange (LCAO in PW) @@ -3411,13 +3423,6 @@ - False: Enforce LibRI to use complex data type. Setting it to True can effectively improve the speed of self-consistent calculations with hybrid functionals. - **Default**: depends on the gamma_only option -### exx_singularity_correction - -- **Type**: String -- **Description**: - spencer: see Phys. Rev. B 77, 193110 (2008). - - revised_spencer: see Phys. Rev. Mater. 5, 013807 (2021). Set the scheme of Coulomb singularity correction. -- **Default**: default - ### rpa_ccp_rmesh_times - **Type**: Real @@ -3455,8 +3460,8 @@ ### exx_gamma_extrapolation - **Type**: Boolean -- **Description**: Whether to use the gamma point extrapolation method to calculate the Fock exchange operator. See https://doi.org/10.1103/PhysRevB.79.205114 for details. Should be set to true most of the time. -- **Default**: True +- **Description**: Whether to use the gamma point extrapolation method to calculate the Fock exchange operator. See https://doi.org/10.1103/PhysRevB.79.205114 for details. Defaults to false for PW exx_singularity_correction=limits (finite screened kernel), and true otherwise. Explicit true is incompatible with the PW limits scheme. +- **Default**: False for PW limits; True otherwise ### ecutexx diff --git a/docs/parameters.yaml b/docs/parameters.yaml index 89a2d975d76..49a21cb1650 100644 --- a/docs/parameters.yaml +++ b/docs/parameters.yaml @@ -4716,11 +4716,16 @@ parameters: unit: "" availability: "" - name: exx_singularity_correction - category: Exact Exchange (LCAO) + category: Exact Exchange (Common) type: String description: | - * spencer: see Phys. Rev. B 77, 193110 (2008). - * revised_spencer: see Phys. Rev. Mater. 5, 013807 (2021). Set the scheme of Coulomb singularity correction. + Scheme for Coulomb singularity / zero-transfer treatment in exact exchange. + * limits: use the finite screened Coulomb-kernel limit, without an auxiliary correction. Default for HSE and cwp22 in both PW and LCAO. PW requires screened exchange and exx_gamma_extrapolation=false; the latter defaults to false for this scheme. + * auxiliary: retain the historical PW auxiliary-function correction. PW only; default for unscreened PW hybrids. For independent-k screened hybrid NSCF this can cause discontinuities at source k points. + * spencer: LCAO spherical truncation, Phys. Rev. B 77, 193110 (2008). + * revised_spencer: LCAO, Phys. Rev. Mater. 5, 013807 (2021). + * massidda / carrier: LCAO auxiliary singularity corrections. + Use the same scheme for SCF and NSCF. Regenerate the SCF source checkpoint after changing schemes. default_value: default unit: "" availability: "" @@ -5328,8 +5333,8 @@ parameters: category: Exact Exchange (PW) type: Boolean description: | - Whether to use the gamma point extrapolation method to calculate the Fock exchange operator. See https://doi.org/10.1103/PhysRevB.79.205114 for details. Should be set to true most of the time. - default_value: "True" + Whether to use the gamma point extrapolation method to calculate the Fock exchange operator. See https://doi.org/10.1103/PhysRevB.79.205114 for details. Defaults to false for PW exx_singularity_correction=limits (finite screened kernel), and true otherwise. Explicit true is incompatible with the PW limits scheme. + default_value: False for PW limits; True otherwise unit: "" availability: "" - name: ecutexx diff --git a/source/source_hamilt/module_xc/exx_info.cpp b/source/source_hamilt/module_xc/exx_info.cpp index 5edf434be3f..ed0858ea8b0 100644 --- a/source/source_hamilt/module_xc/exx_info.cpp +++ b/source/source_hamilt/module_xc/exx_info.cpp @@ -114,7 +114,8 @@ bool init_general_exx_info(General_Exx_Info& info, const Input_para& inp) { info.coulomb_param[Conv_Coulomb_Pot_K::Coulomb_Type::Erfc] = {{ {"alpha", ModuleBase::GlobalFunc::TO_STRING(erfc_alpha[i])}, - {"omega", ModuleBase::GlobalFunc::TO_STRING(inp.exx_erfc_omega[i])} }}; + {"omega", ModuleBase::GlobalFunc::TO_STRING(inp.exx_erfc_omega[i])}, + {"singularity_correction", inp.exx_singularity_correction} }}; } } } diff --git a/source/source_io/module_parameter/read_inp_exx_dftu.cpp b/source/source_io/module_parameter/read_inp_exx_dftu.cpp index 7eff18f20a8..7b9408a1243 100644 --- a/source/source_io/module_parameter/read_inp_exx_dftu.cpp +++ b/source/source_io/module_parameter/read_inp_exx_dftu.cpp @@ -466,14 +466,19 @@ void ReadInput::item_exx() { Input_Item item("exx_singularity_correction"); item.annotation = "set the scheme of Coulomb singularity correction"; - item.category = "Exact Exchange (LCAO)"; + item.category = "Exact Exchange (Common)"; item.type = "String"; - item.description = R"(* spencer: see Phys. Rev. B 77, 193110 (2008). -* revised_spencer: see Phys. Rev. Mater. 5, 013807 (2021). Set the scheme of Coulomb singularity correction.)"; + item.description = R"(Scheme for Coulomb singularity / zero-transfer treatment in exact exchange. +* limits: use the finite screened Coulomb-kernel limit, without an auxiliary correction. Default for HSE and cwp22 in both PW and LCAO. PW requires screened exchange and exx_gamma_extrapolation=false; the latter defaults to false for this scheme. +* auxiliary: retain the historical PW auxiliary-function correction. PW only; default for unscreened PW hybrids. For independent-k screened hybrid NSCF this can cause discontinuities at source k points. +* spencer: LCAO spherical truncation, Phys. Rev. B 77, 193110 (2008). +* revised_spencer: LCAO, Phys. Rev. Mater. 5, 013807 (2021). +* massidda / carrier: LCAO auxiliary singularity corrections. +Use the same scheme for SCF and NSCF. Regenerate the SCF source checkpoint after changing schemes.)"; item.default_value = "default"; item.unit = ""; read_sync_string(input.exx_singularity_correction); - item.reset_value = [](const Input_Item& item, Parameter& para) { + item.reset_value = [this](const Input_Item& item, Parameter& para) { if (para.input.exx_singularity_correction == "default") { std::string& dft_functional = para.input.dft_functional; @@ -490,13 +495,58 @@ void ReadInput::item_exx() || dft_functional_lower == "lrc_wpbeh" || dft_functional_lower == "cam_pbeh") { - para.input.exx_singularity_correction = "spencer"; + if (para.input.basis_type == "pw") + { + para.input.exx_singularity_correction = "auxiliary"; + } + else + { + para.input.exx_singularity_correction = "spencer"; + } } else if (dft_functional_lower == "hse" || dft_functional_lower == "cwp22") { para.input.exx_singularity_correction = "limits"; } } + if (para.input.basis_type == "pw" && para.input.exx_singularity_correction == "limits") + { + const auto gamma_item = std::find_if(this->input_lists.begin(), this->input_lists.end(), + [](const std::pair& entry) { + return entry.first == "exx_gamma_extrapolation"; + }); + if (gamma_item != this->input_lists.end() && !gamma_item->second.is_read()) + { + para.input.exx_gamma_extrapolation = false; + } + } + }; + item.check_value = [](const Input_Item& item, const Parameter& para) { + const std::string& scheme = para.input.exx_singularity_correction; + if (para.input.basis_type == "pw" && scheme != "default") + { + if (scheme != "limits" && scheme != "auxiliary") + { + ModuleBase::WARNING_QUIT("ReadInput", "PW exx_singularity_correction must be limits or auxiliary"); + } + if (scheme == "limits") + { + bool has_fock = false; + for (const auto& alpha : para.input.exx_fock_alpha) + { + has_fock = has_fock || std::stod(alpha) != 0.0; + } + if (has_fock || para.input.exx_gamma_extrapolation) + { + ModuleBase::WARNING_QUIT("ReadInput", + "PW limits requires screened exchange and exx_gamma_extrapolation=false"); + } + } + } + else if (para.input.basis_type != "pw" && scheme == "auxiliary") + { + ModuleBase::WARNING_QUIT("ReadInput", "exx_singularity_correction auxiliary is only supported for PW"); + } }; this->add_item(item); } diff --git a/source/source_io/module_parameter/read_inp_other.cpp b/source/source_io/module_parameter/read_inp_other.cpp index d4431fd4421..9d0f93ab9b7 100644 --- a/source/source_io/module_parameter/read_inp_other.cpp +++ b/source/source_io/module_parameter/read_inp_other.cpp @@ -886,8 +886,8 @@ When false (default), both the direction and magnitude of the magnetic moment ar item.annotation = "whether to perform gamma extrapolation in exxpw"; item.category = "Exact Exchange (PW)"; item.type = "Boolean"; - item.description = "Whether to use the gamma point extrapolation method to calculate the Fock exchange operator. See https://doi.org/10.1103/PhysRevB.79.205114 for details. Should be set to true most of the time."; - item.default_value = "True"; + item.description = "Whether to use the gamma point extrapolation method to calculate the Fock exchange operator. See https://doi.org/10.1103/PhysRevB.79.205114 for details. Defaults to false for PW exx_singularity_correction=limits (finite screened kernel), and true otherwise. Explicit true is incompatible with the PW limits scheme."; + item.default_value = "False for PW limits; True otherwise"; item.unit = ""; read_sync_bool(input.exx_gamma_extrapolation); this->add_item(item); diff --git a/source/source_io/test_serial/read_input_item_test.cpp b/source/source_io/test_serial/read_input_item_test.cpp index 1e445385a2a..50f0140a962 100644 --- a/source/source_io/test_serial/read_input_item_test.cpp +++ b/source/source_io/test_serial/read_input_item_test.cpp @@ -1726,6 +1726,7 @@ TEST_F(InputTest, Item_test2) } { // exx_singluarity_correction auto it = find_label("exx_singularity_correction", readinput.input_lists); + param.input.basis_type = "lcao"; param.input.exx_singularity_correction = "default"; param.input.dft_functional = "HF"; it->second.reset_value(it->second, param); @@ -1740,6 +1741,27 @@ TEST_F(InputTest, Item_test2) param.input.dft_functional = "HSE"; it->second.reset_value(it->second, param); EXPECT_EQ(param.input.exx_singularity_correction, "limits"); + + param.input.basis_type = "pw"; + param.input.dft_functional = "PBE0"; + param.input.exx_singularity_correction = "default"; + it->second.reset_value(it->second, param); + EXPECT_EQ(param.input.exx_singularity_correction, "auxiliary"); + + param.input.dft_functional = "HSE"; + param.input.exx_singularity_correction = "default"; + param.input.exx_gamma_extrapolation = true; + it->second.reset_value(it->second, param); + EXPECT_EQ(param.input.exx_singularity_correction, "limits"); + EXPECT_FALSE(param.input.exx_gamma_extrapolation); + + auto gamma = find_label("exx_gamma_extrapolation", readinput.input_lists); + gamma->second.str_values = {"true"}; + param.input.exx_gamma_extrapolation = true; + it->second.reset_value(it->second, param); + EXPECT_TRUE(param.input.exx_gamma_extrapolation); + gamma->second.str_values.clear(); + param.input.exx_gamma_extrapolation = false; } { // exx_ccp_rmesh_times auto it = find_label("exx_ccp_rmesh_times", readinput.input_lists); diff --git a/source/source_pw/module_pwdft/op_pw_exx.cpp b/source/source_pw/module_pwdft/op_pw_exx.cpp index 61b156fed19..99a2ec41aad 100644 --- a/source/source_pw/module_pwdft/op_pw_exx.cpp +++ b/source/source_pw/module_pwdft/op_pw_exx.cpp @@ -122,14 +122,20 @@ OperatorEXXPW::OperatorEXXPW(const int* isk_in, auto param_erfc = this->coulomb_param[Conv_Coulomb_Pot_K::Coulomb_Type::Erfc]; for (auto param: param_erfc) { - erfc_div.push_back(exx_divergence(Conv_Coulomb_Pot_K::Coulomb_Type::Erfc, - std::stod(param["omega"]), - kv, - wfcpw, - rhopw_dev, - tpiba, - gamma_extrapolation, - ucell->omega)); + double correction = 0.0; + if (param.at("singularity_correction") == "auxiliary") + { + const double omega = std::stod(param.at("omega")); + correction = exx_divergence(Conv_Coulomb_Pot_K::Coulomb_Type::Erfc, + omega, + kv, + wfcpw, + rhopw_dev, + tpiba, + gamma_extrapolation, + ucell->omega); + } + erfc_div.push_back(correction); } } // end of constructor @@ -254,6 +260,29 @@ void OperatorEXXPW::set_source(const ModulePW::PW_Basis_K& source_bas source_points_ = &source_points; psi = source_psi; wg = &source_weights; + // Cache the auxiliary correction on the frozen source mesh, rather than + // the independent target path. Limits keeps this correction at zero. + const auto screened = coulomb_param.find(Conv_Coulomb_Pot_K::Coulomb_Type::Erfc); + if (screened != coulomb_param.end()) + { + for (std::size_t i = 0; i < screened->second.size(); ++i) + { + const auto& param = screened->second[i]; + erfc_div[i] = 0.0; + if (param.at("singularity_correction") == "auxiliary") + { + const double omega = std::stod(param.at("omega")); + erfc_div[i] = exx_divergence(Conv_Coulomb_Pot_K::Coulomb_Type::Erfc, + omega, + &source_points, + &source_basis, + rhopw_dev, + tpiba, + gamma_extrapolation, + ucell->omega); + } + } + } q_points.clear(); first_iter = false; } diff --git a/source/source_pw/module_pwdft/op_pw_exx_pot.cpp b/source/source_pw/module_pwdft/op_pw_exx_pot.cpp index c79d050a616..5d72dc913cf 100644 --- a/source/source_pw/module_pwdft/op_pw_exx_pot.cpp +++ b/source/source_pw/module_pwdft/op_pw_exx_pot.cpp @@ -168,15 +168,9 @@ void get_exx_potential(const K_Vectors* kv, double erfc_omega = std::stod(param["omega"]); double erfc_omega2 = erfc_omega * erfc_omega; double alpha = std::stod(param["alpha"]); - // double exx_div = OperatorEXXPW, Device>::erfc_div[i]; - double exx_div = exx_divergence(Conv_Coulomb_Pot_K::Coulomb_Type::Erfc, - erfc_omega, - kv, - source_basis, - rhopw_dev, - tpiba, - gamma_extrapolation, - ucell_omega); + // Initialized on the SCF mesh, or replaced with the frozen source + // correction by set_source. The shared limits scheme stores zero. + const double exx_div = OperatorEXXPW, Device>::erfc_div[i]; const ModuleBase::Vector3 k_c = wfcpw->kvec_c[ik]; const ModuleBase::Vector3 k_d = wfcpw->kvec_d[ik]; const ModuleBase::Vector3 q_c = qvec_c[iq]; diff --git a/tests/integrate/tools/test_hybrid_nscf.py b/tests/integrate/tools/test_hybrid_nscf.py index 8ce0a22ee65..02723a9174b 100644 --- a/tests/integrate/tools/test_hybrid_nscf.py +++ b/tests/integrate/tools/test_hybrid_nscf.py @@ -138,6 +138,63 @@ def verify(executable, root, mpi_ranks): print("failed SCF invalidates the previous source checkpoint") +def verify_correction(executable, root, gpu=False): + """Check the shared finite-limit scheme and restart convention on each device.""" + device = "gpu" if gpu else "cpu" + scf = create_case(root, f"limits_{device}_scf", + "calculation scf\nout_chg 1\nout_wfc_pw 2\n") + # Exercise the defaults, including automatic disabling of gamma extrapolation. + text = (scf / "INPUT").read_text().replace("exx_gamma_extrapolation false\n", "") + text = text.replace("device cpu", f"device {device}") + (scf / "INPUT").write_text(text) + run(executable, scf, []) + source = scf / "OUT.hybrid" + original = digest(source) + extra = f"calculation nscf\nread_file_dir {source}\nexx_singularity_correction limits\n" + near_gamma = "K_POINTS\n3\nDirect\n0 0 0 1\n0.00001 0 0 1\n-0.00001 0 0 1\n" + target = create_case(root, f"limits_{device}_continuity", extra, near_gamma) + text = (target / "INPUT").read_text().replace("device cpu", f"device {device}") + (target / "INPUT").write_text(text) + run(executable, target, []) + values = bands(target) + delta = max(max_difference([values[0]], [row]) for row in values[1:]) + assert delta < 5e-3, f"Finite-limit discontinuity near Gamma: {delta} eV" + assert max_difference([bands(scf)[0]], [values[0]]) < 2e-4 + assert digest(source) == original + print(f"{device} default/explicit limits, Gamma +/-1e-5: max difference {delta:.3g} eV") + + mismatch = create_case(root, f"{device}_correction_mismatch", + extra.replace("correction limits", "correction auxiliary")) + run(executable, mismatch, [], "EXX source") + bad = create_case(root, f"{device}_bad_correction", extra.replace("correction limits", "correction spencer")) + run(executable, bad, [], "PW exx_singularity_correction must be limits or auxiliary") + gamma = create_case(root, f"{device}_limits_gamma", extra) + text = (gamma / "INPUT").read_text().replace("exx_gamma_extrapolation false", "exx_gamma_extrapolation true") + (gamma / "INPUT").write_text(text) + run(executable, gamma, [], "PW limits requires screened exchange") + unscreened = create_case(root, f"{device}_limits_fock", extra) + text = (unscreened / "INPUT").read_text().replace("dft_functional HSE", "dft_functional PBE0") + (unscreened / "INPUT").write_text(text) + run(executable, unscreened, [], "PW limits requires screened exchange") + + auxiliary = create_case(root, f"auxiliary_{device}_scf", + "calculation scf\nout_chg 1\nout_wfc_pw 2\nexx_singularity_correction auxiliary\n") + text = (auxiliary / "INPUT").read_text().replace("device cpu", f"device {device}") + (auxiliary / "INPUT").write_text(text) + run(executable, auxiliary, []) + aux_source = auxiliary / "OUT.hybrid" + aux_target = create_case(root, f"auxiliary_{device}_nscf", + f"calculation nscf\nread_file_dir {aux_source}\nexx_singularity_correction auxiliary\n") + text = (aux_target / "INPUT").read_text().replace("device cpu", f"device {device}") + (aux_target / "INPUT").write_text(text) + run(executable, aux_target, []) + assert max_difference(bands(auxiliary), bands(aux_target)) < 2e-4 + shift = max_difference(bands(scf), bands(auxiliary)) + assert shift > 1e-5, "limits and auxiliary unexpectedly produced identical SCF bands" + print(f"{device} auxiliary SCF/NSCF matched; limits/auxiliary SCF difference {shift:.3g} eV") + print("mismatched scheme, unsupported scheme, gamma and unscreened limits rejected") + + def verify_gpu(executable, root): """Compare devices using the same frozen ensemble, then reverse the restart.""" cpu_scf = create_case(root, "cpu_scf", "calculation scf\nout_chg 1\nout_wfc_pw 2\n") @@ -210,9 +267,11 @@ def main(): if args.workdir: args.workdir.mkdir(parents=True, exist_ok=True) verify_case(executable, args.workdir.resolve()) + verify_correction(executable, args.workdir.resolve(), args.gpu) else: with tempfile.TemporaryDirectory(prefix="abacus-hybrid-nscf-") as directory: verify_case(executable, Path(directory)) + verify_correction(executable, Path(directory), args.gpu) print("PASS: screened hybrid NSCF regression") From 984923a2e72346a0b5772f7ab283ea0d61fbd3ff Mon Sep 17 00:00:00 2001 From: Hongxu Ren Date: Thu, 8 Oct 2026 01:35:23 +0800 Subject: [PATCH 09/25] refactor(pw): keep exchange convolution interface minimal --- source/source_pw/module_pwdft/op_pw_exx.cpp | 7 ++++--- source/source_pw/module_pwdft/op_pw_exx.h | 1 - source/source_pw/module_pwdft/op_pw_exx_pot.cpp | 5 ----- source/source_pw/module_pwdft/stress_exx.cpp | 4 ++-- 4 files changed, 6 insertions(+), 11 deletions(-) diff --git a/source/source_pw/module_pwdft/op_pw_exx.cpp b/source/source_pw/module_pwdft/op_pw_exx.cpp index 8696973a207..d97d0ab0c9e 100644 --- a/source/source_pw/module_pwdft/op_pw_exx.cpp +++ b/source/source_pw/module_pwdft/op_pw_exx.cpp @@ -317,7 +317,7 @@ void OperatorEXXPW::act_op(const int nbands, for (int iq: q_points) { const int iq_nospin = iq % nk; - get_exx_potential(source_points_, wfcpw, source_basis_, rhopw_dev, pot, tpiba, gamma_extrapolation, ucell->omega, this->ik, iq_nospin, false, this->coulomb_param); + get_exx_potential(source_points_, wfcpw, rhopw_dev, pot, tpiba, gamma_extrapolation, ucell->omega, this->ik, iq_nospin, false, this->coulomb_param); for (int m_iband = 0; m_iband < psi.get_nbands(); m_iband++) { // occupation of the source state (m, iq), not of the target k-point @@ -382,7 +382,7 @@ void OperatorEXXPW::act_op_kpar(const int nbands, for (int iq = 0; iq < nqs; iq++) { // for \psi_nk, get the pw of iq and band m - get_exx_potential(kv, wfcpw, wfcpw, rhopw_dev, pot, tpiba, gamma_extrapolation, ucell->omega, this->ik, iq, false, this->coulomb_param); + get_exx_potential(kv, wfcpw, rhopw_dev, pot, tpiba, gamma_extrapolation, ucell->omega, this->ik, iq, false, this->coulomb_param); // decide which pool does the iq belong to int iq_pool = kv->para_k.whichpool[iq]; @@ -1112,7 +1112,8 @@ double OperatorEXXPW::cal_exx_energy_op(psi::Psi *ppsi_) c for (int iq: q_points_ik) { - get_exx_potential(kv, wfcpw, wfcpw, rhopw_dev, pot, tpiba, gamma_extrapolation, ucell->omega, ik, iq % nk, false, this->coulomb_param); + const int iq_nospin = iq % nk; + get_exx_potential(kv, wfcpw, rhopw_dev, pot, tpiba, gamma_extrapolation, ucell->omega, ik, iq_nospin, false, this->coulomb_param); for (int m_iband = 0; m_iband < nb; m_iband++) { const double wg_iqb_real = (*wg)(iq, m_iband); diff --git a/source/source_pw/module_pwdft/op_pw_exx.h b/source/source_pw/module_pwdft/op_pw_exx.h index c6af5c933a3..799f8f60385 100644 --- a/source/source_pw/module_pwdft/op_pw_exx.h +++ b/source/source_pw/module_pwdft/op_pw_exx.h @@ -354,7 +354,6 @@ extern template class OperatorEXXPW, base_device::DEVICE_GP template void get_exx_potential(const K_Vectors* kv, const ModulePW::PW_Basis_K* wfcpw, - const ModulePW::PW_Basis_K* source_basis, ModulePW::PW_Basis* rhopw_dev, Real* pot, double tpiba, diff --git a/source/source_pw/module_pwdft/op_pw_exx_pot.cpp b/source/source_pw/module_pwdft/op_pw_exx_pot.cpp index 4ea46b182cb..6ae2a6d2c35 100644 --- a/source/source_pw/module_pwdft/op_pw_exx_pot.cpp +++ b/source/source_pw/module_pwdft/op_pw_exx_pot.cpp @@ -59,7 +59,6 @@ extern template class OperatorEXXPW, base_device::DEVICE_GP template void get_exx_potential(const K_Vectors* kv, const ModulePW::PW_Basis_K* wfcpw, - const ModulePW::PW_Basis_K* source_basis, ModulePW::PW_Basis* rhopw_dev, Real* pot, double tpiba, @@ -551,7 +550,6 @@ double exx_divergence(Conv_Coulomb_Pot_K::Coulomb_Type coulomb_type, return exx_div; } template void get_exx_potential(const K_Vectors*, - const ModulePW::PW_Basis_K*, const ModulePW::PW_Basis_K*, ModulePW::PW_Basis*, float*, @@ -563,7 +561,6 @@ template void get_exx_potential(const K_Vectors* bool, const CoulombParam&); template void get_exx_potential(const K_Vectors*, - const ModulePW::PW_Basis_K*, const ModulePW::PW_Basis_K*, ModulePW::PW_Basis*, double*, @@ -596,7 +593,6 @@ template void get_exx_stress_potential(const K_ const CoulombParam&); #if ((defined __CUDA) || (defined __ROCM)) template void get_exx_potential(const K_Vectors*, - const ModulePW::PW_Basis_K*, const ModulePW::PW_Basis_K*, ModulePW::PW_Basis*, float*, @@ -608,7 +604,6 @@ template void get_exx_potential(const K_Vectors* bool, const CoulombParam&); template void get_exx_potential(const K_Vectors*, - const ModulePW::PW_Basis_K*, const ModulePW::PW_Basis_K*, ModulePW::PW_Basis*, double*, diff --git a/source/source_pw/module_pwdft/stress_exx.cpp b/source/source_pw/module_pwdft/stress_exx.cpp index 2ff1e221b55..72353923cbb 100644 --- a/source/source_pw/module_pwdft/stress_exx.cpp +++ b/source/source_pw/module_pwdft/stress_exx.cpp @@ -63,7 +63,7 @@ void Stress_PW::stress_exx(ModuleBase::matrix& sigma, resmem_real_op()(pot, rhopw->npw); resmem_real_op()(pot_stress, rhopw->npw); - // hamilt::get_exx_potential(p_kv, wfcpw, wfcpw, rhopw, pot, tpiba, gamma_extrapolation, omega); + // hamilt::get_exx_potential(p_kv, wfcpw, rhopw, pot, tpiba, gamma_extrapolation, omega); // hamilt::get_exx_stress_potential(p_kv, wfcpw, rhopw, pot_stress, tpiba, gamma_extrapolation, omega); // calculate the stress @@ -81,7 +81,7 @@ void Stress_PW::stress_exx(ModuleBase::matrix& sigma, for (int iq = 0; iq < nqs; iq++) { - hamilt::get_exx_potential(p_kv, wfcpw, wfcpw, rhopw, pot, tpiba, gamma_extrapolation, omega, ik, iq, true, exx_info.coulomb_param); + hamilt::get_exx_potential(p_kv, wfcpw, rhopw, pot, tpiba, gamma_extrapolation, omega, ik, iq, true, exx_info.coulomb_param); hamilt::get_exx_stress_potential(p_kv, wfcpw, rhopw, pot_stress, tpiba, gamma_extrapolation, omega, ik, iq, exx_info.coulomb_param); for (int mband = 0; mband < d_psi_in->get_nbands(); mband++) { From 34ec48482d5848ebf95c73889e7df184f5f429ff Mon Sep 17 00:00:00 2001 From: Hongxu Ren Date: Thu, 8 Oct 2026 12:26:17 +0800 Subject: [PATCH 10/25] fix(pw): name the auxiliary-function correction gygi --- docs/advanced/elec_properties/hybrid_nscf.md | 12 +++--- docs/advanced/input_files/input-main.md | 2 +- docs/parameters.yaml | 2 +- .../module_parameter/read_inp_exx_dftu.cpp | 12 +++--- .../test_serial/read_input_item_test.cpp | 2 +- source/source_pw/module_pwdft/op_pw_exx.cpp | 6 +-- tests/integrate/tools/test_hybrid_nscf.py | 39 ++++++++++--------- 7 files changed, 40 insertions(+), 35 deletions(-) diff --git a/docs/advanced/elec_properties/hybrid_nscf.md b/docs/advanced/elec_properties/hybrid_nscf.md index 12fb44f7cce..ec4f2489378 100644 --- a/docs/advanced/elec_properties/hybrid_nscf.md +++ b/docs/advanced/elec_properties/hybrid_nscf.md @@ -123,11 +123,13 @@ an auxiliary-function correction. It uses `exx_gamma_extra false`, which is selected automatically when omitted. Explicit gamma extrapolation with `limits`, and unscreened Fock terms with `limits`, are rejected in PW. -Set `exx_singularity_correction auxiliary` explicitly to retain the historical -PW auxiliary correction (including the existing gamma-extrapolation option). +Set `exx_singularity_correction gygi` explicitly to retain the historical +PW Gygi-Baldereschi auxiliary-function correction (including the existing +gamma-extrapolation option). This is also the default for unscreened PW hybrids; it does not enable -unscreened hybrid NSCF. For screened independent-k targets the auxiliary -correction can cause a jump when a target coincides with a source point. +unscreened hybrid NSCF. For screened independent-k targets the Gygi correction +can cause a jump when a target coincides with a source point. +The name follows [QE's `gygi-baldereschi` terminology](https://www.quantum-espresso.org/Doc/INPUT_PW.html). LCAO-specific `spencer`, `revised_spencer`, `massidda` and `carrier` schemes are not implemented for PW and are rejected rather than silently ignored. @@ -135,7 +137,7 @@ SCF and NSCF must use the same scheme. The scheme is part of the `EXX_SOURCE` configuration, and an incompatible restart is rejected. Regenerate the SCF source before switching schemes; checkpoints from the earlier implementation must also be regenerated. The cross-code results below used the historical -auxiliary scheme and do not constitute validation of the new default. +Gygi scheme and do not constitute validation of the new default. ## Reproducible verification diff --git a/docs/advanced/input_files/input-main.md b/docs/advanced/input_files/input-main.md index b8f16219275..1ad2cf352ac 100644 --- a/docs/advanced/input_files/input-main.md +++ b/docs/advanced/input_files/input-main.md @@ -3307,7 +3307,7 @@ - **Type**: String - **Description**: Scheme for Coulomb singularity / zero-transfer treatment in exact exchange. - limits: use the finite screened Coulomb-kernel limit, without an auxiliary correction. Default for HSE and cwp22 in both PW and LCAO. PW requires screened exchange and exx_gamma_extra=false; the latter defaults to false for this scheme. - - auxiliary: retain the historical PW auxiliary-function correction. PW only; default for unscreened PW hybrids. For independent-k screened hybrid NSCF this can cause discontinuities at source k points. + - gygi: retain the historical PW Gygi-Baldereschi auxiliary-function correction. PW only; default for unscreened PW hybrids. For independent-k screened hybrid NSCF this can cause discontinuities at source k points. - spencer: LCAO spherical truncation, Phys. Rev. B 77, 193110 (2008). - revised_spencer: LCAO, Phys. Rev. Mater. 5, 013807 (2021). - massidda / carrier: LCAO auxiliary singularity corrections. diff --git a/docs/parameters.yaml b/docs/parameters.yaml index 1931e3ade5e..6e4cbda0d06 100644 --- a/docs/parameters.yaml +++ b/docs/parameters.yaml @@ -4757,7 +4757,7 @@ parameters: description: | Scheme for Coulomb singularity / zero-transfer treatment in exact exchange. * limits: use the finite screened Coulomb-kernel limit, without an auxiliary correction. Default for HSE and cwp22 in both PW and LCAO. PW requires screened exchange and exx_gamma_extra=false; the latter defaults to false for this scheme. - * auxiliary: retain the historical PW auxiliary-function correction. PW only; default for unscreened PW hybrids. For independent-k screened hybrid NSCF this can cause discontinuities at source k points. + * gygi: retain the historical PW Gygi-Baldereschi auxiliary-function correction. PW only; default for unscreened PW hybrids. For independent-k screened hybrid NSCF this can cause discontinuities at source k points. * spencer: LCAO spherical truncation, Phys. Rev. B 77, 193110 (2008). * revised_spencer: LCAO, Phys. Rev. Mater. 5, 013807 (2021). * massidda / carrier: LCAO auxiliary singularity corrections. diff --git a/source/source_io/module_parameter/read_inp_exx_dftu.cpp b/source/source_io/module_parameter/read_inp_exx_dftu.cpp index 3d20090280a..2e3111ea5e5 100644 --- a/source/source_io/module_parameter/read_inp_exx_dftu.cpp +++ b/source/source_io/module_parameter/read_inp_exx_dftu.cpp @@ -470,7 +470,7 @@ void ReadInput::item_exx() item.type = "String"; item.description = R"(Scheme for Coulomb singularity / zero-transfer treatment in exact exchange. * limits: use the finite screened Coulomb-kernel limit, without an auxiliary correction. Default for HSE and cwp22 in both PW and LCAO. PW requires screened exchange and exx_gamma_extra=false; the latter defaults to false for this scheme. -* auxiliary: retain the historical PW auxiliary-function correction. PW only; default for unscreened PW hybrids. For independent-k screened hybrid NSCF this can cause discontinuities at source k points. +* gygi: retain the historical PW Gygi-Baldereschi auxiliary-function correction. PW only; default for unscreened PW hybrids. For independent-k screened hybrid NSCF this can cause discontinuities at source k points. * spencer: LCAO spherical truncation, Phys. Rev. B 77, 193110 (2008). * revised_spencer: LCAO, Phys. Rev. Mater. 5, 013807 (2021). * massidda / carrier: LCAO auxiliary singularity corrections. @@ -497,7 +497,7 @@ Use the same scheme for SCF and NSCF. Regenerate the SCF source checkpoint after { if (para.input.basis_type == "pw") { - para.input.exx_singularity_correction = "auxiliary"; + para.input.exx_singularity_correction = "gygi"; } else { @@ -525,9 +525,9 @@ Use the same scheme for SCF and NSCF. Regenerate the SCF source checkpoint after const std::string& scheme = para.input.exx_singularity_correction; if (para.input.basis_type == "pw" && scheme != "default") { - if (scheme != "limits" && scheme != "auxiliary") + if (scheme != "limits" && scheme != "gygi") { - ModuleBase::WARNING_QUIT("ReadInput", "PW exx_singularity_correction must be limits or auxiliary"); + ModuleBase::WARNING_QUIT("ReadInput", "PW exx_singularity_correction must be limits or gygi"); } if (scheme == "limits") { @@ -543,9 +543,9 @@ Use the same scheme for SCF and NSCF. Regenerate the SCF source checkpoint after } } } - else if (para.input.basis_type != "pw" && scheme == "auxiliary") + else if (para.input.basis_type != "pw" && scheme == "gygi") { - ModuleBase::WARNING_QUIT("ReadInput", "exx_singularity_correction auxiliary is only supported for PW"); + ModuleBase::WARNING_QUIT("ReadInput", "exx_singularity_correction gygi is only supported for PW"); } }; this->add_item(item); diff --git a/source/source_io/test_serial/read_input_item_test.cpp b/source/source_io/test_serial/read_input_item_test.cpp index f74f3915210..7e42d5d6e3c 100644 --- a/source/source_io/test_serial/read_input_item_test.cpp +++ b/source/source_io/test_serial/read_input_item_test.cpp @@ -1760,7 +1760,7 @@ TEST_F(InputTest, Item_test2) TestParameters::input(param).dft_functional = "PBE0"; TestParameters::input(param).exx_singularity_correction = "default"; it->second.reset_value(it->second, param); - EXPECT_EQ(TestParameters::input(param).exx_singularity_correction, "auxiliary"); + EXPECT_EQ(TestParameters::input(param).exx_singularity_correction, "gygi"); TestParameters::input(param).dft_functional = "HSE"; TestParameters::input(param).exx_singularity_correction = "default"; diff --git a/source/source_pw/module_pwdft/op_pw_exx.cpp b/source/source_pw/module_pwdft/op_pw_exx.cpp index d97d0ab0c9e..b05d003422e 100644 --- a/source/source_pw/module_pwdft/op_pw_exx.cpp +++ b/source/source_pw/module_pwdft/op_pw_exx.cpp @@ -123,7 +123,7 @@ OperatorEXXPW::OperatorEXXPW(const int* isk_in, for (auto param: param_erfc) { double correction = 0.0; - if (param.at("singularity_correction") == "auxiliary") + if (param.at("singularity_correction") == "gygi") { const double omega = std::stod(param.at("omega")); correction = exx_divergence(Conv_Coulomb_Pot_K::Coulomb_Type::Erfc, @@ -260,7 +260,7 @@ void OperatorEXXPW::set_source(const ModulePW::PW_Basis_K& source_bas source_points_ = &source_points; psi = source_psi; wg = &source_weights; - // Cache the auxiliary correction on the frozen source mesh, rather than + // Cache the Gygi-Baldereschi auxiliary correction on the frozen source mesh, rather than // the independent target path. Limits keeps this correction at zero. const auto screened = coulomb_param.find(Conv_Coulomb_Pot_K::Coulomb_Type::Erfc); if (screened != coulomb_param.end()) @@ -269,7 +269,7 @@ void OperatorEXXPW::set_source(const ModulePW::PW_Basis_K& source_bas { const auto& param = screened->second[i]; erfc_div[i] = 0.0; - if (param.at("singularity_correction") == "auxiliary") + if (param.at("singularity_correction") == "gygi") { const double omega = std::stod(param.at("omega")); erfc_div[i] = exx_divergence(Conv_Coulomb_Pot_K::Coulomb_Type::Erfc, diff --git a/tests/integrate/tools/test_hybrid_nscf.py b/tests/integrate/tools/test_hybrid_nscf.py index 7d64e3d5a7d..79f40ab316d 100644 --- a/tests/integrate/tools/test_hybrid_nscf.py +++ b/tests/integrate/tools/test_hybrid_nscf.py @@ -164,10 +164,13 @@ def verify_correction(executable, root, gpu=False): print(f"{device} default/explicit limits, Gamma +/-1e-3: max difference {delta:.3g} eV") mismatch = create_case(root, f"{device}_correction_mismatch", - extra.replace("correction limits", "correction auxiliary")) + extra.replace("correction limits", "correction gygi")) run(executable, mismatch, [], "EXX source") bad = create_case(root, f"{device}_bad_correction", extra.replace("correction limits", "correction spencer")) - run(executable, bad, [], "PW exx_singularity_correction must be limits or auxiliary") + run(executable, bad, [], "PW exx_singularity_correction must be limits or gygi") + old_name = create_case(root, f"{device}_obsolete_correction", + extra.replace("correction limits", "correction auxiliary")) + run(executable, old_name, [], "PW exx_singularity_correction must be limits or gygi") gamma = create_case(root, f"{device}_limits_gamma", extra) text = (gamma / "INPUT").read_text().replace("exx_gamma_extra false", "exx_gamma_extra true") (gamma / "INPUT").write_text(text) @@ -177,22 +180,22 @@ def verify_correction(executable, root, gpu=False): (unscreened / "INPUT").write_text(text) run(executable, unscreened, [], "PW limits requires screened exchange") - auxiliary = create_case(root, f"auxiliary_{device}_scf", - "calculation scf\nout_chg 1\nout_wfc_pw 2\nexx_singularity_correction auxiliary\n") - text = (auxiliary / "INPUT").read_text().replace("device cpu", f"device {device}") - (auxiliary / "INPUT").write_text(text) - run(executable, auxiliary, []) - aux_source = auxiliary / "OUT.hybrid" - aux_target = create_case(root, f"auxiliary_{device}_nscf", - f"calculation nscf\nread_file_dir {aux_source}\nexx_singularity_correction auxiliary\n") + gygi = create_case(root, f"gygi_{device}_scf", + "calculation scf\nout_chg 1\nout_wfc_pw 2\nexx_singularity_correction gygi\n") + text = (gygi / "INPUT").read_text().replace("device cpu", f"device {device}") + (gygi / "INPUT").write_text(text) + run(executable, gygi, []) + aux_source = gygi / "OUT.hybrid" + aux_target = create_case(root, f"gygi_{device}_nscf", + f"calculation nscf\nread_file_dir {aux_source}\nexx_singularity_correction gygi\n") text = (aux_target / "INPUT").read_text().replace("device cpu", f"device {device}") (aux_target / "INPUT").write_text(text) run(executable, aux_target, []) - assert max_difference(bands(auxiliary), bands(aux_target)) < 2e-4 + assert max_difference(bands(gygi), bands(aux_target)) < 2e-4 # Cross the zero-transfer threshold with the same source: the historical - # auxiliary scheme must exhibit the jump this test is intended to detect. - aux_near = create_case(root, f"auxiliary_{device}_continuity", - f"calculation nscf\nread_file_dir {aux_source}\nexx_singularity_correction auxiliary\n", + # gygi scheme must exhibit the jump this test is intended to detect. + aux_near = create_case(root, f"gygi_{device}_continuity", + f"calculation nscf\nread_file_dir {aux_source}\nexx_singularity_correction gygi\n", near_gamma) text = (aux_near / "INPUT").read_text().replace("device cpu", f"device {device}") (aux_near / "INPUT").write_text(text) @@ -200,10 +203,10 @@ def verify_correction(executable, root, gpu=False): aux_values = bands(aux_near) aux_jump = max(max_difference([aux_values[0]], [row]) for row in aux_values[1:]) assert aux_jump > 5e-3, "Auxiliary control failed to expose the zero-transfer jump" - shift = max_difference(bands(scf), bands(auxiliary)) - assert shift > 1e-5, "limits and auxiliary unexpectedly produced identical SCF bands" - print(f"{device} auxiliary control jump near Gamma: {aux_jump:.3g} eV") - print(f"{device} auxiliary SCF/NSCF matched; limits/auxiliary SCF difference {shift:.3g} eV") + shift = max_difference(bands(scf), bands(gygi)) + assert shift > 1e-5, "limits and gygi unexpectedly produced identical SCF bands" + print(f"{device} gygi control jump near Gamma: {aux_jump:.3g} eV") + print(f"{device} gygi SCF/NSCF matched; limits/gygi SCF difference {shift:.3g} eV") print("mismatched scheme, unsupported scheme, gamma and unscreened limits rejected") From 6250df90827c42c063a55d62f4f7197da8a35e6a Mon Sep 17 00:00:00 2001 From: Hongxu Ren Date: Thu, 8 Oct 2026 12:40:17 +0800 Subject: [PATCH 11/25] Add readers for existing PW source metadata and eig_occ occupations --- source/source_io/module_wf/exx_source_io.cpp | 147 +++++++++++++++++++ source/source_io/module_wf/exx_source_io.h | 23 +++ source/source_io/test/test_exx_source_io.cpp | 114 ++++++++++++++ 3 files changed, 284 insertions(+) diff --git a/source/source_io/module_wf/exx_source_io.cpp b/source/source_io/module_wf/exx_source_io.cpp index d652970c289..611e19a725d 100644 --- a/source/source_io/module_wf/exx_source_io.cpp +++ b/source/source_io/module_wf/exx_source_io.cpp @@ -3,7 +3,10 @@ #include "source_base/matrix.h" #include "source_cell/klist.h" +#include #include +#include +#include #include #include #include @@ -111,3 +114,147 @@ void ModuleIO::read_exx_source(std::istream& in, throw std::runtime_error("Unexpected trailing EXX source checkpoint data"); } } + +namespace +{ +template +void read_binary(std::istream& in, T& value) +{ + in.read(reinterpret_cast(&value), sizeof(T)); + if (!in) + { + throw std::runtime_error("Missing or truncated EXX source wavefunction"); + } +} +} + +ModuleIO::ExxSourceHeader ModuleIO::read_exx_source_header(std::istream& in) +{ + ExxSourceHeader header{}; + int record = 0; + read_binary(in, record); + if (record != 72) + { + throw std::runtime_error("Invalid EXX source wavefunction header"); + } + read_binary(in, header.ik); + read_binary(in, header.nks); + for (double& coordinate : header.kvec_c) + { + read_binary(in, coordinate); + if (!std::isfinite(coordinate)) + { + throw std::runtime_error("Invalid EXX source wavefunction k point"); + } + } + read_binary(in, header.weight); + read_binary(in, header.npw); + read_binary(in, header.nbands); + read_binary(in, header.ecutwfc); + read_binary(in, header.lat0); + read_binary(in, header.tpiba); + read_binary(in, record); + if (record != 72 || header.ik <= 0 || header.nks < header.ik || header.nks > 100000 + || header.nbands <= 0 || header.nbands > 100000 || header.npw <= 0 + || !std::isfinite(header.weight) || header.weight <= 0 + || !std::isfinite(header.ecutwfc) || header.ecutwfc <= 0 + || !std::isfinite(header.lat0) || header.lat0 <= 0 + || !std::isfinite(header.tpiba) || header.tpiba <= 0) + { + throw std::runtime_error("Invalid EXX source wavefunction dimensions or metadata"); + } + // Two 72-byte records, a Miller-index record, and complex band records. + const long long expected_bytes = 160LL + 8 + 12LL * header.npw + + header.nbands * (8LL + 16LL * header.npw); + in.seekg(0, std::ios::end); + if (!in || in.tellg() != expected_bytes) + { + throw std::runtime_error("Truncated or invalid EXX source wavefunction size"); + } + return header; +} + +void ModuleIO::read_exx_source_occupations(std::istream& in, + const std::vector& headers, + int nspin, + ModuleBase::matrix& weights) +{ + const int spin_mult = nspin == 2 ? 2 : 1; + const int nks = headers.size(); + if ((nspin != 1 && nspin != 2) || nks == 0 || nks % spin_mult != 0) + { + throw std::runtime_error("Invalid EXX source spin dimensions"); + } + const int nq = nks / spin_mult; + const int nbands = headers.front().nbands; + if (static_cast(nks) * nbands > 100000000) + { + throw std::runtime_error("Invalid EXX source occupation dimensions"); + } + std::string line; + std::getline(in, line); + std::getline(in, line); + std::getline(in, line); + int saved_spin = 0; + if (std::sscanf(line.c_str(), " Spin number %d", &saved_spin) != 1 || saved_spin != nspin) + { + throw std::runtime_error("Missing or incompatible EXX source eig_occ.txt"); + } + weights.create(nks, nbands); + const double expected_weight = nspin == 1 ? 2.0 / nq : 1.0 / nq; + for (int iq = 0; iq < nks; ++iq) + { + const auto& header = headers[iq]; + do + { + if (!std::getline(in, line)) + { + throw std::runtime_error("Truncated EXX source eig_occ.txt"); + } + } while (line.find_first_not_of(" \t\r") == std::string::npos); + int spin = 0; + int index = 0; + int total = 0; + int npw = 0; + double q[3] = {}; + const int fields = std::sscanf(line.c_str(), + " spin=%d k-point=%d/%d Cartesian=%lf %lf %lf (%d plane wave)", + &spin, &index, &total, &q[0], &q[1], &q[2], &npw); + if (fields != 7 || spin != iq / nq + 1 || index != iq % nq + 1 || total != nq + || npw != header.npw || header.ik != iq + 1 || header.nks != nks + || header.nbands != nbands || std::abs(header.weight - expected_weight) > 1e-10) + { + throw std::runtime_error("EXX source requires matching eig_occ.txt and a complete uniform q mesh"); + } + for (int axis = 0; axis < 3; ++axis) + { + // eig_occ.txt prints Cartesian coordinates with at least eight significant digits. + const double tolerance = 5e-8 * std::max(1.0, std::abs(header.kvec_c[axis])); + if (!std::isfinite(q[axis]) || std::abs(q[axis] - header.kvec_c[axis]) > tolerance) + { + throw std::runtime_error("EXX source eig_occ.txt k point differs from wavefunction"); + } + } + for (int ib = 0; ib < nbands; ++ib) + { + std::getline(in, line); + std::istringstream band(line); + double energy = 0; + band >> index >> energy >> weights(iq, ib); + const bool parsed = static_cast(band); + std::string extra; + const bool trailing = static_cast(band >> extra); + if (!parsed || trailing || index != ib + 1 || !std::isfinite(energy) + || !std::isfinite(weights(iq, ib)) || weights(iq, ib) < 0 + || weights(iq, ib) > expected_weight + 1e-10) + { + throw std::runtime_error("Invalid EXX source occupation in eig_occ.txt"); + } + } + } + in >> std::ws; + if (!in.eof()) + { + throw std::runtime_error("Unexpected trailing EXX source eig_occ.txt data; use a single SCF snapshot"); + } +} diff --git a/source/source_io/module_wf/exx_source_io.h b/source/source_io/module_wf/exx_source_io.h index 1e8394a31ff..94905dbab95 100644 --- a/source/source_io/module_wf/exx_source_io.h +++ b/source/source_io/module_wf/exx_source_io.h @@ -3,6 +3,7 @@ #include #include +#include class K_Vectors; namespace ModuleBase @@ -12,6 +13,28 @@ class matrix; namespace ModuleIO { +// Metadata already present in the existing binary PW wavefunction format. +struct ExxSourceHeader +{ + int ik; + int nks; + int npw; + int nbands; + double kvec_c[3]; + double weight; + double ecutwfc; + double lat0; + double tpiba; +}; + +ExxSourceHeader read_exx_source_header(std::istream& in); + +// Read the existing, k-weighted occupation column without changing its format. +void read_exx_source_occupations(std::istream& in, + const std::vector& headers, + int nspin, + ModuleBase::matrix& weights); + // A versioned companion to WAVEFUNC*.dat, containing the frozen SCF ensemble. // Streams keep serialization independent of process ownership and file paths. void write_exx_source(std::ostream& out, diff --git a/source/source_io/test/test_exx_source_io.cpp b/source/source_io/test/test_exx_source_io.cpp index ffd05a5fccb..5fc645f7f4f 100644 --- a/source/source_io/test/test_exx_source_io.cpp +++ b/source/source_io/test/test_exx_source_io.cpp @@ -5,6 +5,7 @@ #include "gtest/gtest.h" #include +#include #include #include @@ -90,3 +91,116 @@ TEST(ExxSourceIO, RejectsTruncationInvalidOccupationsAndTrailingData) std::istringstream negative(invalid); EXPECT_THROW(ModuleIO::read_exx_source(negative, points, weights, 1, 15, 15, 15, "HSE:10:40"), std::runtime_error); } + +namespace +{ +std::vector source_headers(int nspin) +{ + const int nks = nspin == 2 ? 4 : 2; + std::vector headers(nks); + for (int iq = 0; iq < nks; ++iq) + { + auto& header = headers[iq]; + header.ik = iq + 1; + header.nks = nks; + header.npw = 100; + header.nbands = 3; + header.kvec_c[0] = 0.123456789123456 * (iq % 2); + header.weight = nspin == 1 ? 1.0 : 0.5; + } + return headers; +} + +std::string eig_occ(int nspin) +{ + const auto headers = source_headers(nspin); + std::ostringstream out; + out << "1 # ionic step\n Electronic state energy (eV) and occupations\n Spin number " << nspin << '\n'; + for (int iq = 0; iq < headers.size(); ++iq) + { + const auto& header = headers[iq]; + out << " spin=" << iq / 2 + 1 << " k-point=" << iq % 2 + 1 + << "/2 Cartesian=" << std::setprecision(8) << header.kvec_c[0] + << " 0 0 (100 plane wave)\n"; + out << "1 -1 " << header.weight << "\n2 0 " << header.weight * 0.125 << "\n3 1 0\n\n"; + } + return out.str(); +} +} + +TEST(ExxSourceIO, ReadsExistingWeightedOccupationsForBothSpins) +{ + for (int nspin = 1; nspin <= 2; ++nspin) + { + const auto headers = source_headers(nspin); + std::istringstream in(eig_occ(nspin)); + ModuleBase::matrix weights; + ModuleIO::read_exx_source_occupations(in, headers, nspin, weights); + EXPECT_EQ(weights.nr, headers.size()); + EXPECT_EQ(weights.nc, 3); + EXPECT_DOUBLE_EQ(weights(1, 1), headers[1].weight * 0.125); + } +} + +TEST(ExxSourceIO, RejectsInvalidExistingOccupationFiles) +{ + const auto headers = source_headers(1); + ModuleBase::matrix weights; + const std::string saved = eig_occ(1); + std::istringstream truncated(saved.substr(0, saved.size() - 6)); + EXPECT_THROW(ModuleIO::read_exx_source_occupations(truncated, headers, 1, weights), std::runtime_error); + std::istringstream trailing(saved + saved); + EXPECT_THROW(ModuleIO::read_exx_source_occupations(trailing, headers, 1, weights), std::runtime_error); + std::istringstream wrong_spin(saved); + EXPECT_THROW(ModuleIO::read_exx_source_occupations(wrong_spin, headers, 2, weights), std::runtime_error); + auto changed = headers; + changed[1].kvec_c[0] += 0.1; + std::istringstream wrong_coordinates(saved); + EXPECT_THROW(ModuleIO::read_exx_source_occupations(wrong_coordinates, changed, 1, weights), std::runtime_error); + std::string invalid = saved; + invalid.replace(invalid.find("0.125"), 5, "-0.25"); + std::istringstream negative(invalid); + EXPECT_THROW(ModuleIO::read_exx_source_occupations(negative, headers, 1, weights), std::runtime_error); +} + +TEST(ExxSourceIO, ReadsExistingBinaryWavefunctionHeader) +{ + // Native binary record layout from write_wfc_pw; no new wavefunction format. + std::ostringstream out(std::ios::binary); + const int record = 72; + const int ik = 1; + const int nks = 2; + const int npw = 1; + const int nbands = 3; + const double coordinate = 0.123456789123456; + const double weight = 1; + const double cutoff = 10; + const double lattice = 5; + const double tpiba = 1.256637061435917; + out.write(reinterpret_cast(&record), sizeof(record)); + out.write(reinterpret_cast(&ik), sizeof(ik)); + out.write(reinterpret_cast(&nks), sizeof(nks)); + for (int axis = 0; axis < 3; ++axis) + { + out.write(reinterpret_cast(&coordinate), sizeof(coordinate)); + } + out.write(reinterpret_cast(&weight), sizeof(weight)); + out.write(reinterpret_cast(&npw), sizeof(npw)); + out.write(reinterpret_cast(&nbands), sizeof(nbands)); + out.write(reinterpret_cast(&cutoff), sizeof(cutoff)); + out.write(reinterpret_cast(&lattice), sizeof(lattice)); + out.write(reinterpret_cast(&tpiba), sizeof(tpiba)); + out.write(reinterpret_cast(&record), sizeof(record)); + std::string saved = out.str(); + saved.resize(160 + 8 + 12 * npw + nbands * (8 + 16 * npw), '\0'); + std::istringstream in(saved, std::ios::binary); + const auto header = ModuleIO::read_exx_source_header(in); + EXPECT_EQ(header.nbands, 3); + EXPECT_DOUBLE_EQ(header.kvec_c[0], coordinate); + EXPECT_DOUBLE_EQ(header.weight, weight); + std::istringstream truncated(saved.substr(0, saved.size() - 1), std::ios::binary); + EXPECT_THROW(ModuleIO::read_exx_source_header(truncated), std::runtime_error); + saved[0] = 0; + std::istringstream invalid(saved, std::ios::binary); + EXPECT_THROW(ModuleIO::read_exx_source_header(invalid), std::runtime_error); +} From 19ee525c5b04898f902f586ca028c84c69a9a0a7 Mon Sep 17 00:00:00 2001 From: Hongxu Ren Date: Thu, 8 Oct 2026 12:45:12 +0800 Subject: [PATCH 12/25] Reuse standard SCF outputs for hybrid NSCF without changing existing IO --- docs/advanced/elec_properties/hybrid_nscf.md | 44 ++-- docs/advanced/input_files/input-main.md | 4 +- docs/parameters.yaml | 4 +- source/source_esolver/CMakeLists.txt | 1 + source/source_esolver/esolver_ks_pw.cpp | 10 - source/source_esolver/pw_hybrid_nscf.cpp | 234 +++++++++++++----- source/source_esolver/pw_hybrid_nscf.h | 22 -- .../pw_hybrid_source.cpp} | 112 +-------- source/source_esolver/pw_hybrid_source.h | 37 +++ source/source_esolver/test/CMakeLists.txt | 6 + .../test/test_pw_hybrid_source.cpp | 122 +++++++++ source/source_io/CMakeLists.txt | 1 - .../module_parameter/read_inp_exx_dftu.cpp | 2 +- .../module_parameter/read_inp_sys.cpp | 2 +- source/source_io/module_wf/exx_source_io.h | 58 ----- source/source_io/test/CMakeLists.txt | 8 - source/source_io/test/test_exx_source_io.cpp | 206 --------------- tests/integrate/tools/test_hybrid_nscf.py | 52 ++-- 18 files changed, 401 insertions(+), 524 deletions(-) rename source/{source_io/module_wf/exx_source_io.cpp => source_esolver/pw_hybrid_source.cpp} (57%) create mode 100644 source/source_esolver/pw_hybrid_source.h create mode 100644 source/source_esolver/test/test_pw_hybrid_source.cpp delete mode 100644 source/source_io/module_wf/exx_source_io.h delete mode 100644 source/source_io/test/test_exx_source_io.cpp diff --git a/docs/advanced/elec_properties/hybrid_nscf.md b/docs/advanced/elec_properties/hybrid_nscf.md index ec4f2489378..eed6f6ccd05 100644 --- a/docs/advanced/elec_properties/hybrid_nscf.md +++ b/docs/advanced/elec_properties/hybrid_nscf.md @@ -33,14 +33,14 @@ cal_force 0 cal_stress 0 ``` -The output directory contains the charge density, `wfk*_pw.dat` binary -wavefunctions and `EXX_SOURCE`. The versioned companion file records source -q coordinates, spin labels, k weights, actual weighted occupations, source band -count, FFT dimensions and exchange configuration. Fractional occupations are -preserved. Checkpoints from older runs without `EXX_SOURCE` must be regenerated. -An existing companion is invalidated before SCF wavefunctions are overwritten; -an unconverged calculation does not produce a usable new companion. Reaching -the EXX outer iteration limit is conservatively treated as unconverged here. +The output directory contains the charge density, existing `wfk*_pw.dat` +binary wavefunctions and `eig_occ.txt`. No new checkpoint format or companion +file is required. Precise source q coordinates, k weights and band count come +from the existing wavefunction headers; the occupation column in `eig_occ.txt` +already contains the k-weighted occupations required by EXX, including fractional +occupations. Use files from the same converged SCF calculation. The workflow +consumes these outputs without changing the existing wavefunction or occupation +writers/readers. ## Solve target states @@ -71,9 +71,14 @@ SCF may run on CPU or GPU. The binary checkpoint format is shared between these devices. ROCm NSCF remains disabled pending backend verification. Use `OMP_NUM_THREADS=1` for runtime tests. -Missing, truncated or incompatible companion files and invalid occupations -produce an error. The existing wavefunction reader additionally verifies k -coordinates, cell, source band count and plane-wave count. NSCF does not update +Missing or truncated wavefunctions/occupation files and invalid occupations +produce an error. Source dimensions, spin order, uniform q weights and occupation +K points must agree. The existing wavefunction reader additionally verifies k +coordinates, cell, source band count and plane-wave count. `INPUT.info`, when +available, is used only to warn about exchange configuration differences. Older +outputs without this metadata are accepted with a warning; regeneration is not +required solely because metadata is missing. +NSCF does not update the frozen ensemble or run the EXX SCF outer loop. Its target occupations are used for ordinary output only, and its printed total energy is not a new self-consistent hybrid total energy. @@ -133,17 +138,18 @@ The name follows [QE's `gygi-baldereschi` terminology](https://www.quantum-espre LCAO-specific `spencer`, `revised_spencer`, `massidda` and `carrier` schemes are not implemented for PW and are rejected rather than silently ignored. -SCF and NSCF must use the same scheme. The scheme is part of the `EXX_SOURCE` -configuration, and an incompatible restart is rejected. Regenerate the SCF -source before switching schemes; checkpoints from the earlier implementation -must also be regenerated. The cross-code results below used the historical +Use the same scheme in SCF and NSCF for consistent bands. A different scheme +produces a warning and continues with the existing frozen source and the current +NSCF exchange settings. This also permits deliberate comparisons between schemes. + +The cross-code results below used the historical Gygi scheme and do not constitute validation of the new default. ## Reproducible verification ```bash -cmake --build build --target MODULE_IO_exx_source_io -j 8 -OMP_NUM_THREADS=1 ctest --test-dir build -V -R '^MODULE_IO_exx_source_io$' +cmake --build build --target MODULE_ESOLVER_pw_hybrid_source -j 8 +OMP_NUM_THREADS=1 ctest --test-dir build -V -R '^MODULE_ESOLVER_pw_hybrid_source$' python3 tests/integrate/tools/test_hybrid_nscf.py ./build/abacus --mpi-ranks 2 ``` @@ -174,13 +180,13 @@ at the printed precision, as did all eight bands at nine Si L-Gamma-X points using the same frozen CPU source (`20 Ry`, `2x2x2` source mesh). The Si check compared raw eigenvalues without an energy shift. The three-band H single-precision GPU path differed by at most `5.76e-5 eV` from double precision. -The CPU build also passed its checkpoint unit tests and NSCF integration test. +The CPU build also passed its source-adapter unit tests and NSCF integration test. This validates device consistency; it does not change the cross-code convergence limits below. On the initial local two-q-point, 10 Ry test, the same-mesh SCF/NSCF maximum band difference was `3.7e-5 eV`; the shared Gamma point and serial/two-rank NSCF -results agreed to printed precision. Three checkpoint unit tests passed. +results agreed to printed precision. Three source-adapter unit tests passed. A QE SCF comparison at this low cutoff showed band differences up to about `0.03 eV`; that H test alone does not establish cross-code agreement. diff --git a/docs/advanced/input_files/input-main.md b/docs/advanced/input_files/input-main.md index 1ad2cf352ac..d793e4e4bb0 100644 --- a/docs/advanced/input_files/input-main.md +++ b/docs/advanced/input_files/input-main.md @@ -637,7 +637,7 @@ - **Description**: Specify the type of calculation. - scf: perform self-consistent electronic structure calculations - - nscf: perform non-self-consistent electronic structure calculations. A charge density file is required. PW screened hybrid NSCF additionally reads EXX_SOURCE and binary SCF wavefunctions from read_file_dir; see the hybrid NSCF workflow documentation. The initial implementation supports CPU or CUDA GPU and requires kpar=bndpar=1, nspin=1/2, symmetry=-1/0, exxace=false, exx_gamma_extra=false and cal_force=cal_stress=false. + - nscf: perform non-self-consistent electronic structure calculations. A charge density file is required. PW screened hybrid NSCF additionally reads eig_occ.txt and existing binary SCF wavefunctions from read_file_dir; see the hybrid NSCF workflow documentation. The initial implementation supports CPU or CUDA GPU and requires kpar=bndpar=1, nspin=1/2, symmetry=-1/0, exxace=false, exx_gamma_extra=false and cal_force=cal_stress=false. - relax: perform structure relaxation calculations, the relax_nmax parameter depicts the maximal number of ionic iterations - cell-relax: perform cell relaxation calculations - md: perform molecular dynamics simulations @@ -3311,7 +3311,7 @@ - spencer: LCAO spherical truncation, Phys. Rev. B 77, 193110 (2008). - revised_spencer: LCAO, Phys. Rev. Mater. 5, 013807 (2021). - massidda / carrier: LCAO auxiliary singularity corrections. - Use the same scheme for SCF and NSCF. Regenerate the SCF source checkpoint after changing schemes. + Use the same scheme for consistent SCF and NSCF bands. A source configuration mismatch produces a warning and does not prevent reading the existing SCF files. - **Default**: default [back to top](#full-list-of-input-keywords) diff --git a/docs/parameters.yaml b/docs/parameters.yaml index 6e4cbda0d06..52d176783f2 100644 --- a/docs/parameters.yaml +++ b/docs/parameters.yaml @@ -32,7 +32,7 @@ parameters: Specify the type of calculation. * scf: perform self-consistent electronic structure calculations - * nscf: perform non-self-consistent electronic structure calculations. A charge density file is required. PW screened hybrid NSCF additionally reads EXX_SOURCE and binary SCF wavefunctions from read_file_dir; see the hybrid NSCF workflow documentation. The initial implementation supports CPU or CUDA GPU and requires kpar=bndpar=1, nspin=1/2, symmetry=-1/0, exxace=false, exx_gamma_extra=false and cal_force=cal_stress=false. + * nscf: perform non-self-consistent electronic structure calculations. A charge density file is required. PW screened hybrid NSCF additionally reads eig_occ.txt and existing binary SCF wavefunctions from read_file_dir; see the hybrid NSCF workflow documentation. The initial implementation supports CPU or CUDA GPU and requires kpar=bndpar=1, nspin=1/2, symmetry=-1/0, exxace=false, exx_gamma_extra=false and cal_force=cal_stress=false. * relax: perform structure relaxation calculations, the relax_nmax parameter depicts the maximal number of ionic iterations * cell-relax: perform cell relaxation calculations * md: perform molecular dynamics simulations @@ -4761,7 +4761,7 @@ parameters: * spencer: LCAO spherical truncation, Phys. Rev. B 77, 193110 (2008). * revised_spencer: LCAO, Phys. Rev. Mater. 5, 013807 (2021). * massidda / carrier: LCAO auxiliary singularity corrections. - Use the same scheme for SCF and NSCF. Regenerate the SCF source checkpoint after changing schemes. + Use the same scheme for consistent SCF and NSCF bands. A source configuration mismatch produces a warning and does not prevent reading the existing SCF files. default_value: default unit: "" availability: "" diff --git a/source/source_esolver/CMakeLists.txt b/source/source_esolver/CMakeLists.txt index 32872777e18..059b0540a0b 100644 --- a/source/source_esolver/CMakeLists.txt +++ b/source/source_esolver/CMakeLists.txt @@ -4,6 +4,7 @@ list(APPEND objects esolver_fp.cpp esolver_ks_pw.cpp pw_hybrid_nscf.cpp + pw_hybrid_source.cpp esolver_ks_pw_tddft.cpp esolver_ks_lcaopw.cpp esolver_sdft_pw.cpp diff --git a/source/source_esolver/esolver_ks_pw.cpp b/source/source_esolver/esolver_ks_pw.cpp index a994d4139e2..6fb4fdda12f 100644 --- a/source/source_esolver/esolver_ks_pw.cpp +++ b/source/source_esolver/esolver_ks_pw.cpp @@ -101,8 +101,6 @@ void ESolver_KS_PW::before_all_runners(BaseCell& basecell, const Inpu this->solvent, inp); - invalidate_exx_source(inp, this->general_exx_info_, *this->pw_wfc, PARAM.globalv.global_out_dir); - this->stp.before_runner(ucell, this->kv, this->sf, *this->pw_wfc, this->ppcell.lmaxkb, *this->inp_); ModuleBase::GlobalFunc::DONE(GlobalV::ofs_running, "INIT BASIS"); @@ -378,14 +376,6 @@ void ESolver_KS_PW::after_scf(UnitCell& ucell, const int istep, const this->Pgrid, *this->inp_); - const bool exchange_converged = !this->exx_helper->get_op_first_iter() - && this->exx_helper->iteration_count() < this->inp_->exx_hybrid_step; - if (conv_esolver && exchange_converged) - { - save_exx_source(*this->inp_, this->general_exx_info_, this->kv, this->pelec->wg, - *this->pw_wfc, PARAM.globalv.global_out_dir); - } - ModuleBase::timer::end("ESolver_KS_PW", "after_scf"); } diff --git a/source/source_esolver/pw_hybrid_nscf.cpp b/source/source_esolver/pw_hybrid_nscf.cpp index d3bbd6700b9..96360b126fb 100644 --- a/source/source_esolver/pw_hybrid_nscf.cpp +++ b/source/source_esolver/pw_hybrid_nscf.cpp @@ -1,15 +1,15 @@ #include "pw_hybrid_nscf.h" #include "esolver_ks_pw.h" -#include "source_io/module_wf/exx_source_io.h" +#include "pw_hybrid_source.h" #include "source_io/module_wf/read_wfc_pw.h" #include "source_base/module_out/filename.h" #include "source_hamilt/module_xc/general_exx_info.h" #include "source_pw/module_pwdft/exx_helper.h" -#include -#include #include -#include +#include +#include +#include #include #include @@ -17,32 +17,115 @@ namespace ModuleESolver { namespace { -std::string exx_restart_configuration(const Input_para& inp, const General_Exx_Info& info) +// Check the stored Miller mapping before delegating coefficient loading to the unchanged IO reader. +void validate_source_grid(const std::string& filename, const ModulePW::PW_Basis_K& basis, int iq) { - std::ostringstream out; - out << std::setprecision(17) << inp.dft_functional << ':' << inp.ecutwfc << ':' - << info.ecut_exx << ':' << info.hybrid_alpha << ':' << info.gamma_extrapolation; - for (const auto& kernel : info.coulomb_param) + std::ifstream in(filename, std::ios::binary); + const auto header = read_exx_source_header(in); + in.seekg(160); + int record = 0; + in.read(reinterpret_cast(&record), sizeof(record)); + if (record != 12LL * header.npw) { - out << ':' << static_cast(kernel.first); - for (const auto& term : kernel.second) + throw std::runtime_error("Invalid EXX source Miller record"); + } + const int grid[3] = {basis.nx, basis.ny, basis.nz}; + std::set indices; + for (int ig = 0; ig < header.npw; ++ig) + { + int miller[3] = {}; + ModuleBase::Vector3 direct_g; + for (int axis = 0; axis < 3; ++axis) { - for (const auto& parameter : term) + in.read(reinterpret_cast(&miller[axis]), sizeof(int)); + if (!in || miller[axis] < 0 || miller[axis] >= grid[axis]) { - out << ':' << parameter.first << '=' << parameter.second; + throw std::runtime_error("EXX source Miller index is incompatible with FFT grid"); } + direct_g[axis] = miller[axis] <= grid[axis] / 2 ? miller[axis] : miller[axis] - grid[axis]; + } + const auto gk = direct_g * basis.G + basis.kvec_c[iq]; + const long long index = (static_cast(miller[0]) * basis.ny + miller[1]) * basis.nz + miller[2]; + if (gk.norm2() > basis.gk_ecut * (1.0 + 1e-10) || !indices.insert(index).second) + { + throw std::runtime_error("EXX source Miller mapping is incompatible with FFT basis"); } } - return out.str(); -} } -namespace -{ -bool checkpoint_output_enabled(const Input_para& inp) +void warn_source_configuration(const Input_para& inp, const std::string& readin_dir) { - return inp.out_wfc_pw == 2 && inp.out_freq_ion == 0 && inp.kpar == 1 - && inp.bndpar == 1 && inp.nspin != 4 && inp.symmetry != "1"; + std::map expected; + expected["dft_functional"] = inp.dft_functional; + expected["exx_singularity_correction"] = inp.exx_singularity_correction; + const std::vector>> terms = { + {"exx_erfc_alpha", inp.exx_erfc_alpha}, + {"exx_erfc_omega", inp.exx_erfc_omega}, + {"exx_fock_alpha", inp.exx_fock_alpha}}; + for (const auto& term : terms) + { + std::ostringstream value; + for (const auto& number : term.second) + { + value << number << ' '; + } + expected[term.first] = value.str(); + } + std::ostringstream cutoff; + cutoff << inp.ecutexx; + expected["ecutexx"] = cutoff.str(); + expected["exx_gamma_extra"] = inp.exx_gamma_extra ? "1" : "0"; + std::ifstream input(readin_dir + "INPUT.info"); + std::string line; + std::map saved; + while (std::getline(input, line)) + { + line = line.substr(0, line.find('#')); + std::istringstream record(line); + std::string key; + record >> key; + if (expected.count(key)) + { + std::getline(record, saved[key]); + } + } + for (const auto& item : expected) + { + if (!saved.count(item.first)) + { + ModuleBase::WARNING("ESolver_KS_PW", "EXX source configuration is incomplete or unavailable in INPUT.info; " + "continuing with existing wavefunctions and eig_occ.txt. Verify the source SCF settings."); + return; + } + std::istringstream original(saved[item.first]); + std::istringstream current(item.second); + std::string source_value; + std::string target_value; + bool mismatch = false; + while (original >> source_value) + { + if (!(current >> target_value)) + { + mismatch = true; + break; + } + if (source_value != target_value) + { + mismatch = true; + } + } + if (current >> target_value) + { + mismatch = true; + } + if (mismatch) + { + const std::string message = "EXX source configuration differs for " + item.first + + "; continuing with the frozen SCF source and current NSCF exchange settings. " + "Use matching settings for consistent SCF/NSCF bands."; + ModuleBase::WARNING("ESolver_KS_PW", message); + } + } } } @@ -70,60 +153,63 @@ void validate_hybrid_nscf(const Input_para& inp, const General_Exx_Info& info) } } -void invalidate_exx_source(const Input_para& inp, - const General_Exx_Info& info, - const ModulePW::PW_Basis_K& basis, - const std::string& out_dir) -{ - if (inp.calculation != "scf" || !info.cal_exx || inp.out_wfc_pw != 2 - || inp.kpar != 1 || inp.bndpar != 1 || basis.poolrank != 0) - { - return; - } - const std::string checkpoint = out_dir + "EXX_SOURCE"; - if (std::remove(checkpoint.c_str()) != 0 && errno != ENOENT) - { - ModuleBase::WARNING_QUIT("ESolver_KS_PW", "Cannot invalidate the previous EXX source checkpoint"); - } -} - -void save_exx_source(const Input_para& inp, - const General_Exx_Info& info, - const K_Vectors& points, - const ModuleBase::matrix& weights, - const ModulePW::PW_Basis_K& basis, - const std::string& out_dir) -{ - const bool output_enabled = checkpoint_output_enabled(inp); - if (inp.calculation != "scf" || !info.cal_exx || !output_enabled || basis.poolrank != 0) - { - return; - } - const std::string filename = out_dir + "EXX_SOURCE"; - const std::string configuration = exx_restart_configuration(inp, info); - std::ofstream out(filename); - try - { - ModuleIO::write_exx_source(out, points, weights, inp.nspin, basis.nx, basis.ny, basis.nz, configuration); - } - catch (const std::exception& error) - { - ModuleBase::WARNING_QUIT("ESolver_KS_PW", error.what()); - } -} - template void ESolver_KS_PW::prepare_exx_nscf(const UnitCell& ucell, const std::string& readin_dir) { ModuleBase::timer::start("ESolver_KS_PW", "prepare_exx_nscf"); const Input_para& inp = *this->inp_; - const std::string configuration = exx_restart_configuration(inp, this->general_exx_info_); - const std::string filename = readin_dir + "EXX_SOURCE"; - std::ifstream in(filename); + warn_source_configuration(inp, readin_dir); + const int spin_mult = inp.nspin == 2 ? 2 : 1; + const std::vector first_index(1, 0); + const std::string first_filename = ModuleIO::filename_output(readin_dir, "wf", "pw", 0, + first_index, inp.nspin, spin_mult, 2, false, false, -1); + std::vector headers; try { - ModuleIO::read_exx_source(in, exx_source_points_, exx_source_weights_, inp.nspin, - this->pw_wfc->nx, this->pw_wfc->ny, this->pw_wfc->nz, configuration); + std::ifstream first(first_filename, std::ios::binary); + const auto header = read_exx_source_header(first); + const int nks = header.nks; + if (nks % spin_mult != 0) + { + throw std::runtime_error("Invalid EXX source spin dimensions"); + } + exx_source_points_.set_nks(nks); + exx_source_points_.set_nkstot(nks); + const int nq = nks / spin_mult; + exx_source_points_.set_nkstot_nospin(nq); + exx_source_points_.set_spin_mult(spin_mult); + exx_source_points_.kvec_d.resize(nks); + exx_source_points_.kvec_c.resize(nks); + exx_source_points_.wk.resize(nks); + exx_source_points_.isk.resize(nks); + exx_source_points_.ngk.resize(nks); + exx_source_points_.ik2iktot.resize(nks); + for (int iq = 0; iq < nks; ++iq) + { + exx_source_points_.ik2iktot[iq] = iq; + } + const ModuleBase::Matrix3 inverse_reciprocal = ucell.G.Inverse(); + for (int iq = 0; iq < nks; ++iq) + { + const std::string filename = ModuleIO::filename_output(readin_dir, "wf", "pw", iq, + exx_source_points_.ik2iktot, inp.nspin, nks, 2, false, false, -1); + std::ifstream in(filename, std::ios::binary); + const auto metadata = read_exx_source_header(in); + if (metadata.ecutwfc != inp.ecutwfc) + { + throw std::runtime_error("EXX source wavefunction cutoff differs from the current basis"); + } + headers.push_back(metadata); + auto& q = exx_source_points_.kvec_c[iq]; + q.x = metadata.kvec_c[0]; + q.y = metadata.kvec_c[1]; + q.z = metadata.kvec_c[2]; + exx_source_points_.kvec_d[iq] = q * inverse_reciprocal; + exx_source_points_.wk[iq] = metadata.weight; + exx_source_points_.isk[iq] = iq / nq; + } + std::ifstream occupations(readin_dir + "eig_occ.txt"); + read_exx_source_occupations(occupations, headers, inp.nspin, exx_source_weights_); } catch (const std::exception& error) { @@ -139,13 +225,17 @@ void ESolver_KS_PW::prepare_exx_nscf(const UnitCell& ucell, const std exx_source_basis_->initgrids(ucell.lat0, ucell.latvec, this->pw_wfc->nx, this->pw_wfc->ny, this->pw_wfc->nz); exx_source_basis_->initparameters(false, inp.ecutwfc, nqs, exx_source_points_.kvec_d.data()); + // Preserve the exact stored Cartesian coordinates expected by the existing reader. + for (int iq = 0; iq < nqs; ++iq) + { + exx_source_basis_->kvec_c[iq] = exx_source_points_.kvec_c[iq]; + } exx_source_basis_->fft_bundle.initfftmode(inp.fft_mode); exx_source_basis_->setuptransform(); exx_source_basis_->collect_local_pw(inp.erf_ecut, inp.erf_height, inp.erf_sigma); for (int iq = 0; iq < nqs; ++iq) { exx_source_points_.ngk[iq] = exx_source_basis_->npwk[iq]; - exx_source_points_.kvec_c[iq] = exx_source_points_.kvec_d[iq] * ucell.G; } const int nbands = exx_source_weights_.nc; const int nbasis = exx_source_basis_->npwk_max; @@ -154,6 +244,14 @@ void ESolver_KS_PW::prepare_exx_nscf(const UnitCell& ucell, const std { const std::string wfc_filename = ModuleIO::filename_output(readin_dir, "wf", "pw", iq, exx_source_points_.ik2iktot, inp.nspin, nqs, 2, false, false, -1); + try + { + validate_source_grid(wfc_filename, *exx_source_basis_, iq); + } + catch (const std::exception& error) + { + ModuleBase::WARNING_QUIT("ESolver_KS_PW", error.what()); + } ModuleBase::ComplexMatrix wfc(nbands, nbasis); ModuleIO::read_wfc_pw(wfc_filename, exx_source_basis_.get(), this->pw_wfc->poolrank, this->pw_wfc->poolnproc, nbands, 1, iq, iq, nqs, wfc); diff --git a/source/source_esolver/pw_hybrid_nscf.h b/source/source_esolver/pw_hybrid_nscf.h index db23e72d7e4..763c097b212 100644 --- a/source/source_esolver/pw_hybrid_nscf.h +++ b/source/source_esolver/pw_hybrid_nscf.h @@ -1,32 +1,10 @@ #ifndef PW_HYBRID_NSCF_H #define PW_HYBRID_NSCF_H -#include - struct Input_para; struct General_Exx_Info; -class K_Vectors; -namespace ModuleBase -{ -class matrix; -} -namespace ModulePW -{ -class PW_Basis_K; -} - namespace ModuleESolver { void validate_hybrid_nscf(const Input_para& inp, const General_Exx_Info& info); -void invalidate_exx_source(const Input_para& inp, - const General_Exx_Info& info, - const ModulePW::PW_Basis_K& basis, - const std::string& out_dir); -void save_exx_source(const Input_para& inp, - const General_Exx_Info& info, - const K_Vectors& points, - const ModuleBase::matrix& weights, - const ModulePW::PW_Basis_K& basis, - const std::string& out_dir); } #endif diff --git a/source/source_io/module_wf/exx_source_io.cpp b/source/source_esolver/pw_hybrid_source.cpp similarity index 57% rename from source/source_io/module_wf/exx_source_io.cpp rename to source/source_esolver/pw_hybrid_source.cpp index 611e19a725d..f7f29597398 100644 --- a/source/source_io/module_wf/exx_source_io.cpp +++ b/source/source_esolver/pw_hybrid_source.cpp @@ -1,120 +1,14 @@ -#include "exx_source_io.h" +#include "pw_hybrid_source.h" #include "source_base/matrix.h" -#include "source_cell/klist.h" #include #include #include #include -#include #include -#include #include -void ModuleIO::write_exx_source(std::ostream& out, - const K_Vectors& points, - const ModuleBase::matrix& weights, - int nspin, - int nx, - int ny, - int nz, - const std::string& configuration) -{ - out << "ABACUS_EXX_SOURCE_V1\n" << configuration << '\n'; - out << nspin << ' ' << nx << ' ' << ny << ' ' << nz << ' ' << weights.nr << ' ' << weights.nc << '\n'; - out << points.nmp[0] << ' ' << points.nmp[1] << ' ' << points.nmp[2] << '\n'; - out << std::setprecision(17); - for (int iq = 0; iq < weights.nr; ++iq) - { - const auto& q = points.kvec_d[iq]; - out << q.x << ' ' << q.y << ' ' << q.z << ' ' << points.wk[iq] << ' ' << points.isk[iq]; - for (int ib = 0; ib < weights.nc; ++ib) - { - out << ' ' << weights(iq, ib); - } - out << '\n'; - } - if (!out) - { - throw std::runtime_error("Cannot write EXX source checkpoint"); - } -} - -void ModuleIO::read_exx_source(std::istream& in, - K_Vectors& points, - ModuleBase::matrix& weights, - int nspin, - int nx, - int ny, - int nz, - const std::string& configuration) -{ - std::string magic; - std::string saved_configuration; - std::getline(in, magic); - std::getline(in, saved_configuration); - int saved_spin = 0; - int saved_nx = 0; - int saved_ny = 0; - int saved_nz = 0; - int nks = 0; - int nbands = 0; - in >> saved_spin >> saved_nx >> saved_ny >> saved_nz >> nks >> nbands; - if (!in || magic != "ABACUS_EXX_SOURCE_V1" || saved_configuration != configuration - || saved_spin != nspin || saved_nx != nx || saved_ny != ny || saved_nz != nz - || nks <= 0 || nbands <= 0 || nks > 100000 || nbands > 100000 - || static_cast(nks) * nbands > 100000000) - { - throw std::runtime_error("Missing, incompatible or invalid EXX source checkpoint; regenerate with a converged hybrid SCF"); - } - const int spin_mult = nspin == 2 ? 2 : 1; - if (nks % spin_mult != 0) - { - throw std::runtime_error("Invalid EXX source spin dimensions"); - } - in >> points.nmp[0] >> points.nmp[1] >> points.nmp[2]; - points.set_nks(nks); - points.set_nkstot(nks); - const int nq = nks / spin_mult; - points.set_nkstot_nospin(nq); - points.set_spin_mult(spin_mult); - points.kvec_d.resize(nks); - points.kvec_c.resize(nks); - points.wk.resize(nks); - points.isk.resize(nks); - points.ngk.resize(nks); - points.ik2iktot.resize(nks); - weights.create(nks, nbands); - const double expected_weight = nspin == 1 ? 2.0 / nq : 1.0 / nq; - for (int iq = 0; iq < nks; ++iq) - { - auto& q = points.kvec_d[iq]; - in >> q.x >> q.y >> q.z >> points.wk[iq] >> points.isk[iq]; - if (!in || !std::isfinite(q.x) || !std::isfinite(q.y) || !std::isfinite(q.z) - || !std::isfinite(points.wk[iq]) || std::abs(points.wk[iq] - expected_weight) > 1e-10 - || points.isk[iq] != iq / nq) - { - throw std::runtime_error("EXX source requires a complete uniform q mesh with ordered spin channels"); - } - points.ik2iktot[iq] = iq; - for (int ib = 0; ib < nbands; ++ib) - { - in >> weights(iq, ib); - if (!in || !std::isfinite(weights(iq, ib)) || weights(iq, ib) < 0 - || weights(iq, ib) > expected_weight + 1e-10) - { - throw std::runtime_error("Invalid EXX source occupation"); - } - } - } - in >> std::ws; - if (!in.eof()) - { - throw std::runtime_error("Unexpected trailing EXX source checkpoint data"); - } -} - namespace { template @@ -128,7 +22,7 @@ void read_binary(std::istream& in, T& value) } } -ModuleIO::ExxSourceHeader ModuleIO::read_exx_source_header(std::istream& in) +ModuleESolver::ExxSourceHeader ModuleESolver::read_exx_source_header(std::istream& in) { ExxSourceHeader header{}; int record = 0; @@ -174,7 +68,7 @@ ModuleIO::ExxSourceHeader ModuleIO::read_exx_source_header(std::istream& in) return header; } -void ModuleIO::read_exx_source_occupations(std::istream& in, +void ModuleESolver::read_exx_source_occupations(std::istream& in, const std::vector& headers, int nspin, ModuleBase::matrix& weights) diff --git a/source/source_esolver/pw_hybrid_source.h b/source/source_esolver/pw_hybrid_source.h new file mode 100644 index 00000000000..505a6ef1cb0 --- /dev/null +++ b/source/source_esolver/pw_hybrid_source.h @@ -0,0 +1,37 @@ +#ifndef PW_HYBRID_SOURCE_H +#define PW_HYBRID_SOURCE_H + +#include +#include + +namespace ModuleBase +{ +class matrix; +} + +namespace ModuleESolver +{ +// Metadata already present in the existing binary PW wavefunction format. +struct ExxSourceHeader +{ + int ik; + int nks; + int npw; + int nbands; + double kvec_c[3]; + double weight; + double ecutwfc; + double lat0; + double tpiba; +}; + +ExxSourceHeader read_exx_source_header(std::istream& in); + +// Read the existing, k-weighted occupation column without changing its format. +void read_exx_source_occupations(std::istream& in, + const std::vector& headers, + int nspin, + ModuleBase::matrix& weights); + +} +#endif diff --git a/source/source_esolver/test/CMakeLists.txt b/source/source_esolver/test/CMakeLists.txt index 80ca8f061b1..80cfa0b81ff 100644 --- a/source/source_esolver/test/CMakeLists.txt +++ b/source/source_esolver/test/CMakeLists.txt @@ -26,3 +26,9 @@ AddTest( ../../source_cell/cif_io.cpp ../../source_io/module_output/output_log.cpp ) + +AddTest( + TARGET MODULE_ESOLVER_pw_hybrid_source + LIBS base device + SOURCES test_pw_hybrid_source.cpp ../pw_hybrid_source.cpp +) diff --git a/source/source_esolver/test/test_pw_hybrid_source.cpp b/source/source_esolver/test/test_pw_hybrid_source.cpp new file mode 100644 index 00000000000..2c47305e200 --- /dev/null +++ b/source/source_esolver/test/test_pw_hybrid_source.cpp @@ -0,0 +1,122 @@ +#include "source_esolver/pw_hybrid_source.h" +#include "source_base/matrix.h" + +#include "gtest/gtest.h" + +#include +#include +#include +#include + +namespace +{ +std::vector source_headers(int nspin) +{ + const int nks = nspin == 2 ? 4 : 2; + std::vector headers(nks); + for (int iq = 0; iq < nks; ++iq) + { + auto& header = headers[iq]; + header.ik = iq + 1; + header.nks = nks; + header.npw = 100; + header.nbands = 3; + header.kvec_c[0] = 0.123456789123456 * (iq % 2); + header.weight = nspin == 1 ? 1.0 : 0.5; + } + return headers; +} + +std::string eig_occ(int nspin) +{ + const auto headers = source_headers(nspin); + std::ostringstream out; + out << "1 # ionic step\n Electronic state energy (eV) and occupations\n Spin number " << nspin << '\n'; + for (int iq = 0; iq < headers.size(); ++iq) + { + const auto& header = headers[iq]; + out << " spin=" << iq / 2 + 1 << " k-point=" << iq % 2 + 1 + << "/2 Cartesian=" << std::setprecision(8) << header.kvec_c[0] + << " 0 0 (100 plane wave)\n"; + out << "1 -1 " << header.weight << "\n2 0 " << header.weight * 0.125 << "\n3 1 0\n\n"; + } + return out.str(); +} +} + +TEST(PWHybridSource, ReadsExistingWeightedOccupationsForBothSpins) +{ + for (int nspin = 1; nspin <= 2; ++nspin) + { + const auto headers = source_headers(nspin); + std::istringstream in(eig_occ(nspin)); + ModuleBase::matrix weights; + ModuleESolver::read_exx_source_occupations(in, headers, nspin, weights); + EXPECT_EQ(weights.nr, headers.size()); + EXPECT_EQ(weights.nc, 3); + EXPECT_DOUBLE_EQ(weights(1, 1), headers[1].weight * 0.125); + } +} + +TEST(PWHybridSource, RejectsInvalidExistingOccupationFiles) +{ + const auto headers = source_headers(1); + ModuleBase::matrix weights; + const std::string saved = eig_occ(1); + std::istringstream truncated(saved.substr(0, saved.size() - 6)); + EXPECT_THROW(ModuleESolver::read_exx_source_occupations(truncated, headers, 1, weights), std::runtime_error); + std::istringstream trailing(saved + saved); + EXPECT_THROW(ModuleESolver::read_exx_source_occupations(trailing, headers, 1, weights), std::runtime_error); + std::istringstream wrong_spin(saved); + EXPECT_THROW(ModuleESolver::read_exx_source_occupations(wrong_spin, headers, 2, weights), std::runtime_error); + auto changed = headers; + changed[1].kvec_c[0] += 0.1; + std::istringstream wrong_coordinates(saved); + EXPECT_THROW(ModuleESolver::read_exx_source_occupations(wrong_coordinates, changed, 1, weights), std::runtime_error); + std::string invalid = saved; + invalid.replace(invalid.find("0.125"), 5, "-0.25"); + std::istringstream negative(invalid); + EXPECT_THROW(ModuleESolver::read_exx_source_occupations(negative, headers, 1, weights), std::runtime_error); +} + +TEST(PWHybridSource, ReadsExistingBinaryWavefunctionHeader) +{ + // Native binary record layout from write_wfc_pw; no new wavefunction format. + std::ostringstream out(std::ios::binary); + const int record = 72; + const int ik = 1; + const int nks = 2; + const int npw = 1; + const int nbands = 3; + const double coordinate = 0.123456789123456; + const double weight = 1; + const double cutoff = 10; + const double lattice = 5; + const double tpiba = 1.256637061435917; + out.write(reinterpret_cast(&record), sizeof(record)); + out.write(reinterpret_cast(&ik), sizeof(ik)); + out.write(reinterpret_cast(&nks), sizeof(nks)); + for (int axis = 0; axis < 3; ++axis) + { + out.write(reinterpret_cast(&coordinate), sizeof(coordinate)); + } + out.write(reinterpret_cast(&weight), sizeof(weight)); + out.write(reinterpret_cast(&npw), sizeof(npw)); + out.write(reinterpret_cast(&nbands), sizeof(nbands)); + out.write(reinterpret_cast(&cutoff), sizeof(cutoff)); + out.write(reinterpret_cast(&lattice), sizeof(lattice)); + out.write(reinterpret_cast(&tpiba), sizeof(tpiba)); + out.write(reinterpret_cast(&record), sizeof(record)); + std::string saved = out.str(); + saved.resize(160 + 8 + 12 * npw + nbands * (8 + 16 * npw), '\0'); + std::istringstream in(saved, std::ios::binary); + const auto header = ModuleESolver::read_exx_source_header(in); + EXPECT_EQ(header.nbands, 3); + EXPECT_DOUBLE_EQ(header.kvec_c[0], coordinate); + EXPECT_DOUBLE_EQ(header.weight, weight); + std::istringstream truncated(saved.substr(0, saved.size() - 1), std::ios::binary); + EXPECT_THROW(ModuleESolver::read_exx_source_header(truncated), std::runtime_error); + saved[0] = 0; + std::istringstream invalid(saved, std::ios::binary); + EXPECT_THROW(ModuleESolver::read_exx_source_header(invalid), std::runtime_error); +} diff --git a/source/source_io/CMakeLists.txt b/source/source_io/CMakeLists.txt index d5637b5d94f..488235c6b1e 100644 --- a/source/source_io/CMakeLists.txt +++ b/source/source_io/CMakeLists.txt @@ -21,7 +21,6 @@ list(APPEND objects module_bessel/numerical_descriptor.cpp module_output/print_info.cpp module_output/read_cube.cpp - module_wf/exx_source_io.cpp module_wf/read_wfc_pw.cpp module_wf/read_wf2rho_pw.cpp module_restart/restart.cpp diff --git a/source/source_io/module_parameter/read_inp_exx_dftu.cpp b/source/source_io/module_parameter/read_inp_exx_dftu.cpp index 2e3111ea5e5..4ed0b0b3386 100644 --- a/source/source_io/module_parameter/read_inp_exx_dftu.cpp +++ b/source/source_io/module_parameter/read_inp_exx_dftu.cpp @@ -474,7 +474,7 @@ void ReadInput::item_exx() * spencer: LCAO spherical truncation, Phys. Rev. B 77, 193110 (2008). * revised_spencer: LCAO, Phys. Rev. Mater. 5, 013807 (2021). * massidda / carrier: LCAO auxiliary singularity corrections. -Use the same scheme for SCF and NSCF. Regenerate the SCF source checkpoint after changing schemes.)"; +Use the same scheme for consistent SCF and NSCF bands. A source configuration mismatch produces a warning and does not prevent reading the existing SCF files.)"; item.default_value = "default"; item.unit = ""; read_sync_string(input.exx_singularity_correction); diff --git a/source/source_io/module_parameter/read_inp_sys.cpp b/source/source_io/module_parameter/read_inp_sys.cpp index e37cffb180e..df9e37923fb 100644 --- a/source/source_io/module_parameter/read_inp_sys.cpp +++ b/source/source_io/module_parameter/read_inp_sys.cpp @@ -151,7 +151,7 @@ void ReadInput::item_system() item.description = R"(Specify the type of calculation. * scf: perform self-consistent electronic structure calculations -* nscf: perform non-self-consistent electronic structure calculations. A charge density file is required. PW screened hybrid NSCF additionally reads EXX_SOURCE and binary SCF wavefunctions from read_file_dir; see the hybrid NSCF workflow documentation. The initial implementation supports CPU or CUDA GPU and requires kpar=bndpar=1, nspin=1/2, symmetry=-1/0, exxace=false, exx_gamma_extra=false and cal_force=cal_stress=false. +* nscf: perform non-self-consistent electronic structure calculations. A charge density file is required. PW screened hybrid NSCF additionally reads eig_occ.txt and existing binary SCF wavefunctions from read_file_dir; see the hybrid NSCF workflow documentation. The initial implementation supports CPU or CUDA GPU and requires kpar=bndpar=1, nspin=1/2, symmetry=-1/0, exxace=false, exx_gamma_extra=false and cal_force=cal_stress=false. * relax: perform structure relaxation calculations, the relax_nmax parameter depicts the maximal number of ionic iterations * cell-relax: perform cell relaxation calculations * md: perform molecular dynamics simulations diff --git a/source/source_io/module_wf/exx_source_io.h b/source/source_io/module_wf/exx_source_io.h deleted file mode 100644 index 94905dbab95..00000000000 --- a/source/source_io/module_wf/exx_source_io.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef EXX_SOURCE_IO_H -#define EXX_SOURCE_IO_H - -#include -#include -#include - -class K_Vectors; -namespace ModuleBase -{ -class matrix; -} - -namespace ModuleIO -{ -// Metadata already present in the existing binary PW wavefunction format. -struct ExxSourceHeader -{ - int ik; - int nks; - int npw; - int nbands; - double kvec_c[3]; - double weight; - double ecutwfc; - double lat0; - double tpiba; -}; - -ExxSourceHeader read_exx_source_header(std::istream& in); - -// Read the existing, k-weighted occupation column without changing its format. -void read_exx_source_occupations(std::istream& in, - const std::vector& headers, - int nspin, - ModuleBase::matrix& weights); - -// A versioned companion to WAVEFUNC*.dat, containing the frozen SCF ensemble. -// Streams keep serialization independent of process ownership and file paths. -void write_exx_source(std::ostream& out, - const K_Vectors& points, - const ModuleBase::matrix& weights, - int nspin, - int nx, - int ny, - int nz, - const std::string& configuration); - -void read_exx_source(std::istream& in, - K_Vectors& points, - ModuleBase::matrix& weights, - int nspin, - int nx, - int ny, - int nz, - const std::string& configuration); -} -#endif diff --git a/source/source_io/test/CMakeLists.txt b/source/source_io/test/CMakeLists.txt index f9ca0a8ac99..107ff7de930 100644 --- a/source/source_io/test/CMakeLists.txt +++ b/source/source_io/test/CMakeLists.txt @@ -11,14 +11,6 @@ AddTest( ../../source_cell/parallel_kpoints.cpp ../../source_cell/reciprocal_grid.cpp ) -AddTest( - TARGET MODULE_IO_exx_source_io - LIBS parameter base device symmetry - SOURCES test_exx_source_io.cpp ../module_wf/exx_source_io.cpp - ../../source_cell/klist.cpp ../../source_cell/klist_io.cpp - ../../source_cell/parallel_kpoints.cpp ../../source_cell/reciprocal_grid.cpp -) - if(NOT ENABLE_MPI) return() endif() diff --git a/source/source_io/test/test_exx_source_io.cpp b/source/source_io/test/test_exx_source_io.cpp deleted file mode 100644 index 5fc645f7f4f..00000000000 --- a/source/source_io/test/test_exx_source_io.cpp +++ /dev/null @@ -1,206 +0,0 @@ -#include "source_io/module_wf/exx_source_io.h" -#include "source_base/matrix.h" -#include "source_cell/klist.h" - -#include "gtest/gtest.h" - -#include -#include -#include -#include - -namespace -{ -std::string checkpoint(int nspin) -{ - const int nks = nspin == 2 ? 4 : 2; - K_Vectors points; - points.kvec_d.resize(nks); - points.wk.resize(nks); - points.isk.resize(nks); - points.nmp[0] = 2; - points.nmp[1] = 1; - points.nmp[2] = 1; - ModuleBase::matrix weights(nks, 3); - for (int iq = 0; iq < nks; ++iq) - { - points.kvec_d[iq].x = 0.5 * (iq % 2); - points.wk[iq] = nspin == 1 ? 1.0 : 0.5; - points.isk[iq] = iq / 2; - if (nspin == 1) - { - points.isk[iq] = 0; - } - weights(iq, 0) = points.wk[iq]; - weights(iq, 1) = points.wk[iq] * 0.125; - } - std::ostringstream out; - ModuleIO::write_exx_source(out, points, weights, nspin, 15, 15, 15, "HSE:10:40"); - return out.str(); -} -} - -TEST(ExxSourceIO, PreservesFractionalOccupationsAndSpinOrder) -{ - for (int nspin = 1; nspin <= 2; ++nspin) - { - const std::string saved = checkpoint(nspin); - std::istringstream in(saved); - K_Vectors points; - ModuleBase::matrix weights; - ModuleIO::read_exx_source(in, points, weights, nspin, 15, 15, 15, "HSE:10:40"); - const int nks = nspin == 1 ? 2 : 4; - EXPECT_EQ(points.get_nks(), nks); - EXPECT_EQ(points.get_nkstot_nospin(), 2); - EXPECT_EQ(points.get_spin_mult(), nspin); - EXPECT_EQ(weights.nc, 3); - EXPECT_DOUBLE_EQ(weights(1, 1), points.wk[1] * 0.125); - EXPECT_DOUBLE_EQ(weights(1, 2), 0.0); - EXPECT_DOUBLE_EQ(points.kvec_d[1].x, 0.5); - EXPECT_EQ(points.isk.back(), nspin - 1); - } -} - -TEST(ExxSourceIO, RejectsIncompatibleConfigurationAndGrid) -{ - const std::string saved = checkpoint(1); - K_Vectors points; - ModuleBase::matrix weights; - std::istringstream changed_functional(saved); - EXPECT_THROW(ModuleIO::read_exx_source(changed_functional, points, weights, 1, 15, 15, 15, "PBE0:10:40"), std::runtime_error); - std::istringstream changed_grid(saved); - EXPECT_THROW(ModuleIO::read_exx_source(changed_grid, points, weights, 1, 16, 15, 15, "HSE:10:40"), std::runtime_error); - std::istringstream changed_spin(saved); - EXPECT_THROW(ModuleIO::read_exx_source(changed_spin, points, weights, 2, 15, 15, 15, "HSE:10:40"), std::runtime_error); -} - -TEST(ExxSourceIO, RejectsTruncationInvalidOccupationsAndTrailingData) -{ - const std::string saved = checkpoint(1); - K_Vectors points; - ModuleBase::matrix weights; - const std::string truncated_text = saved.substr(0, saved.size() - 6); - std::istringstream truncated(truncated_text); - EXPECT_THROW(ModuleIO::read_exx_source(truncated, points, weights, 1, 15, 15, 15, "HSE:10:40"), std::runtime_error); - std::istringstream trailing(saved + "unexpected"); - EXPECT_THROW(ModuleIO::read_exx_source(trailing, points, weights, 1, 15, 15, 15, "HSE:10:40"), std::runtime_error); - std::string invalid = saved; - const auto occupation = invalid.find("0.125"); - ASSERT_NE(occupation, std::string::npos); - invalid.replace(occupation, 5, "-0.25"); - std::istringstream negative(invalid); - EXPECT_THROW(ModuleIO::read_exx_source(negative, points, weights, 1, 15, 15, 15, "HSE:10:40"), std::runtime_error); -} - -namespace -{ -std::vector source_headers(int nspin) -{ - const int nks = nspin == 2 ? 4 : 2; - std::vector headers(nks); - for (int iq = 0; iq < nks; ++iq) - { - auto& header = headers[iq]; - header.ik = iq + 1; - header.nks = nks; - header.npw = 100; - header.nbands = 3; - header.kvec_c[0] = 0.123456789123456 * (iq % 2); - header.weight = nspin == 1 ? 1.0 : 0.5; - } - return headers; -} - -std::string eig_occ(int nspin) -{ - const auto headers = source_headers(nspin); - std::ostringstream out; - out << "1 # ionic step\n Electronic state energy (eV) and occupations\n Spin number " << nspin << '\n'; - for (int iq = 0; iq < headers.size(); ++iq) - { - const auto& header = headers[iq]; - out << " spin=" << iq / 2 + 1 << " k-point=" << iq % 2 + 1 - << "/2 Cartesian=" << std::setprecision(8) << header.kvec_c[0] - << " 0 0 (100 plane wave)\n"; - out << "1 -1 " << header.weight << "\n2 0 " << header.weight * 0.125 << "\n3 1 0\n\n"; - } - return out.str(); -} -} - -TEST(ExxSourceIO, ReadsExistingWeightedOccupationsForBothSpins) -{ - for (int nspin = 1; nspin <= 2; ++nspin) - { - const auto headers = source_headers(nspin); - std::istringstream in(eig_occ(nspin)); - ModuleBase::matrix weights; - ModuleIO::read_exx_source_occupations(in, headers, nspin, weights); - EXPECT_EQ(weights.nr, headers.size()); - EXPECT_EQ(weights.nc, 3); - EXPECT_DOUBLE_EQ(weights(1, 1), headers[1].weight * 0.125); - } -} - -TEST(ExxSourceIO, RejectsInvalidExistingOccupationFiles) -{ - const auto headers = source_headers(1); - ModuleBase::matrix weights; - const std::string saved = eig_occ(1); - std::istringstream truncated(saved.substr(0, saved.size() - 6)); - EXPECT_THROW(ModuleIO::read_exx_source_occupations(truncated, headers, 1, weights), std::runtime_error); - std::istringstream trailing(saved + saved); - EXPECT_THROW(ModuleIO::read_exx_source_occupations(trailing, headers, 1, weights), std::runtime_error); - std::istringstream wrong_spin(saved); - EXPECT_THROW(ModuleIO::read_exx_source_occupations(wrong_spin, headers, 2, weights), std::runtime_error); - auto changed = headers; - changed[1].kvec_c[0] += 0.1; - std::istringstream wrong_coordinates(saved); - EXPECT_THROW(ModuleIO::read_exx_source_occupations(wrong_coordinates, changed, 1, weights), std::runtime_error); - std::string invalid = saved; - invalid.replace(invalid.find("0.125"), 5, "-0.25"); - std::istringstream negative(invalid); - EXPECT_THROW(ModuleIO::read_exx_source_occupations(negative, headers, 1, weights), std::runtime_error); -} - -TEST(ExxSourceIO, ReadsExistingBinaryWavefunctionHeader) -{ - // Native binary record layout from write_wfc_pw; no new wavefunction format. - std::ostringstream out(std::ios::binary); - const int record = 72; - const int ik = 1; - const int nks = 2; - const int npw = 1; - const int nbands = 3; - const double coordinate = 0.123456789123456; - const double weight = 1; - const double cutoff = 10; - const double lattice = 5; - const double tpiba = 1.256637061435917; - out.write(reinterpret_cast(&record), sizeof(record)); - out.write(reinterpret_cast(&ik), sizeof(ik)); - out.write(reinterpret_cast(&nks), sizeof(nks)); - for (int axis = 0; axis < 3; ++axis) - { - out.write(reinterpret_cast(&coordinate), sizeof(coordinate)); - } - out.write(reinterpret_cast(&weight), sizeof(weight)); - out.write(reinterpret_cast(&npw), sizeof(npw)); - out.write(reinterpret_cast(&nbands), sizeof(nbands)); - out.write(reinterpret_cast(&cutoff), sizeof(cutoff)); - out.write(reinterpret_cast(&lattice), sizeof(lattice)); - out.write(reinterpret_cast(&tpiba), sizeof(tpiba)); - out.write(reinterpret_cast(&record), sizeof(record)); - std::string saved = out.str(); - saved.resize(160 + 8 + 12 * npw + nbands * (8 + 16 * npw), '\0'); - std::istringstream in(saved, std::ios::binary); - const auto header = ModuleIO::read_exx_source_header(in); - EXPECT_EQ(header.nbands, 3); - EXPECT_DOUBLE_EQ(header.kvec_c[0], coordinate); - EXPECT_DOUBLE_EQ(header.weight, weight); - std::istringstream truncated(saved.substr(0, saved.size() - 1), std::ios::binary); - EXPECT_THROW(ModuleIO::read_exx_source_header(truncated), std::runtime_error); - saved[0] = 0; - std::istringstream invalid(saved, std::ios::binary); - EXPECT_THROW(ModuleIO::read_exx_source_header(invalid), std::runtime_error); -} diff --git a/tests/integrate/tools/test_hybrid_nscf.py b/tests/integrate/tools/test_hybrid_nscf.py index 79f40ab316d..e61021d0a72 100644 --- a/tests/integrate/tools/test_hybrid_nscf.py +++ b/tests/integrate/tools/test_hybrid_nscf.py @@ -7,6 +7,7 @@ from pathlib import Path import shutil import subprocess +import struct import tempfile REPO = Path(__file__).resolve().parents[3] @@ -76,7 +77,8 @@ def verify(executable, root, mpi_ranks): scf = create_case(root, "scf", "calculation scf\nout_chg 1\nout_wfc_pw 2\n") run(executable, scf, []) source = scf / "OUT.hybrid" - assert (source / "EXX_SOURCE").exists() + assert (source / "eig_occ.txt").exists() + assert not (source / "EXX_SOURCE").exists() original = digest(source) extra = f"calculation nscf\nread_file_dir {source}\nout_chg 0\nout_wfc_pw 0\n" # More target bands than source bands, initialized independently. @@ -117,25 +119,36 @@ def verify(executable, root, mpi_ranks): broken_source = root / "broken_source" shutil.copytree(source, broken_source) - (broken_source / "EXX_SOURCE").unlink() + (broken_source / "eig_occ.txt").unlink() broken = create_case(root, "missing", extra.replace(str(source), str(broken_source))) - run(executable, broken, [], "EXX source checkpoint") - (broken_source / "EXX_SOURCE").write_text((source / "EXX_SOURCE").read_text()[:-6]) + run(executable, broken, [], "EXX source eig_occ.txt") + saved_occupations = (source / "eig_occ.txt").read_text() + (broken_source / "eig_occ.txt").write_text(saved_occupations[:len(saved_occupations) // 2]) truncated = create_case(root, "truncated", extra.replace(str(source), str(broken_source))) - run(executable, truncated, [], "Invalid EXX source occupation") + run(executable, truncated, [], "EXX source") + (broken_source / "eig_occ.txt").write_bytes((source / "eig_occ.txt").read_bytes()) + wavefunction = (source / "wfk1_pw.dat").read_bytes() + (broken_source / "wfk1_pw.dat").write_bytes(wavefunction[:90]) + broken_wave = create_case(root, "truncated_wave", extra.replace(str(source), str(broken_source))) + run(executable, broken_wave, [], "EXX source wavefunction") + invalid_miller = bytearray(wavefunction) + struct.pack_into("i", invalid_miller, 164, 2**30) + (broken_source / "wfk1_pw.dat").write_bytes(invalid_miller) + bad_grid = create_case(root, "bad_source_grid", extra.replace(str(source), str(broken_source))) + run(executable, bad_grid, [], "EXX source Miller index is incompatible with FFT grid") unsupported = create_case(root, "unsupported_ace", extra) (unsupported / "INPUT").write_text((unsupported / "INPUT").read_text().replace("exxace false", "exxace true")) run(executable, unsupported, [], "Hybrid NSCF currently requires") - print("missing/truncated checkpoint and unsupported ACE rejected") + print("missing/truncated source, invalid Miller mapping and unsupported ACE rejected") - # A failed SCF must invalidate an older companion before replacing orbitals. - failed = create_case(root, "failed_scf", "calculation scf\nout_chg 1\nout_wfc_pw 2\nexx_hybrid_step 1\n") - shutil.copytree(source, failed / "OUT.hybrid") - text = (failed / "INPUT").read_text().replace("scf_nmax 100", "scf_nmax 1") - (failed / "INPUT").write_text(text) - run(executable, failed, []) - assert not (failed / "OUT.hybrid/EXX_SOURCE").exists(), "Failed SCF left a stale checkpoint" - print("failed SCF invalidates the previous source checkpoint") + legacy_source = root / "legacy_source" + shutil.copytree(source, legacy_source) + (legacy_source / "INPUT.info").unlink() + legacy = create_case(root, "legacy", extra.replace(str(source), str(legacy_source))) + run(executable, legacy, []) + assert "EXX source configuration is incomplete" in (legacy / "OUT.hybrid/warning.log").read_text() + assert max_difference(bands(same), bands(legacy)) < 2e-4 + print("legacy source without INPUT.info is accepted with a warning") def verify_correction(executable, root, gpu=False): @@ -165,7 +178,11 @@ def verify_correction(executable, root, gpu=False): mismatch = create_case(root, f"{device}_correction_mismatch", extra.replace("correction limits", "correction gygi")) - run(executable, mismatch, [], "EXX source") + text = (mismatch / "INPUT").read_text().replace("device cpu", f"device {device}") + (mismatch / "INPUT").write_text(text) + run(executable, mismatch, []) + assert "EXX source configuration differs for exx_singularity_correction" in (mismatch / "OUT.hybrid/warning.log").read_text() + print(f"{device} correction mismatch is accepted with a warning") bad = create_case(root, f"{device}_bad_correction", extra.replace("correction limits", "correction spencer")) run(executable, bad, [], "PW exx_singularity_correction must be limits or gygi") old_name = create_case(root, f"{device}_obsolete_correction", @@ -207,7 +224,7 @@ def verify_correction(executable, root, gpu=False): assert shift > 1e-5, "limits and gygi unexpectedly produced identical SCF bands" print(f"{device} gygi control jump near Gamma: {aux_jump:.3g} eV") print(f"{device} gygi SCF/NSCF matched; limits/gygi SCF difference {shift:.3g} eV") - print("mismatched scheme, unsupported scheme, gamma and unscreened limits rejected") + print("unsupported scheme, gamma and unscreened limits rejected") def verify_gpu(executable, root): @@ -246,7 +263,8 @@ def verify_gpu(executable, root): (gpu_scf / "INPUT").write_text(text) run(executable, gpu_scf, []) source = gpu_scf / "OUT.hybrid" - assert (source / "EXX_SOURCE").exists() + assert (source / "eig_occ.txt").exists() + assert not (source / "EXX_SOURCE").exists() original = digest(source) targets = [] for device in ("cpu", "gpu"): From 72b098c8bb2818475f26d5a881cea314cab611bf Mon Sep 17 00:00:00 2001 From: Hongxu Ren Date: Thu, 8 Oct 2026 14:00:43 +0800 Subject: [PATCH 13/25] Remove unused EXX iteration-count accessor after checkpoint cleanup --- source/source_pw/module_pwdft/exx_helper.h | 2 -- source/source_pw/module_pwdft/exx_helper_base.h | 2 -- 2 files changed, 4 deletions(-) diff --git a/source/source_pw/module_pwdft/exx_helper.h b/source/source_pw/module_pwdft/exx_helper.h index fbb24c47963..2adb945b8b6 100644 --- a/source/source_pw/module_pwdft/exx_helper.h +++ b/source/source_pw/module_pwdft/exx_helper.h @@ -44,8 +44,6 @@ struct Exx_Helper : public Exx_HelperBase double cal_exx_energy(void* psi_) override; - int iteration_count() const override { return exx_iter; } - bool get_op_first_iter() const override { return op_exx ? op_exx->first_iter : false; } void set_op_first_iter(bool flag) override { if (op_exx) op_exx->first_iter = flag; } void set_op_exx(void* op) override { op_exx = reinterpret_cast(op); } diff --git a/source/source_pw/module_pwdft/exx_helper_base.h b/source/source_pw/module_pwdft/exx_helper_base.h index 8699395ffb3..7ebab443948 100644 --- a/source/source_pw/module_pwdft/exx_helper_base.h +++ b/source/source_pw/module_pwdft/exx_helper_base.h @@ -33,8 +33,6 @@ class Exx_HelperBase virtual double cal_exx_energy(void* psi) = 0; - virtual int iteration_count() const = 0; - virtual bool get_op_first_iter() const = 0; virtual void set_op_first_iter(bool flag) = 0; From f7f73560fffd3783ee70cce735f55dc58294a163 Mon Sep 17 00:00:00 2001 From: Hongxu Ren Date: Thu, 8 Oct 2026 14:03:47 +0800 Subject: [PATCH 14/25] Clean hybrid NSCF leftovers and keep workflow regressions outside CMake --- docs/advanced/elec_properties/hybrid_nscf.md | 11 +++--- source/source_esolver/esolver_ks_pw.cpp | 1 - source/source_esolver/pw_hybrid_nscf.cpp | 35 ++++++++++++++++++- source/source_esolver/pw_hybrid_source.cpp | 10 ++++-- source/source_esolver/pw_hybrid_source.h | 6 ++-- .../test/test_pw_hybrid_source.cpp | 14 ++++++++ source/source_pw/module_pwdft/op_pw_exx.cpp | 2 -- tests/integrate/CMakeLists.txt | 23 +----------- tests/integrate/tools/test_hybrid_nscf.py | 13 +++++++ 9 files changed, 77 insertions(+), 38 deletions(-) diff --git a/docs/advanced/elec_properties/hybrid_nscf.md b/docs/advanced/elec_properties/hybrid_nscf.md index eed6f6ccd05..d6ea12ef8e8 100644 --- a/docs/advanced/elec_properties/hybrid_nscf.md +++ b/docs/advanced/elec_properties/hybrid_nscf.md @@ -150,7 +150,7 @@ Gygi scheme and do not constitute validation of the new default. ```bash cmake --build build --target MODULE_ESOLVER_pw_hybrid_source -j 8 OMP_NUM_THREADS=1 ctest --test-dir build -V -R '^MODULE_ESOLVER_pw_hybrid_source$' -python3 tests/integrate/tools/test_hybrid_nscf.py ./build/abacus --mpi-ranks 2 +OMP_NUM_THREADS=1 python3 tests/integrate/tools/test_hybrid_nscf.py ./build/abacus --mpi-ranks 2 ``` Supply the actual configured executable and build directory. The integration @@ -162,8 +162,7 @@ files, and invalid restart/unsupported-option errors. It needs LibXC and MPI. For a CUDA build and an available GPU, also run: ```bash -python3 tests/integrate/tools/test_hybrid_nscf.py ./build/abacus --gpu -OMP_NUM_THREADS=1 ctest --test-dir build -V -R '^PW_HYBRID_NSCF(_GPU)?$' +OMP_NUM_THREADS=1 python3 tests/integrate/tools/test_hybrid_nscf.py ./build/abacus --gpu ``` This compares CPU and GPU targets using one frozen CPU source on both a mesh @@ -172,9 +171,9 @@ spin-polarized source with CPU and GPU targets. Source files must remain unchanged. A three-band single-precision GPU path additionally checks conversion from a double-precision CPU source and the full-grid exchange FFT precision. Single precision uses the existing looser diagonalization threshold; use -`precision double` for accurate high-energy target bands. The corresponding CTest is `PW_HYBRID_NSCF_GPU`. +`precision double` for accurate high-energy target bands. The workflow script is run manually; only unit tests are registered with CMake/CTest. -On a local RTX 3090 with CUDA 13.1, both CTests passed in a CUDA build. +On a local RTX 3090 with CUDA 13.1, the CPU and GPU workflow scripts passed in a CUDA build. The H CPU/GPU mesh, independent path and both spin-channel eigenvalues agreed at the printed precision, as did all eight bands at nine Si L-Gamma-X points using the same frozen CPU source (`20 Ry`, `2x2x2` source mesh). The Si check @@ -186,7 +185,7 @@ consistency; it does not change the cross-code convergence limits below. On the initial local two-q-point, 10 Ry test, the same-mesh SCF/NSCF maximum band difference was `3.7e-5 eV`; the shared Gamma point and serial/two-rank NSCF -results agreed to printed precision. Three source-adapter unit tests passed. +results agreed to printed precision. The source-adapter unit tests cover occupations, spin meshes and binary headers. A QE SCF comparison at this low cutoff showed band differences up to about `0.03 eV`; that H test alone does not establish cross-code agreement. diff --git a/source/source_esolver/esolver_ks_pw.cpp b/source/source_esolver/esolver_ks_pw.cpp index 6fb4fdda12f..f6b7080e802 100644 --- a/source/source_esolver/esolver_ks_pw.cpp +++ b/source/source_esolver/esolver_ks_pw.cpp @@ -29,7 +29,6 @@ namespace ModuleESolver { - template ESolver_KS_PW::ESolver_KS_PW() { diff --git a/source/source_esolver/pw_hybrid_nscf.cpp b/source/source_esolver/pw_hybrid_nscf.cpp index 96360b126fb..2c6bebca8cc 100644 --- a/source/source_esolver/pw_hybrid_nscf.cpp +++ b/source/source_esolver/pw_hybrid_nscf.cpp @@ -6,6 +6,8 @@ #include "source_hamilt/module_xc/general_exx_info.h" #include "source_pw/module_pwdft/exx_helper.h" +#include +#include #include #include #include @@ -53,6 +55,37 @@ void validate_source_grid(const std::string& filename, const ModulePW::PW_Basis_ } } +bool source_parameter_matches(const std::string& key, std::string source_value, std::string target_value) +{ + if (key == "dft_functional") + { + const auto lowercase = [](unsigned char value) { return std::tolower(value); }; + std::transform(source_value.begin(), source_value.end(), source_value.begin(), lowercase); + std::transform(target_value.begin(), target_value.end(), target_value.begin(), lowercase); + } + if (source_value == target_value) + { + return true; + } + std::istringstream source(source_value); + std::istringstream target(target_value); + double source_number = 0; + double target_number = 0; + if (!(source >> source_number) || !(target >> target_number)) + { + return false; + } + std::string remaining; + if ((source >> remaining) || (target >> remaining)) + { + return false; + } + // INPUT.info may print doubles with the standard six significant digits. + const double scale = std::max(std::abs(source_number), std::abs(target_number)); + return std::isfinite(source_number) && std::isfinite(target_number) + && std::abs(source_number - target_number) <= 5e-6 * scale; +} + void warn_source_configuration(const Input_para& inp, const std::string& readin_dir) { std::map expected; @@ -109,7 +142,7 @@ void warn_source_configuration(const Input_para& inp, const std::string& readin_ mismatch = true; break; } - if (source_value != target_value) + if (!source_parameter_matches(item.first, source_value, target_value)) { mismatch = true; } diff --git a/source/source_esolver/pw_hybrid_source.cpp b/source/source_esolver/pw_hybrid_source.cpp index f7f29597398..855b8d29640 100644 --- a/source/source_esolver/pw_hybrid_source.cpp +++ b/source/source_esolver/pw_hybrid_source.cpp @@ -69,9 +69,9 @@ ModuleESolver::ExxSourceHeader ModuleESolver::read_exx_source_header(std::istrea } void ModuleESolver::read_exx_source_occupations(std::istream& in, - const std::vector& headers, - int nspin, - ModuleBase::matrix& weights) + const std::vector& headers, + int nspin, + ModuleBase::matrix& weights) { const int spin_mult = nspin == 2 ? 2 : 1; const int nks = headers.size(); @@ -122,6 +122,10 @@ void ModuleESolver::read_exx_source_occupations(std::istream& in, } for (int axis = 0; axis < 3; ++axis) { + if (nspin == 2 && iq >= nq && header.kvec_c[axis] != headers[iq - nq].kvec_c[axis]) + { + throw std::runtime_error("EXX source spin channels must use the same q mesh"); + } // eig_occ.txt prints Cartesian coordinates with at least eight significant digits. const double tolerance = 5e-8 * std::max(1.0, std::abs(header.kvec_c[axis])); if (!std::isfinite(q[axis]) || std::abs(q[axis] - header.kvec_c[axis]) > tolerance) diff --git a/source/source_esolver/pw_hybrid_source.h b/source/source_esolver/pw_hybrid_source.h index 505a6ef1cb0..98a67cdcb67 100644 --- a/source/source_esolver/pw_hybrid_source.h +++ b/source/source_esolver/pw_hybrid_source.h @@ -29,9 +29,9 @@ ExxSourceHeader read_exx_source_header(std::istream& in); // Read the existing, k-weighted occupation column without changing its format. void read_exx_source_occupations(std::istream& in, - const std::vector& headers, - int nspin, - ModuleBase::matrix& weights); + const std::vector& headers, + int nspin, + ModuleBase::matrix& weights); } #endif diff --git a/source/source_esolver/test/test_pw_hybrid_source.cpp b/source/source_esolver/test/test_pw_hybrid_source.cpp index 2c47305e200..2ff631c2d7b 100644 --- a/source/source_esolver/test/test_pw_hybrid_source.cpp +++ b/source/source_esolver/test/test_pw_hybrid_source.cpp @@ -79,6 +79,20 @@ TEST(PWHybridSource, RejectsInvalidExistingOccupationFiles) EXPECT_THROW(ModuleESolver::read_exx_source_occupations(negative, headers, 1, weights), std::runtime_error); } +TEST(PWHybridSource, RejectsDifferentMeshesInSpinChannels) +{ + auto headers = source_headers(2); + headers[2].kvec_c[0] = 0.2; + std::string saved = eig_occ(2); + const std::string original = "spin=2 k-point=1/2 Cartesian=0"; + const std::size_t location = saved.find(original); + ASSERT_NE(location, std::string::npos); + saved.replace(location, original.size(), "spin=2 k-point=1/2 Cartesian=0.2"); + std::istringstream in(saved); + ModuleBase::matrix weights; + EXPECT_THROW(ModuleESolver::read_exx_source_occupations(in, headers, 2, weights), std::runtime_error); +} + TEST(PWHybridSource, ReadsExistingBinaryWavefunctionHeader) { // Native binary record layout from write_wfc_pw; no new wavefunction format. diff --git a/source/source_pw/module_pwdft/op_pw_exx.cpp b/source/source_pw/module_pwdft/op_pw_exx.cpp index b05d003422e..eae9fc8c717 100644 --- a/source/source_pw/module_pwdft/op_pw_exx.cpp +++ b/source/source_pw/module_pwdft/op_pw_exx.cpp @@ -960,8 +960,6 @@ std::vector OperatorEXXPW::get_q_points(const int ik) const } else if (nspin_ == 2) { - int nk_fac = 2; - int nk = source_basis_->nks / nk_fac; if (source_points_->isk[iq] == isk[ik]) { q_points_ik.push_back(iq); diff --git a/tests/integrate/CMakeLists.txt b/tests/integrate/CMakeLists.txt index a75ca159264..9f737798889 100644 --- a/tests/integrate/CMakeLists.txt +++ b/tests/integrate/CMakeLists.txt @@ -14,25 +14,4 @@ else() COMMAND ${BASH} Autotest.sh -a ${ABACUS_BIN_PATH} -n 4 -j auto WORKING_DIRECTORY ${ABACUS_TEST_DIR}/integrate ) -endif() -if(ENABLE_LIBXC AND ENABLE_MPI) - add_test( - NAME PW_HYBRID_NSCF - COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/tools/test_hybrid_nscf.py - ${ABACUS_BIN_PATH} --mpi-ranks 2 - ) - set_tests_properties(PW_HYBRID_NSCF PROPERTIES - LABELS "PW;EXX;NSCF" PROCESSORS 2 TIMEOUT 300 - ) -endif() - -if(ENABLE_LIBXC AND ENABLE_MPI AND USE_CUDA) - add_test( - NAME PW_HYBRID_NSCF_GPU - COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/tools/test_hybrid_nscf.py - ${ABACUS_BIN_PATH} --gpu - ) - set_tests_properties(PW_HYBRID_NSCF_GPU PROPERTIES - LABELS "PW;EXX;NSCF;GPU" PROCESSORS 1 TIMEOUT 300 RUN_SERIAL TRUE - ) -endif() +endif() \ No newline at end of file diff --git a/tests/integrate/tools/test_hybrid_nscf.py b/tests/integrate/tools/test_hybrid_nscf.py index e61021d0a72..c3f73bf4cce 100644 --- a/tests/integrate/tools/test_hybrid_nscf.py +++ b/tests/integrate/tools/test_hybrid_nscf.py @@ -141,6 +141,19 @@ def verify(executable, root, mpi_ranks): run(executable, unsupported, [], "Hybrid NSCF currently requires") print("missing/truncated source, invalid Miller mapping and unsupported ACE rejected") + equivalent = create_case(root, "equivalent_settings", extra + "exx_erfc_alpha 2.5e-1\nexx_erfc_omega 1.1e-1\n") + text = (equivalent / "INPUT").read_text().replace("dft_functional HSE", "dft_functional hse") + (equivalent / "INPUT").write_text(text) + run(executable, equivalent, []) + assert "EXX source configuration differs" not in (equivalent / "OUT.hybrid/warning.log").read_text() + assert max_difference(bands(same), bands(equivalent)) < 2e-4 + print("equivalent numeric notation and functional case do not trigger mismatch warnings") + + changed_exchange = create_case(root, "changed_exchange", extra + "exx_erfc_alpha 0.3\n") + run(executable, changed_exchange, []) + assert "EXX source configuration differs for exx_erfc_alpha" in (changed_exchange / "OUT.hybrid/warning.log").read_text() + print("changed exchange fraction is accepted with a warning") + legacy_source = root / "legacy_source" shutil.copytree(source, legacy_source) (legacy_source / "INPUT.info").unlink() From 04c334a4e919fdfd3d5231024402894af0b8827f Mon Sep 17 00:00:00 2001 From: Hongxu Ren Date: Thu, 8 Oct 2026 14:10:30 +0800 Subject: [PATCH 15/25] Shorten hybrid NSCF documentation and clarify runtime symmetry --- docs/advanced/elec_properties/hybrid_nscf.md | 209 ++---------------- docs/advanced/input_files/input-main.md | 2 +- docs/parameters.yaml | 2 +- .../module_parameter/read_inp_sys.cpp | 2 +- 4 files changed, 27 insertions(+), 188 deletions(-) diff --git a/docs/advanced/elec_properties/hybrid_nscf.md b/docs/advanced/elec_properties/hybrid_nscf.md index d6ea12ef8e8..94d2a8495f3 100644 --- a/docs/advanced/elec_properties/hybrid_nscf.md +++ b/docs/advanced/elec_properties/hybrid_nscf.md @@ -1,21 +1,13 @@ -# Screened hybrid NSCF with plane waves +# PW screened hybrid NSCF -A hybrid Hamiltonian needs occupied orbitals as well as the charge density. -PW screened hybrid NSCF now reads a **frozen SCF ensemble** on a source q mesh -and diagonalizes the Hamiltonian on an independent target k list. Increasing -`nbands` in NSCF changes the target states, not the source ensemble. +Hybrid NSCF reads the charge density, binary `wfk*_pw.dat` wavefunctions and +weighted occupations in `eig_occ.txt` from a converged SCF calculation. It keeps +that source fixed while solving a new K-point list or additional target bands. +No new file format is required. -This first implementation supports CPU and CUDA GPU calculations, `kpar 1`, `bndpar 1`, -`nspin 1` or `2`, and a complete, uniformly weighted source mesh without symmetry -reduction. Set `symmetry -1`, `exxace false` and -`exx_gamma_extra false` in both calculations. HSE is supported; -unscreened Fock exchange, including PBE0, is rejected pending validation of the -singularity correction for arbitrary target k points. Forces and stress are -also rejected in hybrid NSCF. The LCAO workflow is unchanged. +## SCF -## Prepare the source ensemble - -Run a converged hybrid SCF with the normal source `KPT` and these settings: +Use a complete, uniformly weighted source mesh and: ```text calculation scf @@ -33,193 +25,40 @@ cal_force 0 cal_stress 0 ``` -The output directory contains the charge density, existing `wfk*_pw.dat` -binary wavefunctions and `eig_occ.txt`. No new checkpoint format or companion -file is required. Precise source q coordinates, k weights and band count come -from the existing wavefunction headers; the occupation column in `eig_occ.txt` -already contains the k-weighted occupations required by EXX, including fractional -occupations. Use files from the same converged SCF calculation. The workflow -consumes these outputs without changing the existing wavefunction or occupation -writers/readers. - -## Solve target states +## NSCF -Keep the same structure, pseudopotentials, functional, cutoffs and FFT dimensions. -Point `read_file_dir` to the SCF output, replace `KPT` with the target mesh or -band path, and use: +Keep the same structure, pseudopotentials and cutoffs. In a separate output +directory, retain the shared settings above, replace `KPT` with the target +points, and change: ```text calculation nscf read_file_dir ../scf/OUT.hybrid init_wfc random nbands 20 -pw_diag_thr 1e-10 out_band 1 out_wfc_pw 0 out_chg 0 ``` -Retain the source SCF settings listed above, except its output and calculation -settings. Use a separate NSCF output directory to preserve the SCF files. -`init_wfc file` is rejected for this initial implementation: binary source -orbitals are read separately, whereas target orbitals start independently. -`nbands` may exceed the SCF band count. A different number of MPI processes -within the single PW pool is supported on CPU; binary coefficients are redistributed -by their Miller indices. CUDA NSCF currently uses one MPI rank. Select -`device gpu` and `precision double` for the validated CUDA workflow; the source -SCF may run on CPU or GPU. The binary checkpoint format is shared between -these devices. ROCm NSCF remains disabled pending backend verification. -Use `OMP_NUM_THREADS=1` for runtime tests. - -Missing or truncated wavefunctions/occupation files and invalid occupations -produce an error. Source dimensions, spin order, uniform q weights and occupation -K points must agree. The existing wavefunction reader additionally verifies k -coordinates, cell, source band count and plane-wave count. `INPUT.info`, when -available, is used only to warn about exchange configuration differences. Older -outputs without this metadata are accepted with a warning; regeneration is not -required solely because metadata is missing. -NSCF does not update -the frozen ensemble or run the EXX SCF outer loop. Its target occupations are -used for ordinary output only, and its printed total energy is not a new -self-consistent hybrid total energy. - -## Algorithm and implementation boundaries - -For each target state, exchange uses - -\[ -V_x\psi_{n\mathbf{k}} = -\alpha\sum_{\mathbf{q},m} - w_{\mathbf{q}} f_{m\mathbf{q}}\, - \psi_{m\mathbf{q}}\, - \mathcal{F}^{-1}\!\left[ - v(\mathbf{k}-\mathbf{q}+\mathbf{G}) - \mathcal{F}[\psi^*_{m\mathbf{q}}\psi_{n\mathbf{k}}] - \right]. -\] - -Here the periodic parts of source and target orbitals have separate PW bases. -The uniform source sum uses the same spin and weighted-occupation convention as -ABACUS SCF. The target `KPT` weights never define the exchange quadrature. -`OperatorEXXPW` accepts explicit source basis, points, orbitals and occupations; -the solver owns their lifetime. Coulomb-kernel construction uses target k -coordinates and source q coordinates, with the screened zero-transfer correction -computed from the source mesh. The two-basis path currently uses the full FFT -grid, including for distributed PW transforms. Small-grid acceleration remains -separate follow-up work. CUDA executes the pair-density FFTs and exchange -application on the GPU with separate source and target PW maps. This frozen-source NSCF workflow deliberately uses -direct exchange; ACE is not part of its implementation roadmap. The SCF ACE -projectors are tied to their original target subspace and cannot be reused as a -validated exchange operator on an independent band path. +Supports CPU/CUDA and `nspin 1/2`; use one MPI rank for CUDA. ACE, SOC, +unscreened exchange, forces and stress are unsupported in this workflow. +Set `symmetry -1`: input `0` is accepted but PW EXX resets it to `-1` at runtime. -The local `../q-e` implementation was used to analyze periodic pair densities, -`k-q+G` convolution, occupation normalization and the finite screened -zero-transfer term (`PW/src/exx.f90`, `exx_base.f90`). Its Fortran module/global -architecture was not adopted. That checkout explicitly rejects hybrid NSCF in -`PW/src/setup.f90`, so it cannot provide a direct NSCF reference. Also, its -built-in HSE screening default is `0.106 bohr^-1`; use -`screening_parameter=0.11` for comparison with ABACUS HSE06. +HSE defaults to `exx_singularity_correction limits`, as in LCAO. Set `gygi` to +retain the historical PW correction, which can produce jumps at source K points. +Use matching SCF/NSCF settings for consistent bands. Configuration differences +or missing `INPUT.info` produce warnings; missing or incompatible numerical +source data produces an error. -## Screened zero-transfer treatment +## Verification -PW HSE uses the same `exx_singularity_correction limits` default as NAO/LCAO. -For screened exchange the reciprocal kernel has the finite limit -`-pi * e2 / omega^2` at `k-q+G=0`; this scheme retains that limit without adding -an auxiliary-function correction. It uses `exx_gamma_extra false`, -which is selected automatically when omitted. Explicit gamma extrapolation -with `limits`, and unscreened Fock terms with `limits`, are rejected in PW. - -Set `exx_singularity_correction gygi` explicitly to retain the historical -PW Gygi-Baldereschi auxiliary-function correction (including the existing -gamma-extrapolation option). -This is also the default for unscreened PW hybrids; it does not enable -unscreened hybrid NSCF. For screened independent-k targets the Gygi correction -can cause a jump when a target coincides with a source point. -The name follows [QE's `gygi-baldereschi` terminology](https://www.quantum-espresso.org/Doc/INPUT_PW.html). -LCAO-specific `spencer`, `revised_spencer`, `massidda` and `carrier` schemes -are not implemented for PW and are rejected rather than silently ignored. - -Use the same scheme in SCF and NSCF for consistent bands. A different scheme -produces a warning and continues with the existing frozen source and the current -NSCF exchange settings. This also permits deliberate comparisons between schemes. - -The cross-code results below used the historical -Gygi scheme and do not constitute validation of the new default. - -## Reproducible verification +With MPI and LibXC enabled, substitute your configured executable/build paths: ```bash -cmake --build build --target MODULE_ESOLVER_pw_hybrid_source -j 8 -OMP_NUM_THREADS=1 ctest --test-dir build -V -R '^MODULE_ESOLVER_pw_hybrid_source$' +cmake --build build --target MODULE_ESOLVER_pw_hybrid_source +OMP_NUM_THREADS=1 ctest --test-dir build -R '^MODULE_ESOLVER_pw_hybrid_source$' OMP_NUM_THREADS=1 python3 tests/integrate/tools/test_hybrid_nscf.py ./build/abacus --mpi-ranks 2 -``` - -Supply the actual configured executable and build directory. The integration -script uses the existing H pseudopotential and structure fixture, performs SCF -and NSCF, and checks extra target bands, a different target k list, a shared -Gamma point, MPI redistribution, both collinear spin channels, immutable source -files, and invalid restart/unsupported-option errors. It needs LibXC and MPI. - -For a CUDA build and an available GPU, also run: - -```bash +# Optional: CUDA build and available GPU OMP_NUM_THREADS=1 python3 tests/integrate/tools/test_hybrid_nscf.py ./build/abacus --gpu ``` - -This compares CPU and GPU targets using one frozen CPU source on both a mesh -and an independent path with extra target bands, then checks a GPU-generated -spin-polarized source with CPU and GPU targets. Source files must remain -unchanged. A three-band single-precision GPU path additionally checks conversion -from a double-precision CPU source and the full-grid exchange FFT precision. -Single precision uses the existing looser diagonalization threshold; use -`precision double` for accurate high-energy target bands. The workflow script is run manually; only unit tests are registered with CMake/CTest. - -On a local RTX 3090 with CUDA 13.1, the CPU and GPU workflow scripts passed in a CUDA build. -The H CPU/GPU mesh, independent path and both spin-channel eigenvalues agreed -at the printed precision, as did all eight bands at nine Si L-Gamma-X points -using the same frozen CPU source (`20 Ry`, `2x2x2` source mesh). The Si check -compared raw eigenvalues without an energy shift. The three-band H -single-precision GPU path differed by at most `5.76e-5 eV` from double precision. -The CPU build also passed its source-adapter unit tests and NSCF integration test. -This validates device -consistency; it does not change the cross-code convergence limits below. - -On the initial local two-q-point, 10 Ry test, the same-mesh SCF/NSCF maximum -band difference was `3.7e-5 eV`; the shared Gamma point and serial/two-rank NSCF -results agreed to printed precision. The source-adapter unit tests cover occupations, spin meshes and binary headers. -A QE SCF comparison at this low cutoff showed band differences up to about -`0.03 eV`; that H test alone does not establish cross-code agreement. - -A separate Si comparison used the same two-atom primitive cell (`a=10.2 bohr`), -HSE exchange fraction `0.25`, screening `0.11 bohr^-1`, `20 Ry` cutoff, -`2x2x2` source mesh, eight bands and nine L-Gamma-X target points. VASP 6.2.1 -used `HFSCREEN=0.207869873 Angstrom^-1`, `PRECFOCK=Accurate`, `ISYM=-1`, -`ALGO=Damped`, `EDIFF=1e-9` and `NELMIN=40`. Its explicit k list contained the -eight source points and six additional zero-weight points. Target points -already present in the source mesh were included only once. This follows the -[VASP hybrid band workflow](https://vasp.at/wiki/Band-structure_calculation_using_hybrid_functionals). - -After aligning each code's Gamma valence-band top, the comparison gave: - -| Quantity (eV) | ABACUS NSCF | VASP | -| --- | ---: | ---: | -| Gamma direct gap | 3.604645 | 3.619060 | -| Gap on the sampled path | 1.449187 | 1.486063 | -| L direct gap | 3.967258 | 4.005180 | -| X direct gap | 4.655743 | 4.681974 | - -For bands 2-6 across all nine points, the RMS difference was `0.042351 eV` -and the maximum difference was `0.086995 eV`. Both codes placed the lowest -sampled conduction state at fractional `(0.375, 0, 0.375)`. -ABACUS used `Si_ONCV_PBE-1.0.upf`; VASP used `PAW_PBE Si 05Jan2001`. -The coarse mesh, sparse path and different pseudopotentials make this a -qualitative cross-check, not a cutoff or k-grid convergence study. - -An initial VASP reference with duplicate zero-weight Gamma points gave an -inconsistent band-4 eigenvalue: it differed from the weighted source Gamma -by `0.686083 eV`. Raising `NELMIN` to 60 did not remove that discrepancy. -The comparison above is from a fresh calculation with unique k coordinates, -using the weighted mesh result at coincident path points. No eigenvalues were -edited to align the spectra. - -These checks do not validate PBE0, symmetry reconstruction or source q pools. Direct exchange remains the NSCF method; ACE is not a -planned extension of this workflow. diff --git a/docs/advanced/input_files/input-main.md b/docs/advanced/input_files/input-main.md index d793e4e4bb0..df8a72d29f7 100644 --- a/docs/advanced/input_files/input-main.md +++ b/docs/advanced/input_files/input-main.md @@ -637,7 +637,7 @@ - **Description**: Specify the type of calculation. - scf: perform self-consistent electronic structure calculations - - nscf: perform non-self-consistent electronic structure calculations. A charge density file is required. PW screened hybrid NSCF additionally reads eig_occ.txt and existing binary SCF wavefunctions from read_file_dir; see the hybrid NSCF workflow documentation. The initial implementation supports CPU or CUDA GPU and requires kpar=bndpar=1, nspin=1/2, symmetry=-1/0, exxace=false, exx_gamma_extra=false and cal_force=cal_stress=false. + - nscf: perform non-self-consistent electronic structure calculations using a saved charge density. PW screened hybrids also require SCF binary wavefunctions and eig_occ.txt; see [hybrid NSCF](../elec_properties/hybrid_nscf.md). - relax: perform structure relaxation calculations, the relax_nmax parameter depicts the maximal number of ionic iterations - cell-relax: perform cell relaxation calculations - md: perform molecular dynamics simulations diff --git a/docs/parameters.yaml b/docs/parameters.yaml index 52d176783f2..cef70b444e1 100644 --- a/docs/parameters.yaml +++ b/docs/parameters.yaml @@ -32,7 +32,7 @@ parameters: Specify the type of calculation. * scf: perform self-consistent electronic structure calculations - * nscf: perform non-self-consistent electronic structure calculations. A charge density file is required. PW screened hybrid NSCF additionally reads eig_occ.txt and existing binary SCF wavefunctions from read_file_dir; see the hybrid NSCF workflow documentation. The initial implementation supports CPU or CUDA GPU and requires kpar=bndpar=1, nspin=1/2, symmetry=-1/0, exxace=false, exx_gamma_extra=false and cal_force=cal_stress=false. + * nscf: perform non-self-consistent electronic structure calculations using a saved charge density. PW screened hybrids also require SCF binary wavefunctions and eig_occ.txt; see [hybrid NSCF](../elec_properties/hybrid_nscf.md). * relax: perform structure relaxation calculations, the relax_nmax parameter depicts the maximal number of ionic iterations * cell-relax: perform cell relaxation calculations * md: perform molecular dynamics simulations diff --git a/source/source_io/module_parameter/read_inp_sys.cpp b/source/source_io/module_parameter/read_inp_sys.cpp index df9e37923fb..90fa6a6cc9b 100644 --- a/source/source_io/module_parameter/read_inp_sys.cpp +++ b/source/source_io/module_parameter/read_inp_sys.cpp @@ -151,7 +151,7 @@ void ReadInput::item_system() item.description = R"(Specify the type of calculation. * scf: perform self-consistent electronic structure calculations -* nscf: perform non-self-consistent electronic structure calculations. A charge density file is required. PW screened hybrid NSCF additionally reads eig_occ.txt and existing binary SCF wavefunctions from read_file_dir; see the hybrid NSCF workflow documentation. The initial implementation supports CPU or CUDA GPU and requires kpar=bndpar=1, nspin=1/2, symmetry=-1/0, exxace=false, exx_gamma_extra=false and cal_force=cal_stress=false. +* nscf: perform non-self-consistent electronic structure calculations using a saved charge density. PW screened hybrids also require SCF binary wavefunctions and eig_occ.txt; see [hybrid NSCF](../elec_properties/hybrid_nscf.md). * relax: perform structure relaxation calculations, the relax_nmax parameter depicts the maximal number of ionic iterations * cell-relax: perform cell relaxation calculations * md: perform molecular dynamics simulations From c33bda5209c59b0abf9dd639a5a44652eaafd224 Mon Sep 17 00:00:00 2001 From: Hongxu Ren Date: Wed, 14 Oct 2026 15:48:12 +0800 Subject: [PATCH 16/25] Add hybrid NSCF objects to legacy Makefile build --- source/Makefile.Objects | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/Makefile.Objects b/source/Makefile.Objects index 62df335c194..1186fcdbc25 100644 --- a/source/Makefile.Objects +++ b/source/Makefile.Objects @@ -327,6 +327,8 @@ OBJS_ESOLVER=esolver_factory.o\ esolver_of_tool.o\ esolver_dfpt_pw.o\ pw_others.o\ + pw_hybrid_nscf.o\ + pw_hybrid_source.o\ OBJS_ESOLVER_LCAO=esolver_ks_lcao.o\ esolver_ks_lcao_tddft.o\ From 0a8cf7e2fffde50543a66e374561e58cf041c625 Mon Sep 17 00:00:00 2001 From: Hongxu Ren Date: Wed, 14 Oct 2026 17:21:43 +0800 Subject: [PATCH 17/25] Address review: accept zero Fock coefficients, diagnose smeared source occupations, fix doc suffix - Treat explicit zero exx_fock_alpha as an omitted Fock term in NSCF validation and in SCF/NSCF configuration comparison. - Reject out-of-range source occupations with a diagnostic naming the unsupported smearing, and require smearing_method fixed in the doc. - Add suffix hybrid to the SCF doc snippet so read_file_dir resolves. - Cover the explicit-zero Fock input in the workflow regression and the smearing diagnostic in the occupation unit test. --- docs/advanced/elec_properties/hybrid_nscf.md | 6 ++++- source/source_esolver/pw_hybrid_nscf.cpp | 25 ++++++++++++++++++- source/source_esolver/pw_hybrid_source.cpp | 11 ++++++-- .../test/test_pw_hybrid_source.cpp | 12 ++++++++- tests/integrate/tools/test_hybrid_nscf.py | 5 ++-- 5 files changed, 52 insertions(+), 7 deletions(-) diff --git a/docs/advanced/elec_properties/hybrid_nscf.md b/docs/advanced/elec_properties/hybrid_nscf.md index 94d2a8495f3..dfbf28b7cb4 100644 --- a/docs/advanced/elec_properties/hybrid_nscf.md +++ b/docs/advanced/elec_properties/hybrid_nscf.md @@ -11,8 +11,10 @@ Use a complete, uniformly weighted source mesh and: ```text calculation scf +suffix hybrid basis_type pw dft_functional HSE +smearing_method fixed symmetry -1 kpar 1 bndpar 1 @@ -47,7 +49,9 @@ Set `symmetry -1`: input `0` is accepted but PW EXX resets it to `-1` at runtime HSE defaults to `exx_singularity_correction limits`, as in LCAO. Set `gygi` to retain the historical PW correction, which can produce jumps at source K points. -Use matching SCF/NSCF settings for consistent bands. Configuration differences +Use matching SCF/NSCF settings for consistent bands. The source must use fixed +occupations (`smearing_method fixed`); smearing can write occupations outside +`[0, k-point weight]`, which hybrid NSCF rejects. Configuration differences or missing `INPUT.info` produce warnings; missing or incompatible numerical source data produces an error. diff --git a/source/source_esolver/pw_hybrid_nscf.cpp b/source/source_esolver/pw_hybrid_nscf.cpp index 2c6bebca8cc..59ae02217da 100644 --- a/source/source_esolver/pw_hybrid_nscf.cpp +++ b/source/source_esolver/pw_hybrid_nscf.cpp @@ -100,6 +100,11 @@ void warn_source_configuration(const Input_para& inp, const std::string& readin_ std::ostringstream value; for (const auto& number : term.second) { + // Zero-valued Fock coefficients are equivalent to omitting the term. + if (term.first == "exx_fock_alpha" && std::stod(number) == 0.0) + { + continue; + } value << number << ' '; } expected[term.first] = value.str(); @@ -137,6 +142,11 @@ void warn_source_configuration(const Input_para& inp, const std::string& readin_ bool mismatch = false; while (original >> source_value) { + // Mirror the target-side normalization for saved zero Fock coefficients. + if (item.first == "exx_fock_alpha" && std::stod(source_value) == 0.0) + { + continue; + } if (!(current >> target_value)) { mismatch = true; @@ -168,8 +178,21 @@ void validate_hybrid_nscf(const Input_para& inp, const General_Exx_Info& info) { return; } + bool has_fock = false; const auto fock = info.coulomb_param.find(Conv_Coulomb_Pot_K::Coulomb_Type::Fock); - const bool has_fock = fock != info.coulomb_param.end() && !fock->second.empty(); + if (fock != info.coulomb_param.end()) + { + // An explicit zero coefficient (`exx_fock_alpha 0`) retains a Fock entry but is + // equivalent to omitting the term; only a nonzero coefficient is unscreened exchange. + for (const auto& term : fock->second) + { + if (std::stod(term.at("alpha")) != 0.0) + { + has_fock = true; + break; + } + } + } bool compatible_device = inp.device == "cpu"; #ifdef __CUDA compatible_device = compatible_device || inp.device == "gpu"; diff --git a/source/source_esolver/pw_hybrid_source.cpp b/source/source_esolver/pw_hybrid_source.cpp index 855b8d29640..3603445b08b 100644 --- a/source/source_esolver/pw_hybrid_source.cpp +++ b/source/source_esolver/pw_hybrid_source.cpp @@ -143,11 +143,18 @@ void ModuleESolver::read_exx_source_occupations(std::istream& in, std::string extra; const bool trailing = static_cast(band >> extra); if (!parsed || trailing || index != ib + 1 || !std::isfinite(energy) - || !std::isfinite(weights(iq, ib)) || weights(iq, ib) < 0 - || weights(iq, ib) > expected_weight + 1e-10) + || !std::isfinite(weights(iq, ib))) { throw std::runtime_error("Invalid EXX source occupation in eig_occ.txt"); } + if (weights(iq, ib) < 0 || weights(iq, ib) > expected_weight + 1e-10) + { + // Smearing such as Methfessel-Paxton can write occupations below zero or + // above the k-point weight; hybrid NSCF supports only a fixed-occupation source. + throw std::runtime_error( + "EXX source eig_occ.txt occupation is outside [0, k-point weight]; " + "hybrid NSCF requires a fixed-occupation source (smearing_method fixed)"); + } } } in >> std::ws; diff --git a/source/source_esolver/test/test_pw_hybrid_source.cpp b/source/source_esolver/test/test_pw_hybrid_source.cpp index 2ff631c2d7b..f475a2bd837 100644 --- a/source/source_esolver/test/test_pw_hybrid_source.cpp +++ b/source/source_esolver/test/test_pw_hybrid_source.cpp @@ -76,7 +76,17 @@ TEST(PWHybridSource, RejectsInvalidExistingOccupationFiles) std::string invalid = saved; invalid.replace(invalid.find("0.125"), 5, "-0.25"); std::istringstream negative(invalid); - EXPECT_THROW(ModuleESolver::read_exx_source_occupations(negative, headers, 1, weights), std::runtime_error); + try + { + // A negative occupation is what a Methfessel-Paxton source can produce; the + // diagnostic must name the unsupported smearing rather than report invalid data. + ModuleESolver::read_exx_source_occupations(negative, headers, 1, weights); + FAIL() << "Expected std::runtime_error"; + } + catch (const std::runtime_error& error) + { + EXPECT_NE(std::string(error.what()).find("smearing_method fixed"), std::string::npos); + } } TEST(PWHybridSource, RejectsDifferentMeshesInSpinChannels) diff --git a/tests/integrate/tools/test_hybrid_nscf.py b/tests/integrate/tools/test_hybrid_nscf.py index c3f73bf4cce..92302a36597 100644 --- a/tests/integrate/tools/test_hybrid_nscf.py +++ b/tests/integrate/tools/test_hybrid_nscf.py @@ -81,8 +81,9 @@ def verify(executable, root, mpi_ranks): assert not (source / "EXX_SOURCE").exists() original = digest(source) extra = f"calculation nscf\nread_file_dir {source}\nout_chg 0\nout_wfc_pw 0\n" - # More target bands than source bands, initialized independently. - same = create_case(root, "same", extra) + # More target bands than source bands, initialized independently. An explicit zero + # exx_fock_alpha must be accepted like an omitted Fock term and leave bands unchanged. + same = create_case(root, "same", extra + "exx_fock_alpha 0\n") (same / "INPUT").write_text((same / "INPUT").read_text().replace("nbands 3", "nbands 5")) run(executable, same, []) delta = max_difference(bands(scf), bands(same)) From 99177ba341664a649e97fe321388645a0c7f2d4c Mon Sep 17 00:00:00 2001 From: Hongxu Ren Date: Wed, 14 Oct 2026 18:20:02 +0800 Subject: [PATCH 18/25] Replace hybrid NSCF workflow script with standard integrate cases Drop tests/integrate/tools/test_hybrid_nscf.py and register two cases in tests/01_PW following the get_wf/get_pchg precedent: nscf_hse_same commits the frozen HSE SCF source (binary wavefunctions, eig_occ.txt, charge restart, INPUT.info) and solves the same mesh with more bands plus an explicit zero exx_fock_alpha; nscf_hse_path reads that source through a relative read_file_dir and solves an independent target k-point list. Bands are compared against committed references; both cases are registered for CPU and GPU suites. Update the documentation verification section. --- docs/advanced/elec_properties/hybrid_nscf.md | 6 +- tests/01_PW/CASES_CPU.txt | 2 + tests/01_PW/CASES_GPU.txt | 2 + tests/01_PW/nscf_hse_path/INPUT | 32 + tests/01_PW/nscf_hse_path/KPT | 6 + tests/01_PW/nscf_hse_path/README | 2 + tests/01_PW/nscf_hse_path/STRU | 19 + tests/01_PW/nscf_hse_path/band.txt.ref | 3 + tests/01_PW/nscf_hse_path/result.ref | 4 + tests/01_PW/nscf_hse_same/INPUT | 33 + tests/01_PW/nscf_hse_same/INPUT.info | 612 ++++++++++++++++++ tests/01_PW/nscf_hse_same/KPT | 4 + tests/01_PW/nscf_hse_same/README | 3 + tests/01_PW/nscf_hse_same/STRU | 19 + .../autotest-CHARGE-DENSITY.restart | Bin 0 -> 32008 bytes tests/01_PW/nscf_hse_same/band.txt.ref | 2 + tests/01_PW/nscf_hse_same/eig_occ.txt | 13 + tests/01_PW/nscf_hse_same/result.ref | 4 + tests/01_PW/nscf_hse_same/wfk1_pw.dat | Bin 0 -> 8412 bytes tests/01_PW/nscf_hse_same/wfk2_pw.dat | Bin 0 -> 8472 bytes tests/integrate/tools/test_hybrid_nscf.py | 326 ---------- 21 files changed, 763 insertions(+), 329 deletions(-) create mode 100644 tests/01_PW/nscf_hse_path/INPUT create mode 100644 tests/01_PW/nscf_hse_path/KPT create mode 100644 tests/01_PW/nscf_hse_path/README create mode 100644 tests/01_PW/nscf_hse_path/STRU create mode 100644 tests/01_PW/nscf_hse_path/band.txt.ref create mode 100644 tests/01_PW/nscf_hse_path/result.ref create mode 100644 tests/01_PW/nscf_hse_same/INPUT create mode 100644 tests/01_PW/nscf_hse_same/INPUT.info create mode 100644 tests/01_PW/nscf_hse_same/KPT create mode 100644 tests/01_PW/nscf_hse_same/README create mode 100644 tests/01_PW/nscf_hse_same/STRU create mode 100644 tests/01_PW/nscf_hse_same/autotest-CHARGE-DENSITY.restart create mode 100644 tests/01_PW/nscf_hse_same/band.txt.ref create mode 100644 tests/01_PW/nscf_hse_same/eig_occ.txt create mode 100644 tests/01_PW/nscf_hse_same/result.ref create mode 100644 tests/01_PW/nscf_hse_same/wfk1_pw.dat create mode 100644 tests/01_PW/nscf_hse_same/wfk2_pw.dat delete mode 100644 tests/integrate/tools/test_hybrid_nscf.py diff --git a/docs/advanced/elec_properties/hybrid_nscf.md b/docs/advanced/elec_properties/hybrid_nscf.md index dfbf28b7cb4..a26d7195d53 100644 --- a/docs/advanced/elec_properties/hybrid_nscf.md +++ b/docs/advanced/elec_properties/hybrid_nscf.md @@ -62,7 +62,7 @@ With MPI and LibXC enabled, substitute your configured executable/build paths: ```bash cmake --build build --target MODULE_ESOLVER_pw_hybrid_source OMP_NUM_THREADS=1 ctest --test-dir build -R '^MODULE_ESOLVER_pw_hybrid_source$' -OMP_NUM_THREADS=1 python3 tests/integrate/tools/test_hybrid_nscf.py ./build/abacus --mpi-ranks 2 -# Optional: CUDA build and available GPU -OMP_NUM_THREADS=1 python3 tests/integrate/tools/test_hybrid_nscf.py ./build/abacus --gpu +# Frozen-source band regressions: tests/01_PW/nscf_hse_same and nscf_hse_path +cd tests/01_PW +OMP_NUM_THREADS=1 bash ../integrate/Autotest.sh -a -r '^nscf_hse' ``` diff --git a/tests/01_PW/CASES_CPU.txt b/tests/01_PW/CASES_CPU.txt index 6f2f88dedda..7055c0f8e6a 100644 --- a/tests/01_PW/CASES_CPU.txt +++ b/tests/01_PW/CASES_CPU.txt @@ -123,3 +123,5 @@ scf_dftu_spin2 scf_dftu_spin4 scf_deltaspin2 scf_deltaspin4 +nscf_hse_same +nscf_hse_path diff --git a/tests/01_PW/CASES_GPU.txt b/tests/01_PW/CASES_GPU.txt index ae8dd3be56f..18fdbc7cf7a 100644 --- a/tests/01_PW/CASES_GPU.txt +++ b/tests/01_PW/CASES_GPU.txt @@ -115,3 +115,5 @@ scf_dftu_spin2 scf_dftu_spin4 scf_deltaspin2 scf_deltaspin4 +nscf_hse_same +nscf_hse_path diff --git a/tests/01_PW/nscf_hse_path/INPUT b/tests/01_PW/nscf_hse_path/INPUT new file mode 100644 index 00000000000..907cc77a8b6 --- /dev/null +++ b/tests/01_PW/nscf_hse_path/INPUT @@ -0,0 +1,32 @@ +INPUT_PARAMETERS +#Parameters (1.General) +suffix autotest +calculation nscf +nbands 3 +symmetry -1 + +#Parameters (2.Iteration) +ecutwfc 10 +scf_thr 1e-9 +scf_nmax 100 +pw_diag_thr 1e-10 +pw_seed 1 + +#Parameters (3.Basis) +basis_type pw + +#Parameters (4.Smearing) +smearing_method fixed + +#Parameters (5.ExactExchange) +dft_functional HSE +exxace false +exx_gamma_extra false + +read_file_dir ../nscf_hse_same/ +pseudo_dir ../../PP_ORB +out_band 1 +out_chg 0 +out_wfc_pw 0 +cal_force 0 +cal_stress 0 diff --git a/tests/01_PW/nscf_hse_path/KPT b/tests/01_PW/nscf_hse_path/KPT new file mode 100644 index 00000000000..56f407f00f9 --- /dev/null +++ b/tests/01_PW/nscf_hse_path/KPT @@ -0,0 +1,6 @@ +K_POINTS +3 +Direct +0 0 0 1 +0.125 0 0 1 +0.25 0 0 1 diff --git a/tests/01_PW/nscf_hse_path/README b/tests/01_PW/nscf_hse_path/README new file mode 100644 index 00000000000..748334c0a64 --- /dev/null +++ b/tests/01_PW/nscf_hse_path/README @@ -0,0 +1,2 @@ +PW HSE NSCF on the frozen SCF source committed in ../nscf_hse_same, solved on +an independent target k-point list that shares only the Gamma point. diff --git a/tests/01_PW/nscf_hse_path/STRU b/tests/01_PW/nscf_hse_path/STRU new file mode 100644 index 00000000000..c35003c65ba --- /dev/null +++ b/tests/01_PW/nscf_hse_path/STRU @@ -0,0 +1,19 @@ +ATOMIC_SPECIES +H 1 H_ONCV_PBE-1.0.upf + +LATTICE_CONSTANT +1.889766 + +LATTICE_VECTORS +0.0 2.708337 2.708337 +2.708337 0.0 2.708337 +2.708337 2.708337 0.0 + +ATOMIC_POSITIONS +Direct + +H +0 +2 +0.125 0.125 0.125 0 0 0 +0.675 0.835 0.875 0 0 0 diff --git a/tests/01_PW/nscf_hse_path/band.txt.ref b/tests/01_PW/nscf_hse_path/band.txt.ref new file mode 100644 index 00000000000..6c586d1df5d --- /dev/null +++ b/tests/01_PW/nscf_hse_path/band.txt.ref @@ -0,0 +1,3 @@ + 1 0.00000000 -11.12767527 0.23237114 5.91382475 + 2 0.03997035 -10.53435615 -0.56032894 5.88787937 + 3 0.07994070 -9.30092037 -2.20463726 5.45376065 diff --git a/tests/01_PW/nscf_hse_path/result.ref b/tests/01_PW/nscf_hse_path/result.ref new file mode 100644 index 00000000000..d1062bfbc38 --- /dev/null +++ b/tests/01_PW/nscf_hse_path/result.ref @@ -0,0 +1,4 @@ +etotref -34.96111659019459 +etotperatomref -17.4805582951 +CompareBand_pass 0 +totaltimeref 0.09 diff --git a/tests/01_PW/nscf_hse_same/INPUT b/tests/01_PW/nscf_hse_same/INPUT new file mode 100644 index 00000000000..a81d44ca265 --- /dev/null +++ b/tests/01_PW/nscf_hse_same/INPUT @@ -0,0 +1,33 @@ +INPUT_PARAMETERS +#Parameters (1.General) +suffix autotest +calculation nscf +nbands 5 +symmetry -1 + +#Parameters (2.Iteration) +ecutwfc 10 +scf_thr 1e-9 +scf_nmax 100 +pw_diag_thr 1e-10 +pw_seed 1 + +#Parameters (3.Basis) +basis_type pw + +#Parameters (4.Smearing) +smearing_method fixed + +#Parameters (5.ExactExchange) +dft_functional HSE +exx_fock_alpha 0 +exxace false +exx_gamma_extra false + +read_file_dir ./ +pseudo_dir ../../PP_ORB +out_band 1 +out_chg 0 +out_wfc_pw 0 +cal_force 0 +cal_stress 0 diff --git a/tests/01_PW/nscf_hse_same/INPUT.info b/tests/01_PW/nscf_hse_same/INPUT.info new file mode 100644 index 00000000000..a6818d20fd9 --- /dev/null +++ b/tests/01_PW/nscf_hse_same/INPUT.info @@ -0,0 +1,612 @@ +INPUT_PARAMETERS +#Parameters (1.System) +suffix hybrid #the name of main output directory +ntype 1 #atom species number +cell_replica 1 1 1 #replicate the input structure along the three lattice vectors +calculation scf #scf; relax; md; cell-relax; nscf; get_s; get_wf; get_pchg; gen_bessel; gen_opt_abfs; test_memory; test_neighbour +socket_driver 0 #run as a socket client for external drivers using the i-PI protocol +esolver_type ksdft #the energy solver: ksdft, sdft, ofdft, tdofdft, tddft, lj, dp, ks-lr, lr, dfpt +symmetry -1 #the control of symmetry +symmetry_prec 1e-06 #accuracy for symmetry +symmetry_autoclose 1 #whether to close symmetry automatically when error occurs in symmetry analysis +cal_force 0 #if calculate the force at the end of the electronic iteration +kpar 1 #devide all processors into kpar groups and k points will be distributed among +bndpar 1 #divide each k-point pool into band-parallel groups +latname user_defined_lattice #the name of lattice name +assume_isolated none #isolated-system electrostatic correction +init_wfc atomic #atomic; atomic+random; random; nao; nao+random; file txt; file binary +init_chg atomic #start charge is from 'atomic' or file +init_vel 0 #read velocity from STRU or not +mem_saver 0 #Only for nscf calculations. if set to 1, then a memory saving technique will be used for many k point calculations. +cal_stress 0 #calculate the stress or not +diago_proc 1 #the number of procs used to do diagonalization +nbspline -1 #the order of B-spline basis +kspacing 0 0 0 #unit in 1/bohr, should be > 0, default is 0 which means read KPT file +koffset 0 0 0 #offset for kspacing-generated automatic k-point mesh +kmesh_type gamma #mesh type for kspacing-generated automatic k-point mesh +min_dist_coef 0.2 #factor related to the allowed minimum distance between two atoms +device cpu #the computing device for ABACUS +precision double #the computing precision for ABACUS +gint_precision double #the computing precision for LCAO grid integral +timer_enable_nvtx 0 #enable NVTX labeling for profiling or not +cell_factor 1.2 #used in the construction of the pseudopotential tables +dm_to_rho 0 #reads dmr in npz format and calculates electron density +chg_extrap atomic #atomic; first-order; second-order; dm:coefficients of SIA +ecutwfc 10 #energy cutoff for wave functions +ecutrho 40 #energy cutoff for charge density and potential +nx 0 #number of points along x axis for FFT grid +ny 0 #number of points along y axis for FFT grid +nz 0 #number of points along z axis for FFT grid +ndx 0 #number of points along x axis for FFT smooth grid +ndy 0 #number of points along y axis for FFT smooth grid +ndz 0 #number of points along z axis for FFT smooth grid +pw_seed 1 #random seed for initializing wave functions +diag_subspace 0 #method of subspace diagonalization in dav_subspace. 0:LaPack; 1:genelpa, 2:scalapack +erf_ecut 0 #the value of the constant energy cutoff +fft_mode 0 #mode of FFTW +erf_height 0 #the height of the energy step for reciprocal vectors +erf_sigma 0.1 #the width of the energy step for reciprocal vectors +stru_file STRU #the filename of file containing atom positions +kpoint_file KPT #the name of file containing k points +pseudo_dir /tmp/abacus-hybrid-nscf-pr/tests/PP_ORB/ #the directory containing pseudo files +orbital_dir #the directory containing orbital files +read_file_dir OUT.hybrid/ #directory of files for reading +restart_load 0 #restart from disk +basis_type pw #PW; LCAO in pw; LCAO + +#Parameters (2.Electronic structure) +ks_solver cg #cg; dav; lapack; genelpa; elpa; scalapack_gvx; cusolver +nbands 3 #number of bands +nelec 0 #input number of electrons +nelec_delta 0 #change in the number of total electrons +nupdown 0 #the difference number of electrons between spin-up and spin-down +dft_functional HSE #exchange correlation functional +xc_temperature 0 #temperature for finite temperature functionals +xc_exch_ext #customize Libxc exchange functional parameters +xc_corr_ext #customize Libxc correlation functional parameters +pseudo_rcut 15 #default #exchange correlation functional +pseudo_mesh 0 #0: use our own mesh to do radial renormalization; 1: use mesh as in QE +nspin 1 #1: single spin; 2: up and down spin; 4: noncollinear spin +gga_grad 0 #Noncollinear GGA gradient method: 0 original, 1 local axis, 2 regularized projected LCA +smearing_method fixed #type of smearing_method: gauss; fd; fixed; mp; mp2; mv +smearing_sigma 0.015 #energy range for smearing +mixing_type broyden #plain; pulay; broyden +mixing_beta 0.8 #mixing parameter: 0 means no new charge +mixing_beta_mag -10 #mixing parameter for magnetic density +mixing_ndim 8 #mixing dimension in pulay or broyden +mixing_restart 0 #threshold to restart mixing during SCF +mixing_dmr 0 #whether to mix real-space density matrix +mixing_gg0 1 #mixing parameter in kerker +mixing_gg0_mag 0 #mixing parameter in kerker +mixing_gg0_min 0.1 #the minimum kerker coefficient +mixing_angle -10 #angle mixing parameter for non-colinear calculations +mixing_tau 0 #whether to mix tau in mGGA calculation +mixing_dftu 0 #whether to mix occ_mat in DFT+U calculation +gamma_only 0 #Only for localized orbitals set and gamma point. If set to 1, a fast algorithm is used +scf_nmax 100 #number of electron iterations +scf_thr 1e-09 #charge density error +scf_ene_thr -1 #total energy error threshold +scf_thr_type 1 #type of the criterion of scf_thr, 1: reci drho for pw, 2: real drho for lcao +scf_os_stop 0 #whether to stop scf when oscillation is detected +scf_os_thr -0.01 #charge density threshold for oscillation +scf_os_ndim 8 #number of old iterations used for oscillation detection +sc_os_ndim 5 #number of old iterations used for oscillation detection, for Spin-Constrained DFT +lspinorb 0 #consider the spin-orbit interaction +noncolin 0 #using non-collinear-spin +soc_lambda 1 #The fraction of SOC based on scalar relativity (SR) of the pseudopotential +dfthalf_type 0 #DFT-1/2 type, 0:off; 1:shell DFT-1/2 +pw_diag_thr 1e-10 #threshold for eigenvalues is cg electron iterations +diago_smooth_ethr 0 #smooth ethr for iter methods +use_k_continuity 0 #whether to use k-point continuity for initializing wave functions +pw_diag_nmax 50 #max iteration number for cg +pw_diag_ndim 4 #dimension of workspace for Davidson diagonalization +diago_cg_prec 1 #diago_cg_prec + +#Parameters (3.LCAO) +nb2d 0 #matrix 2d division +lmaxmax 2 #maximum of l channels used +lcao_ecut 0 #energy cutoff for LCAO +lcao_dk 0.01 #delta k for 1D integration in LCAO +lcao_dr 0.01 #delta r for 1D integration in LCAO +lcao_rmax 30 #max R for 1D two-center integration table +search_radius -1 #input search radius (Bohr) +bx 1 #division of an element grid in FFT grid along x +by 1 #division of an element grid in FFT grid along y +bz 1 #division of an element grid in FFT grid along z +elpa_num_thread -1 #Number of threads need to use in elpa +num_stream 4 #the nstream in compute the LCAO with CUDA +bessel_nao_ecut 10.000000 #energy cutoff for spherical bessel functions(Ry) +bessel_nao_tolerence 1e-12 #tolerence for spherical bessel root +bessel_nao_rcut #radial cutoff for spherical bessel functions(a.u.) +bessel_nao_smooth 1 #spherical bessel smooth or not +bessel_nao_sigma 0.1 #spherical bessel smearing_sigma + +#Parameters (4.Relaxation) +relax_method cg 2 #cg; bfgs; sd; cg_bfgs; lbfgs +relax_scale_force 0.5 #controls the size of the first CG 2 step +relax_nmax 1 #number of ion iteration steps +relax_cg_thr 0.5 #threshold for switching from cg to bfgs, unit: eV/Angstrom +force_thr 0.001 #force threshold, unit: Ry/Bohr +force_thr_ev 0.0257112 #force threshold, unit: eV/Angstrom +force_zero_out 0 #force invalid threshold, unit: eV/Angstrom +relax_bfgs_w1 0.01 #wolfe condition 1 for bfgs +relax_bfgs_w2 0.5 #wolfe condition 2 for bfgs +relax_bfgs_rmax 0.2 #maximal trust radius, unit: Bohr +relax_bfgs_rmin 1e-05 #minimal trust radius, unit: Bohr +relax_bfgs_init 0.5 #initial trust radius, unit: Bohr +stress_thr 0.5 #stress threshold +press1 0 #target pressure, unit: KBar +press2 0 #target pressure, unit: KBar +press3 0 #target pressure, unit: KBar +fixed_axes None #which axes are fixed +fixed_ibrav 0 #whether to preseve lattice type during relaxation +fixed_atoms 0 #whether to preseve direct coordinates of atoms during relaxation +relax 0 #allow relaxation along the specific direction + +#Parameters (5.Molecular dynamics) +md_type nvt #choose ensemble +md_nstep 10 #md steps +md_dt 1 #time step +md_thermostat nhc #choose thermostat +md_tfirst -1 #temperature first +md_tlast -1 #temperature last +md_prec_level 0 #precision level for vc-md +md_restart 0 #whether restart +md_restartfreq 5 #The period to output MD restart information +md_dumpfreq 1 #The period to dump MD information +md_neighbor_skin 0 #extra MDCell neighbor-list radius +md_out_force 1 #output all atomic forces into running_md.log or not +dump_force 1 #output atomic forces into the file MD_dump or not +dump_vel 1 #output atomic velocities into the file MD_dump or not +dump_virial 1 #output lattice virial into the file MD_dump or not +md_seed -1 #random seed for MD +md_tfreq 0 #oscillation frequency, used to determine qmass of NHC +md_tchain 1 #number of Nose-Hoover chains +md_pmode iso #NPT ensemble mode: iso, aniso, tri +ref_cell_factor 1 #construct a reference cell bigger than the initial cell +md_pcouple xyz #whether couple different components: xyz, xy, yz, xz, none +md_pfirst -1 #initial target pressure +md_plast -1 #final target pressure +md_pfreq 0 #oscillation frequency, used to determine qmass of thermostats coupled with barostat +md_pchain 1 #num of thermostats coupled with barostat +lj_rule 2 #combination rules used to construct the parameter matrix for LJ potential +lj_eshift 0 #whether to use energy shift for LJ potential +lj_rcut #cutoff radius of LJ potential +lj_epsilon #the value of epsilon for LJ potential +lj_sigma #the value of sigma for LJ potential +pot_file graph.pb #the filename of potential files for CMD such as DP +dp_rescaling 1 #rescaling factor for dp potential +dp_fparam #the frame parameter for dp potential +dp_aparam #the atomic parameter for dp potential +msst_direction 2 #the direction of shock wave +msst_vel 0 #the velocity of shock wave +msst_vis 0 #artificial viscosity +msst_tscale 0.01 #reduction in initial temperature +msst_qmass 1 #mass of thermostat +md_damp 1 #damping parameter (time units) used to add force in Langevin method +md_csvr_tau 100 #CSVR thermostat characteristic time scale +md_tolerance 100 #tolerance for velocity rescaling (K) +md_nraise 1 #parameters used when md_type=nvt +cal_syns 0 8 #calculate asynchronous overlap matrix to output for Hefei-NAMD +dmax 0.01 #maximum displacement of all atoms in one step (bohr) +plumed 0 #use PLUMED for collective variables and enhanced sampling +plumed_file plumed.dat #input file of PLUMED + +#Parameters (6.orbital free density functional theory) +of_kinetic wt #kinetic energy functional, such as tf, vw, wt +of_method tn #optimization method used in OFDFT, including cg1, cg2, tn (default) +of_conv energy #the convergence criterion, potential, energy (default), or both +of_tole 1e-06 #tolerance of the energy change (in Ry) for determining the convergence, default=2e-6 Ry +of_tolp 1e-05 #tolerance of potential for determining the convergence, default=1e-5 in a.u. +of_tf_weight 1 #weight of TF KEDF +of_vw_weight 1 #weight of vW KEDF +of_wt_alpha 0.833333 #parameter alpha of WT KEDF +of_wt_beta 0.833333 #parameter beta of WT KEDF +of_extwt_kappa 0.832442 #parameter kappa of EXT-WT KEDF +of_wt_rho0 0 #the average density of system, used in WT KEDF, in Bohr^-3 +of_hold_rho0 0 #If set to 1, the rho0 will be fixed even if the volume of system has changed, it will be set to 1 automaticly if of_wt_rho0 is not zero +of_lkt_a 1.3 #parameter a of LKT KEDF +of_xwm_rho_ref 0 #The reference density of XWM KEDF +of_xwm_kappa 0 #The parameter kappa of XWM KEDF +of_read_kernel 0 #If set to 1, the kernel of WT KEDF will be filled from file of_kernel_file, not from formula. Only usable for WT KEDF +of_kernel_file WTkernel.txt #The name of WT kernel file. +of_full_pw 1 #If set to 1, ecut will be ignored when collect planewaves, so that all planewaves will be used +of_full_pw_dim 0 #If of_full_pw = true, dimention of FFT is testricted to be (0) either odd or even; (1) odd only; (2) even only +of_ml_gene_data 0 #Generate training data or not +of_ml_device cpu #Run NN on GPU or CPU +of_ml_feg 0 #The Free Electron Gas limit: 0: no, 3: yes +of_ml_nkernel 1 #Number of kernels +of_ml_kernel 1 #Type of kernel, 1 for wt, 2 for yukawa, and 3 for TKK +of_ml_kernel_scaling 1 #Scaling parameter of kernel, w(r-r') = scaling^3 * w(scaling (r-r')) +of_ml_yukawa_alpha 1 #Parameter alpha of yukawa kernel +of_ml_kernel_file none #The file of TKK +of_ml_gamma 0 #Descriptor: gamma = (rho / rho0)^(1/3) +of_ml_p 0 #Descriptor: p = |nabla rho|^2 / [2 (3 pi^2)^(1/3) rho^(4/3)]^2 +of_ml_q 0 #Descriptor: q = nabla^2 rho / [4 (3 pi^2)^(2/3) rho^(5/3)] +of_ml_tanhp 0 #Descriptor: tanhp = tanh(chi_p * p) +of_ml_tanhq 0 #Descriptor: tanhq = tanh(chi_q * q) +of_ml_chi_p 1 #Hyperparameter: tanhp = tanh(chi_p * p) +of_ml_chi_q 1 #Hyperparameter: tanhq = tanh(chi_q * q) +of_ml_gammanl 0 #Descriptor: gammanl = int{gamma(r') * w(r-r') dr'} +of_ml_pnl 0 #Descriptor: pnl = int{p(r') * w(r-r') dr'} +of_ml_qnl 0 #Descriptor: qnl = int{q(r') * w(r-r') dr'} +of_ml_xi 0 #Descriptor: xi = int{rho(r')^(1/3) * w(r-r') dr'} / rho^(1/3) +of_ml_tanhxi 0 #Descriptor: tanhxi = tanh(chi_xi * xi) +of_ml_tanhxi_nl 0 #Descriptor: tanhxi_nl = int{tanhxi(r') * w(r-r') dr'} +of_ml_tanh_pnl 0 #Descriptor: tanh_pnl = tanh(chi_pnl * pnl) +of_ml_tanh_qnl 0 #Descriptor: tanh_qnl = tanh(chi_qnl * qnl) +of_ml_tanhp_nl 0 #Descriptor: tanhp_nl = int{tanhp(r') * w(r-r') dr'} +of_ml_tanhq_nl 0 #Descriptor: tanhq_nl = int{tanhq(r') * w(r-r') dr'} +of_ml_chi_xi 1 #Hyperparameter: tanhpxi = tanh(chi_xi * xi) +of_ml_chi_pnl 1 #Hyperparameter: tanh_pnl = tanh(chi_pnl * pnl) +of_ml_chi_qnl 1 #Hyperparameter: tanh_qnl = tanh(chi_qnl * qnl) +of_ml_local_test 0 #Test: read in the density, and output the F and Pauli potential +ml_exx 0 #Use ML EXX or not + +#Parameters (7.Stochastic DFT) +method_sto 2 #1: slow and save memory, 2: fast and waste memory +nbands_sto 256 #number of stochstic orbitals +nche_sto 100 #Chebyshev expansion orders +emin_sto 0 #trial energy to guess the lower bound of eigen energies of the Hamitonian operator +emax_sto 0 #trial energy to guess the upper bound of eigen energies of the Hamitonian operator +seed_sto 0 #the random seed to generate stochastic orbitals +initsto_ecut 0 #maximum ecut to init stochastic bands +initsto_freq 0 #frequency to generate new stochastic orbitals when running md +npart_sto 1 #Reduce memory when calculating Stochastic DOS + +#Parameters (8.DeepKS) +deepks_out_labels 0 #>0 compute descriptor for deepks. 1 used during training, 2 used for label production +deepks_out_freq_elec 0 #>0 frequency of electronic iteration to output descriptors and labels for deepks. +deepks_out_base none #base functional for output files, with dft_functional as target functional +deepks_scf 0 #>0 add V_delta to Hamiltonian +deepks_equiv 0 #whether to use equivariant version of DeePKS +deepks_model None #file dir of traced pytorch model: 'model.ptg +bessel_descriptor_lmax 2 #lmax used in generating spherical bessel functions +bessel_descriptor_ecut 10.000000 #energy cutoff for spherical bessel functions(Ry) +bessel_descriptor_tolerence 1e-12 #tolerence for spherical bessel root +bessel_descriptor_rcut 6 #radial cutoff for spherical bessel functions(a.u.) +bessel_descriptor_smooth 1 #spherical bessel smooth or not +bessel_descriptor_sigma 0.1 #sphereical bessel smearing_sigma +deepks_bandgap 0 #>0 for bandgap label +deepks_band_range -1 0 #(int, int) range of bands for bandgap label +deepks_v_delta 0 #!=0 for v_delta/v_delta_R label. when output, 1 for vdpre, 2 for phialpha and grad_evdm (can save memory ) -1 for vdrpre, -2 for phialpha_r and gevdm (can save memory) +deepks_out_unittest 0 #if set 1, prints intermediate quantities that shall be used for making unit test +lin_solver gmres #linear solver for real-time propagation +lin_precond kinetic_recycle #right preconditioner for PW real-time propagation +lin_thr 0 #residual tolerance of the linear solver +lin_maxiter 500 #maximum iterations per linear solve +lin_gmres_restart 20 #Arnoldi dimension of restarted GMRES +td_cn_init 1 #CN subspace initial guess and residual reuse +lin_reconstruct 1 #explicit GMRES residual reconstruction +estep_per_md 1 #steps of force change + +#Parameters (9.rt-tddft) +td_dt 1 #time step for evolving wavefunction +td_edm 0 #the method to calculate the energy density matrix +td_print_eij -1 #print eij or not +td_propagator 0 #method of propagator +td_vext 0 #add extern potential or not +td_vext_dire 1 #extern potential direction +td_stype 0 #type of electric field in space domain +td_ttype 0 #type of electric field in time domain +td_tstart 1 # number of steps where electric field starts +td_tend 1000 #number of steps where electric field ends +td_lcut1 0.05 #cut1 of interval in length gauge +td_lcut2 0.95 #cut2 of interval in length gauge +td_gauss_freq 22.13 #frequency (freq) of Gauss type electric field +td_gauss_phase 0 #phase of Gauss type electric field +td_gauss_sigma 30 #sigma of Gauss type electric field +td_gauss_t0 100 #step number of time center (t0) of Gauss type electric field +td_gauss_amp 0.25 #amplitude of Gauss type electric field +td_trape_freq 1.6 #frequency of Trapezoid type electric field +td_trape_phase 0 #phase of Trapezoid type electric field +td_trape_t1 1875 #t1 of Trapezoid type electric field +td_trape_t2 5625 #t2 of Trapezoid type electric field +td_trape_t3 7500 #t3 of Trapezoid type electric field +td_trape_amp 2.74 #amplitude of Trapezoid type electric field +td_trigo_freq1 1.16466 #frequency 1 of Trigonometric type electric field +td_trigo_freq2 0.029116 #frequency 2 of Trigonometric type electric field +td_trigo_phase1 0 #phase 1 of Trigonometric type electric field +td_trigo_phase2 0 #phase 2 of Trigonometric type electric field +td_trigo_amp 2.74 #amplitude of Trigonometric type electric field +td_heavi_t0 100 #t0 of Heaviside type electric field +td_heavi_amp 1 #amplitude of Heaviside type electric field +td_supsine_amp 0.27 #carrier electric-field scale of the supersine pulse +td_supsine_freq 0.18737 #carrier frequency of the supersine pulse +td_supsine_phase 0 #carrier phase at the center of the supersine pulse +td_supsine_sigma 0.75 #shape parameter of the supersine envelope +td_supsine_tstart default #start boundary step of the supersine pulse +td_supsine_tend default #end boundary step of the supersine pulse +init_vecpot_file 0 #init vector potential through file or not +ocp 0 #change occupation or not +ocp_set #set occupation +of_cd 0 #add CD Potential or not +of_mcd_alpha 1 #parameter of modified CD Potential +xc_kernel LDA #exchange correlation (XC) kernel for LR-TDDFT +lr_init_xc_kernel default #The method to initalize the xc kernel +lr_solver dav #the eigensolver for LR-TDDFT +lr_thr 0.01 #convergence threshold of the LR-TDDFT eigensolver +nocc 3 #the number of occupied orbitals to form the 2-particle basis ( <= nelec/2) +nvirt 1 #the number of virtual orbitals to form the 2-particle basis (nocc + nvirt <= nbands) + +#Parameters (10.lr-tddft) +lr_nstates 1 #the number of 2-particle states to be solved +lr_unrestricted 0 #Whether to use unrestricted construction for LR-TDDFT +abs_wavelen_range 0 0 #the range of wavelength(nm) to output the absorption spectrum +out_wfc_lr 0 #whether to output the eigenvectors (excitation amplitudes) in the particle-hole basis +abs_gauge velocity #whether to use length or velocity gauge to calculate the absorption spectrum in LR-TDDFT +abs_broadening 0.01 #the broadening (eta) for LR-TDDFT absorption spectrum +bse_tda tda #whether Tamm-Dancoff Approximation is used (can be 'tda', 'full' or 'both') +bse_spin_types singlet triplet #which spin type is calculated (can be 'singlet', 'triplet', also for test 'rpa', 'ipa') +bse_mem_save 0 #whether to save memory by adding V and W to BSE matrix directly +bse_ri_hartree 1 #whether to use RI approximation for Hartree term in BSE +bse_use_fine_kgrid 0 #Fine k-grid mode for BSE +bse_q_approx_mode 0 #q->kpair mapping mode: 0=exact, 1=coarse q grid, 2=mixed, 3=truncate +bse_q_approx_threshold 0.1 #threshold radius (in unit of 2*pi/lat0) for exact q mapping in mode 2; in mode 3 pairs with larger |q| are dropped entirely +out_bse_ab 0 #whether to output the AB matrix to file +bse_continue 0 #which step to continue from previous BSE calculation +plot_istate 0 #which state of exciton to be ploted +exciton_plot_type average #exciton density plot type: average or conditional +exciton_plot_format cube #exciton plot format: average supports cube, slice, or both; conditional supports slice only +exciton_fixed_coordinate 0 0 0 0 0 0 #fixed hole and electron Cartesian coordinates (Bohr): hx hy hz ex ey ez +exciton_slice_plane ab #cross-section plane: ab, bc, or ca +exciton_slice_pos 0 #offset along perpendicular direction (Bohr) for slice +exciton_slice_npoints 200 #grid points per dimension for slice +exciton_slice_range -1 2 -1 2 #slice cell range: ustart uend vstart vend +dfpt_qmesh 1 1 1 #Monkhorst-Pack q mesh for DFPT, should be >= 1, and commensurate with the KPT mesh +dfpt_qfile #file containing the DFPT q points; empty means the dfpt_qmesh Monkhorst-Pack mesh +dfpt_compute_q0 0 #whether to compute epsilon_inf and Born effective charges at q = 0 +dfpt_loto 0 #whether to apply the LO-TO non-analytic correction at q = 0 +dfpt_conv_thr 1e-08 #convergence threshold of the DFPT first-order density +dfpt_max_iter 100 #max number of the DFPT first-order density mixing iterations +dfpt_mix_beta 0.4 #mixing coefficient of the DFPT first-order density +out_freq_ion 0 #print information every few ionic steps +out_freq_td 0 #print information every few completed electronic iterations in RT-TDDFT +out_freq_elec 100 #print information every few electronic steps +out_chg 1 3 #> 0 output charge density for selected electron steps, second parameter controls the precision, default is 3. +out_pot 0 8 #output real space potential (with precision 8) +out_dmk 0 8 #>0 output density matrix DM(k) for each k-point +out_dmr 0 8 #output density matrix DM(R) with respect to lattice vector R (with precision 8) +out_wfc_pw 2 #output wave functions +out_wfc_lcao 0 #ouput LCAO wave functions, 0, no output 1: text, 2: binary +out_dos 0 #output energy and dos +out_ldos 0 3 #output mode of local density of states, second parameter controls the precision +out_band 1 8 #output energy and band structure (with precision 8) +out_proj_band 0 #output projected band structure + +#Parameters (11.Output) +out_stru 0 #output the structure files per ion step +out_level ie #ie(for electrons); i(for ions); +out_hsk 0 8 #output H(k) and S(k) matrices in reciprocal space +out_hsr 0 8 #output H(R) and S(R) matrices in real space +out_mat_tk 0 8 #output kinetic matrix of electrons T(k) +out_mat_r 0 8 #output r(R) matrix +out_mat_t 0 8 #output T(R) matrix +out_mat_dh 0 8 #output Hamiltonian derivatives dH/dR matrices +out_mat_dh_t 0 8 #output kinetic energy dH/dR (dT/dR) matrices +out_mat_dh_vl 0 8 #output local pseudopotential dH/dR (dV^L/dR) matrices +out_mat_dh_vnl 0 8 #output nonlocal pseudopotential dH/dR (dV^NL/dR) matrices +out_mat_dh_vh 0 8 #output Hartree dH/dR (dV^H/dR) matrices +out_mat_dh_vxc 0 8 #output exchange-correlation dH/dR (dV^XC/dR) matrices +out_mat_h_t 0 8 #output kinetic energy T(R) matrix +out_mat_h_vnl 0 8 #output nonlocal pseudopotential Vnl(R) matrix +out_mat_h_vl 0 8 #output local pseudopotential Vl(R) matrix +out_mat_h_vh 0 8 #output Hartree Vh(R) matrix +out_mat_h_vxc 0 8 #output exchange-correlation Vxc(R) matrix +out_mat_h_exx 0 8 #output exact-exchange Vexx(R) matrix +out_mat_ds 0 8 #output of derivative of S(R) matrix +out_mat_xc 0 #output exchange-correlation matrix in KS-orbital representation +out_mat_xc2 0 8 #output exchange-correlation matrix in NAO representation +out_mat_l 0 8 #output the expectation values of angular momentum operators +out_xc_r -1 3 #if >=0, output the derivatives of exchange correlation in realspace, second parameter controls the precision +out_eband_terms 0 #output the band energy terms separately +out_hr_npz 0 #output H(R) matrix in npz format +out_dm_npz 0 #output DM(R) matrix in npz format +out_mul 0 #mulliken charge or not +out_app_flag 1 #whether output r(R), H(R), S(R), T(R), and dH(R) matrices in an append manner during MD +out_ndigits 8 #the length of decimal part of output data +out_element_info 0 #output (projected) wavefunction of each element +restart_save 0 #print to disk every step for restart +rpa 0 #true:generate output files used in rpa calculation; false:(default) +rpa_out_vel 0 #whether to output velocity matrix for librpa +rpa_outdir OUT.librpa/ #output directory for librpa +out_pchg #specify the bands to be calculated for the partial (band-decomposed) charge densities +out_wfc_norm #specify the bands to be calculated for the norm of wavefunctions +out_wfc_re_im #specify the bands to be calculated for the real and imaginary parts of wavefunctions +if_separate_k 0 #specify whether to write the partial charge densities for all k-points to individual files or merge them +out_elf 0 3 #> 0 output electron localization function (ELF) for selected electron steps, second parameter controls the precision, default is 3. +out_spillage 0 #output spillage of wavefunctions. This parameter only accepts 0 or 2. +out_dipole 0 #output dipole or not +out_current 0 #output current or not +out_current_k 0 #output current for each k +out_efield 0 #output dipole or not +out_vecpot 0 #output TDDFT vector potential or not +cal_symm_repr 0 3 #output matrix representation of symmetry operation into running log file > 0 output the matrix representation of symmetry operation , the second parameter controls the precision, default is 3. +spillage_outdir ./ #output directory for spillage of wavefunctions. +dos_edelta_ev 0.03 #delta energy for dos +dos_sigma 0.07 #gauss b coefficeinet(default=0.07) +dos_scale 0.01 #scale dos range by + +#Parameters (12.Postprocess) +dos_emin_ev -15 #minimal range for dos +dos_emax_ev 15 #maximal range for dos +dos_nche 100 #orders of Chebyshev expansions for dos +stm_bias 1 0.1 1 #bias voltage used to calculate ldos +ldos_line 0 0 0 0 0 1 100 #start and end point of the line (direct coordinates) and number of points +cal_cond 0 #calculate electronic conductivities +cond_che_thr 1e-08 #control the error of Chebyshev expansions for conductivities +cond_dw 0.1 #frequency interval for conductivities +cond_wcut 10 #cutoff frequency (omega) for conductivities +cond_dt 0.02 #t interval to integrate Onsager coefficiencies +cond_dtbatch 0 #exp(iH*dt*cond_dtbatch) is expanded with Chebyshev expansion +cond_smear 1 #Smearing method for conductivities +cond_fwhm 0.4 #FWHM for conductivities +cond_nonlocal 1 #Nonlocal effects for conductivities +cond_mgga_vel 1 #Meta-GGA velocity correction for conductivities +berry_phase 0 #calculate berry phase or not +gdir 3 #calculate the polarization in the direction of the lattice vector +towannier90 0 #use wannier90 code interface or not +nnkpfile seedname.nnkp #the wannier90 code nnkp file name +wannier_method 1 #different implementation methods under Lcao basis set +wannier_spin up #calculate spin in wannier90 code interface +out_wannier_mmn 1 #output .mmn file or not +out_wannier_amn 1 #output .amn file or not +out_wannier_eig 1 #output .eig file or not +out_wannier_unk 0 #output UNK. file or not +out_wannier_wvfn_formatted 1 #output UNK. file in text format or in binary format + +#Parameters (13.Model) +efield_flag 0 #add electric field +dip_cor_flag 0 #dipole correction +efield_dir 2 #the direction of the electric field or dipole correction +efield_pos_max -1 #position of the maximum of the saw-like potential along crystal axis efield_dir +efield_pos_dec -1 #zone in the unit cell where the saw-like potential decreases +efield_amp 0 #amplitude of the electric field +gate_flag 0 #compensating charge or not +zgate 0.5 #position of charged plate +block 0 #add a block potential or not +block_down 0.45 #low bound of the block +block_up 0.55 #high bound of the block +block_height 0.1 #height of the block +imp_sol 0 #calculate implicit solvation correction or not +eb_k 80 #the relative permittivity of the bulk solvent +tau 1.0798e-05 #the effective surface tension parameter +sigma_k 0.6 #the width of the diffuse cavity +nc_k 0.00037 #the cut-off charge density + +#Parameters (14.vdW Correction) +vdw_method none #the method of calculating vdw (none ; d2 ; d3_0 ; d3_bj ; d4) +vdw_d4_xc default #functional name passed to DFT-D4 +vdw_d4_model d4 #DFT-D4 dispersion model +vdw_s6 default #scale parameter of d2/d3_0/d3_bj +vdw_s8 default #scale parameter of d3_0/d3_bj +vdw_a1 default #damping parameter of d3_0/d3_bj +vdw_a2 default #damping parameter of d3_0/d3_bj +vdw_d 20 #damping parameter of d2 +vdw_abc 0 #third-order term? +vdw_c6_file default #filename of C6 +vdw_c6_unit Jnm6/mol #unit of C6, Jnm6/mol or eVA6 +vdw_r0_file default #filename of R0 +vdw_r0_unit A #unit of R0, A or Bohr +vdw_cutoff_type radius #expression model of periodic structure, radius or period +vdw_cutoff_radius 0 #radius cutoff for periodic structure +vdw_radius_unit Bohr #unit of radius cutoff for periodic structure +vdw_cutoff_width2 0.05 #smooth cutoff width for two-body dispersion +vdw_cutoff_width3 0 #smooth cutoff width for three-body dispersion +vdw_cutoff_period 3 3 3 #periods of periodic structure +vdw_cn_thr 40 #radius cutoff for cn +vdw_cn_thr_unit Bohr #unit of cn_thr, Bohr or Angstrom + +#Parameters (15.exx) +exx_fock_alpha #fraction of Fock exchange 1/r in hybrid functionals +exx_erfc_alpha 0.25 #fraction of exchange erfc(wr)/r in hybrid functionals +exx_erfc_omega 0.11 #range-separation parameter erfc(wr)/r in hybrid functionals +exx_separate_loop 1 #if 1, a two-step method is employed, else it will start with a GGA-Loop, and then Hybrid-Loop +exx_hybrid_step 100 #the maximal electronic iteration number in the evaluation of Fock exchange +exx_mixing_beta 1 #mixing_beta for outer-loop when exx_separate_loop=1 +exx_fock_lambda #used to compensate for divergence points at G=0 in the evaluation of Fock exchange using lcao_in_pw method +exx_pca_threshold 0.0001 #threshold to screen on-site ABFs in exx +exx_c_threshold 0.0001 #threshold to screen C matrix in exx +exx_cs_inv_thr -1 #threshold to inverse Vq in abfs for generating Cs +exx_v_threshold 0.1 #threshold to screen C matrix in exx +exx_dm_threshold 0.0001 #threshold to screen density matrix in exx +exx_c_grad_threshold 0.0001 #threshold to screen nabla C matrix in exx +exx_v_grad_threshold 0.1 #threshold to screen nabla V matrix in exx +exx_c_grad_r_threshold 0.0001 #threshold to screen nabla C * R matrix in exx +exx_v_grad_r_threshold 0.1 #threshold to screen nabla V * R matrix in exx +exx_ccp_rmesh_times 1.5 #how many times larger the radial mesh required for calculating Columb potential is to that of atomic orbitals +exx_opt_orb_lmax 0 #the maximum l of the spherical Bessel functions for opt ABFs +exx_opt_orb_ecut 0 #the cut-off of plane wave expansion for opt ABFs +exx_opt_orb_tolerence 0 #the threshold when solving for the zeros of spherical Bessel functions for opt ABFs +exx_real_number 0 #exx calculated in real or complex +exx_singularity_correction limits #set the scheme of Coulomb singularity correction +rpa_ccp_rmesh_times 10 #how many times larger the radial mesh required for calculating Columb potential is to that of atomic orbitals +exx_symmetry_realspace 0 #whether to reduce real-space sector in Hexx calculation +out_ri_cv 0 #Whether to output the coefficient tensor C and ABFs-representation Coulomb matrix V +out_unshrinked_v 0 #whether to output the large Vq matrix in unshrinked auxiliary basis +exx_coul_moment 0 #whether to use moment method for Coulomb calculation +exx_rotate_abfs 0 #whether to rotate auxiliary basis for Coulomb calculation +exx_multip_moments_threshold 1e-10 #threshold to screen multipole moments in Coulomb calculation +shrink_abfs_pca_thr -1 #threshold to shrink auxiliary basis for GW/RPA +shrink_lu_inv_thr 1e-06 #threshold to get inverse of overlap matrix by LU decomposition in auxiliary basis representation + +#Parameters (16.dft+u) +dft_plus_u 0 #DFT+U correction method +dft_plus_dmft 0 #true:DFT+DMFT; false: standard DFT calcullation(default) +orbital_corr -1 #which correlated orbitals need corrected ; d:2 ,f:3, do not need correction:-1 +hubbard_u 0 #Hubbard Coulomb interaction parameter U(ev) +yukawa_potential 0 #default: false +yukawa_lambda -1 #default:0.0 +uramping -1 #increasing U values during SCF +omc 0 #the mode of occupation matrix control +onsite_radius 0 #radius of the sphere for onsite projection (Bohr) + +#Parameters (17.non-collinear spin-constrained DFT) +sc_mag_switch 0 #switch to control spin-constrained DFT +decay_grad_switch 0 #switch to control gradient break condition +sc_thr 1e-06 #Convergence criterion of spin-constrained iteration (RMS) in uB +nsc 100 #Maximal number of spin-constrained iteration +nsc_min 2 #Minimum number of spin-constrained iteration +alpha_trial 0.01 #Initial trial step size for lambda in eV/uB^2 +sccut 3 #Maximal step size for lambda in eV/uB +sc_drop_thr 0.001 #Convergence criterion ratio of lambda iteration in Spin-constrained DFT +sc_scf_thr 0.001 #Density error threshold for inner loop of spin-constrained SCF +sc_direction_only 0 #only optimize the direction of magnetization +sc_lambda_strategy bfgs #lambda update strategy for spin-constrained DFT +sc_scan_lambda_start 0 #start value for linear lambda scan (eV/uB) +sc_scan_lambda_end 1 #end value for linear lambda scan (eV/uB) +sc_scan_steps 20 #number of steps for linear lambda scan + +#Parameters (18.Quasiatomic Orbital analysis) +qo_switch 0 #switch to control quasiatomic orbital analysis +qo_basis szv #type of QO basis function: hydrogen: hydrogen-like basis, pswfc: read basis from pseudopotential +qo_strategy all #strategy to generate generate radial orbitals +qo_screening_coeff 0.1 #rescale the shape of radial orbitals +qo_thr 1e-06 #accuracy for evaluating cutoff radius of QO basis function + +#Parameters (19.PEXSI) +pexsi_npole 40 #Number of poles in expansion +pexsi_inertia 1 #Whether inertia counting is used at the very beginning of PEXSI process +pexsi_nmax 80 #Maximum number of PEXSI iterations after each inertia counting procedure +pexsi_comm 1 #Whether to construct PSelInv communication pattern +pexsi_storage 1 #Storage space used by the Selected Inversion algorithm for symmetric matrices +pexsi_ordering 0 #Ordering strategy for factorization and selected inversion +pexsi_row_ordering 1 #Row permutation strategy for factorization and selected inversion, 0: NoRowPerm, 1: LargeDiag +pexsi_nproc 1 #Number of processors for parmetis +pexsi_symm 1 #Matrix symmetry +pexsi_trans 0 #Whether to transpose +pexsi_method 1 #pole expansion method, 1: Cauchy Contour Integral, 2: Moussa optimized method +pexsi_nproc_pole 1 #Number of processes used by each pole +pexsi_temp 0.015 #Temperature, in the same unit as H +pexsi_gap 0 #Spectral gap +pexsi_delta_e 20 #An upper bound for the spectral radius of S^{-1} H +pexsi_mu_lower -10 #Initial guess of lower bound for mu +pexsi_mu_upper 10 #Initial guess of upper bound for mu +pexsi_mu 0 #Initial guess for mu (for the solver) +pexsi_mu_thr 0.05 #Stopping criterion in terms of the chemical potential for the inertia counting procedure +pexsi_mu_expand 0.3 #If the chemical potential is not in the initial interval, the interval is expanded by muInertiaExpansion +pexsi_mu_guard 0.2 #Safe guard criterion in terms of the chemical potential to reinvoke the inertia counting procedure +pexsi_elec_thr 0.001 #Stopping criterion of the PEXSI iteration in terms of the number of electrons compared to numElectronExact +pexsi_zero_thr 1e-10 #if the absolute value of matrix element is less than ZERO_Limit, it will be considered as 0 + +#Parameters (20.Test) +out_alllog 0 #output information for each processor, when parallel +nurse 0 #for coders +t_in_h 1 #calculate the kinetic energy or not +vl_in_h 1 #calculate the local potential or not +vnl_in_h 1 #calculate the nonlocal potential or not +vh_in_h 1 #calculate the hartree potential or not +vion_in_h 1 #calculate the local ionic potential or not +test_force 0 #test the force +test_stress 0 #test the stress +test_skip_ewald 0 #whether to skip ewald +ri_hartree_benchmark none #whether to use the RI approximation for the Hartree term in LR-TDDFT for benchmark (with FHI-aims/ABACUS read-in style) +aims_nbasis #the number of basis functions for each atom type used in FHI-aims (for benchmark) +rdmft 0 #whether to perform rdmft calculation, default is false +rdmft_power_alpha 0.656 #the alpha parameter of power-functional, g(occ_number) = occ_number^alpha used in exx-type functionals such as muller and power +exxace 0 #whether to perform ace calculation in exxpw +exx_gamma_extra 0 #whether to perform gamma extrapolation in exxpw +ecutexx 0 #energy cutoff for exx calculation, Ry +exx_batch_size 0 #band chunk width of the EXX batched path, 0 = all bands +exx_thr_type density #threshold type for exx outer loop, energy or density +exx_ene_thr 1e-05 #threshold for exx outer loop when exx_thr_type = energy diff --git a/tests/01_PW/nscf_hse_same/KPT b/tests/01_PW/nscf_hse_same/KPT new file mode 100644 index 00000000000..e769af76382 --- /dev/null +++ b/tests/01_PW/nscf_hse_same/KPT @@ -0,0 +1,4 @@ +K_POINTS +0 +Gamma +2 1 1 0 0 0 diff --git a/tests/01_PW/nscf_hse_same/README b/tests/01_PW/nscf_hse_same/README new file mode 100644 index 00000000000..d93148add80 --- /dev/null +++ b/tests/01_PW/nscf_hse_same/README @@ -0,0 +1,3 @@ +PW HSE NSCF on the frozen SCF source committed in this directory (binary +wavefunctions, eig_occ.txt, charge restart). Same k mesh with more target +bands; an explicit zero exx_fock_alpha is accepted like an omitted Fock term. diff --git a/tests/01_PW/nscf_hse_same/STRU b/tests/01_PW/nscf_hse_same/STRU new file mode 100644 index 00000000000..c35003c65ba --- /dev/null +++ b/tests/01_PW/nscf_hse_same/STRU @@ -0,0 +1,19 @@ +ATOMIC_SPECIES +H 1 H_ONCV_PBE-1.0.upf + +LATTICE_CONSTANT +1.889766 + +LATTICE_VECTORS +0.0 2.708337 2.708337 +2.708337 0.0 2.708337 +2.708337 2.708337 0.0 + +ATOMIC_POSITIONS +Direct + +H +0 +2 +0.125 0.125 0.125 0 0 0 +0.675 0.835 0.875 0 0 0 diff --git a/tests/01_PW/nscf_hse_same/autotest-CHARGE-DENSITY.restart b/tests/01_PW/nscf_hse_same/autotest-CHARGE-DENSITY.restart new file mode 100644 index 0000000000000000000000000000000000000000..f7c30f6865330e9be0986ad66c07a7fc25cda6b0 GIT binary patch literal 32008 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 literal 0 HcmV?d00001 diff --git a/tests/01_PW/nscf_hse_same/band.txt.ref b/tests/01_PW/nscf_hse_same/band.txt.ref new file mode 100644 index 00000000000..6648ef56ac4 --- /dev/null +++ b/tests/01_PW/nscf_hse_same/band.txt.ref @@ -0,0 +1,2 @@ + 1 0.00000000 -11.12767527 0.23237114 5.91382475 9.84140426 10.33312736 + 2 0.15988140 -8.18994369 -4.74422564 4.63092625 7.73162354 8.50832814 diff --git a/tests/01_PW/nscf_hse_same/eig_occ.txt b/tests/01_PW/nscf_hse_same/eig_occ.txt new file mode 100644 index 00000000000..cf5895f7dc4 --- /dev/null +++ b/tests/01_PW/nscf_hse_same/eig_occ.txt @@ -0,0 +1,13 @@ +1 # ionic step + Electronic state energy (eV) and occupations + Spin number 1 + spin=1 k-point=1/2 Cartesian=0.0000000 0.0000000 0.0000000 (137 plane wave) + 1 -11.12768112632454 1.000000000000000 + 2 0.2323374417247880 0.000000000000000 + 3 5.913816152912471 0.000000000000000 + + spin=1 k-point=2/2 Cartesian=-0.09230756733744730 0.09230756733744730 0.09230756733744730 (138 plane wave) + 1 -8.189957518901499 1.000000000000000 + 2 -4.744242172101769 0.000000000000000 + 3 4.630928303470863 0.000000000000000 + diff --git a/tests/01_PW/nscf_hse_same/result.ref b/tests/01_PW/nscf_hse_same/result.ref new file mode 100644 index 00000000000..d98de699753 --- /dev/null +++ b/tests/01_PW/nscf_hse_same/result.ref @@ -0,0 +1,4 @@ +etotref -33.63676769132638 +etotperatomref -16.8183838457 +CompareBand_pass 0 +totaltimeref 0.08 diff --git a/tests/01_PW/nscf_hse_same/wfk1_pw.dat b/tests/01_PW/nscf_hse_same/wfk1_pw.dat new file mode 100644 index 0000000000000000000000000000000000000000..da05022468cb2e19e101eb459a42a8a7a1ed6f70 GIT binary patch literal 8412 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 literal 0 HcmV?d00001 diff --git a/tests/01_PW/nscf_hse_same/wfk2_pw.dat b/tests/01_PW/nscf_hse_same/wfk2_pw.dat new file mode 100644 index 0000000000000000000000000000000000000000..64e9328b426b80e132f1b401a239c32c23427741 GIT binary patch literal 8472 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 literal 0 HcmV?d00001 diff --git a/tests/integrate/tools/test_hybrid_nscf.py b/tests/integrate/tools/test_hybrid_nscf.py deleted file mode 100644 index 92302a36597..00000000000 --- a/tests/integrate/tools/test_hybrid_nscf.py +++ /dev/null @@ -1,326 +0,0 @@ -#!/usr/bin/env python3 -"""Exercise a frozen HSE ensemble on independent PW target k points.""" -import argparse -import hashlib -import math -import os -from pathlib import Path -import shutil -import subprocess -import struct -import tempfile - -REPO = Path(__file__).resolve().parents[3] -COMMON = """INPUT_PARAMETERS -suffix hybrid -basis_type pw -device cpu -precision double -nbands 3 -ecutwfc 10 -scf_thr 1e-9 -scf_nmax 100 -pw_diag_thr 1e-10 -pw_seed 1 -smearing_method fixed -dft_functional HSE -symmetry -1 -exxace false -exx_gamma_extra false -out_band 1 -cal_force 0 -cal_stress 0 -""" -MESH = "K_POINTS\n0\nGamma\n2 1 1 0 0 0\n" -PATH = "K_POINTS\n3\nDirect\n0 0 0 1\n0.125 0 0 1\n0.25 0 0 1\n" - - -def create_case(root, name, extra, points=MESH): - case = root / name - case.mkdir() - shutil.copy(REPO / "tests/01_PW/scf_pbe0_spin1/STRU", case / "STRU") - text = COMMON + f"pseudo_dir {REPO / 'tests/PP_ORB'}\n" + extra - (case / "INPUT").write_text(text) - (case / "KPT").write_text(points) - return case - - -def run(executable, case, launcher, expected_error=None): - env = dict(os.environ, OMP_NUM_THREADS="1") - with (case / "run.log").open("w") as log: - result = subprocess.run(launcher + [str(executable)], cwd=case, env=env, - stdout=log, stderr=subprocess.STDOUT, timeout=180) - text = (case / "run.log").read_text() - if expected_error: - assert expected_error in text, text[-4000:] - else: - assert result.returncode == 0 and "TOTAL Time" in text, text[-4000:] - - -def bands(case, spin=0): - filename = "band.txt" if spin == 0 else f"bands{spin}.txt" - lines = (case / "OUT.hybrid" / filename).read_text().splitlines() - return [[float(value) for value in line.split()[2:]] for line in lines if line.strip()] - - -def max_difference(reference, target): - assert len(reference) == len(target) - return max(abs(a - b) for row, other in zip(reference, target) for a, b in zip(row, other)) - - -def digest(directory): - return {p.name: hashlib.sha256(p.read_bytes()).hexdigest() - for p in directory.iterdir() if p.is_file()} - - -def verify(executable, root, mpi_ranks): - scf = create_case(root, "scf", "calculation scf\nout_chg 1\nout_wfc_pw 2\n") - run(executable, scf, []) - source = scf / "OUT.hybrid" - assert (source / "eig_occ.txt").exists() - assert not (source / "EXX_SOURCE").exists() - original = digest(source) - extra = f"calculation nscf\nread_file_dir {source}\nout_chg 0\nout_wfc_pw 0\n" - # More target bands than source bands, initialized independently. An explicit zero - # exx_fock_alpha must be accepted like an omitted Fock term and leave bands unchanged. - same = create_case(root, "same", extra + "exx_fock_alpha 0\n") - (same / "INPUT").write_text((same / "INPUT").read_text().replace("nbands 3", "nbands 5")) - run(executable, same, []) - delta = max_difference(bands(scf), bands(same)) - assert delta < 2e-4, f"SCF/NSCF eigenvalue mismatch: {delta} eV" - print(f"same mesh, source 3 bands / target 5 bands: max difference {delta:.3g} eV") - - path = create_case(root, "path", extra, PATH) - run(executable, path, []) - values = bands(path) - assert len(values) == 3 and all(math.isfinite(x) for row in values for x in row) - gamma_delta = max_difference([bands(same)[0]], [values[0]]) - assert gamma_delta < 2e-4 - assert abs(values[1][0] - values[0][0]) > 0.1 - print(f"independent 3-point target / 2-point source: shared Gamma difference {gamma_delta:.3g} eV") - - if mpi_ranks > 1: - parallel = create_case(root, "parallel", extra) - (parallel / "INPUT").write_text((parallel / "INPUT").read_text().replace("nbands 3", "nbands 5")) - run(executable, parallel, ["mpirun", "-np", str(mpi_ranks)]) - delta = max_difference(bands(same), bands(parallel)) - assert delta < 2e-6, delta - print(f"serial SCF restart into {mpi_ranks} MPI ranks: max difference {delta:.3g} eV") - - spin_scf = create_case(root, "spin_scf", "calculation scf\nout_chg 1\nout_wfc_pw 2\nnspin 2\n") - run(executable, spin_scf, []) - spin_source = spin_scf / "OUT.hybrid" - spin = create_case(root, "spin_nscf", f"calculation nscf\nread_file_dir {spin_source}\nnspin 2\n") - run(executable, spin, []) - for channel in (1, 2): - delta = max_difference(bands(spin_scf, channel), bands(spin, channel)) - assert delta < 2e-4, delta - print(f"spin channel {channel}: max difference {delta:.3g} eV") - assert digest(source) == original, "NSCF modified the SCF restart ensemble" - - broken_source = root / "broken_source" - shutil.copytree(source, broken_source) - (broken_source / "eig_occ.txt").unlink() - broken = create_case(root, "missing", extra.replace(str(source), str(broken_source))) - run(executable, broken, [], "EXX source eig_occ.txt") - saved_occupations = (source / "eig_occ.txt").read_text() - (broken_source / "eig_occ.txt").write_text(saved_occupations[:len(saved_occupations) // 2]) - truncated = create_case(root, "truncated", extra.replace(str(source), str(broken_source))) - run(executable, truncated, [], "EXX source") - (broken_source / "eig_occ.txt").write_bytes((source / "eig_occ.txt").read_bytes()) - wavefunction = (source / "wfk1_pw.dat").read_bytes() - (broken_source / "wfk1_pw.dat").write_bytes(wavefunction[:90]) - broken_wave = create_case(root, "truncated_wave", extra.replace(str(source), str(broken_source))) - run(executable, broken_wave, [], "EXX source wavefunction") - invalid_miller = bytearray(wavefunction) - struct.pack_into("i", invalid_miller, 164, 2**30) - (broken_source / "wfk1_pw.dat").write_bytes(invalid_miller) - bad_grid = create_case(root, "bad_source_grid", extra.replace(str(source), str(broken_source))) - run(executable, bad_grid, [], "EXX source Miller index is incompatible with FFT grid") - unsupported = create_case(root, "unsupported_ace", extra) - (unsupported / "INPUT").write_text((unsupported / "INPUT").read_text().replace("exxace false", "exxace true")) - run(executable, unsupported, [], "Hybrid NSCF currently requires") - print("missing/truncated source, invalid Miller mapping and unsupported ACE rejected") - - equivalent = create_case(root, "equivalent_settings", extra + "exx_erfc_alpha 2.5e-1\nexx_erfc_omega 1.1e-1\n") - text = (equivalent / "INPUT").read_text().replace("dft_functional HSE", "dft_functional hse") - (equivalent / "INPUT").write_text(text) - run(executable, equivalent, []) - assert "EXX source configuration differs" not in (equivalent / "OUT.hybrid/warning.log").read_text() - assert max_difference(bands(same), bands(equivalent)) < 2e-4 - print("equivalent numeric notation and functional case do not trigger mismatch warnings") - - changed_exchange = create_case(root, "changed_exchange", extra + "exx_erfc_alpha 0.3\n") - run(executable, changed_exchange, []) - assert "EXX source configuration differs for exx_erfc_alpha" in (changed_exchange / "OUT.hybrid/warning.log").read_text() - print("changed exchange fraction is accepted with a warning") - - legacy_source = root / "legacy_source" - shutil.copytree(source, legacy_source) - (legacy_source / "INPUT.info").unlink() - legacy = create_case(root, "legacy", extra.replace(str(source), str(legacy_source))) - run(executable, legacy, []) - assert "EXX source configuration is incomplete" in (legacy / "OUT.hybrid/warning.log").read_text() - assert max_difference(bands(same), bands(legacy)) < 2e-4 - print("legacy source without INPUT.info is accepted with a warning") - - -def verify_correction(executable, root, gpu=False): - """Check the shared finite-limit scheme and restart convention on each device.""" - device = "gpu" if gpu else "cpu" - scf = create_case(root, f"limits_{device}_scf", - "calculation scf\nout_chg 1\nout_wfc_pw 2\n") - # Exercise the defaults, including automatic disabling of gamma extrapolation. - text = (scf / "INPUT").read_text().replace("exx_gamma_extra false\n", "") - text = text.replace("device cpu", f"device {device}") - (scf / "INPUT").write_text(text) - run(executable, scf, []) - source = scf / "OUT.hybrid" - original = digest(source) - extra = f"calculation nscf\nread_file_dir {source}\nexx_singularity_correction limits\n" - near_gamma = "K_POINTS\n3\nDirect\n0 0 0 1\n0.001 0 0 1\n-0.001 0 0 1\n" - target = create_case(root, f"limits_{device}_continuity", extra, near_gamma) - text = (target / "INPUT").read_text().replace("device cpu", f"device {device}") - (target / "INPUT").write_text(text) - run(executable, target, []) - values = bands(target) - delta = max(max_difference([values[0]], [row]) for row in values[1:]) - assert delta < 5e-3, f"Finite-limit discontinuity near Gamma: {delta} eV" - assert max_difference([bands(scf)[0]], [values[0]]) < 2e-4 - assert digest(source) == original - print(f"{device} default/explicit limits, Gamma +/-1e-3: max difference {delta:.3g} eV") - - mismatch = create_case(root, f"{device}_correction_mismatch", - extra.replace("correction limits", "correction gygi")) - text = (mismatch / "INPUT").read_text().replace("device cpu", f"device {device}") - (mismatch / "INPUT").write_text(text) - run(executable, mismatch, []) - assert "EXX source configuration differs for exx_singularity_correction" in (mismatch / "OUT.hybrid/warning.log").read_text() - print(f"{device} correction mismatch is accepted with a warning") - bad = create_case(root, f"{device}_bad_correction", extra.replace("correction limits", "correction spencer")) - run(executable, bad, [], "PW exx_singularity_correction must be limits or gygi") - old_name = create_case(root, f"{device}_obsolete_correction", - extra.replace("correction limits", "correction auxiliary")) - run(executable, old_name, [], "PW exx_singularity_correction must be limits or gygi") - gamma = create_case(root, f"{device}_limits_gamma", extra) - text = (gamma / "INPUT").read_text().replace("exx_gamma_extra false", "exx_gamma_extra true") - (gamma / "INPUT").write_text(text) - run(executable, gamma, [], "PW limits requires screened exchange") - unscreened = create_case(root, f"{device}_limits_fock", extra) - text = (unscreened / "INPUT").read_text().replace("dft_functional HSE", "dft_functional PBE0") - (unscreened / "INPUT").write_text(text) - run(executable, unscreened, [], "PW limits requires screened exchange") - - gygi = create_case(root, f"gygi_{device}_scf", - "calculation scf\nout_chg 1\nout_wfc_pw 2\nexx_singularity_correction gygi\n") - text = (gygi / "INPUT").read_text().replace("device cpu", f"device {device}") - (gygi / "INPUT").write_text(text) - run(executable, gygi, []) - aux_source = gygi / "OUT.hybrid" - aux_target = create_case(root, f"gygi_{device}_nscf", - f"calculation nscf\nread_file_dir {aux_source}\nexx_singularity_correction gygi\n") - text = (aux_target / "INPUT").read_text().replace("device cpu", f"device {device}") - (aux_target / "INPUT").write_text(text) - run(executable, aux_target, []) - assert max_difference(bands(gygi), bands(aux_target)) < 2e-4 - # Cross the zero-transfer threshold with the same source: the historical - # gygi scheme must exhibit the jump this test is intended to detect. - aux_near = create_case(root, f"gygi_{device}_continuity", - f"calculation nscf\nread_file_dir {aux_source}\nexx_singularity_correction gygi\n", - near_gamma) - text = (aux_near / "INPUT").read_text().replace("device cpu", f"device {device}") - (aux_near / "INPUT").write_text(text) - run(executable, aux_near, []) - aux_values = bands(aux_near) - aux_jump = max(max_difference([aux_values[0]], [row]) for row in aux_values[1:]) - assert aux_jump > 5e-3, "Auxiliary control failed to expose the zero-transfer jump" - shift = max_difference(bands(scf), bands(gygi)) - assert shift > 1e-5, "limits and gygi unexpectedly produced identical SCF bands" - print(f"{device} gygi control jump near Gamma: {aux_jump:.3g} eV") - print(f"{device} gygi SCF/NSCF matched; limits/gygi SCF difference {shift:.3g} eV") - print("unsupported scheme, gamma and unscreened limits rejected") - - -def verify_gpu(executable, root): - """Compare devices using the same frozen ensemble, then reverse the restart.""" - cpu_scf = create_case(root, "cpu_scf", "calculation scf\nout_chg 1\nout_wfc_pw 2\n") - run(executable, cpu_scf, []) - source = cpu_scf / "OUT.hybrid" - original = digest(source) - extra = f"calculation nscf\nread_file_dir {source}\n" - for name, points in (("same", MESH), ("path", PATH)): - reference = create_case(root, f"cpu_{name}", extra, points) - target = create_case(root, f"gpu_{name}", extra, points) - for case in (reference, target): - text = (case / "INPUT").read_text().replace("nbands 3", "nbands 5") - if case == target: - text = text.replace("device cpu", "device gpu") - (case / "INPUT").write_text(text) - run(executable, case, []) - delta = max_difference(bands(reference), bands(target)) - assert delta < 2e-6, f"CPU/GPU {name} mismatch: {delta} eV" - print(f"CPU source, CPU/GPU {name} targets: max difference {delta:.3g} eV") - single = create_case(root, "gpu_single", extra, PATH) - text = (single / "INPUT").read_text().replace("device cpu", "device gpu") - text = text.replace("precision double", "precision single") - text = text.replace("pw_diag_thr 1e-10", "pw_diag_thr 1e-6") - (single / "INPUT").write_text(text) - run(executable, single, []) - reference = [row[:3] for row in bands(root / "cpu_path")] - delta = max_difference(reference, bands(single)) - assert delta < 2e-4, f"Single-precision GPU restart mismatch: {delta} eV" - print(f"CPU double source, GPU single 3-band path: max difference {delta:.3g} eV") - assert digest(source) == original, "GPU NSCF modified CPU source files" - - gpu_scf = create_case(root, "gpu_scf", "calculation scf\nout_chg 1\nout_wfc_pw 2\nnspin 2\n") - text = (gpu_scf / "INPUT").read_text().replace("device cpu", "device gpu") - (gpu_scf / "INPUT").write_text(text) - run(executable, gpu_scf, []) - source = gpu_scf / "OUT.hybrid" - assert (source / "eig_occ.txt").exists() - assert not (source / "EXX_SOURCE").exists() - original = digest(source) - targets = [] - for device in ("cpu", "gpu"): - target = create_case(root, f"{device}_spin", f"calculation nscf\nread_file_dir {source}\nnspin 2\n", PATH) - text = (target / "INPUT").read_text().replace("device cpu", f"device {device}") - (target / "INPUT").write_text(text) - run(executable, target, []) - targets.append(target) - for channel in (1, 2): - delta = max_difference(bands(targets[0], channel), bands(targets[1], channel)) - assert delta < 2e-6, delta - gamma_delta = max_difference([bands(gpu_scf, channel)[0]], [bands(targets[1], channel)[0]]) - assert gamma_delta < 2e-4, gamma_delta - print(f"GPU source, spin {channel}, independent CPU/GPU targets: {delta:.3g} eV") - assert digest(source) == original, "NSCF modified GPU source files" - unsupported = create_case(root, "gpu_unsupported_ace", extra) - text = (unsupported / "INPUT").read_text().replace("device cpu", "device gpu") - text = text.replace("exxace false", "exxace true") - (unsupported / "INPUT").write_text(text) - run(executable, unsupported, [], "Hybrid NSCF currently requires") - print("CUDA NSCF rejects ACE") - - -def main(): - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument("executable", type=Path) - parser.add_argument("--workdir", type=Path) - parser.add_argument("--gpu", action="store_true", help="verify CUDA using one rank and double precision") - parser.add_argument("--mpi-ranks", type=int, default=2) - args = parser.parse_args() - executable = args.executable.resolve() - verify_case = verify_gpu if args.gpu else lambda exe, root: verify(exe, root, args.mpi_ranks) - if args.workdir: - args.workdir.mkdir(parents=True, exist_ok=True) - verify_case(executable, args.workdir.resolve()) - verify_correction(executable, args.workdir.resolve(), args.gpu) - else: - with tempfile.TemporaryDirectory(prefix="abacus-hybrid-nscf-") as directory: - verify_case(executable, Path(directory)) - verify_correction(executable, Path(directory), args.gpu) - print("PASS: screened hybrid NSCF regression") - - -if __name__ == "__main__": - main() From e6b9b9efd79bfddf19e3ba85907d29266e311447 Mon Sep 17 00:00:00 2001 From: Hongxu Ren Date: Wed, 14 Oct 2026 18:42:14 +0800 Subject: [PATCH 19/25] Name Methfessel-Paxton in the out-of-range source occupation diagnostic Only the MP smearing family can write occupations outside [0, k-point weight]; fixed, gauss, mv and fd stay non-negative and are accepted. Say so in the error message and the hybrid NSCF documentation. --- docs/advanced/elec_properties/hybrid_nscf.md | 7 ++++--- source/source_esolver/pw_hybrid_source.cpp | 9 ++++++--- source/source_esolver/test/test_pw_hybrid_source.cpp | 1 + 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/docs/advanced/elec_properties/hybrid_nscf.md b/docs/advanced/elec_properties/hybrid_nscf.md index a26d7195d53..36caf3c2a12 100644 --- a/docs/advanced/elec_properties/hybrid_nscf.md +++ b/docs/advanced/elec_properties/hybrid_nscf.md @@ -49,9 +49,10 @@ Set `symmetry -1`: input `0` is accepted but PW EXX resets it to `-1` at runtime HSE defaults to `exx_singularity_correction limits`, as in LCAO. Set `gygi` to retain the historical PW correction, which can produce jumps at source K points. -Use matching SCF/NSCF settings for consistent bands. The source must use fixed -occupations (`smearing_method fixed`); smearing can write occupations outside -`[0, k-point weight]`, which hybrid NSCF rejects. Configuration differences +Use matching SCF/NSCF settings for consistent bands. Do not use Methfessel-Paxton +smearing (`mp`/`mp2`/`mp3`) for the source: it can write occupations outside +`[0, k-point weight]`, which hybrid NSCF rejects; the non-negative schemes +(`fixed`, `gauss`, `mv`, `fd`) are accepted. Configuration differences or missing `INPUT.info` produce warnings; missing or incompatible numerical source data produces an error. diff --git a/source/source_esolver/pw_hybrid_source.cpp b/source/source_esolver/pw_hybrid_source.cpp index 3603445b08b..fefcff31097 100644 --- a/source/source_esolver/pw_hybrid_source.cpp +++ b/source/source_esolver/pw_hybrid_source.cpp @@ -149,11 +149,14 @@ void ModuleESolver::read_exx_source_occupations(std::istream& in, } if (weights(iq, ib) < 0 || weights(iq, ib) > expected_weight + 1e-10) { - // Smearing such as Methfessel-Paxton can write occupations below zero or - // above the k-point weight; hybrid NSCF supports only a fixed-occupation source. + // Methfessel-Paxton smearing can write occupations below zero or above + // the k-point weight, and the EXX operator silently drops wg < 1e-12; + // only non-negative occupation schemes are supported. throw std::runtime_error( "EXX source eig_occ.txt occupation is outside [0, k-point weight]; " - "hybrid NSCF requires a fixed-occupation source (smearing_method fixed)"); + "Methfessel-Paxton smearing (mp/mp2/mp3) can produce such occupations, " + "which hybrid NSCF does not support. Rerun the SCF source with " + "smearing_method fixed, gauss, mv or fd"); } } } diff --git a/source/source_esolver/test/test_pw_hybrid_source.cpp b/source/source_esolver/test/test_pw_hybrid_source.cpp index f475a2bd837..a0f03632aa9 100644 --- a/source/source_esolver/test/test_pw_hybrid_source.cpp +++ b/source/source_esolver/test/test_pw_hybrid_source.cpp @@ -85,6 +85,7 @@ TEST(PWHybridSource, RejectsInvalidExistingOccupationFiles) } catch (const std::runtime_error& error) { + EXPECT_NE(std::string(error.what()).find("Methfessel-Paxton"), std::string::npos); EXPECT_NE(std::string(error.what()).find("smearing_method fixed"), std::string::npos); } } From 9245343b74dd62f209b22b5e0d19f40424d43224 Mon Sep 17 00:00:00 2001 From: Hongxu Ren Date: Wed, 14 Oct 2026 19:33:57 +0800 Subject: [PATCH 20/25] Move frozen EXX source ownership from ESolver into OperatorEXXPW set_source now takes the source basis, k points and occupations by value handle and keeps them alive itself, instead of storing observer pointers into ESolver members. prepare_exx_nscf becomes a free function with local state only, ESolver_KS_PW drops its four exx_source members, and the staging wavefunction copy is released when the function returns instead of persisting alongside the operator's own copy for the whole NSCF run. The precision-converting constructor now rejects operators with an installed source. --- source/source_esolver/esolver_ks_pw.cpp | 4 +- source/source_esolver/esolver_ks_pw.h | 8 -- source/source_esolver/pw_hybrid_nscf.cpp | 110 +++++++++++--------- source/source_esolver/pw_hybrid_nscf.h | 17 +++ source/source_pw/module_pwdft/op_pw_exx.cpp | 34 +++--- source/source_pw/module_pwdft/op_pw_exx.h | 13 ++- 6 files changed, 110 insertions(+), 76 deletions(-) diff --git a/source/source_esolver/esolver_ks_pw.cpp b/source/source_esolver/esolver_ks_pw.cpp index a806de24b71..592f505d1c6 100644 --- a/source/source_esolver/esolver_ks_pw.cpp +++ b/source/source_esolver/esolver_ks_pw.cpp @@ -198,7 +198,9 @@ void ESolver_KS_PW::before_scf(UnitCell& ucell, const int istep) if (this->inp_->calculation == "nscf" && this->general_exx_info_.cal_exx) { - this->prepare_exx_nscf(ucell, PARAM.globalv.global_readin_dir); + const Input_para& inp = *this->inp_; + const std::string& readin_dir = PARAM.globalv.global_readin_dir; + ModuleESolver::prepare_exx_nscf(inp, ucell, this->pw_wfc, this->exx_helper, readin_dir); } ModuleBase::timer::end("ESolver_KS_PW", "before_scf"); diff --git a/source/source_esolver/esolver_ks_pw.h b/source/source_esolver/esolver_ks_pw.h index 8ef92e7ddd4..a03e73c943e 100644 --- a/source/source_esolver/esolver_ks_pw.h +++ b/source/source_esolver/esolver_ks_pw.h @@ -49,14 +49,6 @@ class ESolver_KS_PW : public ESolver_KS virtual void allocate_hamilt(const UnitCell& ucell); - void prepare_exx_nscf(const UnitCell& ucell, const std::string& readin_dir); - - // Owned SCF ensemble; its lifetime covers every target diagonalization. - std::unique_ptr exx_source_basis_; - K_Vectors exx_source_points_; - ModuleBase::matrix exx_source_weights_; - std::unique_ptr> exx_source_psi_; - /** @brief Let RT-TDDFT bind its endpoint field before wavefunction initialization uses H; ordinary DFT does nothing. */ virtual void prepare_init_hamilt(const UnitCell& ucell); diff --git a/source/source_esolver/pw_hybrid_nscf.cpp b/source/source_esolver/pw_hybrid_nscf.cpp index 59ae02217da..32796984846 100644 --- a/source/source_esolver/pw_hybrid_nscf.cpp +++ b/source/source_esolver/pw_hybrid_nscf.cpp @@ -210,10 +210,15 @@ void validate_hybrid_nscf(const Input_para& inp, const General_Exx_Info& info) } template -void ESolver_KS_PW::prepare_exx_nscf(const UnitCell& ucell, const std::string& readin_dir) +void prepare_exx_nscf(const Input_para& inp, + const UnitCell& ucell, + const ModulePW::PW_Basis_K* pw_wfc, + Exx_HelperBase* exx_helper, + const std::string& readin_dir) { ModuleBase::timer::start("ESolver_KS_PW", "prepare_exx_nscf"); - const Input_para& inp = *this->inp_; + std::unique_ptr source_points(new K_Vectors); + ModuleBase::matrix source_weights; warn_source_configuration(inp, readin_dir); const int spin_mult = inp.nspin == 2 ? 2 : 1; const std::vector first_index(1, 0); @@ -229,26 +234,26 @@ void ESolver_KS_PW::prepare_exx_nscf(const UnitCell& ucell, const std { throw std::runtime_error("Invalid EXX source spin dimensions"); } - exx_source_points_.set_nks(nks); - exx_source_points_.set_nkstot(nks); + source_points->set_nks(nks); + source_points->set_nkstot(nks); const int nq = nks / spin_mult; - exx_source_points_.set_nkstot_nospin(nq); - exx_source_points_.set_spin_mult(spin_mult); - exx_source_points_.kvec_d.resize(nks); - exx_source_points_.kvec_c.resize(nks); - exx_source_points_.wk.resize(nks); - exx_source_points_.isk.resize(nks); - exx_source_points_.ngk.resize(nks); - exx_source_points_.ik2iktot.resize(nks); + source_points->set_nkstot_nospin(nq); + source_points->set_spin_mult(spin_mult); + source_points->kvec_d.resize(nks); + source_points->kvec_c.resize(nks); + source_points->wk.resize(nks); + source_points->isk.resize(nks); + source_points->ngk.resize(nks); + source_points->ik2iktot.resize(nks); for (int iq = 0; iq < nks; ++iq) { - exx_source_points_.ik2iktot[iq] = iq; + source_points->ik2iktot[iq] = iq; } const ModuleBase::Matrix3 inverse_reciprocal = ucell.G.Inverse(); for (int iq = 0; iq < nks; ++iq) { const std::string filename = ModuleIO::filename_output(readin_dir, "wf", "pw", iq, - exx_source_points_.ik2iktot, inp.nspin, nks, 2, false, false, -1); + source_points->ik2iktot, inp.nspin, nks, 2, false, false, -1); std::ifstream in(filename, std::ios::binary); const auto metadata = read_exx_source_header(in); if (metadata.ecutwfc != inp.ecutwfc) @@ -256,62 +261,64 @@ void ESolver_KS_PW::prepare_exx_nscf(const UnitCell& ucell, const std throw std::runtime_error("EXX source wavefunction cutoff differs from the current basis"); } headers.push_back(metadata); - auto& q = exx_source_points_.kvec_c[iq]; + auto& q = source_points->kvec_c[iq]; q.x = metadata.kvec_c[0]; q.y = metadata.kvec_c[1]; q.z = metadata.kvec_c[2]; - exx_source_points_.kvec_d[iq] = q * inverse_reciprocal; - exx_source_points_.wk[iq] = metadata.weight; - exx_source_points_.isk[iq] = iq / nq; + source_points->kvec_d[iq] = q * inverse_reciprocal; + source_points->wk[iq] = metadata.weight; + source_points->isk[iq] = iq / nq; } std::ifstream occupations(readin_dir + "eig_occ.txt"); - read_exx_source_occupations(occupations, headers, inp.nspin, exx_source_weights_); + read_exx_source_occupations(occupations, headers, inp.nspin, source_weights); } catch (const std::exception& error) { ModuleBase::WARNING_QUIT("ESolver_KS_PW", error.what()); } - const int nqs = exx_source_points_.get_nks(); - int nq = exx_source_points_.get_nkstot_nospin(); - exx_source_points_.para_k.kinfo(nq, 1, 0, this->pw_wfc->poolrank, this->pw_wfc->poolnproc, inp.nspin); - exx_source_basis_.reset(new ModulePW::PW_Basis_K(inp.device, inp.precision)); + const int nqs = source_points->get_nks(); + int nq = source_points->get_nkstot_nospin(); + source_points->para_k.kinfo(nq, 1, 0, pw_wfc->poolrank, pw_wfc->poolnproc, inp.nspin); + std::unique_ptr source_basis( + new ModulePW::PW_Basis_K(inp.device, inp.precision)); #ifdef __MPI - exx_source_basis_->initmpi(this->pw_wfc->poolnproc, this->pw_wfc->poolrank, this->pw_wfc->pool_world); + source_basis->initmpi(pw_wfc->poolnproc, pw_wfc->poolrank, pw_wfc->pool_world); #endif - exx_source_basis_->initgrids(ucell.lat0, ucell.latvec, - this->pw_wfc->nx, this->pw_wfc->ny, this->pw_wfc->nz); - exx_source_basis_->initparameters(false, inp.ecutwfc, nqs, exx_source_points_.kvec_d.data()); + source_basis->initgrids(ucell.lat0, ucell.latvec, + pw_wfc->nx, pw_wfc->ny, pw_wfc->nz); + source_basis->initparameters(false, inp.ecutwfc, nqs, source_points->kvec_d.data()); // Preserve the exact stored Cartesian coordinates expected by the existing reader. for (int iq = 0; iq < nqs; ++iq) { - exx_source_basis_->kvec_c[iq] = exx_source_points_.kvec_c[iq]; + source_basis->kvec_c[iq] = source_points->kvec_c[iq]; } - exx_source_basis_->fft_bundle.initfftmode(inp.fft_mode); - exx_source_basis_->setuptransform(); - exx_source_basis_->collect_local_pw(inp.erf_ecut, inp.erf_height, inp.erf_sigma); + source_basis->fft_bundle.initfftmode(inp.fft_mode); + source_basis->setuptransform(); + source_basis->collect_local_pw(inp.erf_ecut, inp.erf_height, inp.erf_sigma); for (int iq = 0; iq < nqs; ++iq) { - exx_source_points_.ngk[iq] = exx_source_basis_->npwk[iq]; + source_points->ngk[iq] = source_basis->npwk[iq]; } - const int nbands = exx_source_weights_.nc; - const int nbasis = exx_source_basis_->npwk_max; - exx_source_psi_.reset(new psi::Psi(nqs, nbands, nbasis, exx_source_points_.ngk, true)); + const int nbands = source_weights.nc; + const int nbasis = source_basis->npwk_max; + std::unique_ptr> source_psi( + new psi::Psi(nqs, nbands, nbasis, source_points->ngk, true)); for (int iq = 0; iq < nqs; ++iq) { const std::string wfc_filename = ModuleIO::filename_output(readin_dir, "wf", "pw", iq, - exx_source_points_.ik2iktot, inp.nspin, nqs, 2, false, false, -1); + source_points->ik2iktot, inp.nspin, nqs, 2, false, false, -1); try { - validate_source_grid(wfc_filename, *exx_source_basis_, iq); + validate_source_grid(wfc_filename, *source_basis, iq); } catch (const std::exception& error) { ModuleBase::WARNING_QUIT("ESolver_KS_PW", error.what()); } ModuleBase::ComplexMatrix wfc(nbands, nbasis); - ModuleIO::read_wfc_pw(wfc_filename, exx_source_basis_.get(), this->pw_wfc->poolrank, - this->pw_wfc->poolnproc, nbands, 1, iq, iq, nqs, wfc); - exx_source_psi_->fix_k(iq); + ModuleIO::read_wfc_pw(wfc_filename, source_basis.get(), pw_wfc->poolrank, + pw_wfc->poolnproc, nbands, 1, iq, iq, nqs, wfc); + source_psi->fix_k(iq); std::vector coefficients(nbands * nbasis); for (int ib = 0; ib < nbands; ++ib) { @@ -321,22 +328,23 @@ void ESolver_KS_PW::prepare_exx_nscf(const UnitCell& ucell, const std } } base_device::memory::synchronize_memory_op()( - exx_source_psi_->get_pointer(), coefficients.data(), coefficients.size()); + source_psi->get_pointer(), coefficients.data(), coefficients.size()); } - auto* helper = static_cast*>(this->exx_helper); - helper->op_exx->set_source(*exx_source_basis_, exx_source_points_, *exx_source_psi_, exx_source_weights_); + auto* helper = static_cast*>(exx_helper); + helper->op_exx->set_source(std::move(source_basis), std::move(source_points), + *source_psi, std::move(source_weights)); ModuleBase::timer::end("ESolver_KS_PW", "prepare_exx_nscf"); } -template void ESolver_KS_PW, base_device::DEVICE_CPU>::prepare_exx_nscf( - const UnitCell&, const std::string&); -template void ESolver_KS_PW, base_device::DEVICE_CPU>::prepare_exx_nscf( - const UnitCell&, const std::string&); +template void prepare_exx_nscf, base_device::DEVICE_CPU>( + const Input_para&, const UnitCell&, const ModulePW::PW_Basis_K*, Exx_HelperBase*, const std::string&); +template void prepare_exx_nscf, base_device::DEVICE_CPU>( + const Input_para&, const UnitCell&, const ModulePW::PW_Basis_K*, Exx_HelperBase*, const std::string&); #if defined(__CUDA) || defined(__ROCM) -template void ESolver_KS_PW, base_device::DEVICE_GPU>::prepare_exx_nscf( - const UnitCell&, const std::string&); -template void ESolver_KS_PW, base_device::DEVICE_GPU>::prepare_exx_nscf( - const UnitCell&, const std::string&); +template void prepare_exx_nscf, base_device::DEVICE_GPU>( + const Input_para&, const UnitCell&, const ModulePW::PW_Basis_K*, Exx_HelperBase*, const std::string&); +template void prepare_exx_nscf, base_device::DEVICE_GPU>( + const Input_para&, const UnitCell&, const ModulePW::PW_Basis_K*, Exx_HelperBase*, const std::string&); #endif } // namespace ModuleESolver diff --git a/source/source_esolver/pw_hybrid_nscf.h b/source/source_esolver/pw_hybrid_nscf.h index 763c097b212..91805d29a47 100644 --- a/source/source_esolver/pw_hybrid_nscf.h +++ b/source/source_esolver/pw_hybrid_nscf.h @@ -1,10 +1,27 @@ #ifndef PW_HYBRID_NSCF_H #define PW_HYBRID_NSCF_H +#include + struct Input_para; struct General_Exx_Info; +class UnitCell; +class Exx_HelperBase; +namespace ModulePW +{ +class PW_Basis_K; +} namespace ModuleESolver { void validate_hybrid_nscf(const Input_para& inp, const General_Exx_Info& info); + +// Read the frozen SCF ensemble in readin_dir and install it into the EXX operator +// held by exx_helper, which takes ownership for its whole remaining lifetime. +template +void prepare_exx_nscf(const Input_para& inp, + const UnitCell& ucell, + const ModulePW::PW_Basis_K* pw_wfc, + Exx_HelperBase* exx_helper, + const std::string& readin_dir); } #endif diff --git a/source/source_pw/module_pwdft/op_pw_exx.cpp b/source/source_pw/module_pwdft/op_pw_exx.cpp index eae9fc8c717..b580cad1f62 100644 --- a/source/source_pw/module_pwdft/op_pw_exx.cpp +++ b/source/source_pw/module_pwdft/op_pw_exx.cpp @@ -239,27 +239,30 @@ void OperatorEXXPW::act(const int nbands, } template -void OperatorEXXPW::set_source(const ModulePW::PW_Basis_K& source_basis, - const K_Vectors& source_points, +void OperatorEXXPW::set_source(std::unique_ptr source_basis, + std::unique_ptr source_points, const psi::Psi& source_psi, - const ModuleBase::matrix& source_weights) + ModuleBase::matrix source_weights) { if (exxace_ || gamma_extrapolation || exx_sg_init) { ModuleBase::WARNING_QUIT("OperatorEXXPW", "Independent EXX sources require direct exchange without gamma extrapolation, before FFT initialization"); } - if (source_basis.nks != source_points.get_nks() || source_psi.get_nk() != source_basis.nks - || source_weights.nr != source_basis.nks || source_weights.nc != source_psi.get_nbands() - || source_psi.get_nbasis() != source_basis.npwk_max - || source_basis.nx != wfcpw->nx || source_basis.ny != wfcpw->ny || source_basis.nz != wfcpw->nz - || source_basis.nrxx != wfcpw->nrxx || source_basis.poolnproc != wfcpw->poolnproc) + if (source_basis->nks != source_points->get_nks() || source_psi.get_nk() != source_basis->nks + || source_weights.nr != source_basis->nks || source_weights.nc != source_psi.get_nbands() + || source_psi.get_nbasis() != source_basis->npwk_max + || source_basis->nx != wfcpw->nx || source_basis->ny != wfcpw->ny || source_basis->nz != wfcpw->nz + || source_basis->nrxx != wfcpw->nrxx || source_basis->poolnproc != wfcpw->poolnproc) { ModuleBase::WARNING_QUIT("OperatorEXXPW", "Incompatible EXX source dimensions or FFT distribution"); } - source_basis_ = &source_basis; - source_points_ = &source_points; + owned_source_basis_ = std::move(source_basis); + owned_source_points_ = std::move(source_points); + owned_source_weights_ = std::move(source_weights); + source_basis_ = owned_source_basis_.get(); + source_points_ = owned_source_points_.get(); + wg = &owned_source_weights_; psi = source_psi; - wg = &source_weights; // Cache the Gygi-Baldereschi auxiliary correction on the frozen source mesh, rather than // the independent target path. Limits keeps this correction at zero. const auto screened = coulomb_param.find(Conv_Coulomb_Pot_K::Coulomb_Type::Erfc); @@ -274,8 +277,8 @@ void OperatorEXXPW::set_source(const ModulePW::PW_Basis_K& source_bas const double omega = std::stod(param.at("omega")); erfc_div[i] = exx_divergence(Conv_Coulomb_Pot_K::Coulomb_Type::Erfc, omega, - &source_points, - &source_basis, + source_points_, + source_basis_, rhopw_dev, tpiba, gamma_extrapolation, @@ -1010,6 +1013,11 @@ template template OperatorEXXPW::OperatorEXXPW(const OperatorEXXPW *op) { + if (op->owned_source_basis_ || op->owned_source_points_) + { + ModuleBase::WARNING_QUIT("OperatorEXXPW", + "Precision conversion after EXX source installation is unsupported"); + } // copy all the datas this->isk = op->isk; this->wfcpw = op->wfcpw; diff --git a/source/source_pw/module_pwdft/op_pw_exx.h b/source/source_pw/module_pwdft/op_pw_exx.h index 799f8f60385..2715a497161 100644 --- a/source/source_pw/module_pwdft/op_pw_exx.h +++ b/source/source_pw/module_pwdft/op_pw_exx.h @@ -60,10 +60,12 @@ class OperatorEXXPW : public OperatorPW void set_wg(const ModuleBase::matrix *wg_in) { wg = wg_in; } // The source orbitals remain fixed while target states are diagonalized. - void set_source(const ModulePW::PW_Basis_K& source_basis, - const K_Vectors& source_points, + // Takes ownership of the frozen ensemble: the operator keeps observer pointers + // to these objects, so their lifetime must match the operator's own. + void set_source(std::unique_ptr source_basis, + std::unique_ptr source_points, const psi::Psi& source_psi, - const ModuleBase::matrix& source_weights); + ModuleBase::matrix source_weights); void construct_ace() const; @@ -79,6 +81,11 @@ class OperatorEXXPW : public OperatorPW const ModulePW::PW_Basis_K* wfcpw = nullptr; const ModulePW::PW_Basis_K* source_basis_ = nullptr; const K_Vectors* source_points_ = nullptr; + // Owned frozen SCF source for hybrid NSCF; null in ordinary SCF, where the + // observer pointers above alias wfcpw/kv instead. + std::unique_ptr owned_source_basis_; + std::unique_ptr owned_source_points_; + ModuleBase::matrix owned_source_weights_; const ModulePW::PW_Basis* rhopw = nullptr; ModulePW::PW_Basis* rhopw_dev = nullptr; // for device const UnitCell *ucell = nullptr; From 0a91abde60fed9a383dfb3b12f74d343ff854d81 Mon Sep 17 00:00:00 2001 From: Hongxu Ren Date: Sun, 18 Oct 2026 14:01:23 +0800 Subject: [PATCH 21/25] ci: disable PW HSE NSCF GPU cases until libxc is available --- tests/01_PW/CASES_GPU.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/01_PW/CASES_GPU.txt b/tests/01_PW/CASES_GPU.txt index 089879dbc8c..a36319912e2 100644 --- a/tests/01_PW/CASES_GPU.txt +++ b/tests/01_PW/CASES_GPU.txt @@ -115,5 +115,6 @@ scf_brav_bco_smear_mv #relax_dftu_spin4 scf_deltaspin2 scf_deltaspin4 -nscf_hse_same -nscf_hse_path +# Disabled until the CUDA CI build provides libxc for PW HSE NSCF. +#nscf_hse_same +#nscf_hse_path From 6fd1f44c5f1ca01f580f7c65fc87f20bdeb8facd Mon Sep 17 00:00:00 2001 From: Hongxu Ren Date: Sun, 18 Oct 2026 21:25:26 +0800 Subject: [PATCH 22/25] refactor: move PW hybrid NSCF source preparation into module_pwdft --- docs/advanced/elec_properties/hybrid_nscf.md | 4 +- source/Makefile.Objects | 4 +- source/source_esolver/CMakeLists.txt | 2 - source/source_esolver/esolver_ks_pw.cpp | 7 +-- source/source_esolver/test/CMakeLists.txt | 6 --- source/source_pw/module_pwdft/CMakeLists.txt | 2 + .../module_pwdft}/pw_hybrid_nscf.cpp | 43 +++++++++++-------- .../module_pwdft}/pw_hybrid_nscf.h | 14 +++--- .../module_pwdft}/pw_hybrid_source.cpp | 4 +- .../module_pwdft}/pw_hybrid_source.h | 2 +- .../module_pwdft/test/CMakeLists.txt | 6 +++ .../test/test_pw_hybrid_source.cpp | 26 +++++------ 12 files changed, 66 insertions(+), 54 deletions(-) rename source/{source_esolver => source_pw/module_pwdft}/pw_hybrid_nscf.cpp (91%) rename source/{source_esolver => source_pw/module_pwdft}/pw_hybrid_nscf.h (70%) rename source/{source_esolver => source_pw/module_pwdft}/pw_hybrid_source.cpp (97%) rename source/{source_esolver => source_pw/module_pwdft}/pw_hybrid_source.h (97%) rename source/{source_esolver => source_pw/module_pwdft}/test/test_pw_hybrid_source.cpp (80%) diff --git a/docs/advanced/elec_properties/hybrid_nscf.md b/docs/advanced/elec_properties/hybrid_nscf.md index 36caf3c2a12..1994a14e5d7 100644 --- a/docs/advanced/elec_properties/hybrid_nscf.md +++ b/docs/advanced/elec_properties/hybrid_nscf.md @@ -61,8 +61,8 @@ source data produces an error. With MPI and LibXC enabled, substitute your configured executable/build paths: ```bash -cmake --build build --target MODULE_ESOLVER_pw_hybrid_source -OMP_NUM_THREADS=1 ctest --test-dir build -R '^MODULE_ESOLVER_pw_hybrid_source$' +cmake --build build --target MODULE_PW_pw_hybrid_source +OMP_NUM_THREADS=1 ctest --test-dir build -R '^MODULE_PW_pw_hybrid_source$' # Frozen-source band regressions: tests/01_PW/nscf_hse_same and nscf_hse_path cd tests/01_PW OMP_NUM_THREADS=1 bash ../integrate/Autotest.sh -a -r '^nscf_hse' diff --git a/source/Makefile.Objects b/source/Makefile.Objects index a4cdd3336c9..bbe0c49fc34 100644 --- a/source/Makefile.Objects +++ b/source/Makefile.Objects @@ -336,8 +336,6 @@ OBJS_ESOLVER=esolver_factory.o\ esolver_of_tool.o\ esolver_dfpt_pw.o\ pw_others.o\ - pw_hybrid_nscf.o\ - pw_hybrid_source.o\ OBJS_ESOLVER_LCAO=esolver_ks_lcao.o\ esolver_ks_lcao_tddft.o\ @@ -374,6 +372,8 @@ OBJS_GINT=batch_biggrid.o\ unitcell_info.o\ OBJS_HAMILT=hamilt_pw.o\ + pw_hybrid_nscf.o\ + pw_hybrid_source.o\ td_history_pw.o\ td_pw.o\ hs_matrix_k.o\ diff --git a/source/source_esolver/CMakeLists.txt b/source/source_esolver/CMakeLists.txt index 059b0540a0b..95488f4be33 100644 --- a/source/source_esolver/CMakeLists.txt +++ b/source/source_esolver/CMakeLists.txt @@ -3,8 +3,6 @@ list(APPEND objects esolver_ks.cpp esolver_fp.cpp esolver_ks_pw.cpp - pw_hybrid_nscf.cpp - pw_hybrid_source.cpp esolver_ks_pw_tddft.cpp esolver_ks_lcaopw.cpp esolver_sdft_pw.cpp diff --git a/source/source_esolver/esolver_ks_pw.cpp b/source/source_esolver/esolver_ks_pw.cpp index 592f505d1c6..b77f95c9b0a 100644 --- a/source/source_esolver/esolver_ks_pw.cpp +++ b/source/source_esolver/esolver_ks_pw.cpp @@ -1,5 +1,5 @@ #include "esolver_ks_pw.h" -#include "pw_hybrid_nscf.h" +#include "source_pw/module_pwdft/pw_hybrid_nscf.h" #include "source_estate/elecstate_pw.h" #include "source_estate/module_charge/chg_symm.h" @@ -83,7 +83,7 @@ void ESolver_KS_PW::before_all_runners(BaseCell& basecell, const Inpu ESolver_KS::before_all_runners(ucell, inp); - validate_hybrid_nscf(inp, this->general_exx_info_); + pw::validate_hybrid_nscf(inp, this->general_exx_info_); //! setup and allocation for pelec, potentials, etc. elecstate::setup_estate_pw(ucell, @@ -200,7 +200,8 @@ void ESolver_KS_PW::before_scf(UnitCell& ucell, const int istep) { const Input_para& inp = *this->inp_; const std::string& readin_dir = PARAM.globalv.global_readin_dir; - ModuleESolver::prepare_exx_nscf(inp, ucell, this->pw_wfc, this->exx_helper, readin_dir); + auto* helper = static_cast*>(this->exx_helper); + pw::prepare_exx_nscf(inp, ucell, this->pw_wfc, *helper->op_exx, readin_dir); } ModuleBase::timer::end("ESolver_KS_PW", "before_scf"); diff --git a/source/source_esolver/test/CMakeLists.txt b/source/source_esolver/test/CMakeLists.txt index 7cc6b83c493..2b7a04a122c 100644 --- a/source/source_esolver/test/CMakeLists.txt +++ b/source/source_esolver/test/CMakeLists.txt @@ -27,9 +27,3 @@ AddTest( ../../source_cell/module_neighlist/neighbor_list.cpp ../../source_io/module_output/output_log.cpp ) - -AddTest( - TARGET MODULE_ESOLVER_pw_hybrid_source - LIBS base device - SOURCES test_pw_hybrid_source.cpp ../pw_hybrid_source.cpp -) diff --git a/source/source_pw/module_pwdft/CMakeLists.txt b/source/source_pw/module_pwdft/CMakeLists.txt index cf652068f3d..33f40497c5b 100644 --- a/source/source_pw/module_pwdft/CMakeLists.txt +++ b/source/source_pw/module_pwdft/CMakeLists.txt @@ -2,6 +2,8 @@ list(APPEND objects hamilt_pw.cpp + pw_hybrid_nscf.cpp + pw_hybrid_source.cpp td_history_pw.cpp td_pw.cpp op_pw_ekin.cpp diff --git a/source/source_esolver/pw_hybrid_nscf.cpp b/source/source_pw/module_pwdft/pw_hybrid_nscf.cpp similarity index 91% rename from source/source_esolver/pw_hybrid_nscf.cpp rename to source/source_pw/module_pwdft/pw_hybrid_nscf.cpp index 32796984846..3969f78d579 100644 --- a/source/source_esolver/pw_hybrid_nscf.cpp +++ b/source/source_pw/module_pwdft/pw_hybrid_nscf.cpp @@ -1,10 +1,14 @@ #include "pw_hybrid_nscf.h" -#include "esolver_ks_pw.h" #include "pw_hybrid_source.h" #include "source_io/module_wf/read_wfc_pw.h" #include "source_base/module_out/filename.h" #include "source_hamilt/module_xc/general_exx_info.h" -#include "source_pw/module_pwdft/exx_helper.h" +#include "source_pw/module_pwdft/op_pw_exx.h" +#include "source_cell/unitcell.h" +#include "source_io/module_parameter/input_parameter.h" +#include "source_base/parallel_device.h" +#include "source_base/timer.h" +#include "source_base/tool_quit.h" #include #include @@ -15,7 +19,7 @@ #include #include -namespace ModuleESolver +namespace pw { namespace { @@ -131,7 +135,7 @@ void warn_source_configuration(const Input_para& inp, const std::string& readin_ { if (!saved.count(item.first)) { - ModuleBase::WARNING("ESolver_KS_PW", "EXX source configuration is incomplete or unavailable in INPUT.info; " + ModuleBase::WARNING("PW_Hybrid_NSCF", "EXX source configuration is incomplete or unavailable in INPUT.info; " "continuing with existing wavefunctions and eig_occ.txt. Verify the source SCF settings."); return; } @@ -166,7 +170,7 @@ void warn_source_configuration(const Input_para& inp, const std::string& readin_ const std::string message = "EXX source configuration differs for " + item.first + "; continuing with the frozen SCF source and current NSCF exchange settings. " "Use matching settings for consistent SCF/NSCF bands."; - ModuleBase::WARNING("ESolver_KS_PW", message); + ModuleBase::WARNING("PW_Hybrid_NSCF", message); } } } @@ -202,7 +206,7 @@ void validate_hybrid_nscf(const Input_para& inp, const General_Exx_Info& info) const bool compatible_targets = inp.symmetry != "1" && inp.init_wfc != "file" && !inp.cal_force && !inp.cal_stress; if (!compatible_execution || !compatible_exchange || !compatible_targets) { - ModuleBase::WARNING_QUIT("ESolver_KS_PW", + ModuleBase::WARNING_QUIT("PW_Hybrid_NSCF", "Hybrid NSCF currently requires CPU or CUDA GPU, kpar=bndpar=1, nspin=1/2, symmetry=-1/0, " "exxace=false, exx_gamma_extra=false, screened exchange, " "cal_force=cal_stress=false and fresh target wavefunctions"); @@ -213,10 +217,10 @@ template void prepare_exx_nscf(const Input_para& inp, const UnitCell& ucell, const ModulePW::PW_Basis_K* pw_wfc, - Exx_HelperBase* exx_helper, + hamilt::OperatorEXXPW& op_exx, const std::string& readin_dir) { - ModuleBase::timer::start("ESolver_KS_PW", "prepare_exx_nscf"); + ModuleBase::timer::start("PW_Hybrid_NSCF", "prepare_exx_nscf"); std::unique_ptr source_points(new K_Vectors); ModuleBase::matrix source_weights; warn_source_configuration(inp, readin_dir); @@ -274,7 +278,7 @@ void prepare_exx_nscf(const Input_para& inp, } catch (const std::exception& error) { - ModuleBase::WARNING_QUIT("ESolver_KS_PW", error.what()); + ModuleBase::WARNING_QUIT("PW_Hybrid_NSCF", error.what()); } const int nqs = source_points->get_nks(); int nq = source_points->get_nkstot_nospin(); @@ -313,7 +317,7 @@ void prepare_exx_nscf(const Input_para& inp, } catch (const std::exception& error) { - ModuleBase::WARNING_QUIT("ESolver_KS_PW", error.what()); + ModuleBase::WARNING_QUIT("PW_Hybrid_NSCF", error.what()); } ModuleBase::ComplexMatrix wfc(nbands, nbasis); ModuleIO::read_wfc_pw(wfc_filename, source_basis.get(), pw_wfc->poolrank, @@ -330,21 +334,24 @@ void prepare_exx_nscf(const Input_para& inp, base_device::memory::synchronize_memory_op()( source_psi->get_pointer(), coefficients.data(), coefficients.size()); } - auto* helper = static_cast*>(exx_helper); - helper->op_exx->set_source(std::move(source_basis), std::move(source_points), + op_exx.set_source(std::move(source_basis), std::move(source_points), *source_psi, std::move(source_weights)); - ModuleBase::timer::end("ESolver_KS_PW", "prepare_exx_nscf"); + ModuleBase::timer::end("PW_Hybrid_NSCF", "prepare_exx_nscf"); } template void prepare_exx_nscf, base_device::DEVICE_CPU>( - const Input_para&, const UnitCell&, const ModulePW::PW_Basis_K*, Exx_HelperBase*, const std::string&); + const Input_para&, const UnitCell&, const ModulePW::PW_Basis_K*, + hamilt::OperatorEXXPW, base_device::DEVICE_CPU>&, const std::string&); template void prepare_exx_nscf, base_device::DEVICE_CPU>( - const Input_para&, const UnitCell&, const ModulePW::PW_Basis_K*, Exx_HelperBase*, const std::string&); + const Input_para&, const UnitCell&, const ModulePW::PW_Basis_K*, + hamilt::OperatorEXXPW, base_device::DEVICE_CPU>&, const std::string&); #if defined(__CUDA) || defined(__ROCM) template void prepare_exx_nscf, base_device::DEVICE_GPU>( - const Input_para&, const UnitCell&, const ModulePW::PW_Basis_K*, Exx_HelperBase*, const std::string&); + const Input_para&, const UnitCell&, const ModulePW::PW_Basis_K*, + hamilt::OperatorEXXPW, base_device::DEVICE_GPU>&, const std::string&); template void prepare_exx_nscf, base_device::DEVICE_GPU>( - const Input_para&, const UnitCell&, const ModulePW::PW_Basis_K*, Exx_HelperBase*, const std::string&); + const Input_para&, const UnitCell&, const ModulePW::PW_Basis_K*, + hamilt::OperatorEXXPW, base_device::DEVICE_GPU>&, const std::string&); #endif -} // namespace ModuleESolver +} // namespace pw diff --git a/source/source_esolver/pw_hybrid_nscf.h b/source/source_pw/module_pwdft/pw_hybrid_nscf.h similarity index 70% rename from source/source_esolver/pw_hybrid_nscf.h rename to source/source_pw/module_pwdft/pw_hybrid_nscf.h index 91805d29a47..c1ca6eb71df 100644 --- a/source/source_esolver/pw_hybrid_nscf.h +++ b/source/source_pw/module_pwdft/pw_hybrid_nscf.h @@ -6,22 +6,26 @@ struct Input_para; struct General_Exx_Info; class UnitCell; -class Exx_HelperBase; +namespace hamilt +{ +template +class OperatorEXXPW; +} namespace ModulePW { class PW_Basis_K; } -namespace ModuleESolver +namespace pw { void validate_hybrid_nscf(const Input_para& inp, const General_Exx_Info& info); -// Read the frozen SCF ensemble in readin_dir and install it into the EXX operator -// held by exx_helper, which takes ownership for its whole remaining lifetime. +// Read the frozen SCF ensemble in readin_dir and install it into the EXX operator, +// which takes ownership for its whole remaining lifetime. template void prepare_exx_nscf(const Input_para& inp, const UnitCell& ucell, const ModulePW::PW_Basis_K* pw_wfc, - Exx_HelperBase* exx_helper, + hamilt::OperatorEXXPW& op_exx, const std::string& readin_dir); } #endif diff --git a/source/source_esolver/pw_hybrid_source.cpp b/source/source_pw/module_pwdft/pw_hybrid_source.cpp similarity index 97% rename from source/source_esolver/pw_hybrid_source.cpp rename to source/source_pw/module_pwdft/pw_hybrid_source.cpp index fefcff31097..138c87392f9 100644 --- a/source/source_esolver/pw_hybrid_source.cpp +++ b/source/source_pw/module_pwdft/pw_hybrid_source.cpp @@ -22,7 +22,7 @@ void read_binary(std::istream& in, T& value) } } -ModuleESolver::ExxSourceHeader ModuleESolver::read_exx_source_header(std::istream& in) +pw::ExxSourceHeader pw::read_exx_source_header(std::istream& in) { ExxSourceHeader header{}; int record = 0; @@ -68,7 +68,7 @@ ModuleESolver::ExxSourceHeader ModuleESolver::read_exx_source_header(std::istrea return header; } -void ModuleESolver::read_exx_source_occupations(std::istream& in, +void pw::read_exx_source_occupations(std::istream& in, const std::vector& headers, int nspin, ModuleBase::matrix& weights) diff --git a/source/source_esolver/pw_hybrid_source.h b/source/source_pw/module_pwdft/pw_hybrid_source.h similarity index 97% rename from source/source_esolver/pw_hybrid_source.h rename to source/source_pw/module_pwdft/pw_hybrid_source.h index 98a67cdcb67..786730d7de3 100644 --- a/source/source_esolver/pw_hybrid_source.h +++ b/source/source_pw/module_pwdft/pw_hybrid_source.h @@ -9,7 +9,7 @@ namespace ModuleBase class matrix; } -namespace ModuleESolver +namespace pw { // Metadata already present in the existing binary PW wavefunction format. struct ExxSourceHeader diff --git a/source/source_pw/module_pwdft/test/CMakeLists.txt b/source/source_pw/module_pwdft/test/CMakeLists.txt index ad7674a93e8..19773fdc64c 100644 --- a/source/source_pw/module_pwdft/test/CMakeLists.txt +++ b/source/source_pw/module_pwdft/test/CMakeLists.txt @@ -92,3 +92,9 @@ AddTest( ../../../source_cell/cal_nelec_nband.cpp ../../../source_cell/read_orb.cpp ) + +AddTest( + TARGET MODULE_PW_pw_hybrid_source + LIBS base device + SOURCES test_pw_hybrid_source.cpp ../pw_hybrid_source.cpp +) diff --git a/source/source_esolver/test/test_pw_hybrid_source.cpp b/source/source_pw/module_pwdft/test/test_pw_hybrid_source.cpp similarity index 80% rename from source/source_esolver/test/test_pw_hybrid_source.cpp rename to source/source_pw/module_pwdft/test/test_pw_hybrid_source.cpp index a0f03632aa9..3e92154f820 100644 --- a/source/source_esolver/test/test_pw_hybrid_source.cpp +++ b/source/source_pw/module_pwdft/test/test_pw_hybrid_source.cpp @@ -1,4 +1,4 @@ -#include "source_esolver/pw_hybrid_source.h" +#include "source_pw/module_pwdft/pw_hybrid_source.h" #include "source_base/matrix.h" #include "gtest/gtest.h" @@ -10,10 +10,10 @@ namespace { -std::vector source_headers(int nspin) +std::vector source_headers(int nspin) { const int nks = nspin == 2 ? 4 : 2; - std::vector headers(nks); + std::vector headers(nks); for (int iq = 0; iq < nks; ++iq) { auto& header = headers[iq]; @@ -51,7 +51,7 @@ TEST(PWHybridSource, ReadsExistingWeightedOccupationsForBothSpins) const auto headers = source_headers(nspin); std::istringstream in(eig_occ(nspin)); ModuleBase::matrix weights; - ModuleESolver::read_exx_source_occupations(in, headers, nspin, weights); + pw::read_exx_source_occupations(in, headers, nspin, weights); EXPECT_EQ(weights.nr, headers.size()); EXPECT_EQ(weights.nc, 3); EXPECT_DOUBLE_EQ(weights(1, 1), headers[1].weight * 0.125); @@ -64,15 +64,15 @@ TEST(PWHybridSource, RejectsInvalidExistingOccupationFiles) ModuleBase::matrix weights; const std::string saved = eig_occ(1); std::istringstream truncated(saved.substr(0, saved.size() - 6)); - EXPECT_THROW(ModuleESolver::read_exx_source_occupations(truncated, headers, 1, weights), std::runtime_error); + EXPECT_THROW(pw::read_exx_source_occupations(truncated, headers, 1, weights), std::runtime_error); std::istringstream trailing(saved + saved); - EXPECT_THROW(ModuleESolver::read_exx_source_occupations(trailing, headers, 1, weights), std::runtime_error); + EXPECT_THROW(pw::read_exx_source_occupations(trailing, headers, 1, weights), std::runtime_error); std::istringstream wrong_spin(saved); - EXPECT_THROW(ModuleESolver::read_exx_source_occupations(wrong_spin, headers, 2, weights), std::runtime_error); + EXPECT_THROW(pw::read_exx_source_occupations(wrong_spin, headers, 2, weights), std::runtime_error); auto changed = headers; changed[1].kvec_c[0] += 0.1; std::istringstream wrong_coordinates(saved); - EXPECT_THROW(ModuleESolver::read_exx_source_occupations(wrong_coordinates, changed, 1, weights), std::runtime_error); + EXPECT_THROW(pw::read_exx_source_occupations(wrong_coordinates, changed, 1, weights), std::runtime_error); std::string invalid = saved; invalid.replace(invalid.find("0.125"), 5, "-0.25"); std::istringstream negative(invalid); @@ -80,7 +80,7 @@ TEST(PWHybridSource, RejectsInvalidExistingOccupationFiles) { // A negative occupation is what a Methfessel-Paxton source can produce; the // diagnostic must name the unsupported smearing rather than report invalid data. - ModuleESolver::read_exx_source_occupations(negative, headers, 1, weights); + pw::read_exx_source_occupations(negative, headers, 1, weights); FAIL() << "Expected std::runtime_error"; } catch (const std::runtime_error& error) @@ -101,7 +101,7 @@ TEST(PWHybridSource, RejectsDifferentMeshesInSpinChannels) saved.replace(location, original.size(), "spin=2 k-point=1/2 Cartesian=0.2"); std::istringstream in(saved); ModuleBase::matrix weights; - EXPECT_THROW(ModuleESolver::read_exx_source_occupations(in, headers, 2, weights), std::runtime_error); + EXPECT_THROW(pw::read_exx_source_occupations(in, headers, 2, weights), std::runtime_error); } TEST(PWHybridSource, ReadsExistingBinaryWavefunctionHeader) @@ -135,13 +135,13 @@ TEST(PWHybridSource, ReadsExistingBinaryWavefunctionHeader) std::string saved = out.str(); saved.resize(160 + 8 + 12 * npw + nbands * (8 + 16 * npw), '\0'); std::istringstream in(saved, std::ios::binary); - const auto header = ModuleESolver::read_exx_source_header(in); + const auto header = pw::read_exx_source_header(in); EXPECT_EQ(header.nbands, 3); EXPECT_DOUBLE_EQ(header.kvec_c[0], coordinate); EXPECT_DOUBLE_EQ(header.weight, weight); std::istringstream truncated(saved.substr(0, saved.size() - 1), std::ios::binary); - EXPECT_THROW(ModuleESolver::read_exx_source_header(truncated), std::runtime_error); + EXPECT_THROW(pw::read_exx_source_header(truncated), std::runtime_error); saved[0] = 0; std::istringstream invalid(saved, std::ios::binary); - EXPECT_THROW(ModuleESolver::read_exx_source_header(invalid), std::runtime_error); + EXPECT_THROW(pw::read_exx_source_header(invalid), std::runtime_error); } From 8bc0c9aef0fe253095cfbfdfcf4fa6042771c435 Mon Sep 17 00:00:00 2001 From: Hongxu Ren Date: Sun, 18 Oct 2026 21:26:07 +0800 Subject: [PATCH 23/25] ci: simplify libxc availability comment --- tests/01_PW/CASES_GPU.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/01_PW/CASES_GPU.txt b/tests/01_PW/CASES_GPU.txt index a36319912e2..390cc8ac339 100644 --- a/tests/01_PW/CASES_GPU.txt +++ b/tests/01_PW/CASES_GPU.txt @@ -115,6 +115,6 @@ scf_brav_bco_smear_mv #relax_dftu_spin4 scf_deltaspin2 scf_deltaspin4 -# Disabled until the CUDA CI build provides libxc for PW HSE NSCF. +# Disabled until the CUDA CI build provides libxc. #nscf_hse_same #nscf_hse_path From 2c9b67cfc807a55be28ecec3e2379481d36faff1 Mon Sep 17 00:00:00 2001 From: Hongxu Ren Date: Mon, 19 Oct 2026 14:05:03 +0800 Subject: [PATCH 24/25] test: use standard charge cube for PW hybrid NSCF cases --- tests/01_PW/nscf_hse_path/band.txt.ref | 6 +- tests/01_PW/nscf_hse_path/result.ref | 4 +- tests/01_PW/nscf_hse_same/README | 8 +- .../autotest-CHARGE-DENSITY.restart | Bin 32008 -> 0 bytes tests/01_PW/nscf_hse_same/band.txt.ref | 4 +- tests/01_PW/nscf_hse_same/chg.cube | 683 ++++++++++++++++++ 6 files changed, 697 insertions(+), 8 deletions(-) delete mode 100644 tests/01_PW/nscf_hse_same/autotest-CHARGE-DENSITY.restart create mode 100644 tests/01_PW/nscf_hse_same/chg.cube diff --git a/tests/01_PW/nscf_hse_path/band.txt.ref b/tests/01_PW/nscf_hse_path/band.txt.ref index 6c586d1df5d..83c5d91b3a7 100644 --- a/tests/01_PW/nscf_hse_path/band.txt.ref +++ b/tests/01_PW/nscf_hse_path/band.txt.ref @@ -1,3 +1,3 @@ - 1 0.00000000 -11.12767527 0.23237114 5.91382475 - 2 0.03997035 -10.53435615 -0.56032894 5.88787937 - 3 0.07994070 -9.30092037 -2.20463726 5.45376065 + 1 0.00000000 -11.12775535 0.23225985 5.91375790 + 2 0.03997035 -10.53443745 -0.56043732 5.88781574 + 3 0.07994070 -9.30100379 -2.20473701 5.45370497 diff --git a/tests/01_PW/nscf_hse_path/result.ref b/tests/01_PW/nscf_hse_path/result.ref index d1062bfbc38..8f96f930871 100644 --- a/tests/01_PW/nscf_hse_path/result.ref +++ b/tests/01_PW/nscf_hse_path/result.ref @@ -1,4 +1,4 @@ -etotref -34.96111659019459 -etotperatomref -17.4805582951 +etotref -34.96110759412895 +etotperatomref -17.4805537971 CompareBand_pass 0 totaltimeref 0.09 diff --git a/tests/01_PW/nscf_hse_same/README b/tests/01_PW/nscf_hse_same/README index d93148add80..63c9decfc1a 100644 --- a/tests/01_PW/nscf_hse_same/README +++ b/tests/01_PW/nscf_hse_same/README @@ -1,3 +1,9 @@ PW HSE NSCF on the frozen SCF source committed in this directory (binary -wavefunctions, eig_occ.txt, charge restart). Same k mesh with more target +wavefunctions, eig_occ.txt, chg.cube). Same k mesh with more target bands; an explicit zero exx_fock_alpha is accepted like an omitted Fock term. + +The charge density is standard SCF output generated with out_chg 1 12. +To regenerate the source, use the same STRU/KPT and INPUT with calculation scf, +nbands 3, out_chg 1 12, and out_wfc_pw 2. +The cube-based band references differ from the former binary-restart references +by at most 1.12e-4 eV: out_chg writes rho, while the binary restart writes rho_save. diff --git a/tests/01_PW/nscf_hse_same/autotest-CHARGE-DENSITY.restart b/tests/01_PW/nscf_hse_same/autotest-CHARGE-DENSITY.restart deleted file mode 100644 index f7c30f6865330e9be0986ad66c07a7fc25cda6b0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32008 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 diff --git a/tests/01_PW/nscf_hse_same/band.txt.ref b/tests/01_PW/nscf_hse_same/band.txt.ref index 6648ef56ac4..18e672a68cd 100644 --- a/tests/01_PW/nscf_hse_same/band.txt.ref +++ b/tests/01_PW/nscf_hse_same/band.txt.ref @@ -1,2 +1,2 @@ - 1 0.00000000 -11.12767527 0.23237114 5.91382475 9.84140426 10.33312736 - 2 0.15988140 -8.18994369 -4.74422564 4.63092625 7.73162354 8.50832814 + 1 0.00000000 -11.12775535 0.23225985 5.91375790 9.84135070 10.33308037 + 2 0.15988140 -8.19003581 -4.74430941 4.63087285 7.73156801 8.50826860 diff --git a/tests/01_PW/nscf_hse_same/chg.cube b/tests/01_PW/nscf_hse_same/chg.cube new file mode 100644 index 00000000000..7d794c115cc --- /dev/null +++ b/tests/01_PW/nscf_hse_same/chg.cube @@ -0,0 +1,683 @@ +Ionic_Step 1 Cubefile created from ABACUS. Inner loop is z, followed by y and x +1 # number of spin directions -0.601951 # Fermi energy, in Ry +2 0.0 0.0 0.0 +15 0.000000 0.341208 0.341208 +15 0.341208 0.000000 0.341208 +15 0.341208 0.341208 0.000000 + 1 1.000000 1.279531 1.279531 1.279531 + 1 1.000000 8.751991 7.933091 7.728366 + 3.747870620906e-03 6.511001055776e-03 1.148480521288e-02 1.679999195507e-02 1.803031963864e-02 1.389220981674e-02 + 8.372443407802e-03 4.874875564120e-03 3.315291499453e-03 2.558087313494e-03 2.063900126690e-03 1.775311578410e-03 + 1.707037967889e-03 1.923085863233e-03 2.506247575810e-03 + 6.488534474249e-03 1.338847455506e-02 2.401162996513e-02 3.145220458474e-02 2.821451876224e-02 1.766315081897e-02 + 8.787449385168e-03 4.516643406212e-03 2.865250760351e-03 2.091879282320e-03 1.671961485142e-03 1.547568377343e-03 + 1.719434751543e-03 2.272439915237e-03 3.481427093402e-03 + 1.143431780925e-02 2.397531952705e-02 3.828227306968e-02 4.184598537508e-02 3.068411620464e-02 1.593898975116e-02 + 7.053704958863e-03 3.569496761836e-03 2.298050247422e-03 1.683248602076e-03 1.413250464233e-03 1.475949407595e-03 + 1.918501690360e-03 2.886580479468e-03 5.230322557302e-03 + 1.671123466972e-02 3.135971215368e-02 4.178296097192e-02 3.734475562212e-02 2.268865469819e-02 1.040585240669e-02 + 4.643734957937e-03 2.617165358632e-03 1.803767529498e-03 1.379156896496e-03 1.286333017420e-03 1.570429013334e-03 + 2.262400896827e-03 3.694774544300e-03 7.489042289991e-03 + 1.793039994294e-02 2.811206710433e-02 3.061511494614e-02 2.267117562896e-02 1.209132965947e-02 5.567225584360e-03 + 2.931098444614e-03 1.946366576505e-03 1.431649057135e-03 1.189080596315e-03 1.298728740684e-03 1.774164222820e-03 + 2.610779424447e-03 4.390752877482e-03 8.918413668184e-03 + 1.387030904174e-02 1.766455961479e-02 1.596882446664e-02 1.044376947818e-02 5.590830408559e-03 3.078303170587e-03 + 2.037057906042e-03 1.499743892826e-03 1.162369788142e-03 1.110411505699e-03 1.413835501328e-03 2.002790221634e-03 + 2.874702274542e-03 4.612866838731e-03 8.330657430575e-03 + 8.476297710107e-03 8.914840519444e-03 7.177123039897e-03 4.731383938276e-03 2.979502078806e-03 2.054841417520e-03 + 1.532383694527e-03 1.162718518441e-03 9.940105506742e-04 1.134104200071e-03 1.588428781547e-03 2.224844260394e-03 + 3.008067654796e-03 4.289885938326e-03 6.369035471582e-03 + 5.072139746731e-03 4.695906916104e-03 3.714474463174e-03 2.716130057462e-03 2.002181826027e-03 1.520152074661e-03 + 1.164594980543e-03 9.517765292966e-04 9.652993079204e-04 1.263432877451e-03 1.798728361079e-03 2.401517330927e-03 + 3.020710241333e-03 3.784777171475e-03 4.626784526016e-03 + 3.567313856358e-03 3.049730262435e-03 2.438413924904e-03 1.903903893065e-03 1.486534794216e-03 1.178524282951e-03 + 9.929848490793e-04 9.630225260725e-04 1.133161729699e-03 1.521386217478e-03 2.043500757750e-03 2.584202560376e-03 + 3.104176227525e-03 3.551283316380e-03 3.757286937064e-03 + 2.825068836421e-03 2.270745898481e-03 1.824773761146e-03 1.482369540760e-03 1.241248789601e-03 1.123947988061e-03 + 1.131039918602e-03 1.259938510099e-03 1.521014464161e-03 1.900341940801e-03 2.387378277951e-03 2.964661367229e-03 + 3.482589405809e-03 3.662411705017e-03 3.378530219647e-03 + 2.282007612333e-03 1.824018502092e-03 1.542375909483e-03 1.376422664908e-03 1.341030263338e-03 1.421749206388e-03 + 1.575384199713e-03 1.781091282343e-03 2.015641591713e-03 2.338689998564e-03 2.884723307620e-03 3.582369975504e-03 + 3.979902602208e-03 3.700546425620e-03 2.972913623725e-03 + 1.892438095245e-03 1.642385346633e-03 1.565093381145e-03 1.632405296645e-03 1.804521477958e-03 1.996004317198e-03 + 2.182267916378e-03 2.332683921019e-03 2.461168341018e-03 2.758898817862e-03 3.379107627948e-03 4.001189500132e-03 + 3.985936301901e-03 3.266337366456e-03 2.430485955810e-03 + 1.739976369083e-03 1.766297577595e-03 1.975688831121e-03 2.311835534413e-03 2.639103101135e-03 2.855114117135e-03 + 2.933374443540e-03 2.882881989958e-03 2.849586748453e-03 3.070533930588e-03 3.526174869718e-03 3.729464739002e-03 + 3.297734311591e-03 2.537462873552e-03 1.966851702382e-03 + 1.932376563413e-03 2.307485549476e-03 2.938248778074e-03 3.752031849322e-03 4.433967770008e-03 4.604491159115e-03 + 4.206063595749e-03 3.600025689764e-03 3.212297330171e-03 3.160001594252e-03 3.186548423485e-03 2.951637052407e-03 + 2.446568162767e-03 1.982467584830e-03 1.805875257866e-03 + 2.517023652253e-03 3.515166472680e-03 5.284443136200e-03 7.562767592637e-03 8.992055930783e-03 8.347484043002e-03 + 6.283432633434e-03 4.424998641378e-03 3.430563840821e-03 2.965135324456e-03 2.601829669672e-03 2.221587313785e-03 + 1.908590455381e-03 1.803275662847e-03 2.000419505460e-03 + 7.974928154209e-03 1.573677709964e-02 2.715891256312e-02 3.484257273611e-02 3.110695231771e-02 1.960300338241e-02 + 9.835357654464e-03 5.041180570325e-03 3.169480239387e-03 2.284360169842e-03 1.777490265280e-03 1.644124908586e-03 + 1.940569216413e-03 2.748908836948e-03 4.352571316468e-03 + 1.567349216559e-02 3.237946632275e-02 5.095331637607e-02 5.523008641423e-02 4.033289189920e-02 2.080432052532e-02 + 8.988559012550e-03 4.353865353164e-03 2.703344346267e-03 1.927370848822e-03 1.591600715751e-03 1.721723973881e-03 + 2.384682930320e-03 3.797648252680e-03 7.141418049431e-03 + 2.699241739909e-02 5.083583605841e-02 6.739616729797e-02 5.973343532978e-02 3.565854385753e-02 1.567985188160e-02 + 6.467387909187e-03 3.355839374985e-03 2.200526618816e-03 1.621034080686e-03 1.501736788588e-03 1.916703974186e-03 + 2.974242951432e-03 5.341229305011e-03 1.171134362877e-02 + 3.453408439176e-02 5.497669941792e-02 5.963794243770e-02 4.317201722828e-02 2.176736119395e-02 9.008333030197e-03 + 4.178253310122e-03 2.566823861030e-03 1.801819360628e-03 1.422773753750e-03 1.533168976482e-03 2.207151547213e-03 + 3.637811400326e-03 7.116674548827e-03 1.627329274108e-02 + 3.073486994140e-02 4.009216738305e-02 3.562627232360e-02 2.181098225233e-02 1.026026353864e-02 4.812479224506e-03 + 2.890871316099e-03 2.059769639786e-03 1.514820584701e-03 1.340233127022e-03 1.671920964496e-03 2.521866475734e-03 + 4.170652704017e-03 8.113285250621e-03 1.707498293950e-02 + 1.936401598745e-02 2.074578963563e-02 1.577360399073e-02 9.100315927306e-03 4.840760690566e-03 3.020484051414e-03 + 2.236551812801e-03 1.669203237207e-03 1.304685611072e-03 1.355867618583e-03 1.869506567721e-03 2.771562904884e-03 + 4.298507414241e-03 7.481963154580e-03 1.321336328028e-02 + 9.801984939414e-03 9.077240365017e-03 6.597570175257e-03 4.252791529944e-03 2.896528760702e-03 2.213523560100e-03 + 1.718496571173e-03 1.311345192430e-03 1.179962216629e-03 1.444074875408e-03 2.053451207425e-03 2.849822313036e-03 + 3.938436679698e-03 5.752719879716e-03 8.186147351839e-03 + 5.124787320123e-03 4.476805256835e-03 3.457448983077e-03 2.601003134805e-03 2.028678854891e-03 1.614276855782e-03 + 1.280489440047e-03 1.105781762795e-03 1.198521385329e-03 1.587773263089e-03 2.153642510446e-03 2.729606036798e-03 + 3.364757101434e-03 4.178375831316e-03 4.948653637692e-03 + 3.286554019460e-03 2.816984909561e-03 2.279880703889e-03 1.822817688666e-03 1.482721907326e-03 1.254422597980e-03 + 1.146425329825e-03 1.188805738540e-03 1.408801326598e-03 1.773485234434e-03 2.173224668918e-03 2.548497042466e-03 + 2.931987851879e-03 3.296926433834e-03 3.469253297150e-03 + 2.395366922113e-03 2.033703224678e-03 1.707827595433e-03 1.468260871610e-03 1.344235178259e-03 1.339611796899e-03 + 1.430920230226e-03 1.585091061835e-03 1.770543553090e-03 1.969552579846e-03 2.197145916181e-03 2.467560249556e-03 + 2.721348263831e-03 2.827143345560e-03 2.700816104500e-03 + 1.856470452777e-03 1.686809430546e-03 1.602945761257e-03 1.617161016756e-03 1.727719839787e-03 1.896697784156e-03 + 2.059831811486e-03 2.142044660241e-03 2.138032854785e-03 2.154334382802e-03 2.285859660029e-03 2.472508142894e-03 + 2.533677611456e-03 2.378702246340e-03 2.105940590802e-03 + 1.676794704256e-03 1.798841734014e-03 2.035165783836e-03 2.338295323867e-03 2.631361029351e-03 2.832253235892e-03 + 2.856318222307e-03 2.683204433248e-03 2.451068343294e-03 2.346015645599e-03 2.387826485671e-03 2.390085317075e-03 + 2.200528148795e-03 1.909231714921e-03 1.706857514265e-03 + 1.953657825958e-03 2.467451741695e-03 3.122401919107e-03 3.815293810401e-03 4.330187008070e-03 4.399434245566e-03 + 3.960252374212e-03 3.300001123186e-03 2.789286102597e-03 2.541730599388e-03 2.390231157810e-03 2.142300523331e-03 + 1.822027366942e-03 1.610649658248e-03 1.648136909465e-03 + 2.777147417860e-03 3.896785644478e-03 5.510780775786e-03 7.336670865776e-03 8.346491043774e-03 7.665804674747e-03 + 5.825162213136e-03 4.125806849685e-03 3.153348834274e-03 2.653097372646e-03 2.247461333310e-03 1.857945261675e-03 + 1.610757236863e-03 1.643592749484e-03 2.037785420868e-03 + 4.383739829035e-03 7.235760469408e-03 1.188738317154e-02 1.654476626927e-02 1.740845420799e-02 1.348300205187e-02 + 8.286892885110e-03 4.901268393081e-03 3.346623891576e-03 2.567477098061e-03 2.015727996043e-03 1.682475207962e-03 + 1.662692135337e-03 2.045324255521e-03 2.884147369637e-03 + 1.642578888110e-02 3.150895205978e-02 4.761756221445e-02 5.092866989002e-02 3.754897986576e-02 2.003588704024e-02 + 9.155312874528e-03 4.689947795750e-03 3.016712204257e-03 2.205922226720e-03 1.879432974944e-03 2.124208041079e-03 + 3.017968468970e-03 4.709280848524e-03 8.238755844842e-03 + 3.136897568361e-02 5.710652302178e-02 7.450137624914e-02 6.590067797377e-02 3.976120337411e-02 1.786779453122e-02 + 7.537713782172e-03 3.948603897902e-03 2.612217449707e-03 1.976886608083e-03 1.916577309397e-03 2.535796290257e-03 + 3.946830294899e-03 6.894973571865e-03 1.433957757598e-02 + 4.725106053967e-02 7.427530697550e-02 8.005964978941e-02 5.784287450057e-02 2.908510765857e-02 1.185242393014e-02 + 5.294321732790e-03 3.138565896548e-03 2.188457304992e-03 1.770896296616e-03 1.994329552351e-03 2.976071802067e-03 + 5.035493598140e-03 9.977700817824e-03 2.263316713043e-02 + 5.032843643761e-02 6.553948370056e-02 5.778787777066e-02 3.468922866155e-02 1.557223927717e-02 6.716885679839e-03 + 3.709366756801e-03 2.532243713068e-03 1.840622062518e-03 1.653384366637e-03 2.151615736614e-03 3.444031249319e-03 + 6.134974994090e-03 1.275246719626e-02 2.773169926711e-02 + 3.692887274569e-02 3.951745887020e-02 2.915586327900e-02 1.565478164753e-02 7.394207209287e-03 4.110776392266e-03 + 2.878709652735e-03 2.096936717544e-03 1.599733253693e-03 1.661316207791e-03 2.392148117199e-03 3.837920898080e-03 + 6.666360817972e-03 1.296622760606e-02 2.451374690657e-02 + 1.965310864096e-02 1.783001089829e-02 1.198942478057e-02 6.802462383383e-03 4.113630651089e-03 3.002163053455e-03 + 2.310999837080e-03 1.703111750911e-03 1.453482581027e-03 1.765680901864e-03 2.614402965865e-03 3.923439895723e-03 + 6.122927211404e-03 1.018799319044e-02 1.586194395368e-02 + 9.026566775241e-03 7.595064256799e-03 5.392454240149e-03 3.730265761311e-03 2.818894275947e-03 2.249698785986e-03 + 1.729676377245e-03 1.376017698704e-03 1.410491243839e-03 1.884920069005e-03 2.661256110670e-03 3.584542835633e-03 + 4.836617255512e-03 6.663573558246e-03 8.521626912710e-03 + 4.689842946441e-03 4.013615248425e-03 3.185697108736e-03 2.501923165778e-03 2.000010318471e-03 1.613147254431e-03 + 1.340385501667e-03 1.278775907373e-03 1.496083856337e-03 1.954440434951e-03 2.500972263014e-03 3.036446857008e-03 + 3.637551220755e-03 4.321726455220e-03 4.801383414592e-03 + 3.059295285332e-03 2.676125410217e-03 2.231899941078e-03 1.829339966617e-03 1.544128895002e-03 1.400974889354e-03 + 1.391188046023e-03 1.499805874030e-03 1.708399709744e-03 1.982945363559e-03 2.280732442835e-03 2.592888880347e-03 + 2.918429718036e-03 3.185067001360e-03 3.255067159243e-03 + 2.256887473200e-03 2.060951165188e-03 1.863048152482e-03 1.719820787711e-03 1.695533033881e-03 1.789867736821e-03 + 1.916297086619e-03 1.980246547116e-03 1.986239346630e-03 2.022782163977e-03 2.150335154109e-03 2.337968604874e-03 + 2.487691345307e-03 2.517139574958e-03 2.422941613047e-03 + 1.922132524491e-03 2.029852736245e-03 2.161140667245e-03 2.324499458729e-03 2.537587256719e-03 2.727618301838e-03 + 2.739329946856e-03 2.526712566314e-03 2.255058034756e-03 2.113533379913e-03 2.116875566271e-03 2.133046877033e-03 + 2.060856860154e-03 1.941811823558e-03 1.880949444138e-03 + 2.161099142766e-03 2.689707151142e-03 3.226683111767e-03 3.720806330067e-03 4.083412308598e-03 4.112009113044e-03 + 3.695345499609e-03 3.050560925171e-03 2.529252504249e-03 2.256328560542e-03 2.089512280625e-03 1.874283992235e-03 + 1.651904262104e-03 1.578074659841e-03 1.752858520768e-03 + 3.079965774877e-03 4.146556750330e-03 5.345699958900e-03 6.489974556363e-03 7.013192031339e-03 6.415187716510e-03 + 5.014068700272e-03 3.672458775314e-03 2.853105385778e-03 2.401074509937e-03 2.013488047301e-03 1.646696006808e-03 + 1.468968869536e-03 1.633192159861e-03 2.198228844295e-03 + 4.797177092948e-03 7.110432093871e-03 1.031998273144e-02 1.320056354849e-02 1.347640687745e-02 1.064302066492e-02 + 6.934932282381e-03 4.399967010481e-03 3.152550070890e-03 2.463785316340e-03 1.923372813736e-03 1.597035843423e-03 + 1.656814535093e-03 2.213749162609e-03 3.261474099435e-03 + 8.309457820490e-03 1.453717633746e-02 2.300535813598e-02 2.830611844835e-02 2.519611924843e-02 1.641423776807e-02 + 8.804157300307e-03 4.877434617985e-03 3.237521511783e-03 2.390712547743e-03 1.875292678420e-03 1.777625832340e-03 + 2.220070578568e-03 3.254762296418e-03 5.008360722176e-03 + 2.738345680885e-02 4.631161817945e-02 5.842137995814e-02 5.163061897283e-02 3.223702741223e-02 1.564842130108e-02 + 7.335172249907e-03 4.149421081630e-03 2.854867902324e-03 2.289506995625e-03 2.387322537279e-03 3.244147218865e-03 + 4.868036576387e-03 7.745599569756e-03 1.409576586368e-02 + 4.603641302187e-02 6.987875040327e-02 7.449823916068e-02 5.441711812985e-02 2.838781717503e-02 1.230031997570e-02 + 5.801460867527e-03 3.503392573969e-03 2.513603590884e-03 2.199682511132e-03 2.656021745739e-03 3.962907720059e-03 + 6.337739796257e-03 1.143772386001e-02 2.356659494774e-02 + 5.781550201535e-02 7.421321159711e-02 6.535652561689e-02 3.967047007057e-02 1.816093069009e-02 7.902928582487e-03 + 4.268556557240e-03 2.857889350923e-03 2.154548188465e-03 2.114144227332e-03 2.914562540407e-03 4.657604043180e-03 + 8.010486099671e-03 1.582038218877e-02 3.283387262457e-02 + 5.086125890026e-02 5.410582493121e-02 3.967921063970e-02 2.101724185625e-02 9.564016962847e-03 4.973909618660e-03 + 3.280636065765e-03 2.356948863474e-03 1.888797690741e-03 2.130105558975e-03 3.229685040267e-03 5.292045619832e-03 + 9.293379527650e-03 1.810283894950e-02 3.401281743679e-02 + 3.158848307222e-02 2.824125377286e-02 1.826067582289e-02 9.620839178220e-03 5.282359839883e-03 3.583890799239e-03 + 2.673307473384e-03 1.975682425462e-03 1.757750020227e-03 2.271754547732e-03 3.535374880450e-03 5.555769335478e-03 + 9.147290053727e-03 1.592539856434e-02 2.539648950458e-02 + 1.526194486052e-02 1.227497638700e-02 7.992547813422e-03 4.997481588960e-03 3.551380212826e-03 2.787101679911e-03 + 2.119911173777e-03 1.663101827411e-03 1.731726638927e-03 2.424986839737e-03 3.594419639172e-03 5.121763426592e-03 + 7.417039072833e-03 1.090863624309e-02 1.445695774192e-02 + 7.159576724435e-03 5.812842806385e-03 4.308232291350e-03 3.244343859291e-03 2.582688151744e-03 2.063451739923e-03 + 1.635061553878e-03 1.488812997476e-03 1.767302580218e-03 2.430171171854e-03 3.269747438548e-03 4.164169576489e-03 + 5.256395151258e-03 6.549246489266e-03 7.441734995746e-03 + 4.095558632213e-03 3.537315320737e-03 2.888316247245e-03 2.320986771581e-03 1.901207934887e-03 1.618762941115e-03 + 1.487683048787e-03 1.557803689722e-03 1.839254743464e-03 2.272794596412e-03 2.755784677942e-03 3.237602031575e-03 + 3.729276300359e-03 4.163137852365e-03 4.335566301880e-03 + 2.874024258065e-03 2.596040722220e-03 2.242412772781e-03 1.934765987050e-03 1.776925013085e-03 1.766705992985e-03 + 1.825188622708e-03 1.883399680780e-03 1.955527534795e-03 2.108328958257e-03 2.362237474566e-03 2.659534491989e-03 + 2.907147646403e-03 3.036195829033e-03 3.024203577039e-03 + 2.352317468813e-03 2.349659466543e-03 2.304424123238e-03 2.306456801899e-03 2.426960710840e-03 2.579440015175e-03 + 2.574131799746e-03 2.362818341361e-03 2.131529741453e-03 2.071880213880e-03 2.182318932421e-03 2.315694245337e-03 + 2.356422250421e-03 2.330916327241e-03 2.325553931800e-03 + 2.471847224048e-03 2.878243596888e-03 3.224752962654e-03 3.548635641875e-03 3.828698035443e-03 3.858498960616e-03 + 3.472773015814e-03 2.852892375459e-03 2.364214401410e-03 2.154901900851e-03 2.086365502508e-03 1.984017397239e-03 + 1.860094604365e-03 1.862813900246e-03 2.084770917222e-03 + 3.353813758340e-03 4.251810089981e-03 5.061183523965e-03 5.715608298056e-03 5.955316729677e-03 5.474737731484e-03 + 4.412050142368e-03 3.333880097342e-03 2.637870485747e-03 2.261144864828e-03 1.958739863887e-03 1.678432668581e-03 + 1.583986249908e-03 1.837888097898e-03 2.475275446652e-03 + 5.013797840822e-03 6.667366201529e-03 8.472341646327e-03 9.816928553220e-03 9.690911400570e-03 7.910628568728e-03 + 5.590324003712e-03 3.864280054422e-03 2.906906166631e-03 2.320573231268e-03 1.851609300777e-03 1.598072278800e-03 + 1.756934261648e-03 2.438769762336e-03 3.584305373088e-03 + 7.908448425922e-03 1.179218998403e-02 1.636781825486e-02 1.880829655314e-02 1.670340647861e-02 1.158214414811e-02 + 6.973129444569e-03 4.347568155150e-03 3.079823429456e-03 2.335893570448e-03 1.887281501872e-03 1.881375796628e-03 + 2.467347520901e-03 3.651925742140e-03 5.369067964064e-03 + 1.422676614676e-02 2.393291237561e-02 3.349026317285e-02 3.490246398717e-02 2.631011513842e-02 1.514397419736e-02 + 7.823595726627e-03 4.495567561292e-03 3.066653185029e-03 2.329858499214e-03 2.096698399523e-03 2.495509247312e-03 + 3.579961343430e-03 5.336582101878e-03 8.337707506697e-03 + 3.541943121229e-02 4.972877175210e-02 5.132287769718e-02 3.808810433407e-02 2.141735981822e-02 1.057040588131e-02 + 5.619435220318e-03 3.553124722429e-03 2.647912956331e-03 2.527963823777e-03 3.249597301361e-03 4.793656710743e-03 + 7.181638482628e-03 1.152757998105e-02 2.051653849665e-02 + 4.922643663307e-02 6.072234680432e-02 5.315519822224e-02 3.335597367351e-02 1.651368715952e-02 7.903936106683e-03 + 4.456842505336e-03 3.000554694813e-03 2.407095435719e-03 2.625602868627e-03 3.763249692977e-03 5.789252641116e-03 + 9.161768095592e-03 1.616281083955e-02 3.013034514196e-02 + 5.053124846571e-02 5.289698710881e-02 3.910116809587e-02 2.142920951492e-02 1.022111277265e-02 5.391260898277e-03 + 3.457093478533e-03 2.500450242599e-03 2.202323110537e-03 2.747876709079e-03 4.235815545822e-03 6.670868564531e-03 + 1.098407141272e-02 1.988317035799e-02 3.513522685599e-02 + 3.737294099814e-02 3.316461410987e-02 2.144916408264e-02 1.127994570081e-02 6.030253324950e-03 3.873599178975e-03 + 2.790401790282e-03 2.143945023616e-03 2.123639212962e-03 2.962506918201e-03 4.656018676218e-03 7.195796157994e-03 + 1.157567193341e-02 1.962367165973e-02 3.054874419297e-02 + 2.091291361903e-02 1.642120246068e-02 1.025680612522e-02 6.035609630841e-03 4.029150167944e-03 3.036254613144e-03 + 2.308701702703e-03 1.914349750034e-03 2.164217370366e-03 3.186058689911e-03 4.806967856367e-03 6.935308322619e-03 + 1.019684941290e-02 1.514397284651e-02 2.004776820073e-02 + 1.024697980913e-02 7.845725451011e-03 5.395681070160e-03 3.841822935707e-03 2.998070509532e-03 2.388362997076e-03 + 1.903835563949e-03 1.780324415323e-03 2.218287046855e-03 3.193095673334e-03 4.439861888946e-03 5.827908170877e-03 + 7.589233050420e-03 9.661317383208e-03 1.096841207277e-02 + 5.447461482951e-03 4.440671970133e-03 3.464018614061e-03 2.757147739863e-03 2.269098678609e-03 1.898646931060e-03 + 1.686650989380e-03 1.761695850405e-03 2.185852636149e-03 2.879495368967e-03 3.661613261736e-03 4.431658232992e-03 + 5.200925857721e-03 5.844282596476e-03 6.002269429604e-03 + 3.524211534090e-03 3.072036869511e-03 2.580329517830e-03 2.188603044826e-03 1.953829199602e-03 1.846066720369e-03 + 1.826185888625e-03 1.896483217245e-03 2.093975676664e-03 2.442818529635e-03 2.897474312379e-03 3.349643798644e-03 + 3.692461461521e-03 3.857708198851e-03 3.805038201511e-03 + 2.737485681499e-03 2.586485186662e-03 2.399780799978e-03 2.300744232006e-03 2.341901016583e-03 2.417607342442e-03 + 2.368067936532e-03 2.192003915132e-03 2.073348621214e-03 2.165745464618e-03 2.434693522892e-03 2.702609417980e-03 + 2.831251246984e-03 2.840154557732e-03 2.808399799934e-03 + 2.686271544203e-03 2.903490422724e-03 3.079004814043e-03 3.294858701304e-03 3.522565954339e-03 3.535481077333e-03 + 3.166775793126e-03 2.605008890896e-03 2.211045449405e-03 2.127235166088e-03 2.214801905437e-03 2.270040944752e-03 + 2.249667935441e-03 2.274525138513e-03 2.437975330404e-03 + 3.438363356649e-03 4.121821286904e-03 4.684441062036e-03 5.115070957760e-03 5.258869679412e-03 4.868225005668e-03 + 3.990926644579e-03 3.063767922832e-03 2.465985213013e-03 2.197420155748e-03 2.049328931241e-03 1.922229745183e-03 + 1.911206585369e-03 2.163137569006e-03 2.717804901391e-03 + 5.010683906663e-03 6.217241225326e-03 7.215498715086e-03 7.757945511570e-03 7.481896749446e-03 6.323434003930e-03 + 4.787759943138e-03 3.512108028104e-03 2.716608073992e-03 2.233822361059e-03 1.904659911478e-03 1.778480719004e-03 + 2.000808680865e-03 2.674676102920e-03 3.752496842843e-03 + 7.459197469690e-03 9.696792861800e-03 1.168601666226e-02 1.232230871061e-02 1.091790580031e-02 8.209983966598e-03 + 5.624678004740e-03 3.889849052427e-03 2.868079056382e-03 2.232951174729e-03 1.910832783129e-03 2.017415271681e-03 + 2.668727243386e-03 3.868818653285e-03 5.493143426663e-03 + 1.187693602562e-02 1.686235326724e-02 2.083882624180e-02 2.064102123301e-02 1.607381526558e-02 1.039473854584e-02 + 6.315143815414e-03 4.082127322257e-03 2.900891417052e-03 2.278156328916e-03 2.179100073491e-03 2.708621140436e-03 + 3.885655557214e-03 5.623272723585e-03 8.098402445032e-03 + 2.082916622502e-02 3.090369217617e-02 3.622435745752e-02 3.164311112896e-02 2.094716591804e-02 1.160634287437e-02 + 6.381324116688e-03 3.967874318379e-03 2.825685667943e-03 2.397206235087e-03 2.679672502490e-03 3.721073301014e-03 + 5.431021343954e-03 8.007937461278e-03 1.265786840200e-02 + 3.735798926696e-02 4.165443031793e-02 3.505299036009e-02 2.290100684537e-02 1.283710390670e-02 7.133897768990e-03 + 4.329443552306e-03 2.963799535934e-03 2.530907830606e-03 2.996375013998e-03 4.385135293846e-03 6.633589689891e-03 + 1.012015406827e-02 1.629695766688e-02 2.634368186148e-02 + 4.090211706574e-02 4.050244488753e-02 2.995931143559e-02 1.758383115563e-02 9.427523387185e-03 5.399695903899e-03 + 3.482232803771e-03 2.574428665484e-03 2.496005663639e-03 3.344576873364e-03 5.132764569118e-03 7.820147668245e-03 + 1.216985284410e-02 1.995797810753e-02 3.135471039874e-02 + 3.422240339402e-02 2.976743743330e-02 1.973528949644e-02 1.106708482729e-02 6.250122246794e-03 3.981414775836e-03 + 2.806492883131e-03 2.284499767385e-03 2.529314476361e-03 3.691491438620e-03 5.693505970176e-03 8.509783167338e-03 + 1.303143790659e-02 2.052254314320e-02 2.957667395411e-02 + 2.235309204113e-02 1.745598354149e-02 1.105315155044e-02 6.568690406378e-03 4.269959548346e-03 3.079863520723e-03 + 2.359352746709e-03 2.141619413377e-03 2.656937371519e-03 3.992542493556e-03 5.932840900788e-03 8.417998864114e-03 + 1.209007958843e-02 1.729531955141e-02 2.200662302502e-02 + 1.246954625674e-02 9.312356238960e-03 6.205847891595e-03 4.242012589860e-03 3.180063726450e-03 2.499460026201e-03 + 2.074172594413e-03 2.102109838773e-03 2.774041848054e-03 4.057776118191e-03 5.657950587876e-03 7.462276160287e-03 + 9.727016064206e-03 1.225614669411e-02 1.365128003580e-02 + 6.863283818143e-03 5.299988137109e-03 3.936451135517e-03 3.051214097009e-03 2.495994808557e-03 2.103625509391e-03 + 1.913399077874e-03 2.082508923866e-03 2.710777760817e-03 3.714509443089e-03 4.850542557256e-03 5.968174131340e-03 + 7.049450159128e-03 7.866128642482e-03 7.886674961383e-03 + 4.206917601816e-03 3.484941579967e-03 2.846213409261e-03 2.405695543036e-03 2.137948221333e-03 1.978512626893e-03 + 1.927169819667e-03 2.058293197880e-03 2.447151450392e-03 3.082212585523e-03 3.825664170862e-03 4.483144115195e-03 + 4.912278048409e-03 5.030193398143e-03 4.783066722111e-03 + 3.027936722133e-03 2.731382544182e-03 2.462388020768e-03 2.319977518301e-03 2.299982633725e-03 2.287479268029e-03 + 2.196451018127e-03 2.103708124821e-03 2.179398447415e-03 2.507748176859e-03 2.982551167373e-03 3.364478400194e-03 + 3.500618814367e-03 3.434565932802e-03 3.267027963810e-03 + 2.736584896833e-03 2.789825509723e-03 2.851775169119e-03 2.992314977182e-03 3.143249063411e-03 3.091064378478e-03 + 2.743376924975e-03 2.317890444489e-03 2.113327676986e-03 2.216438099316e-03 2.470192351515e-03 2.639181730161e-03 + 2.649375917252e-03 2.619877482355e-03 2.658244164766e-03 + 3.272818351508e-03 3.744361114825e-03 4.151330742807e-03 4.478118041629e-03 4.573691813601e-03 4.222700075573e-03 + 3.476570957780e-03 2.718475543696e-03 2.277205617021e-03 2.163524663686e-03 2.188727036758e-03 2.204000736404e-03 + 2.232483077846e-03 2.403506330680e-03 2.780331195852e-03 + 4.706746321282e-03 5.652225418704e-03 6.313281788746e-03 6.561739007074e-03 6.267508546148e-03 5.404089029820e-03 + 4.235177344905e-03 3.191920349698e-03 2.520500203087e-03 2.176388467735e-03 2.030332431382e-03 2.039713873589e-03 + 2.263526575194e-03 2.803249475969e-03 3.672441435114e-03 + 7.092400762600e-03 8.598078436116e-03 9.422286151290e-03 9.267330532083e-03 8.183859060530e-03 6.556461058059e-03 + 4.891800854644e-03 3.557378830869e-03 2.664753573108e-03 2.166116092776e-03 2.015705758879e-03 2.217151572206e-03 + 2.819367906947e-03 3.884536603006e-03 5.382042026569e-03 + 1.087425925399e-02 1.340442163643e-02 1.440530663883e-02 1.325569683385e-02 1.060865005027e-02 7.706910400662e-03 + 5.348360820394e-03 3.699351125792e-03 2.670634154401e-03 2.189654837742e-03 2.238192374717e-03 2.822449334345e-03 + 3.955967450099e-03 5.674240795331e-03 8.035541144770e-03 + 1.731002207085e-02 2.161479674365e-02 2.227081610919e-02 1.865425696906e-02 1.320151339742e-02 8.536209642620e-03 + 5.456633171620e-03 3.612151634595e-03 2.619293206573e-03 2.343286938972e-03 2.766090535805e-03 3.874039473773e-03 + 5.640976595499e-03 8.265617893395e-03 1.220909165399e-02 + 2.715203128932e-02 3.289446565134e-02 3.114642256115e-02 2.312526575738e-02 1.439019523922e-02 8.404395805151e-03 + 5.087911918649e-03 3.343754305540e-03 2.573903149694e-03 2.640485627176e-03 3.542490055896e-03 5.229832075486e-03 + 7.766211013716e-03 1.188108252312e-02 1.862377532798e-02 + 3.522578013597e-02 3.048885476587e-02 2.144439945799e-02 1.337661543091e-02 8.188360084962e-03 5.158794882858e-03 + 3.394496339861e-03 2.591803714373e-03 2.706025557829e-03 3.762283806202e-03 5.840097201637e-03 9.292633552415e-03 + 1.502254651769e-02 2.344124610934e-02 3.198726605356e-02 + 2.960677394974e-02 2.383681038617e-02 1.595642425114e-02 9.815063478712e-03 6.121436982756e-03 4.001704997571e-03 + 2.815388728124e-03 2.433945940949e-03 2.908311242620e-03 4.313065785066e-03 6.691438380412e-03 1.032949949152e-02 + 1.589094733848e-02 2.316083167814e-02 2.917279147293e-02 + 2.071824075646e-02 1.581783231265e-02 1.043950910899e-02 6.626534639227e-03 4.384585595383e-03 3.072544734494e-03 + 2.389099641725e-03 2.367750676083e-03 3.121594485772e-03 4.687378724414e-03 6.977442604908e-03 1.009452497331e-02 + 1.433642567946e-02 1.911498421979e-02 2.204414714517e-02 + 1.297097475530e-02 9.688265096494e-03 6.578060055279e-03 4.475066835549e-03 3.218128749617e-03 2.472541978430e-03 + 2.162272774597e-03 2.395859306752e-03 3.282483107412e-03 4.777615630767e-03 6.683031548023e-03 8.932151291011e-03 + 1.153734206692e-02 1.391686871086e-02 1.468744817122e-02 + 7.885065891837e-03 5.969588415678e-03 4.306191251828e-03 3.194662142218e-03 2.525961601256e-03 2.152435260453e-03 + 2.080736926575e-03 2.418849838355e-03 3.245602807909e-03 4.492114868230e-03 5.937896405859e-03 7.390326833321e-03 + 8.699236976528e-03 9.504617812760e-03 9.272133679399e-03 + 4.933413948899e-03 3.908553749593e-03 3.055690735347e-03 2.503830792542e-03 2.201193053912e-03 2.057815450797e-03 + 2.072560313682e-03 2.332935163746e-03 2.934634357047e-03 3.863421845848e-03 4.912115140199e-03 5.786056547683e-03 + 6.283162952258e-03 6.309475834879e-03 5.827551869882e-03 + 3.356459437541e-03 2.888812545829e-03 2.516322839781e-03 2.321072838784e-03 2.255521828125e-03 2.203922195777e-03 + 2.137487718628e-03 2.180082099714e-03 2.497027883692e-03 3.117784659674e-03 3.827041339314e-03 4.291642106485e-03 + 4.366463109948e-03 4.156406558552e-03 3.799824417913e-03 + 2.760000784537e-03 2.683803011067e-03 2.652342226907e-03 2.711483733196e-03 2.765995116059e-03 2.649967721283e-03 + 2.364777999283e-03 2.138692057741e-03 2.189595703353e-03 2.526120962702e-03 2.923781153045e-03 3.110430716364e-03 + 3.049867937173e-03 2.914618409869e-03 2.825390635457e-03 + 3.011965895416e-03 3.296859198778e-03 3.554917453061e-03 3.760941562183e-03 3.769494913229e-03 3.432127519214e-03 + 2.851080889824e-03 2.346352276144e-03 2.139425033954e-03 2.202307797827e-03 2.342972720134e-03 2.400824198352e-03 + 2.402747919098e-03 2.486210739162e-03 2.712635069171e-03 + 4.167570145519e-03 4.872318721289e-03 5.333055486713e-03 5.452357942058e-03 5.164350763373e-03 4.470427317355e-03 + 3.561773016882e-03 2.759544744436e-03 2.271129861696e-03 2.086320269612e-03 2.084449370679e-03 2.173456711497e-03 + 2.367918680082e-03 2.760821337787e-03 3.395328416749e-03 + 6.498087915507e-03 7.689975369869e-03 8.087894554527e-03 7.675820760069e-03 6.745845592991e-03 5.549867702209e-03 + 4.272482869604e-03 3.150836575881e-03 2.399407184557e-03 2.070868049973e-03 2.088198197908e-03 2.353789420055e-03 + 2.856830158526e-03 3.708814693620e-03 4.990810836910e-03 + 1.062487847077e-02 1.225582236647e-02 1.200679316950e-02 1.036509234961e-02 8.336952608629e-03 6.430057527004e-03 + 4.710804131514e-03 3.299598898351e-03 2.413170721981e-03 2.116999687594e-03 2.315173645517e-03 2.892554077250e-03 + 3.877432198241e-03 5.512068213060e-03 7.946508763885e-03 + 1.732651940194e-02 1.894430271760e-02 1.702806340327e-02 1.328398696068e-02 9.707474952776e-03 6.923442921205e-03 + 4.763673673299e-03 3.199340484393e-03 2.371328020760e-03 2.275761347289e-03 2.793918658500e-03 3.851347795876e-03 + 5.640637070514e-03 8.673079454528e-03 1.305730253139e-02 + 2.614903647666e-02 2.659830832892e-02 2.186237595636e-02 1.551301386926e-02 1.038154759381e-02 6.879652701441e-03 + 4.489788091477e-03 2.993503623330e-03 2.393942760691e-03 2.621258332535e-03 3.592112201263e-03 5.361976185776e-03 + 8.431089534176e-03 1.361002682803e-02 2.054834537837e-02 + 3.369810787055e-02 3.161778667044e-02 2.389069621346e-02 1.568590751610e-02 9.853424033536e-03 6.236801499065e-03 + 3.996807817365e-03 2.785162662593e-03 2.521405038127e-03 3.151933870050e-03 4.684454895102e-03 7.360255826177e-03 + 1.199947751176e-02 1.944353484956e-02 2.829128833955e-02 + 3.154404301618e-02 2.171562619114e-02 1.360299819069e-02 8.700254547422e-03 5.800795003177e-03 3.882768348731e-03 + 2.781484458611e-03 2.557430554816e-03 3.200276736708e-03 4.817161745335e-03 8.010297070036e-03 1.410499372262e-02 + 2.374603884257e-02 3.367778129749e-02 3.717823383378e-02 + 2.088773600196e-02 1.449486245293e-02 9.580505818613e-03 6.446204646065e-03 4.393258441849e-03 3.055614022061e-03 + 2.448377187812e-03 2.599596463187e-03 3.523255076244e-03 5.368053106975e-03 8.629028372387e-03 1.395455515620e-02 + 2.077787557518e-02 2.597090075008e-02 2.593970833773e-02 + 1.304610313557e-02 9.472882276931e-03 6.602799539192e-03 4.569213168420e-03 3.193627917493e-03 2.412211970554e-03 + 2.231986272377e-03 2.651741964900e-03 3.689829540925e-03 5.443312184604e-03 8.111964264628e-03 1.169020915075e-02 + 1.530815343969e-02 1.720766791692e-02 1.621136604811e-02 + 8.383300770826e-03 6.311063368149e-03 4.514069947052e-03 3.203929667863e-03 2.404224005425e-03 2.070840463552e-03 + 2.165400903850e-03 2.680418087487e-03 3.643470976045e-03 5.105411836397e-03 7.023114415932e-03 9.084696988167e-03 + 1.066648158940e-02 1.111203501295e-02 1.021348677597e-02 + 5.538714390650e-03 4.256616137489e-03 3.151715039238e-03 2.418524405339e-03 2.064660653018e-03 2.002597924145e-03 + 2.174519623001e-03 2.596478735163e-03 3.360514321248e-03 4.515609735479e-03 5.864872883384e-03 6.991815298439e-03 + 7.542701113961e-03 7.413435347834e-03 6.685062782634e-03 + 3.736397558038e-03 3.041043386409e-03 2.485524676128e-03 2.187416640206e-03 2.102982651662e-03 2.112303119969e-03 + 2.169441390140e-03 2.376904177456e-03 2.909640763931e-03 3.786141335691e-03 4.700650118827e-03 5.234271481399e-03 + 5.253120032159e-03 4.920000784617e-03 4.394488455742e-03 + 2.847650558714e-03 2.619242279318e-03 2.463260092431e-03 2.432259491219e-03 2.434175519657e-03 2.338253293818e-03 + 2.175980720616e-03 2.156920558194e-03 2.459629644619e-03 3.023433421129e-03 3.521480063926e-03 3.662276637701e-03 + 3.496873382755e-03 3.259981027171e-03 3.057738073662e-03 + 2.814805777585e-03 2.932566388019e-03 3.031518817337e-03 3.103113112234e-03 3.032828130340e-03 2.739874431784e-03 + 2.354080124893e-03 2.122366530360e-03 2.165563419443e-03 2.384629889393e-03 2.553387652098e-03 2.552975940819e-03 + 2.488650299699e-03 2.515621209595e-03 2.655211305235e-03 + 3.608908472216e-03 4.038327091591e-03 4.273540237343e-03 4.266891089447e-03 3.983444042413e-03 3.450258642543e-03 + 2.826424817726e-03 2.326204959119e-03 2.061883855676e-03 2.000883102011e-03 2.042721396232e-03 2.128100700115e-03 + 2.293015537429e-03 2.609927664734e-03 3.083466166260e-03 + 5.548446590848e-03 6.385685282703e-03 6.548785089875e-03 6.105567309424e-03 5.344826421455e-03 4.441088868624e-03 + 3.477887830390e-03 2.621603884326e-03 2.071033784490e-03 1.893121356689e-03 2.011407519898e-03 2.304926311601e-03 + 2.735917173468e-03 3.404414127559e-03 4.399895254358e-03 + 9.753754719035e-03 1.097473792817e-02 1.033106582214e-02 8.631022998193e-03 6.898645134815e-03 5.387535134929e-03 + 3.970733857606e-03 2.776969189509e-03 2.095518494302e-03 1.993809941405e-03 2.318259314101e-03 2.872148179703e-03 + 3.679344115611e-03 5.086788845040e-03 7.323360415773e-03 + 1.790450142094e-02 1.848542142515e-02 1.533726090168e-02 1.125941456162e-02 8.130496919058e-03 5.892704711367e-03 + 4.060332518064e-03 2.715095616102e-03 2.118169757135e-03 2.229788020846e-03 2.821685232503e-03 3.760432649401e-03 + 5.434479710989e-03 8.689882976359e-03 1.360245126401e-02 + 2.963052267632e-02 2.699059100623e-02 1.962295882091e-02 1.287542609060e-02 8.579229262369e-03 5.838764842450e-03 + 3.825052537905e-03 2.571617311411e-03 2.210202524346e-03 2.602845328032e-03 3.566190274656e-03 5.314880002931e-03 + 8.960120224342e-03 1.582473520055e-02 2.456529283382e-02 + 3.934422871274e-02 3.154603164001e-02 2.065852051237e-02 1.270753690680e-02 8.172570144800e-03 5.384688696175e-03 + 3.482973769724e-03 2.497409214126e-03 2.441745311344e-03 3.183507168031e-03 4.768849071633e-03 8.035852126683e-03 + 1.487064024503e-02 2.606573607176e-02 3.698176850558e-02 + 3.995761726083e-02 2.896502633013e-02 1.798662183923e-02 1.102145070565e-02 7.149023091629e-03 4.701438975973e-03 + 3.137135283566e-03 2.513406452481e-03 2.802545594012e-03 3.982792131212e-03 6.443234114465e-03 1.157559450063e-02 + 2.122079529331e-02 3.405395846378e-02 4.261508740426e-02 + 2.612476752741e-02 1.538211298955e-02 9.250542635556e-03 6.104818135930e-03 4.155647771335e-03 2.909695231712e-03 + 2.452651878206e-03 2.766125803426e-03 3.831574778315e-03 6.164252249561e-03 1.147853790220e-02 2.185184977290e-02 + 3.529946448329e-02 4.302235793283e-02 3.835526614151e-02 + 1.475690833251e-02 9.595246852158e-03 6.479586986602e-03 4.477463024479e-03 3.089731375329e-03 2.358915187583e-03 + 2.319078595210e-03 2.883477699025e-03 4.076964763033e-03 6.441807840478e-03 1.109280313633e-02 1.828227710048e-02 + 2.499622537608e-02 2.636050063328e-02 2.155302836640e-02 + 8.870028340925e-03 6.395246238359e-03 4.510365457118e-03 3.099918702114e-03 2.241966797322e-03 1.984590740218e-03 + 2.241520841837e-03 2.894749796309e-03 3.997032464616e-03 5.942626094462e-03 9.094829523676e-03 1.280797292393e-02 + 1.513606934467e-02 1.460572822821e-02 1.192462990383e-02 + 5.860522422628e-03 4.369127189319e-03 3.075003726246e-03 2.195026193350e-03 1.820856385965e-03 1.880588970888e-03 + 2.233563099148e-03 2.791732303928e-03 3.676829675673e-03 5.119052448968e-03 7.011305057753e-03 8.653729000900e-03 + 9.244108191097e-03 8.649336428075e-03 7.362884379327e-03 + 3.973810633074e-03 3.040347964832e-03 2.285313251936e-03 1.884924960609e-03 1.829183449848e-03 1.983549691229e-03 + 2.219838481962e-03 2.573892663528e-03 3.247231486207e-03 4.308349968256e-03 5.422122342397e-03 6.066045450677e-03 + 6.045739452329e-03 5.568194911805e-03 4.853405847528e-03 + 2.885730460669e-03 2.464063415454e-03 2.166136091709e-03 2.076393909159e-03 2.118384219142e-03 2.149128144793e-03 + 2.152428614123e-03 2.305328050381e-03 2.787130750103e-03 3.502669498484e-03 4.060255473621e-03 4.168882649908e-03 + 3.935817389903e-03 3.614964663710e-03 3.282076624383e-03 + 2.627788925179e-03 2.590335269749e-03 2.567800461816e-03 2.575396811840e-03 2.516835384101e-03 2.328770700557e-03 + 2.125919534935e-03 2.108976387706e-03 2.347371971086e-03 2.671066772004e-03 2.815443624739e-03 2.725668241264e-03 + 2.588269048027e-03 2.559152460990e-03 2.609644317753e-03 + 3.115486338831e-03 3.315233983984e-03 3.377234841870e-03 3.295355260034e-03 3.047553117708e-03 2.672154947215e-03 + 2.302070456399e-03 2.069767666175e-03 1.996841047386e-03 1.998500245957e-03 1.996750225094e-03 2.013117255941e-03 + 2.137007758220e-03 2.417131047567e-03 2.787831538779e-03 + 4.469988471123e-03 4.899538464499e-03 4.875948429969e-03 4.492062751751e-03 3.941605210625e-03 3.329905192238e-03 + 2.701277421723e-03 2.149745319074e-03 1.795842311158e-03 1.693367508144e-03 1.810228430255e-03 2.074799990608e-03 + 2.465167069160e-03 3.026566082946e-03 3.751574463821e-03 + 7.796815986635e-03 8.522945082186e-03 7.877884021050e-03 6.543848583068e-03 5.262237246964e-03 4.156303181232e-03 + 3.100971981876e-03 2.217659842001e-03 1.756664191850e-03 1.783588423829e-03 2.159237059297e-03 2.675771851745e-03 + 3.335955847310e-03 4.422614562879e-03 6.085001419538e-03 + 1.578784479054e-02 1.595590983776e-02 1.286546507960e-02 9.216163991279e-03 6.573118136087e-03 4.726886586030e-03 + 3.226873111143e-03 2.191541589964e-03 1.849264076861e-03 2.135515847557e-03 2.768167728242e-03 3.558730110153e-03 + 4.929678865732e-03 7.754380589687e-03 1.210475969996e-02 + 3.046209208360e-02 2.660868314269e-02 1.820095932997e-02 1.125448470478e-02 7.204333976641e-03 4.766376228039e-03 + 3.062172594730e-03 2.129901355406e-03 2.039391425625e-03 2.585943837498e-03 3.490469269122e-03 5.034604570931e-03 + 8.651776674373e-03 1.602692536245e-02 2.552751460497e-02 + 4.654203305816e-02 3.444973664470e-02 2.037169061038e-02 1.143522348431e-02 6.947817050129e-03 4.417417292556e-03 + 2.822701863866e-03 2.153295087777e-03 2.339698910997e-03 3.155053641530e-03 4.666299924681e-03 8.224177695201e-03 + 1.680393111062e-02 3.166544907850e-02 4.551993187271e-02 + 5.173655451699e-02 3.311083030114e-02 1.794608648006e-02 9.958577681727e-03 6.161794209189e-03 3.954417294716e-03 + 2.666033468135e-03 2.314388921206e-03 2.786060821365e-03 4.017218078154e-03 6.798895269588e-03 1.389112036840e-02 + 2.890193394974e-02 4.894324283409e-02 5.989930623533e-02 + 4.170787154172e-02 2.442026540864e-02 1.330694724452e-02 7.951072021559e-03 5.202484555421e-03 3.463561417286e-03 + 2.569991308914e-03 2.554620042858e-03 3.336826670018e-03 5.165724010134e-03 9.598958071565e-03 1.994710993027e-02 + 3.757951830940e-02 5.421591931452e-02 5.596617674227e-02 + 1.853259771931e-02 1.019886281523e-02 6.178914946441e-03 4.080836106473e-03 2.791976692164e-03 2.210722293685e-03 + 2.319581808087e-03 3.003255730225e-03 4.412558784929e-03 7.803590581365e-03 1.585230361210e-02 2.960094615765e-02 + 4.230191460439e-02 4.312104415756e-02 3.176062222008e-02 + 9.829602822261e-03 6.345454895673e-03 4.269671643987e-03 2.879254929759e-03 2.096027223981e-03 1.953321769066e-03 + 2.335817372198e-03 3.099762252046e-03 4.463321830705e-03 7.435701793546e-03 1.317773670056e-02 2.046282100075e-02 + 2.447122898723e-02 2.190532465839e-02 1.550496928546e-02 + 5.951105415409e-03 4.212808954489e-03 2.860297358627e-03 1.978806593757e-03 1.665379544518e-03 1.843885331201e-03 + 2.330203657428e-03 2.993543949637e-03 4.077140477151e-03 6.144441851010e-03 9.250201202231e-03 1.203530703384e-02 + 1.261707553133e-02 1.082986304284e-02 8.208220065452e-03 + 3.922616703106e-03 2.835514724065e-03 1.998294289525e-03 1.590564219784e-03 1.608420793704e-03 1.906043246504e-03 + 2.291754197395e-03 2.750283793736e-03 3.539930383162e-03 4.843301949524e-03 6.308652838685e-03 7.162798125035e-03 + 7.000583586394e-03 6.140395340754e-03 5.053259156814e-03 + 2.730252153426e-03 2.156246612262e-03 1.786893818183e-03 1.708476520454e-03 1.848709824850e-03 2.039891519781e-03 + 2.200128441304e-03 2.470379077968e-03 3.042597608791e-03 3.836279419094e-03 4.451952705113e-03 4.572948985648e-03 + 4.286570904716e-03 3.842518450162e-03 3.326542366922e-03 + 2.315197342019e-03 2.165661235880e-03 2.106562631307e-03 2.147936486460e-03 2.187503723949e-03 2.143231168711e-03 + 2.095378028382e-03 2.218496243400e-03 2.562790900480e-03 2.930374155883e-03 3.052152451648e-03 2.906759942280e-03 + 2.699501172177e-03 2.565246251240e-03 2.461192461720e-03 + 2.595964372684e-03 2.695315864383e-03 2.728609102570e-03 2.676162174905e-03 2.508308928961e-03 2.268554018791e-03 + 2.075390418618e-03 2.018600296787e-03 2.065881178348e-03 2.087932368230e-03 2.017249082073e-03 1.939257137183e-03 + 1.981792787993e-03 2.172073263022e-03 2.413616274227e-03 + 3.488542438294e-03 3.691276544455e-03 3.619662269505e-03 3.337333773670e-03 2.962554900375e-03 2.571381226423e-03 + 2.197271226022e-03 1.879240238441e-03 1.660590649841e-03 1.563420899937e-03 1.597135126370e-03 1.767600571889e-03 + 2.090124119583e-03 2.555014486904e-03 3.067849565093e-03 + 5.557487390595e-03 5.853417813599e-03 5.375507973967e-03 4.543717853798e-03 3.760654255380e-03 3.067045100569e-03 + 2.380018546055e-03 1.791983199370e-03 1.483977252145e-03 1.522617394675e-03 1.829843196264e-03 2.265359513195e-03 + 2.817197967244e-03 3.603674370827e-03 4.628199121562e-03 + 1.113939029151e-02 1.106996778631e-02 8.944184288551e-03 6.524703415806e-03 4.771851309074e-03 3.506617548532e-03 + 2.450446926951e-03 1.740666927832e-03 1.569764384573e-03 1.903310416597e-03 2.488650626782e-03 3.127555876293e-03 + 4.118139584189e-03 6.041348922505e-03 8.872387497899e-03 + 2.410421976137e-02 2.080270395551e-02 1.404878657328e-02 8.599728275431e-03 5.470418433914e-03 3.602550040937e-03 + 2.341629950380e-03 1.737324428569e-03 1.841364800949e-03 2.454761388786e-03 3.241535593731e-03 4.410715170998e-03 + 7.196906614918e-03 1.297868238597e-02 2.041102779952e-02 + 4.370456572565e-02 3.144544928536e-02 1.777499667081e-02 9.450140549552e-03 5.466331350096e-03 3.364126307207e-03 + 2.175083915838e-03 1.820861243020e-03 2.194477194549e-03 3.013308026245e-03 4.283484950862e-03 7.393040874538e-03 + 1.541741708723e-02 2.979413789891e-02 4.319280957915e-02 + 5.738667866000e-02 3.462704617734e-02 1.718008106619e-02 8.629866362433e-03 4.929605015973e-03 3.032748950179e-03 + 2.104054223319e-03 2.032474725592e-03 2.638435899276e-03 3.805837539044e-03 6.504434267630e-03 1.421537063344e-02 + 3.177032628152e-02 5.580216511673e-02 6.837862196958e-02 + 5.250624027643e-02 2.773366359614e-02 1.322104800737e-02 6.996821637519e-03 4.241066830103e-03 2.756274001865e-03 + 2.159366473872e-03 2.365066621014e-03 3.232452244450e-03 5.137968878483e-03 1.047199262587e-02 2.457404122119e-02 + 5.008777563254e-02 7.402128346580e-02 7.486895437815e-02 + 3.463804005455e-02 1.750710494686e-02 9.054440801528e-03 5.426391283427e-03 3.538187210252e-03 2.499956423116e-03 + 2.258491896069e-03 2.728271437841e-03 3.908409888391e-03 6.789931074216e-03 1.466663611065e-02 3.192415290093e-02 + 5.509517489561e-02 6.719525706476e-02 5.669505514833e-02 + 1.080172803582e-02 6.042785473381e-03 3.777718911831e-03 2.520777299795e-03 1.902686073726e-03 1.871775381230e-03 + 2.326629190525e-03 3.182737076481e-03 4.891245621266e-03 9.198114767741e-03 1.840412824865e-02 3.063592420154e-02 + 3.697718530540e-02 3.148920959361e-02 1.994220524868e-02 + 5.869765292977e-03 3.857462999727e-03 2.583466107847e-03 1.842798513157e-03 1.643140914981e-03 1.897235163876e-03 + 2.451140153612e-03 3.222318822602e-03 4.650101308087e-03 7.766441617013e-03 1.289990941184e-02 1.758134082914e-02 + 1.802797554622e-02 1.411083687332e-02 9.274100481569e-03 + 3.650414171308e-03 2.552522884468e-03 1.801829452219e-03 1.495892026097e-03 1.599695716325e-03 1.975346062496e-03 + 2.440407712405e-03 2.985357862342e-03 3.962528864875e-03 5.718768267299e-03 7.834134756451e-03 9.018043082001e-03 + 8.463359033372e-03 6.793762278430e-03 5.054366193145e-03 + 2.444613018517e-03 1.855966076851e-03 1.541353773510e-03 1.540889732905e-03 1.770388043913e-03 2.064565610343e-03 + 2.318357514709e-03 2.653190860248e-03 3.280174662765e-03 4.156174060508e-03 4.867221583819e-03 5.001816838577e-03 + 4.580926528686e-03 3.903121346495e-03 3.165633738404e-03 + 1.941408074716e-03 1.770074337752e-03 1.757755940888e-03 1.884249960774e-03 2.035033386259e-03 2.110161126724e-03 + 2.165894179193e-03 2.360487333404e-03 2.734776045294e-03 3.102586617176e-03 3.221239461982e-03 3.061300865334e-03 + 2.780257620901e-03 2.490870311991e-03 2.205724780591e-03 + 2.063187004190e-03 2.168682032150e-03 2.276231672989e-03 2.323394807771e-03 2.259237742955e-03 2.129275316986e-03 + 2.051663764567e-03 2.096422939965e-03 2.201762379837e-03 2.224841654902e-03 2.108728345854e-03 1.950623275738e-03 + 1.871315277435e-03 1.895436877573e-03 1.972594070188e-03 + 2.680372359512e-03 2.881087782805e-03 2.896243946719e-03 2.730835230804e-03 2.472615692043e-03 2.213272652655e-03 + 1.994339101755e-03 1.816885200905e-03 1.670126972243e-03 1.549581602160e-03 1.482553209579e-03 1.523125301387e-03 + 1.707150220964e-03 2.013029717953e-03 2.364757245206e-03 + 3.864452093552e-03 4.026066650926e-03 3.762539419622e-03 3.293242454778e-03 2.834042952086e-03 2.408732700021e-03 + 1.967808848953e-03 1.567714633376e-03 1.328638552172e-03 1.301460099087e-03 1.461674070210e-03 1.758232300993e-03 + 2.177701399377e-03 2.725080302637e-03 3.345252277984e-03 + 6.756099017632e-03 6.646415365864e-03 5.546870321094e-03 4.307533065955e-03 3.369770637716e-03 2.616103542101e-03 + 1.919800140371e-03 1.428455159996e-03 1.301714267052e-03 1.532585034092e-03 1.966255843766e-03 2.461423291660e-03 + 3.137652094537e-03 4.236634508780e-03 5.685680523167e-03 + 1.443870669056e-02 1.250437884909e-02 8.717002089443e-03 5.650291185289e-03 3.833385316292e-03 2.660475672278e-03 + 1.816501512873e-03 1.422373552816e-03 1.555584500724e-03 2.076439505584e-03 2.693785103508e-03 3.482212385485e-03 + 5.167886205648e-03 8.467490008635e-03 1.253795167936e-02 + 2.963354482529e-02 2.129525980695e-02 1.212474159989e-02 6.581303010476e-03 3.922113425988e-03 2.492446243950e-03 + 1.695439082163e-03 1.530322575288e-03 1.938344986195e-03 2.647112948772e-03 3.566879864917e-03 5.671719441490e-03 + 1.106089737276e-02 2.064685078443e-02 2.948261488031e-02 + 4.646154224574e-02 2.748523273079e-02 1.324323431843e-02 6.456176678104e-03 3.621934133459e-03 2.240803946847e-03 + 1.641459794139e-03 1.731762033486e-03 2.345387370567e-03 3.310429114923e-03 5.402289935270e-03 1.154118283463e-02 + 2.584823135229e-02 4.564797706505e-02 5.589188144372e-02 + 5.066849373552e-02 2.546018585086e-02 1.125099509362e-02 5.497613849333e-03 3.161901844663e-03 2.045737660357e-03 + 1.709980195882e-03 2.036871793688e-03 2.868203488327e-03 4.551781192005e-03 9.505962503725e-03 2.335150579910e-02 + 4.921518586334e-02 7.366744380208e-02 7.408421436212e-02 + 3.833987134072e-02 1.759307817614e-02 8.046025905565e-03 4.362598452110e-03 2.708081638134e-03 1.940900588321e-03 + 1.887944690446e-03 2.438129985382e-03 3.609095135170e-03 6.618517901350e-03 1.563695323127e-02 3.664409236865e-02 + 6.559800922617e-02 8.041138739495e-02 6.633062653367e-02 + 2.164328352783e-02 1.028142526476e-02 5.470207966213e-03 3.373596827148e-03 2.285193687929e-03 1.891022645977e-03 + 2.115754010104e-03 2.866411437191e-03 4.433617738645e-03 8.696650736688e-03 1.989942523628e-02 4.015789855824e-02 + 5.902852581789e-02 5.934450473021e-02 4.129872097478e-02 + 5.467227682267e-03 3.369220511967e-03 2.293152443176e-03 1.751003996711e-03 1.652048605827e-03 1.917272198549e-03 + 2.472568965154e-03 3.323163834828e-03 5.062119049590e-03 9.129993046047e-03 1.617273564946e-02 2.264076038325e-02 + 2.280500666930e-02 1.668141101510e-02 9.772017250737e-03 + 3.289505142682e-03 2.322043133624e-03 1.763104279211e-03 1.599986761149e-03 1.770512621940e-03 2.160355418964e-03 + 2.646012556122e-03 3.266102700891e-03 4.473153809155e-03 6.794409189329e-03 9.710792678083e-03 1.123543358252e-02 + 1.006215059035e-02 7.330066784112e-03 4.872212349791e-03 + 2.214126788081e-03 1.747354038243e-03 1.578672448867e-03 1.708353815350e-03 2.022527099442e-03 2.348961284011e-03 + 2.603602941920e-03 2.938909653556e-03 3.608164955325e-03 4.597088971605e-03 5.423918437627e-03 5.514496658987e-03 + 4.832517685439e-03 3.835489713724e-03 2.920783750617e-03 + 1.726292350941e-03 1.635291328180e-03 1.758232305301e-03 2.041900569727e-03 2.306951568314e-03 2.405824082655e-03 + 2.426717016602e-03 2.578968783537e-03 2.908707226932e-03 3.235914378883e-03 3.341060578200e-03 3.168519247023e-03 + 2.807977900983e-03 2.379646444393e-03 1.993396562094e-03 + 1.736985224519e-03 1.914288239060e-03 2.184285551509e-03 2.418259024779e-03 2.459340784678e-03 2.331243765099e-03 + 2.228699126693e-03 2.266627909902e-03 2.361885738272e-03 2.362355501244e-03 2.227182355849e-03 2.026566001855e-03 + 1.834354594940e-03 1.706244324787e-03 1.672155545380e-03 + 2.141724317895e-03 2.448220558771e-03 2.656371371379e-03 2.657499732873e-03 2.467115324824e-03 2.224700879648e-03 + 2.044275337128e-03 1.924492539749e-03 1.802264931825e-03 1.652031245553e-03 1.510577515651e-03 1.433488739741e-03 + 1.462514673837e-03 1.606833930557e-03 1.843808747912e-03 + 2.873155897893e-03 3.123060352980e-03 3.085960582084e-03 2.827606401373e-03 2.498992804386e-03 2.176414931306e-03 + 1.852529973995e-03 1.542421768118e-03 1.313899519548e-03 1.209661889631e-03 1.229349504205e-03 1.368793632156e-03 + 1.627198403407e-03 1.997154278187e-03 2.444273358504e-03 + 4.186553223894e-03 4.206449893922e-03 3.746375731295e-03 3.161255556982e-03 2.652673013736e-03 2.166986087907e-03 + 1.658188814285e-03 1.258818016471e-03 1.099978123817e-03 1.179937730432e-03 1.427160184491e-03 1.773862325776e-03 + 2.235472507585e-03 2.872946740968e-03 3.627629150481e-03 + 7.419180815867e-03 6.624362240509e-03 5.049228252779e-03 3.711007593454e-03 2.820548546624e-03 2.105503078779e-03 + 1.495385906706e-03 1.166728220117e-03 1.201460563105e-03 1.521885408744e-03 1.959819720475e-03 2.494024783040e-03 + 3.397907607261e-03 4.917851494622e-03 6.647310950986e-03 + 1.495961594641e-02 1.110694770163e-02 6.848814615229e-03 4.204341669061e-03 2.828263706329e-03 1.949260917908e-03 + 1.383758829948e-03 1.241893660661e-03 1.518838638416e-03 2.027949210441e-03 2.644998298627e-03 3.820019017296e-03 + 6.510853888027e-03 1.100066803855e-02 1.497735176873e-02 + 2.652394710860e-02 1.595368311056e-02 8.061019244419e-03 4.282720645316e-03 2.635303938767e-03 1.747429354795e-03 + 1.336180561811e-03 1.422736298588e-03 1.899162525161e-03 2.587038400715e-03 3.889411533530e-03 7.460006002666e-03 + 1.549480812026e-02 2.640064592602e-02 3.189968446492e-02 + 3.445871944439e-02 1.721668807997e-02 7.677621106666e-03 3.882222474917e-03 2.334655290592e-03 1.577899262588e-03 + 1.376468138792e-03 1.675581784810e-03 2.337594023818e-03 3.549925664432e-03 6.965610852628e-03 1.643425551249e-02 + 3.410274878628e-02 5.074037130438e-02 5.075431102068e-02 + 3.104428888284e-02 1.374116716706e-02 6.065775034374e-03 3.238980504123e-03 2.024738203517e-03 1.499551548790e-03 + 1.527510928735e-03 2.026052901369e-03 3.001710376749e-03 5.443752473345e-03 1.287355676415e-02 3.049795512110e-02 + 5.501669054221e-02 6.740180185758e-02 5.499539358664e-02 + 2.002178797300e-02 8.783942687058e-03 4.353687950828e-03 2.604519735868e-03 1.785527826619e-03 1.542032583727e-03 + 1.794016693633e-03 2.494749368976e-03 3.953695469226e-03 8.068611501829e-03 1.932994440272e-02 4.023525184605e-02 + 5.981090881465e-02 5.969593627134e-02 4.038446889137e-02 + 1.046415287058e-02 5.259203988462e-03 3.117253359412e-03 2.099932014167e-03 1.661663124341e-03 1.694201976114e-03 + 2.142105847867e-03 3.003522103005e-03 4.847775257336e-03 9.801553494451e-03 2.092160050510e-02 3.605983587385e-02 + 4.368482796666e-02 3.617866609900e-02 2.144937311087e-02 + 2.897067969921e-03 2.163605956587e-03 1.822115567659e-03 1.795373866309e-03 2.009484024991e-03 2.370946402554e-03 + 2.819497326028e-03 3.431070328592e-03 4.684135997433e-03 7.209443924744e-03 1.047232563013e-02 1.207998811390e-02 + 1.044610976668e-02 7.110670958159e-03 4.390528081435e-03 + 2.115853136729e-03 1.844270265169e-03 1.866665689406e-03 2.184190308252e-03 2.630219703779e-03 2.962176275320e-03 + 3.115242963207e-03 3.328699698662e-03 3.936586896287e-03 4.952287080143e-03 5.812420625681e-03 5.789517466748e-03 + 4.837492159415e-03 3.613710350389e-03 2.676463984084e-03 + 1.771188157118e-03 1.858491056511e-03 2.274404798580e-03 2.939637724211e-03 3.446473133079e-03 3.441563543446e-03 + 3.138928208848e-03 3.000424416838e-03 3.143124188352e-03 3.351289037160e-03 3.388165226627e-03 3.169540516573e-03 + 2.746848570012e-03 2.275465124977e-03 1.926992521927e-03 + 1.796789539133e-03 2.220536090311e-03 2.982772060770e-03 3.774607457603e-03 3.983028458090e-03 3.496854288384e-03 + 2.902839164090e-03 2.619762138117e-03 2.544327171734e-03 2.452272839248e-03 2.289281577632e-03 2.083475071090e-03 + 1.848928086157e-03 1.676195579921e-03 1.648689767224e-03 + 2.103882268208e-03 2.763963240063e-03 3.587979117640e-03 4.072432866326e-03 3.810421002166e-03 3.101115862441e-03 + 2.513424688376e-03 2.204007034376e-03 2.007000975363e-03 1.807461473240e-03 1.625101105513e-03 1.485243283951e-03 + 1.431512037628e-03 1.512524577667e-03 1.720103288905e-03 + 2.592779021453e-03 3.236400940293e-03 3.717747233493e-03 3.697774604708e-03 3.196502434292e-03 2.569988169674e-03 + 2.072858664983e-03 1.716669342623e-03 1.451535404090e-03 1.277806515610e-03 1.202129533186e-03 1.236490119726e-03 + 1.400582144497e-03 1.675521991621e-03 2.058868833428e-03 + 3.226780670427e-03 3.581351258736e-03 3.568864238114e-03 3.215817959651e-03 2.701613459341e-03 2.163542624254e-03 + 1.660909758947e-03 1.264617842827e-03 1.046774991790e-03 1.007877284369e-03 1.115630820924e-03 1.351993377480e-03 + 1.698595858632e-03 2.146252641829e-03 2.683404001954e-03 + 4.310767697510e-03 4.181472975045e-03 3.641905311901e-03 3.029240118116e-03 2.464370774167e-03 1.890295182915e-03 + 1.350177537222e-03 1.005639695487e-03 9.247452662178e-04 1.064536679739e-03 1.358060631105e-03 1.764917986603e-03 + 2.321193460621e-03 3.066696287359e-03 3.855110378292e-03 + 6.821615992615e-03 5.577267937076e-03 4.080143623951e-03 3.020877668816e-03 2.301744991378e-03 1.669206160750e-03 + 1.171992661797e-03 9.629041198270e-04 1.058132758627e-03 1.370510657946e-03 1.813805707514e-03 2.488275979659e-03 + 3.665547730758e-03 5.351428176550e-03 6.758721373841e-03 + 1.160496810231e-02 7.617408035660e-03 4.536694547159e-03 2.946013219865e-03 2.094303328035e-03 1.478029990209e-03 + 1.108086472077e-03 1.081524028554e-03 1.354464217469e-03 1.810929492672e-03 2.561592658545e-03 4.217251580583e-03 + 7.484193424033e-03 1.161558938250e-02 1.362012088352e-02 + 1.678921923097e-02 8.935367443813e-03 4.550481870898e-03 2.728755253284e-03 1.864772144319e-03 1.335433012089e-03 + 1.144731320141e-03 1.312828856097e-03 1.748995619100e-03 2.497394740258e-03 4.314865042008e-03 8.892847296055e-03 + 1.699878667946e-02 2.440926447077e-02 2.425377669342e-02 + 1.789473259968e-02 8.254680666745e-03 4.008898568396e-03 2.408369036571e-03 1.644806605782e-03 1.275620389533e-03 + 1.289437728663e-03 1.640902019640e-03 2.313495375181e-03 3.843640882855e-03 8.204779064405e-03 1.822042843418e-02 + 3.192879356430e-02 3.865675004277e-02 3.143001769198e-02 + 1.373751138620e-02 6.126164119108e-03 3.198932684562e-03 2.045690654970e-03 1.494466546187e-03 1.345623344454e-03 + 1.548105925705e-03 2.086090952907e-03 3.162712435421e-03 6.066659317858e-03 1.391295824666e-02 2.844828965839e-02 + 4.197547604429e-02 4.159842219375e-02 2.787568364778e-02 + 8.221211104854e-03 4.079638271075e-03 2.484965349997e-03 1.776211392724e-03 1.499887952885e-03 1.553477485943e-03 + 1.917559278184e-03 2.638603630886e-03 4.175075862974e-03 8.297432060869e-03 1.768002109569e-02 3.056707101981e-02 + 3.692056382426e-02 3.015139723150e-02 1.740411324709e-02 + 4.599251119014e-03 2.820979789500e-03 2.034261611745e-03 1.690209968183e-03 1.663887525768e-03 1.889476943709e-03 + 2.370415069310e-03 3.165912909499e-03 4.833070911901e-03 8.817998336935e-03 1.589691525477e-02 2.242361790289e-02 + 2.231993953824e-02 1.574225376947e-02 8.690643212578e-03 + 2.079996999711e-03 2.027522657674e-03 2.271715477053e-03 2.825699634941e-03 3.446707574620e-03 3.774752701139e-03 + 3.737288009769e-03 3.671933060654e-03 4.005122230571e-03 4.795254933599e-03 5.488106655395e-03 5.345100122264e-03 + 4.338755190015e-03 3.178260839840e-03 2.417921277215e-03 + 1.998237983150e-03 2.368164809305e-03 3.285210946890e-03 4.643295112375e-03 5.606819493450e-03 5.390483426881e-03 + 4.408907991033e-03 3.639517198689e-03 3.392161204020e-03 3.374676794848e-03 3.275717824173e-03 2.985226376699e-03 + 2.554255894522e-03 2.159169210796e-03 1.961790440846e-03 + 2.245789631267e-03 3.281396360190e-03 5.247543152848e-03 7.414705116477e-03 7.987830968947e-03 6.465410580047e-03 + 4.471285237885e-03 3.286804077704e-03 2.778914552198e-03 2.482198390251e-03 2.238460609745e-03 2.033468038701e-03 + 1.839310409499e-03 1.745007250990e-03 1.846125406814e-03 + 2.838625965740e-03 4.670670814877e-03 7.441247740986e-03 9.394442997124e-03 8.638674473532e-03 6.039233439700e-03 + 3.835399514031e-03 2.736286655866e-03 2.235456320204e-03 1.913070304377e-03 1.692165306639e-03 1.552096480485e-03 + 1.516092174044e-03 1.658291068863e-03 2.009919643109e-03 + 3.530969750019e-03 5.711063712315e-03 8.078781029213e-03 8.679117034854e-03 6.922817677792e-03 4.502995959187e-03 + 2.888375501830e-03 2.102820412714e-03 1.689285265317e-03 1.429834319662e-03 1.296012064028e-03 1.297815207832e-03 + 1.472674319450e-03 1.787172444927e-03 2.334946208476e-03 + 3.971177877052e-03 5.617309242015e-03 6.654601154509e-03 6.140410202278e-03 4.542648573348e-03 3.013964013316e-03 + 2.045311390488e-03 1.500509354240e-03 1.191039936133e-03 1.054598775167e-03 1.082602498720e-03 1.287448587753e-03 + 1.621748120279e-03 2.046138704711e-03 2.734575335607e-03 + 4.094357254322e-03 4.781760192472e-03 4.764813395084e-03 4.014370398288e-03 2.993062284656e-03 2.104829803237e-03 + 1.463519708031e-03 1.059567051915e-03 8.774025830362e-04 8.973172574004e-04 1.110410915919e-03 1.483073379774e-03 + 1.942052808268e-03 2.484242937490e-03 3.205195384704e-03 + 4.350913116998e-03 4.216863390666e-03 3.670280559247e-03 2.970300264477e-03 2.271448421643e-03 1.627520747991e-03 + 1.120731013372e-03 8.383965668717e-04 7.968125661255e-04 9.745214553686e-04 1.342558916499e-03 1.861709280198e-03 + 2.508942588015e-03 3.257367350373e-03 3.965908837695e-03 + 5.355881028047e-03 4.274283618057e-03 3.235195142290e-03 2.492712714880e-03 1.893673400154e-03 1.348423675803e-03 + 9.582021987504e-04 8.173642959285e-04 9.235697407573e-04 1.239567794411e-03 1.759994167750e-03 2.572521582304e-03 + 3.759373436255e-03 5.057866309449e-03 5.750129513843e-03 + 7.022913535841e-03 4.521848412920e-03 2.971193192978e-03 2.173777895340e-03 1.629458440434e-03 1.186626760681e-03 + 9.512039614524e-04 9.765952985783e-04 1.228286093732e-03 1.701635932442e-03 2.594420932553e-03 4.335486629841e-03 + 6.987032945488e-03 9.260539576869e-03 9.255222651137e-03 + 8.064792960943e-03 4.393520229333e-03 2.677866948654e-03 1.926526793910e-03 1.448693235808e-03 1.150149455789e-03 + 1.106833793624e-03 1.301345170398e-03 1.714449172524e-03 2.530789219989e-03 4.454421046526e-03 8.374398659825e-03 + 1.341781637251e-02 1.579345220676e-02 1.309345764341e-02 + 7.284417862917e-03 3.751355813870e-03 2.343562251463e-03 1.719628095670e-03 1.367878379766e-03 1.270907213520e-03 + 1.405821685948e-03 1.756119661116e-03 2.404362482196e-03 3.927123518683e-03 7.703695491298e-03 1.439784489801e-02 + 2.047208135113e-02 2.015459666930e-02 1.379113693291e-02 + 5.256853092007e-03 2.920646002797e-03 2.012634999277e-03 1.596659412171e-03 1.458574695850e-03 1.532383514222e-03 + 1.793925039970e-03 2.288559202475e-03 3.246095336649e-03 5.646471517006e-03 1.099126868350e-02 1.827588011703e-02 + 2.178431542618e-02 1.779050358208e-02 1.046802463803e-02 + 3.451898057855e-03 2.301272117621e-03 1.835094570544e-03 1.678740183589e-03 1.730542630644e-03 1.915577258165e-03 + 2.271058439943e-03 2.851628807803e-03 3.998236299460e-03 6.707214363945e-03 1.158432603488e-02 1.610228307306e-02 + 1.591987487745e-02 1.118517655373e-02 6.235169382183e-03 + 2.474935954005e-03 2.027517568360e-03 1.898146618444e-03 2.008910969392e-03 2.266213886232e-03 2.576701677285e-03 + 2.919940279733e-03 3.365383822248e-03 4.294811874154e-03 6.274070703782e-03 8.919533536512e-03 1.018028837608e-02 + 8.671350272040e-03 5.793044478456e-03 3.576228682692e-03 + 2.268618836602e-03 2.982142759893e-03 4.461885056599e-03 6.537459356656e-03 7.942674916590e-03 7.477629162836e-03 + 5.743308896384e-03 4.241394311177e-03 3.522761098666e-03 3.236299167052e-03 2.982254388023e-03 2.632774575925e-03 + 2.250807203523e-03 1.998580512941e-03 1.997046706867e-03 + 2.966285611839e-03 4.944922257700e-03 8.687781951197e-03 1.282227947469e-02 1.387636519460e-02 1.080750473352e-02 + 6.719971996048e-03 4.188422479893e-03 3.070509795204e-03 2.505312099215e-03 2.131322639275e-03 1.898296833273e-03 + 1.776120804033e-03 1.830924368860e-03 2.153339884472e-03 + 4.446338670275e-03 8.681196515929e-03 1.531233663949e-02 2.005997666539e-02 1.815556322248e-02 1.167190428286e-02 + 6.217182506716e-03 3.578478521029e-03 2.512922156236e-03 1.970484295191e-03 1.667258130283e-03 1.546560098645e-03 + 1.601748815429e-03 1.914613826236e-03 2.632385319242e-03 + 6.536568808969e-03 1.282075205938e-02 2.005260974174e-02 2.197907299739e-02 1.652262039960e-02 9.167006056066e-03 + 4.617491232581e-03 2.731303803510e-03 1.962567583487e-03 1.552614257779e-03 1.361729751671e-03 1.380711143185e-03 + 1.652358223182e-03 2.204113146915e-03 3.416256458650e-03 + 7.983714587715e-03 1.391266982005e-02 1.815915915623e-02 1.650676079435e-02 1.069337079587e-02 5.610093627904e-03 + 3.018604414406e-03 1.965867436594e-03 1.470432930204e-03 1.212126999655e-03 1.178633052979e-03 1.400796572336e-03 + 1.840438994227e-03 2.548703250583e-03 4.187341567259e-03 + 7.609142325993e-03 1.093547396202e-02 1.174367164353e-02 9.188220280864e-03 5.622934351117e-03 3.175588805963e-03 + 1.975027299172e-03 1.399382063742e-03 1.087934574497e-03 9.937231831086e-04 1.155170238481e-03 1.547554809607e-03 + 2.067412691384e-03 2.859390962239e-03 4.536340999066e-03 + 5.992182606686e-03 6.952027556323e-03 6.378426282987e-03 4.713904411249e-03 3.085157359148e-03 2.016540783167e-03 + 1.394997844785e-03 1.024782034364e-03 8.599301054168e-04 9.365495759237e-04 1.270274134631e-03 1.777720482965e-03 + 2.355416090190e-03 3.127674190504e-03 4.386968454330e-03 + 4.641658258076e-03 4.500480026557e-03 3.785903588756e-03 2.876325609686e-03 2.083029297002e-03 1.482932126300e-03 + 1.060202027290e-03 8.245982741500e-04 8.075305113545e-04 1.036600716863e-03 1.499939349561e-03 2.099542473379e-03 + 2.743469083220e-03 3.448482695829e-03 4.177846622998e-03 + 4.142690549862e-03 3.446474424951e-03 2.733066943687e-03 2.129434125586e-03 1.611539918395e-03 1.181994933580e-03 + 9.022418623609e-04 8.179471391097e-04 9.450652477357e-04 1.301362189100e-03 1.878205258062e-03 2.634298947807e-03 + 3.487995764779e-03 4.216589272688e-03 4.481273832221e-03 + 4.044273572412e-03 2.911057482056e-03 2.196073362507e-03 1.727047749188e-03 1.343264607924e-03 1.065430868704e-03 + 9.621311831057e-04 1.038045054216e-03 1.299008049927e-03 1.780311752236e-03 2.580718976064e-03 3.796818096698e-03 + 5.157049226945e-03 5.848825843318e-03 5.312433416968e-03 + 3.751728522322e-03 2.487499603935e-03 1.873883002262e-03 1.513433756092e-03 1.265677079423e-03 1.182899125243e-03 + 1.259577194074e-03 1.476077165736e-03 1.850486685659e-03 2.523771491732e-03 3.850078832382e-03 5.931238981560e-03 + 7.743974059323e-03 7.694124818620e-03 5.817713857052e-03 + 3.124636426664e-03 2.127956394525e-03 1.692326765257e-03 1.469044158731e-03 1.421823391966e-03 1.518739438792e-03 + 1.713647770846e-03 2.018696809745e-03 2.487096037289e-03 3.465823949012e-03 5.491118439748e-03 8.173652555191e-03 + 9.455648065136e-03 7.969117175364e-03 5.189755023325e-03 + 2.449240665060e-03 1.882946953462e-03 1.675631441824e-03 1.673956392669e-03 1.811175299377e-03 1.991421342351e-03 + 2.234220736745e-03 2.557455553087e-03 3.083009389681e-03 4.285750926193e-03 6.488292543136e-03 8.553256426766e-03 + 8.445003211817e-03 6.190558238097e-03 3.810924486135e-03 + 2.052309656922e-03 1.879313490745e-03 1.947739562108e-03 2.198719620734e-03 2.504679330161e-03 2.760083452611e-03 + 2.957586282287e-03 3.136381438875e-03 3.530773905669e-03 4.525106878160e-03 5.958192927969e-03 6.632984936989e-03 + 5.694020767048e-03 3.961337122988e-03 2.655465515461e-03 + 2.014026344200e-03 2.183931751441e-03 2.654003798912e-03 3.413042310553e-03 4.146482145219e-03 4.424599204174e-03 + 4.172228759558e-03 3.776886719031e-03 3.702333308130e-03 4.051536570209e-03 4.406412048518e-03 4.198306829766e-03 + 3.407008591650e-03 2.574144489405e-03 2.110287575508e-03 From da563d7b9aacb3e96093f12f0e870c4c05b7ab04 Mon Sep 17 00:00:00 2001 From: Hongxu Ren Date: Mon, 19 Oct 2026 14:05:09 +0800 Subject: [PATCH 25/25] test: retain only hybrid NSCF source metadata in INPUT.info --- tests/01_PW/nscf_hse_same/INPUT.info | 620 +-------------------------- tests/01_PW/nscf_hse_same/README | 1 + 2 files changed, 9 insertions(+), 612 deletions(-) diff --git a/tests/01_PW/nscf_hse_same/INPUT.info b/tests/01_PW/nscf_hse_same/INPUT.info index a6818d20fd9..f0a54c70cd6 100644 --- a/tests/01_PW/nscf_hse_same/INPUT.info +++ b/tests/01_PW/nscf_hse_same/INPUT.info @@ -1,612 +1,8 @@ -INPUT_PARAMETERS -#Parameters (1.System) -suffix hybrid #the name of main output directory -ntype 1 #atom species number -cell_replica 1 1 1 #replicate the input structure along the three lattice vectors -calculation scf #scf; relax; md; cell-relax; nscf; get_s; get_wf; get_pchg; gen_bessel; gen_opt_abfs; test_memory; test_neighbour -socket_driver 0 #run as a socket client for external drivers using the i-PI protocol -esolver_type ksdft #the energy solver: ksdft, sdft, ofdft, tdofdft, tddft, lj, dp, ks-lr, lr, dfpt -symmetry -1 #the control of symmetry -symmetry_prec 1e-06 #accuracy for symmetry -symmetry_autoclose 1 #whether to close symmetry automatically when error occurs in symmetry analysis -cal_force 0 #if calculate the force at the end of the electronic iteration -kpar 1 #devide all processors into kpar groups and k points will be distributed among -bndpar 1 #divide each k-point pool into band-parallel groups -latname user_defined_lattice #the name of lattice name -assume_isolated none #isolated-system electrostatic correction -init_wfc atomic #atomic; atomic+random; random; nao; nao+random; file txt; file binary -init_chg atomic #start charge is from 'atomic' or file -init_vel 0 #read velocity from STRU or not -mem_saver 0 #Only for nscf calculations. if set to 1, then a memory saving technique will be used for many k point calculations. -cal_stress 0 #calculate the stress or not -diago_proc 1 #the number of procs used to do diagonalization -nbspline -1 #the order of B-spline basis -kspacing 0 0 0 #unit in 1/bohr, should be > 0, default is 0 which means read KPT file -koffset 0 0 0 #offset for kspacing-generated automatic k-point mesh -kmesh_type gamma #mesh type for kspacing-generated automatic k-point mesh -min_dist_coef 0.2 #factor related to the allowed minimum distance between two atoms -device cpu #the computing device for ABACUS -precision double #the computing precision for ABACUS -gint_precision double #the computing precision for LCAO grid integral -timer_enable_nvtx 0 #enable NVTX labeling for profiling or not -cell_factor 1.2 #used in the construction of the pseudopotential tables -dm_to_rho 0 #reads dmr in npz format and calculates electron density -chg_extrap atomic #atomic; first-order; second-order; dm:coefficients of SIA -ecutwfc 10 #energy cutoff for wave functions -ecutrho 40 #energy cutoff for charge density and potential -nx 0 #number of points along x axis for FFT grid -ny 0 #number of points along y axis for FFT grid -nz 0 #number of points along z axis for FFT grid -ndx 0 #number of points along x axis for FFT smooth grid -ndy 0 #number of points along y axis for FFT smooth grid -ndz 0 #number of points along z axis for FFT smooth grid -pw_seed 1 #random seed for initializing wave functions -diag_subspace 0 #method of subspace diagonalization in dav_subspace. 0:LaPack; 1:genelpa, 2:scalapack -erf_ecut 0 #the value of the constant energy cutoff -fft_mode 0 #mode of FFTW -erf_height 0 #the height of the energy step for reciprocal vectors -erf_sigma 0.1 #the width of the energy step for reciprocal vectors -stru_file STRU #the filename of file containing atom positions -kpoint_file KPT #the name of file containing k points -pseudo_dir /tmp/abacus-hybrid-nscf-pr/tests/PP_ORB/ #the directory containing pseudo files -orbital_dir #the directory containing orbital files -read_file_dir OUT.hybrid/ #directory of files for reading -restart_load 0 #restart from disk -basis_type pw #PW; LCAO in pw; LCAO - -#Parameters (2.Electronic structure) -ks_solver cg #cg; dav; lapack; genelpa; elpa; scalapack_gvx; cusolver -nbands 3 #number of bands -nelec 0 #input number of electrons -nelec_delta 0 #change in the number of total electrons -nupdown 0 #the difference number of electrons between spin-up and spin-down -dft_functional HSE #exchange correlation functional -xc_temperature 0 #temperature for finite temperature functionals -xc_exch_ext #customize Libxc exchange functional parameters -xc_corr_ext #customize Libxc correlation functional parameters -pseudo_rcut 15 #default #exchange correlation functional -pseudo_mesh 0 #0: use our own mesh to do radial renormalization; 1: use mesh as in QE -nspin 1 #1: single spin; 2: up and down spin; 4: noncollinear spin -gga_grad 0 #Noncollinear GGA gradient method: 0 original, 1 local axis, 2 regularized projected LCA -smearing_method fixed #type of smearing_method: gauss; fd; fixed; mp; mp2; mv -smearing_sigma 0.015 #energy range for smearing -mixing_type broyden #plain; pulay; broyden -mixing_beta 0.8 #mixing parameter: 0 means no new charge -mixing_beta_mag -10 #mixing parameter for magnetic density -mixing_ndim 8 #mixing dimension in pulay or broyden -mixing_restart 0 #threshold to restart mixing during SCF -mixing_dmr 0 #whether to mix real-space density matrix -mixing_gg0 1 #mixing parameter in kerker -mixing_gg0_mag 0 #mixing parameter in kerker -mixing_gg0_min 0.1 #the minimum kerker coefficient -mixing_angle -10 #angle mixing parameter for non-colinear calculations -mixing_tau 0 #whether to mix tau in mGGA calculation -mixing_dftu 0 #whether to mix occ_mat in DFT+U calculation -gamma_only 0 #Only for localized orbitals set and gamma point. If set to 1, a fast algorithm is used -scf_nmax 100 #number of electron iterations -scf_thr 1e-09 #charge density error -scf_ene_thr -1 #total energy error threshold -scf_thr_type 1 #type of the criterion of scf_thr, 1: reci drho for pw, 2: real drho for lcao -scf_os_stop 0 #whether to stop scf when oscillation is detected -scf_os_thr -0.01 #charge density threshold for oscillation -scf_os_ndim 8 #number of old iterations used for oscillation detection -sc_os_ndim 5 #number of old iterations used for oscillation detection, for Spin-Constrained DFT -lspinorb 0 #consider the spin-orbit interaction -noncolin 0 #using non-collinear-spin -soc_lambda 1 #The fraction of SOC based on scalar relativity (SR) of the pseudopotential -dfthalf_type 0 #DFT-1/2 type, 0:off; 1:shell DFT-1/2 -pw_diag_thr 1e-10 #threshold for eigenvalues is cg electron iterations -diago_smooth_ethr 0 #smooth ethr for iter methods -use_k_continuity 0 #whether to use k-point continuity for initializing wave functions -pw_diag_nmax 50 #max iteration number for cg -pw_diag_ndim 4 #dimension of workspace for Davidson diagonalization -diago_cg_prec 1 #diago_cg_prec - -#Parameters (3.LCAO) -nb2d 0 #matrix 2d division -lmaxmax 2 #maximum of l channels used -lcao_ecut 0 #energy cutoff for LCAO -lcao_dk 0.01 #delta k for 1D integration in LCAO -lcao_dr 0.01 #delta r for 1D integration in LCAO -lcao_rmax 30 #max R for 1D two-center integration table -search_radius -1 #input search radius (Bohr) -bx 1 #division of an element grid in FFT grid along x -by 1 #division of an element grid in FFT grid along y -bz 1 #division of an element grid in FFT grid along z -elpa_num_thread -1 #Number of threads need to use in elpa -num_stream 4 #the nstream in compute the LCAO with CUDA -bessel_nao_ecut 10.000000 #energy cutoff for spherical bessel functions(Ry) -bessel_nao_tolerence 1e-12 #tolerence for spherical bessel root -bessel_nao_rcut #radial cutoff for spherical bessel functions(a.u.) -bessel_nao_smooth 1 #spherical bessel smooth or not -bessel_nao_sigma 0.1 #spherical bessel smearing_sigma - -#Parameters (4.Relaxation) -relax_method cg 2 #cg; bfgs; sd; cg_bfgs; lbfgs -relax_scale_force 0.5 #controls the size of the first CG 2 step -relax_nmax 1 #number of ion iteration steps -relax_cg_thr 0.5 #threshold for switching from cg to bfgs, unit: eV/Angstrom -force_thr 0.001 #force threshold, unit: Ry/Bohr -force_thr_ev 0.0257112 #force threshold, unit: eV/Angstrom -force_zero_out 0 #force invalid threshold, unit: eV/Angstrom -relax_bfgs_w1 0.01 #wolfe condition 1 for bfgs -relax_bfgs_w2 0.5 #wolfe condition 2 for bfgs -relax_bfgs_rmax 0.2 #maximal trust radius, unit: Bohr -relax_bfgs_rmin 1e-05 #minimal trust radius, unit: Bohr -relax_bfgs_init 0.5 #initial trust radius, unit: Bohr -stress_thr 0.5 #stress threshold -press1 0 #target pressure, unit: KBar -press2 0 #target pressure, unit: KBar -press3 0 #target pressure, unit: KBar -fixed_axes None #which axes are fixed -fixed_ibrav 0 #whether to preseve lattice type during relaxation -fixed_atoms 0 #whether to preseve direct coordinates of atoms during relaxation -relax 0 #allow relaxation along the specific direction - -#Parameters (5.Molecular dynamics) -md_type nvt #choose ensemble -md_nstep 10 #md steps -md_dt 1 #time step -md_thermostat nhc #choose thermostat -md_tfirst -1 #temperature first -md_tlast -1 #temperature last -md_prec_level 0 #precision level for vc-md -md_restart 0 #whether restart -md_restartfreq 5 #The period to output MD restart information -md_dumpfreq 1 #The period to dump MD information -md_neighbor_skin 0 #extra MDCell neighbor-list radius -md_out_force 1 #output all atomic forces into running_md.log or not -dump_force 1 #output atomic forces into the file MD_dump or not -dump_vel 1 #output atomic velocities into the file MD_dump or not -dump_virial 1 #output lattice virial into the file MD_dump or not -md_seed -1 #random seed for MD -md_tfreq 0 #oscillation frequency, used to determine qmass of NHC -md_tchain 1 #number of Nose-Hoover chains -md_pmode iso #NPT ensemble mode: iso, aniso, tri -ref_cell_factor 1 #construct a reference cell bigger than the initial cell -md_pcouple xyz #whether couple different components: xyz, xy, yz, xz, none -md_pfirst -1 #initial target pressure -md_plast -1 #final target pressure -md_pfreq 0 #oscillation frequency, used to determine qmass of thermostats coupled with barostat -md_pchain 1 #num of thermostats coupled with barostat -lj_rule 2 #combination rules used to construct the parameter matrix for LJ potential -lj_eshift 0 #whether to use energy shift for LJ potential -lj_rcut #cutoff radius of LJ potential -lj_epsilon #the value of epsilon for LJ potential -lj_sigma #the value of sigma for LJ potential -pot_file graph.pb #the filename of potential files for CMD such as DP -dp_rescaling 1 #rescaling factor for dp potential -dp_fparam #the frame parameter for dp potential -dp_aparam #the atomic parameter for dp potential -msst_direction 2 #the direction of shock wave -msst_vel 0 #the velocity of shock wave -msst_vis 0 #artificial viscosity -msst_tscale 0.01 #reduction in initial temperature -msst_qmass 1 #mass of thermostat -md_damp 1 #damping parameter (time units) used to add force in Langevin method -md_csvr_tau 100 #CSVR thermostat characteristic time scale -md_tolerance 100 #tolerance for velocity rescaling (K) -md_nraise 1 #parameters used when md_type=nvt -cal_syns 0 8 #calculate asynchronous overlap matrix to output for Hefei-NAMD -dmax 0.01 #maximum displacement of all atoms in one step (bohr) -plumed 0 #use PLUMED for collective variables and enhanced sampling -plumed_file plumed.dat #input file of PLUMED - -#Parameters (6.orbital free density functional theory) -of_kinetic wt #kinetic energy functional, such as tf, vw, wt -of_method tn #optimization method used in OFDFT, including cg1, cg2, tn (default) -of_conv energy #the convergence criterion, potential, energy (default), or both -of_tole 1e-06 #tolerance of the energy change (in Ry) for determining the convergence, default=2e-6 Ry -of_tolp 1e-05 #tolerance of potential for determining the convergence, default=1e-5 in a.u. -of_tf_weight 1 #weight of TF KEDF -of_vw_weight 1 #weight of vW KEDF -of_wt_alpha 0.833333 #parameter alpha of WT KEDF -of_wt_beta 0.833333 #parameter beta of WT KEDF -of_extwt_kappa 0.832442 #parameter kappa of EXT-WT KEDF -of_wt_rho0 0 #the average density of system, used in WT KEDF, in Bohr^-3 -of_hold_rho0 0 #If set to 1, the rho0 will be fixed even if the volume of system has changed, it will be set to 1 automaticly if of_wt_rho0 is not zero -of_lkt_a 1.3 #parameter a of LKT KEDF -of_xwm_rho_ref 0 #The reference density of XWM KEDF -of_xwm_kappa 0 #The parameter kappa of XWM KEDF -of_read_kernel 0 #If set to 1, the kernel of WT KEDF will be filled from file of_kernel_file, not from formula. Only usable for WT KEDF -of_kernel_file WTkernel.txt #The name of WT kernel file. -of_full_pw 1 #If set to 1, ecut will be ignored when collect planewaves, so that all planewaves will be used -of_full_pw_dim 0 #If of_full_pw = true, dimention of FFT is testricted to be (0) either odd or even; (1) odd only; (2) even only -of_ml_gene_data 0 #Generate training data or not -of_ml_device cpu #Run NN on GPU or CPU -of_ml_feg 0 #The Free Electron Gas limit: 0: no, 3: yes -of_ml_nkernel 1 #Number of kernels -of_ml_kernel 1 #Type of kernel, 1 for wt, 2 for yukawa, and 3 for TKK -of_ml_kernel_scaling 1 #Scaling parameter of kernel, w(r-r') = scaling^3 * w(scaling (r-r')) -of_ml_yukawa_alpha 1 #Parameter alpha of yukawa kernel -of_ml_kernel_file none #The file of TKK -of_ml_gamma 0 #Descriptor: gamma = (rho / rho0)^(1/3) -of_ml_p 0 #Descriptor: p = |nabla rho|^2 / [2 (3 pi^2)^(1/3) rho^(4/3)]^2 -of_ml_q 0 #Descriptor: q = nabla^2 rho / [4 (3 pi^2)^(2/3) rho^(5/3)] -of_ml_tanhp 0 #Descriptor: tanhp = tanh(chi_p * p) -of_ml_tanhq 0 #Descriptor: tanhq = tanh(chi_q * q) -of_ml_chi_p 1 #Hyperparameter: tanhp = tanh(chi_p * p) -of_ml_chi_q 1 #Hyperparameter: tanhq = tanh(chi_q * q) -of_ml_gammanl 0 #Descriptor: gammanl = int{gamma(r') * w(r-r') dr'} -of_ml_pnl 0 #Descriptor: pnl = int{p(r') * w(r-r') dr'} -of_ml_qnl 0 #Descriptor: qnl = int{q(r') * w(r-r') dr'} -of_ml_xi 0 #Descriptor: xi = int{rho(r')^(1/3) * w(r-r') dr'} / rho^(1/3) -of_ml_tanhxi 0 #Descriptor: tanhxi = tanh(chi_xi * xi) -of_ml_tanhxi_nl 0 #Descriptor: tanhxi_nl = int{tanhxi(r') * w(r-r') dr'} -of_ml_tanh_pnl 0 #Descriptor: tanh_pnl = tanh(chi_pnl * pnl) -of_ml_tanh_qnl 0 #Descriptor: tanh_qnl = tanh(chi_qnl * qnl) -of_ml_tanhp_nl 0 #Descriptor: tanhp_nl = int{tanhp(r') * w(r-r') dr'} -of_ml_tanhq_nl 0 #Descriptor: tanhq_nl = int{tanhq(r') * w(r-r') dr'} -of_ml_chi_xi 1 #Hyperparameter: tanhpxi = tanh(chi_xi * xi) -of_ml_chi_pnl 1 #Hyperparameter: tanh_pnl = tanh(chi_pnl * pnl) -of_ml_chi_qnl 1 #Hyperparameter: tanh_qnl = tanh(chi_qnl * qnl) -of_ml_local_test 0 #Test: read in the density, and output the F and Pauli potential -ml_exx 0 #Use ML EXX or not - -#Parameters (7.Stochastic DFT) -method_sto 2 #1: slow and save memory, 2: fast and waste memory -nbands_sto 256 #number of stochstic orbitals -nche_sto 100 #Chebyshev expansion orders -emin_sto 0 #trial energy to guess the lower bound of eigen energies of the Hamitonian operator -emax_sto 0 #trial energy to guess the upper bound of eigen energies of the Hamitonian operator -seed_sto 0 #the random seed to generate stochastic orbitals -initsto_ecut 0 #maximum ecut to init stochastic bands -initsto_freq 0 #frequency to generate new stochastic orbitals when running md -npart_sto 1 #Reduce memory when calculating Stochastic DOS - -#Parameters (8.DeepKS) -deepks_out_labels 0 #>0 compute descriptor for deepks. 1 used during training, 2 used for label production -deepks_out_freq_elec 0 #>0 frequency of electronic iteration to output descriptors and labels for deepks. -deepks_out_base none #base functional for output files, with dft_functional as target functional -deepks_scf 0 #>0 add V_delta to Hamiltonian -deepks_equiv 0 #whether to use equivariant version of DeePKS -deepks_model None #file dir of traced pytorch model: 'model.ptg -bessel_descriptor_lmax 2 #lmax used in generating spherical bessel functions -bessel_descriptor_ecut 10.000000 #energy cutoff for spherical bessel functions(Ry) -bessel_descriptor_tolerence 1e-12 #tolerence for spherical bessel root -bessel_descriptor_rcut 6 #radial cutoff for spherical bessel functions(a.u.) -bessel_descriptor_smooth 1 #spherical bessel smooth or not -bessel_descriptor_sigma 0.1 #sphereical bessel smearing_sigma -deepks_bandgap 0 #>0 for bandgap label -deepks_band_range -1 0 #(int, int) range of bands for bandgap label -deepks_v_delta 0 #!=0 for v_delta/v_delta_R label. when output, 1 for vdpre, 2 for phialpha and grad_evdm (can save memory ) -1 for vdrpre, -2 for phialpha_r and gevdm (can save memory) -deepks_out_unittest 0 #if set 1, prints intermediate quantities that shall be used for making unit test -lin_solver gmres #linear solver for real-time propagation -lin_precond kinetic_recycle #right preconditioner for PW real-time propagation -lin_thr 0 #residual tolerance of the linear solver -lin_maxiter 500 #maximum iterations per linear solve -lin_gmres_restart 20 #Arnoldi dimension of restarted GMRES -td_cn_init 1 #CN subspace initial guess and residual reuse -lin_reconstruct 1 #explicit GMRES residual reconstruction -estep_per_md 1 #steps of force change - -#Parameters (9.rt-tddft) -td_dt 1 #time step for evolving wavefunction -td_edm 0 #the method to calculate the energy density matrix -td_print_eij -1 #print eij or not -td_propagator 0 #method of propagator -td_vext 0 #add extern potential or not -td_vext_dire 1 #extern potential direction -td_stype 0 #type of electric field in space domain -td_ttype 0 #type of electric field in time domain -td_tstart 1 # number of steps where electric field starts -td_tend 1000 #number of steps where electric field ends -td_lcut1 0.05 #cut1 of interval in length gauge -td_lcut2 0.95 #cut2 of interval in length gauge -td_gauss_freq 22.13 #frequency (freq) of Gauss type electric field -td_gauss_phase 0 #phase of Gauss type electric field -td_gauss_sigma 30 #sigma of Gauss type electric field -td_gauss_t0 100 #step number of time center (t0) of Gauss type electric field -td_gauss_amp 0.25 #amplitude of Gauss type electric field -td_trape_freq 1.6 #frequency of Trapezoid type electric field -td_trape_phase 0 #phase of Trapezoid type electric field -td_trape_t1 1875 #t1 of Trapezoid type electric field -td_trape_t2 5625 #t2 of Trapezoid type electric field -td_trape_t3 7500 #t3 of Trapezoid type electric field -td_trape_amp 2.74 #amplitude of Trapezoid type electric field -td_trigo_freq1 1.16466 #frequency 1 of Trigonometric type electric field -td_trigo_freq2 0.029116 #frequency 2 of Trigonometric type electric field -td_trigo_phase1 0 #phase 1 of Trigonometric type electric field -td_trigo_phase2 0 #phase 2 of Trigonometric type electric field -td_trigo_amp 2.74 #amplitude of Trigonometric type electric field -td_heavi_t0 100 #t0 of Heaviside type electric field -td_heavi_amp 1 #amplitude of Heaviside type electric field -td_supsine_amp 0.27 #carrier electric-field scale of the supersine pulse -td_supsine_freq 0.18737 #carrier frequency of the supersine pulse -td_supsine_phase 0 #carrier phase at the center of the supersine pulse -td_supsine_sigma 0.75 #shape parameter of the supersine envelope -td_supsine_tstart default #start boundary step of the supersine pulse -td_supsine_tend default #end boundary step of the supersine pulse -init_vecpot_file 0 #init vector potential through file or not -ocp 0 #change occupation or not -ocp_set #set occupation -of_cd 0 #add CD Potential or not -of_mcd_alpha 1 #parameter of modified CD Potential -xc_kernel LDA #exchange correlation (XC) kernel for LR-TDDFT -lr_init_xc_kernel default #The method to initalize the xc kernel -lr_solver dav #the eigensolver for LR-TDDFT -lr_thr 0.01 #convergence threshold of the LR-TDDFT eigensolver -nocc 3 #the number of occupied orbitals to form the 2-particle basis ( <= nelec/2) -nvirt 1 #the number of virtual orbitals to form the 2-particle basis (nocc + nvirt <= nbands) - -#Parameters (10.lr-tddft) -lr_nstates 1 #the number of 2-particle states to be solved -lr_unrestricted 0 #Whether to use unrestricted construction for LR-TDDFT -abs_wavelen_range 0 0 #the range of wavelength(nm) to output the absorption spectrum -out_wfc_lr 0 #whether to output the eigenvectors (excitation amplitudes) in the particle-hole basis -abs_gauge velocity #whether to use length or velocity gauge to calculate the absorption spectrum in LR-TDDFT -abs_broadening 0.01 #the broadening (eta) for LR-TDDFT absorption spectrum -bse_tda tda #whether Tamm-Dancoff Approximation is used (can be 'tda', 'full' or 'both') -bse_spin_types singlet triplet #which spin type is calculated (can be 'singlet', 'triplet', also for test 'rpa', 'ipa') -bse_mem_save 0 #whether to save memory by adding V and W to BSE matrix directly -bse_ri_hartree 1 #whether to use RI approximation for Hartree term in BSE -bse_use_fine_kgrid 0 #Fine k-grid mode for BSE -bse_q_approx_mode 0 #q->kpair mapping mode: 0=exact, 1=coarse q grid, 2=mixed, 3=truncate -bse_q_approx_threshold 0.1 #threshold radius (in unit of 2*pi/lat0) for exact q mapping in mode 2; in mode 3 pairs with larger |q| are dropped entirely -out_bse_ab 0 #whether to output the AB matrix to file -bse_continue 0 #which step to continue from previous BSE calculation -plot_istate 0 #which state of exciton to be ploted -exciton_plot_type average #exciton density plot type: average or conditional -exciton_plot_format cube #exciton plot format: average supports cube, slice, or both; conditional supports slice only -exciton_fixed_coordinate 0 0 0 0 0 0 #fixed hole and electron Cartesian coordinates (Bohr): hx hy hz ex ey ez -exciton_slice_plane ab #cross-section plane: ab, bc, or ca -exciton_slice_pos 0 #offset along perpendicular direction (Bohr) for slice -exciton_slice_npoints 200 #grid points per dimension for slice -exciton_slice_range -1 2 -1 2 #slice cell range: ustart uend vstart vend -dfpt_qmesh 1 1 1 #Monkhorst-Pack q mesh for DFPT, should be >= 1, and commensurate with the KPT mesh -dfpt_qfile #file containing the DFPT q points; empty means the dfpt_qmesh Monkhorst-Pack mesh -dfpt_compute_q0 0 #whether to compute epsilon_inf and Born effective charges at q = 0 -dfpt_loto 0 #whether to apply the LO-TO non-analytic correction at q = 0 -dfpt_conv_thr 1e-08 #convergence threshold of the DFPT first-order density -dfpt_max_iter 100 #max number of the DFPT first-order density mixing iterations -dfpt_mix_beta 0.4 #mixing coefficient of the DFPT first-order density -out_freq_ion 0 #print information every few ionic steps -out_freq_td 0 #print information every few completed electronic iterations in RT-TDDFT -out_freq_elec 100 #print information every few electronic steps -out_chg 1 3 #> 0 output charge density for selected electron steps, second parameter controls the precision, default is 3. -out_pot 0 8 #output real space potential (with precision 8) -out_dmk 0 8 #>0 output density matrix DM(k) for each k-point -out_dmr 0 8 #output density matrix DM(R) with respect to lattice vector R (with precision 8) -out_wfc_pw 2 #output wave functions -out_wfc_lcao 0 #ouput LCAO wave functions, 0, no output 1: text, 2: binary -out_dos 0 #output energy and dos -out_ldos 0 3 #output mode of local density of states, second parameter controls the precision -out_band 1 8 #output energy and band structure (with precision 8) -out_proj_band 0 #output projected band structure - -#Parameters (11.Output) -out_stru 0 #output the structure files per ion step -out_level ie #ie(for electrons); i(for ions); -out_hsk 0 8 #output H(k) and S(k) matrices in reciprocal space -out_hsr 0 8 #output H(R) and S(R) matrices in real space -out_mat_tk 0 8 #output kinetic matrix of electrons T(k) -out_mat_r 0 8 #output r(R) matrix -out_mat_t 0 8 #output T(R) matrix -out_mat_dh 0 8 #output Hamiltonian derivatives dH/dR matrices -out_mat_dh_t 0 8 #output kinetic energy dH/dR (dT/dR) matrices -out_mat_dh_vl 0 8 #output local pseudopotential dH/dR (dV^L/dR) matrices -out_mat_dh_vnl 0 8 #output nonlocal pseudopotential dH/dR (dV^NL/dR) matrices -out_mat_dh_vh 0 8 #output Hartree dH/dR (dV^H/dR) matrices -out_mat_dh_vxc 0 8 #output exchange-correlation dH/dR (dV^XC/dR) matrices -out_mat_h_t 0 8 #output kinetic energy T(R) matrix -out_mat_h_vnl 0 8 #output nonlocal pseudopotential Vnl(R) matrix -out_mat_h_vl 0 8 #output local pseudopotential Vl(R) matrix -out_mat_h_vh 0 8 #output Hartree Vh(R) matrix -out_mat_h_vxc 0 8 #output exchange-correlation Vxc(R) matrix -out_mat_h_exx 0 8 #output exact-exchange Vexx(R) matrix -out_mat_ds 0 8 #output of derivative of S(R) matrix -out_mat_xc 0 #output exchange-correlation matrix in KS-orbital representation -out_mat_xc2 0 8 #output exchange-correlation matrix in NAO representation -out_mat_l 0 8 #output the expectation values of angular momentum operators -out_xc_r -1 3 #if >=0, output the derivatives of exchange correlation in realspace, second parameter controls the precision -out_eband_terms 0 #output the band energy terms separately -out_hr_npz 0 #output H(R) matrix in npz format -out_dm_npz 0 #output DM(R) matrix in npz format -out_mul 0 #mulliken charge or not -out_app_flag 1 #whether output r(R), H(R), S(R), T(R), and dH(R) matrices in an append manner during MD -out_ndigits 8 #the length of decimal part of output data -out_element_info 0 #output (projected) wavefunction of each element -restart_save 0 #print to disk every step for restart -rpa 0 #true:generate output files used in rpa calculation; false:(default) -rpa_out_vel 0 #whether to output velocity matrix for librpa -rpa_outdir OUT.librpa/ #output directory for librpa -out_pchg #specify the bands to be calculated for the partial (band-decomposed) charge densities -out_wfc_norm #specify the bands to be calculated for the norm of wavefunctions -out_wfc_re_im #specify the bands to be calculated for the real and imaginary parts of wavefunctions -if_separate_k 0 #specify whether to write the partial charge densities for all k-points to individual files or merge them -out_elf 0 3 #> 0 output electron localization function (ELF) for selected electron steps, second parameter controls the precision, default is 3. -out_spillage 0 #output spillage of wavefunctions. This parameter only accepts 0 or 2. -out_dipole 0 #output dipole or not -out_current 0 #output current or not -out_current_k 0 #output current for each k -out_efield 0 #output dipole or not -out_vecpot 0 #output TDDFT vector potential or not -cal_symm_repr 0 3 #output matrix representation of symmetry operation into running log file > 0 output the matrix representation of symmetry operation , the second parameter controls the precision, default is 3. -spillage_outdir ./ #output directory for spillage of wavefunctions. -dos_edelta_ev 0.03 #delta energy for dos -dos_sigma 0.07 #gauss b coefficeinet(default=0.07) -dos_scale 0.01 #scale dos range by - -#Parameters (12.Postprocess) -dos_emin_ev -15 #minimal range for dos -dos_emax_ev 15 #maximal range for dos -dos_nche 100 #orders of Chebyshev expansions for dos -stm_bias 1 0.1 1 #bias voltage used to calculate ldos -ldos_line 0 0 0 0 0 1 100 #start and end point of the line (direct coordinates) and number of points -cal_cond 0 #calculate electronic conductivities -cond_che_thr 1e-08 #control the error of Chebyshev expansions for conductivities -cond_dw 0.1 #frequency interval for conductivities -cond_wcut 10 #cutoff frequency (omega) for conductivities -cond_dt 0.02 #t interval to integrate Onsager coefficiencies -cond_dtbatch 0 #exp(iH*dt*cond_dtbatch) is expanded with Chebyshev expansion -cond_smear 1 #Smearing method for conductivities -cond_fwhm 0.4 #FWHM for conductivities -cond_nonlocal 1 #Nonlocal effects for conductivities -cond_mgga_vel 1 #Meta-GGA velocity correction for conductivities -berry_phase 0 #calculate berry phase or not -gdir 3 #calculate the polarization in the direction of the lattice vector -towannier90 0 #use wannier90 code interface or not -nnkpfile seedname.nnkp #the wannier90 code nnkp file name -wannier_method 1 #different implementation methods under Lcao basis set -wannier_spin up #calculate spin in wannier90 code interface -out_wannier_mmn 1 #output .mmn file or not -out_wannier_amn 1 #output .amn file or not -out_wannier_eig 1 #output .eig file or not -out_wannier_unk 0 #output UNK. file or not -out_wannier_wvfn_formatted 1 #output UNK. file in text format or in binary format - -#Parameters (13.Model) -efield_flag 0 #add electric field -dip_cor_flag 0 #dipole correction -efield_dir 2 #the direction of the electric field or dipole correction -efield_pos_max -1 #position of the maximum of the saw-like potential along crystal axis efield_dir -efield_pos_dec -1 #zone in the unit cell where the saw-like potential decreases -efield_amp 0 #amplitude of the electric field -gate_flag 0 #compensating charge or not -zgate 0.5 #position of charged plate -block 0 #add a block potential or not -block_down 0.45 #low bound of the block -block_up 0.55 #high bound of the block -block_height 0.1 #height of the block -imp_sol 0 #calculate implicit solvation correction or not -eb_k 80 #the relative permittivity of the bulk solvent -tau 1.0798e-05 #the effective surface tension parameter -sigma_k 0.6 #the width of the diffuse cavity -nc_k 0.00037 #the cut-off charge density - -#Parameters (14.vdW Correction) -vdw_method none #the method of calculating vdw (none ; d2 ; d3_0 ; d3_bj ; d4) -vdw_d4_xc default #functional name passed to DFT-D4 -vdw_d4_model d4 #DFT-D4 dispersion model -vdw_s6 default #scale parameter of d2/d3_0/d3_bj -vdw_s8 default #scale parameter of d3_0/d3_bj -vdw_a1 default #damping parameter of d3_0/d3_bj -vdw_a2 default #damping parameter of d3_0/d3_bj -vdw_d 20 #damping parameter of d2 -vdw_abc 0 #third-order term? -vdw_c6_file default #filename of C6 -vdw_c6_unit Jnm6/mol #unit of C6, Jnm6/mol or eVA6 -vdw_r0_file default #filename of R0 -vdw_r0_unit A #unit of R0, A or Bohr -vdw_cutoff_type radius #expression model of periodic structure, radius or period -vdw_cutoff_radius 0 #radius cutoff for periodic structure -vdw_radius_unit Bohr #unit of radius cutoff for periodic structure -vdw_cutoff_width2 0.05 #smooth cutoff width for two-body dispersion -vdw_cutoff_width3 0 #smooth cutoff width for three-body dispersion -vdw_cutoff_period 3 3 3 #periods of periodic structure -vdw_cn_thr 40 #radius cutoff for cn -vdw_cn_thr_unit Bohr #unit of cn_thr, Bohr or Angstrom - -#Parameters (15.exx) -exx_fock_alpha #fraction of Fock exchange 1/r in hybrid functionals -exx_erfc_alpha 0.25 #fraction of exchange erfc(wr)/r in hybrid functionals -exx_erfc_omega 0.11 #range-separation parameter erfc(wr)/r in hybrid functionals -exx_separate_loop 1 #if 1, a two-step method is employed, else it will start with a GGA-Loop, and then Hybrid-Loop -exx_hybrid_step 100 #the maximal electronic iteration number in the evaluation of Fock exchange -exx_mixing_beta 1 #mixing_beta for outer-loop when exx_separate_loop=1 -exx_fock_lambda #used to compensate for divergence points at G=0 in the evaluation of Fock exchange using lcao_in_pw method -exx_pca_threshold 0.0001 #threshold to screen on-site ABFs in exx -exx_c_threshold 0.0001 #threshold to screen C matrix in exx -exx_cs_inv_thr -1 #threshold to inverse Vq in abfs for generating Cs -exx_v_threshold 0.1 #threshold to screen C matrix in exx -exx_dm_threshold 0.0001 #threshold to screen density matrix in exx -exx_c_grad_threshold 0.0001 #threshold to screen nabla C matrix in exx -exx_v_grad_threshold 0.1 #threshold to screen nabla V matrix in exx -exx_c_grad_r_threshold 0.0001 #threshold to screen nabla C * R matrix in exx -exx_v_grad_r_threshold 0.1 #threshold to screen nabla V * R matrix in exx -exx_ccp_rmesh_times 1.5 #how many times larger the radial mesh required for calculating Columb potential is to that of atomic orbitals -exx_opt_orb_lmax 0 #the maximum l of the spherical Bessel functions for opt ABFs -exx_opt_orb_ecut 0 #the cut-off of plane wave expansion for opt ABFs -exx_opt_orb_tolerence 0 #the threshold when solving for the zeros of spherical Bessel functions for opt ABFs -exx_real_number 0 #exx calculated in real or complex -exx_singularity_correction limits #set the scheme of Coulomb singularity correction -rpa_ccp_rmesh_times 10 #how many times larger the radial mesh required for calculating Columb potential is to that of atomic orbitals -exx_symmetry_realspace 0 #whether to reduce real-space sector in Hexx calculation -out_ri_cv 0 #Whether to output the coefficient tensor C and ABFs-representation Coulomb matrix V -out_unshrinked_v 0 #whether to output the large Vq matrix in unshrinked auxiliary basis -exx_coul_moment 0 #whether to use moment method for Coulomb calculation -exx_rotate_abfs 0 #whether to rotate auxiliary basis for Coulomb calculation -exx_multip_moments_threshold 1e-10 #threshold to screen multipole moments in Coulomb calculation -shrink_abfs_pca_thr -1 #threshold to shrink auxiliary basis for GW/RPA -shrink_lu_inv_thr 1e-06 #threshold to get inverse of overlap matrix by LU decomposition in auxiliary basis representation - -#Parameters (16.dft+u) -dft_plus_u 0 #DFT+U correction method -dft_plus_dmft 0 #true:DFT+DMFT; false: standard DFT calcullation(default) -orbital_corr -1 #which correlated orbitals need corrected ; d:2 ,f:3, do not need correction:-1 -hubbard_u 0 #Hubbard Coulomb interaction parameter U(ev) -yukawa_potential 0 #default: false -yukawa_lambda -1 #default:0.0 -uramping -1 #increasing U values during SCF -omc 0 #the mode of occupation matrix control -onsite_radius 0 #radius of the sphere for onsite projection (Bohr) - -#Parameters (17.non-collinear spin-constrained DFT) -sc_mag_switch 0 #switch to control spin-constrained DFT -decay_grad_switch 0 #switch to control gradient break condition -sc_thr 1e-06 #Convergence criterion of spin-constrained iteration (RMS) in uB -nsc 100 #Maximal number of spin-constrained iteration -nsc_min 2 #Minimum number of spin-constrained iteration -alpha_trial 0.01 #Initial trial step size for lambda in eV/uB^2 -sccut 3 #Maximal step size for lambda in eV/uB -sc_drop_thr 0.001 #Convergence criterion ratio of lambda iteration in Spin-constrained DFT -sc_scf_thr 0.001 #Density error threshold for inner loop of spin-constrained SCF -sc_direction_only 0 #only optimize the direction of magnetization -sc_lambda_strategy bfgs #lambda update strategy for spin-constrained DFT -sc_scan_lambda_start 0 #start value for linear lambda scan (eV/uB) -sc_scan_lambda_end 1 #end value for linear lambda scan (eV/uB) -sc_scan_steps 20 #number of steps for linear lambda scan - -#Parameters (18.Quasiatomic Orbital analysis) -qo_switch 0 #switch to control quasiatomic orbital analysis -qo_basis szv #type of QO basis function: hydrogen: hydrogen-like basis, pswfc: read basis from pseudopotential -qo_strategy all #strategy to generate generate radial orbitals -qo_screening_coeff 0.1 #rescale the shape of radial orbitals -qo_thr 1e-06 #accuracy for evaluating cutoff radius of QO basis function - -#Parameters (19.PEXSI) -pexsi_npole 40 #Number of poles in expansion -pexsi_inertia 1 #Whether inertia counting is used at the very beginning of PEXSI process -pexsi_nmax 80 #Maximum number of PEXSI iterations after each inertia counting procedure -pexsi_comm 1 #Whether to construct PSelInv communication pattern -pexsi_storage 1 #Storage space used by the Selected Inversion algorithm for symmetric matrices -pexsi_ordering 0 #Ordering strategy for factorization and selected inversion -pexsi_row_ordering 1 #Row permutation strategy for factorization and selected inversion, 0: NoRowPerm, 1: LargeDiag -pexsi_nproc 1 #Number of processors for parmetis -pexsi_symm 1 #Matrix symmetry -pexsi_trans 0 #Whether to transpose -pexsi_method 1 #pole expansion method, 1: Cauchy Contour Integral, 2: Moussa optimized method -pexsi_nproc_pole 1 #Number of processes used by each pole -pexsi_temp 0.015 #Temperature, in the same unit as H -pexsi_gap 0 #Spectral gap -pexsi_delta_e 20 #An upper bound for the spectral radius of S^{-1} H -pexsi_mu_lower -10 #Initial guess of lower bound for mu -pexsi_mu_upper 10 #Initial guess of upper bound for mu -pexsi_mu 0 #Initial guess for mu (for the solver) -pexsi_mu_thr 0.05 #Stopping criterion in terms of the chemical potential for the inertia counting procedure -pexsi_mu_expand 0.3 #If the chemical potential is not in the initial interval, the interval is expanded by muInertiaExpansion -pexsi_mu_guard 0.2 #Safe guard criterion in terms of the chemical potential to reinvoke the inertia counting procedure -pexsi_elec_thr 0.001 #Stopping criterion of the PEXSI iteration in terms of the number of electrons compared to numElectronExact -pexsi_zero_thr 1e-10 #if the absolute value of matrix element is less than ZERO_Limit, it will be considered as 0 - -#Parameters (20.Test) -out_alllog 0 #output information for each processor, when parallel -nurse 0 #for coders -t_in_h 1 #calculate the kinetic energy or not -vl_in_h 1 #calculate the local potential or not -vnl_in_h 1 #calculate the nonlocal potential or not -vh_in_h 1 #calculate the hartree potential or not -vion_in_h 1 #calculate the local ionic potential or not -test_force 0 #test the force -test_stress 0 #test the stress -test_skip_ewald 0 #whether to skip ewald -ri_hartree_benchmark none #whether to use the RI approximation for the Hartree term in LR-TDDFT for benchmark (with FHI-aims/ABACUS read-in style) -aims_nbasis #the number of basis functions for each atom type used in FHI-aims (for benchmark) -rdmft 0 #whether to perform rdmft calculation, default is false -rdmft_power_alpha 0.656 #the alpha parameter of power-functional, g(occ_number) = occ_number^alpha used in exx-type functionals such as muller and power -exxace 0 #whether to perform ace calculation in exxpw -exx_gamma_extra 0 #whether to perform gamma extrapolation in exxpw -ecutexx 0 #energy cutoff for exx calculation, Ry -exx_batch_size 0 #band chunk width of the EXX batched path, 0 = all bands -exx_thr_type density #threshold type for exx outer loop, energy or density -exx_ene_thr 1e-05 #threshold for exx outer loop when exx_thr_type = energy +# Source SCF parameters used by the hybrid NSCF consistency check. +dft_functional HSE +exx_fock_alpha +exx_erfc_alpha 0.25 +exx_erfc_omega 0.11 +exx_singularity_correction limits +exx_gamma_extra 0 +ecutexx 0 diff --git a/tests/01_PW/nscf_hse_same/README b/tests/01_PW/nscf_hse_same/README index 63c9decfc1a..acb09a2104e 100644 --- a/tests/01_PW/nscf_hse_same/README +++ b/tests/01_PW/nscf_hse_same/README @@ -7,3 +7,4 @@ To regenerate the source, use the same STRU/KPT and INPUT with calculation scf, nbands 3, out_chg 1 12, and out_wfc_pw 2. The cube-based band references differ from the former binary-restart references by at most 1.12e-4 eV: out_chg writes rho, while the binary restart writes rho_save. +INPUT.info retains only the seven source SCF parameters checked by hybrid NSCF.