Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
9e63c77
Refactor: extract ModuleCell::ReciprocalGrid base for k/q grids (Phas…
Aug 14, 2026
ea27f3b
Refactor: QList on ReciprocalGrid base with star reduction + tests (P…
Aug 14, 2026
2ca25c4
Feat: LittleGroup interface for q-point irreps + wire QList (Phase 3)
Aug 14, 2026
914dfd1
Feat: DFPT per-irrep SCF loop via DFPT_IrrepData adapter + tests (Pha…
Aug 14, 2026
c6a7433
Feat: complete QList q-point management (Cartesian, file read, print,…
Aug 14, 2026
3599973
Feat: reserve DFT+U interface for DFPT (U0)
Aug 14, 2026
fe30cb7
Feat: k+q plane-wave basis enumeration for DFPT (C0)
Aug 14, 2026
dc8a716
Feat: first-order perturbation potentials for DFPT (C1)
Aug 14, 2026
8c4c1c7
Feat: projected CG Sternheimer solver for DFPT (C2)
Aug 14, 2026
e9ac116
Feat: first-order density response for DFPT (C3)
Aug 14, 2026
d1a1fc0
Feat: dynamical matrix for DFPT (C4 guard + C5)
Aug 17, 2026
275dfab
Feat: q->0 response for DFPT (C6: eps, Born, v_hartree_q, XC contract)
Aug 17, 2026
78419b1
Feat: wire DFPT driver and esolver factory (C7)
Aug 17, 2026
a004742
Fix: DFPT screening-channel calibration (q=0 completion, XC central d…
Aug 17, 2026
57f7415
Fix: DFPT plain-mixing default beta 0.7 -> 0.4 (small-G Coulomb stiff…
Aug 17, 2026
d83d435
Docs: record DFPT stage-B gap audit and revised execution plan
Aug 18, 2026
297a2b3
Feat: INPUT-driven DFPT parameters (dfpt_qmesh/qfile/compute_q0/loto/…
Aug 18, 2026
b64ad9f
Test: sync DFPT serial references to production conventions
Aug 18, 2026
dc82fac
Fix: multi-k DFPT ball-label matching and smeared-occupation projecto…
Aug 18, 2026
276a444
Docs: record multi-k DFPT root causes and FD validation matrix in PLAN
Aug 18, 2026
2cf780d
Fix: reject metallic smearing occupations in DFPT with an explicit guard
Aug 18, 2026
6dbb872
Docs: record validation-ladder extension, metallic-regime boundary, M…
Aug 18, 2026
346ab2f
Docs: record non-Gamma q smoke results (dfpt_qfile end-to-end, q<->-q…
Aug 18, 2026
38cee30
Fix: drop spurious 1/nk in DFPT eps/born sums; wg already carries ful…
Aug 19, 2026
3e376d2
Docs: record continuation plan (P0-1 uncommitted-fix intake, P0-2 Zst…
Aug 19, 2026
2da1a4e
Fix: gate same-atom d2V_ext on 2q reciprocal; drop spurious ion_ion d…
Aug 19, 2026
4801371
Debug: DFPT design-phase probes (ZDBG/BPT/NOSC/D2MID/DYNCHK/XB)
Aug 19, 2026
4db12d7
Docs: P0-1 done (2q-reciprocal d2 gate intake, order-dependence fix, …
Aug 19, 2026
0d510b8
DFPT q0: star-rotate the symmetry-reduced eps/Z* tensor sums
Aug 19, 2026
8124a7f
DFPT q0: Sternheimer screened Z* (v4), QE-anchored eps 16pi fix, zsta…
Aug 20, 2026
98c7f11
DFPT q0: promote the E-field SCF solve, compute_eps to the dielec.f90…
Aug 20, 2026
be3e5ee
DFPT: build_occ_kq diagnostic detail in the commensurability error; P…
Aug 20, 2026
a915352
DFPT: fix q!=Gamma phonon frequencies (missing spin factor 2 in drho)…
Aug 24, 2026
d4a6e9a
DFPT PLAN: P0-3 non-Gamma-q defect root-caused and fixed (drho spin f…
Aug 24, 2026
63060a7
DFPT B2: formalize the phonon output (multi-q report, LO-TO corrected…
Aug 24, 2026
6a3caf5
DFPT B3: Kerker-preconditioned density mixing in DFPT_Rho
Aug 24, 2026
3904ecf
DFPT B4: sink the (q,irrep) SCF ledger into DFPT_PW_Data, retire the …
Aug 24, 2026
dbaa0e8
DFPT: retire the B-phase validation instrumentation (net -977 lines)
Aug 25, 2026
3152fff
delete PLAN
Aug 28, 2026
dc99085
merge: 合并 origin/develop
Aug 28, 2026
7690d20
Merge remote-tracking branch 'origin/develop' into dfpt-csj
Sep 1, 2026
469cdbf
Fix: adapt DFPT to the refactored Plus_U interface (compile break + U…
Sep 1, 2026
b1f7f61
Fix: reduce PR global dependency budget to non-increasing
Sep 1, 2026
c42f4f2
Fix: link K_Vectors/ReciprocalGrid sources into tests broken by the R…
Sep 1, 2026
4f17ffd
Merge branch 'deepmodeling:develop' into dfpt-csj
Zanthoxylum Sep 1, 2026
5d927dc
Fix: link K_Vectors/ReciprocalGrid sources into LCAO-side tests and a…
Sep 1, 2026
a321bf1
Docs: resync parameters.yaml and input-main.md with the C++ Input_Ite…
Sep 1, 2026
7e6f180
Fix: compile reciprocal_grid.cpp in deepks unit tests
Sep 1, 2026
a8185af
Fix: use threadsafe death tests in DFPT suites to avoid fork-in-threa…
Sep 1, 2026
ae3e9d1
Refactor DFPT unit tests: consolidate ctor/dtor stubs into shared dfp…
Sep 1, 2026
4f451c4
Refactor DFPT unit tests: share the cubic-cell/stru_lib fixture betwe…
Sep 1, 2026
f19f00c
Refactor DFPT serial tests: derive pert/rho/phon/q0 fixtures from a s…
Sep 1, 2026
b2a7880
test(dfpt): dedupe repeated analytic blocks in the phon serial test
Sep 1, 2026
b36c463
merge: 同步 origin/develop(DFPT 已由 #7875 入上游,取 #7894 更新为准)
Sep 15, 2026
c92ecc8
fix(dfpt): correct dn sign in k+q occupied-state ball folding
Sep 17, 2026
bb4f4e4
merge: 同步 origin/develop(#7980-#7984 测试去 access hack、#7975 EXX 提示等)
Sep 17, 2026
c9f5331
Merge remote-tracking branch 'origin/develop' into dfpt-csj
Zanthoxylum Oct 16, 2026
c7993ce
fix(build): drop predetermined-shared rho_basis from OpenMP shared cl…
Zanthoxylum Oct 16, 2026
74716d9
feat(dfpt): analytic libxc first-order XC kernel with the i(G+q) carr…
Zanthoxylum Oct 16, 2026
f621ab5
fix(dfpt): fold tpiba into the analytic XC kernel gradient factors
Zanthoxylum Oct 17, 2026
a83c3dd
Merge branch 'deepmodeling:develop' into dfpt-csj
Zanthoxylum Oct 17, 2026
aeeaba2
revert(build): restore upstream OpenMP shared clauses in write_elf.cpp
Zanthoxylum Oct 17, 2026
42e5e0c
fix(dfpt): include the nlcc core density in the analytic XC kernel base
Zanthoxylum Oct 17, 2026
7ac3caf
feat(dfpt): explicit input guard for non-LDA/GGA functionals
Zanthoxylum Oct 17, 2026
a5234f6
feat(dfpt): default iteration trace and convergence summary for displ…
Zanthoxylum Oct 17, 2026
8d93aff
chore(dfpt): remove the unused build_efield sawtooth and align stern.…
Zanthoxylum Oct 17, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion source/Makefile.Objects
Original file line number Diff line number Diff line change
Expand Up @@ -434,7 +434,8 @@ OBJS_DFPT=dfpt_hamilt_shift.o\
dfpt_q0.o\
dfpt_q0_pos.o\
dfpt_rho.o\
dfpt_stern.o
dfpt_stern.o\
dfpt_xc_analytic.o

OBJS_HAMILT_LCAO=hamilt_lcao.o\
hamilt_lcao_factory.o\
Expand Down
50 changes: 49 additions & 1 deletion source/source_esolver/esolver_dfpt_pw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,20 @@
#include "source_base/macros.h"
#include "source_base/math_polyint.h"
#include "source_base/tool_quit.h"
#include "source_hamilt/module_xc/xc_functional.h"
#include "source_io/module_parameter/parameter.h"
#include "source_pw/module_dfpt/dfpt_pert.h"
#include "source_pw/module_dfpt/dfpt_pw.h"
#include "source_pw/module_dfpt/dfpt_rho.h"
#ifdef __LIBXC
#include "source_pw/module_dfpt/dfpt_xc_analytic.h"
#endif

#include <cmath>
#include <complex>
#include <cstdlib>
#include <iostream>
#include <sstream>
#include <vector>

namespace {
Expand Down Expand Up @@ -296,9 +301,52 @@ void ESolver_DFPT_PW::init_dfpt(UnitCell& ucell)
veff_r[ir] = veff_smooth(0, ir);
}

// first-order XC kernel adapter around the converged ground-state density
// input guard: the first-order XC kernel supports LDA (1) and GGA (2)
// only. Meta-GGA needs the tau channel (absent in both kernel paths),
// and hybrid functionals need the exact-exchange response -- neither
// exists yet, so reject them explicitly instead of producing silently
// wrong frequencies.
const int xc_func_type = XC_Functional::get_func_type();
if (xc_func_type != 1 && xc_func_type != 2)
{
std::stringstream msg;
msg << "DFPT supports LDA/GGA functionals only; the ground-state functional '"
<< ucell.atoms[0].ncpp.xc_func << "' (func_type " << xc_func_type
<< ") needs response channels that are not implemented";
ModuleBase::WARNING_QUIT("ESolver_DFPT_PW::init_dfpt", msg.str());
}

// first-order XC kernel around the converged ground-state density:
// with libxc use the analytic kernel (libxc second derivatives in the
// dgradcorr form; the gradient operator acts as i(G + q) on the
// physical carrier, so the GGA response is exact at any q); without
// libxc fall back to the amplitude-grid finite differences (exact for
// LDA; at q != 0 the GGA response lacks the i(q . f_grad) A carrier
// term).
#ifdef __LIBXC
// kernel linearization point: the ground-state XC density, i.e. valence
// plus the nonlinear core correction density when the pseudopotentials
// carry one (PotXC_FDM adds chg->rho_core the same way); the first-order
// density itself stays valence-only (a frozen core does not respond)
const Charge* chg0 = this->pelec->charge;
const bool has_core = chg0->rho_core != nullptr;
std::vector<double> rho0_r(this->pw_rho->nrxx, 0.0);
for (int ir = 0; ir < this->pw_rho->nrxx; ++ir)
{
rho0_r[ir] = chg0->rho[0][ir] + (has_core ? chg0->rho_core[ir] : 0.0);
}
xc_adapter_ = new ModuleDFPT::XC_First_Order_Analytic(XC_Functional::get_func_id(),
XC_Functional::get_func_type(),
rho0_r,
this->pw_rho);
#else
ModuleBase::WARNING("ESolver_DFPT_PW::init_dfpt",
"built without libxc: the DFPT XC kernel falls back to the finite-difference "
"amplitude path (LDA-only support; the GGA response at q != 0 lacks the "
"i(q.f_grad)A carrier term)");
xc_adapter_ = new XC_First_Order_FDM(this->inp_->nspin, PARAM.globalv.domag, PARAM.globalv.domag_z, this->inp_->gga_grad,
this->inp_->out_elf[0] > 0, this->inp_->test_charge, this->pw_rho, this->pelec->charge, &ucell);
#endif

if (getenv("DFPT_VKB") != nullptr)
{
Expand Down
9 changes: 9 additions & 0 deletions source/source_pw/module_dfpt/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,19 @@ set(HEADERS
dfpt_q0.h
dfpt_metal.h
dfpt_hamilt_shift.h
dfpt_xc_analytic.h
)

add_library(${MODULE_NAME} ${SOURCES} ${HEADERS})

# analytic libxc kernel for the DFPT first-order XC response; the source is
# an empty translation unit without libxc, so an unconditional build keeps
# every consumer linkable either way
if(ENABLE_LIBXC)
target_sources(${MODULE_NAME} PRIVATE dfpt_xc_analytic.cpp)
target_link_libraries(${MODULE_NAME} PUBLIC Libxc::xc)
endif()

target_include_directories(${MODULE_NAME}
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
Expand Down
41 changes: 0 additions & 41 deletions source/source_pw/module_dfpt/dfpt_pert.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -414,45 +414,4 @@ void DFPT_Pert::d2vloc_r(int atom_idx, int da, int db, std::vector<std::complex<
ModuleBase::timer::end("DFPT_Pert", "d2vloc_r");
}

void DFPT_Pert::build_efield(const ModuleBase::Vector3<double>& field, DFPT_PW_Data& data)
{
ModuleBase::TITLE("DFPT_Pert", "build_efield");
ModuleBase::timer::start("DFPT_Pert", "build_efield");
// first-order electric-field potential: delta V(r) = - r . E (q=0 limit,
// position operator in the periodic cell). Computed directly on the shared
// real-space grid. Only relevant for the Q0 dielectric response (C6).
if (pw_rho_ == nullptr)
{
ModuleBase::timer::end("DFPT_Pert", "build_efield");
return;
}
if (pw_rho_->gamma_only)
{
ModuleBase::WARNING_QUIT("DFPT_Pert::build_efield",
"DFPT requires a complex (gamma_only=false) real-space basis.");
}
std::vector<std::complex<double>> dv_real(pw_rho_->nrxx, std::complex<double>(0.0, 0.0));
const ModuleBase::Matrix3& latvec = ucell_->latvec;
const double lat0 = ucell_->lat0;
// shared real-space grid layout (serial pool): ir = (ix*ny + iy)*nz + iz,
// i.e. z runs fastest (verified against the impulse response of the FFT).
for (int ir = 0; ir < pw_rho_->nrxx; ++ir)
{
const int iz = ir % pw_rho_->nz;
const int rem = ir / pw_rho_->nz;
const int iy = rem % pw_rho_->ny;
const int ix = rem / pw_rho_->ny;
const double fx = ix / static_cast<double>(pw_rho_->nx);
const double fy = iy / static_cast<double>(pw_rho_->ny);
const double fz = iz / static_cast<double>(pw_rho_->nz);
ModuleBase::Vector3<double> r;
r.x = (fx * latvec.e11 + fy * latvec.e12 + fz * latvec.e13) * lat0;
r.y = (fx * latvec.e21 + fy * latvec.e22 + fz * latvec.e23) * lat0;
r.z = (fx * latvec.e31 + fy * latvec.e32 + fz * latvec.e33) * lat0;
dv_real[ir] = -(field * r); // -e r.E (e absorbed in field convention)
}
data.set_dv_rc(0, 0, dv_real);
ModuleBase::timer::end("DFPT_Pert", "build_efield");
}

} // namespace ModuleDFPT
2 changes: 0 additions & 2 deletions source/source_pw/module_dfpt/dfpt_pert.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,6 @@ class DFPT_Pert

void apply_dv(int q_idx, int k_idx, const psi::Psi<std::complex<double>>& psi, DFPT_PW_Data& data);

void build_efield(const ModuleBase::Vector3<double>& field, DFPT_PW_Data& data);

/// C5: real-space kernel of the same-atom second-order LOCAL potential
/// d2V_loc(r) = d^2 V_loc / d tau_{da} d tau_{db} (both displacement
/// dressings e^{i q.R} multiply on the SAME atom, so the cell sum
Expand Down
20 changes: 20 additions & 0 deletions source/source_pw/module_dfpt/dfpt_pw_solve.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <cmath>
#include <complex>
#include <cstdlib>
#include <iomanip>
#include <iostream>
#include <vector>

Expand Down Expand Up @@ -50,6 +51,9 @@ void DFPT_PW::Impl::assemble_v_sc(const ModuleBase::Vector3<double>& q_cart,
{
return;
}
// per-q context: analytic GGA kernels act with i(G + q) on the
// physical carrier of the q-shifted amplitude
xc_->set_context(q_cart);
std::vector<std::complex<double>> a_r(nrxx);
pw_rho_->recip2real(drho_in_g.data(), a_r.data());
std::vector<std::complex<double>> b_r;
Expand Down Expand Up @@ -207,6 +211,7 @@ double DFPT_PW::Impl::solve_displacement(int q_idx, int iat, int idir)

bool converged = false;
double residual = 0.0;
int n_iter_done = 0;
std::vector<std::complex<double>> v_sc_r_last;
for (int iter = 0; iter < max_iter_ && !converged; ++iter)
{
Expand Down Expand Up @@ -251,12 +256,27 @@ double DFPT_PW::Impl::solve_displacement(int q_idx, int iat, int idir)
rho_.compute_drho(gs_psi_, wg_, q_idx, data_);
rho_.mix_drho(q_idx, data_);
residual = rho_.get_residual(q_idx, data_);
// default iteration trace (GS-SCF style); the DFPT_DEBUG snapshots
// above stay opt-in diagnostics
std::cout << " DFPT mix iter=" << std::setw(3) << std::right << iter + 1 << "/" << max_iter_
<< " residual=" << std::setprecision(3) << std::scientific << residual
<< " (thr " << std::setprecision(1) << std::scientific << conv_thr_ << ")"
<< std::endl;
Comment thread
mohanchen marked this conversation as resolved.
if (dbg)
{
std::cout << "DBG iter=" << iter << " residual=" << residual << " conv_thr=" << conv_thr_ << std::endl;
}
converged = (residual < conv_thr_);
++n_iter_done;
}
// convergence summary in the efield-solve style; names the state
// explicitly instead of failing silently at max_iter
std::cout << std::defaultfloat << std::setprecision(4);
std::cout << "DFPT disp q=(" << q_frac.x << "," << q_frac.y << "," << q_frac.z << ") atom=" << iat + 1 << "("
<< ucell_->atoms[ucell_->iat2it[iat]].label << ") dir=" << static_cast<char>('x' + idir) << " "
<< (converged ? "converged" : "NOT converged (max_iter reached)") << ", residual=" << std::scientific
<< std::setprecision(6) << residual << " (iter=" << n_iter_done << ")" << std::defaultfloat
<< std::endl;
stash_converged_disp_response(q_idx, iat, idir, v_sc_r_last, nk, nbands);

ModuleBase::timer::end("DFPT_PW", "solve_displacement");
Expand Down
12 changes: 12 additions & 0 deletions source/source_pw/module_dfpt/dfpt_rho.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,18 @@ class XC_First_Order
public:
virtual ~XC_First_Order() = default;

/// Optional per-q context before the first apply of a new phonon q
/// (cartesian, ucell::G units). Analytic GGA kernels need the phonon q
/// so the gradient operator acts as i(G + q) on the physical carrier;
/// amplitude-grid implementations ignore it (their gradient of the
/// carrier-free amplitude is only exact at q = 0). Const like apply:
/// the kernel is held as pointer-to-const by the solver, and context
/// injection between solves is the sanctioned state change.
virtual void set_context(const ModuleBase::Vector3<double>& q_cart) const
{
(void)q_cart;
}

/// dvxc_r(r) = delta V_xc[drho_r](r), complex q-shifted amplitude on
/// the shared real-space grid. Implementations must not resize or
/// alias drho_r; dvxc_r is resized to drho_r.size() and fully
Expand Down
6 changes: 4 additions & 2 deletions source/source_pw/module_dfpt/dfpt_stern.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@ namespace ModuleDFPT
*
* The shifted Hamiltonian action is injected through LinearOperator so the
* solver core stays decoupled from the ground-state operator chain: the
* production adapter reuses hamilt::Hamilt::ops->hPsi at the k+q point
* (wired in C7), while unit tests supply analytic operators.
* production adapter (DFPT_HamiltShift, dfpt_hamilt_shift.h) builds the
* (H(k+q) - eps) action itself on the k+q basis rather than reusing
* hamilt::Hamilt::ops->hPsi (a potential future refactor to shrink the
* reimplementation surface); unit tests supply analytic operators.
*/
class DFPT_Stern
{
Expand Down
Loading
Loading