Skip to content

Commit ecbde57

Browse files
committed
DeltaP PW fix: reset s_lambda_set each SCF + add dp_escon
Fix #1 (s_lambda_set): reset to false in set_deltap_pw_hamilt() so lambda is re-evaluated each SCF cycle (enables geometry optimization with adaptive constraint). Fix #2 (dp_escon): compute constraint energy correction dp_escon = -Sum lambda_I * gamma_I in deltap_iter_finish() and apply to pelec->f_en.dp_escon in iter_finish(). This corrects the double-counting of constraint energy in the band energy, following the DeltaSpin escon pattern. Verified: H2O PW with dp_target=0.5/-0.25/-0.25 escon=0.110726 Ry E_tot=-415.54 eV (previously -417.01 without escon) -415.54 + 1.506 = -414.03 (adjusted, closer to baseline -442.09) BN LCAO regression passes.
1 parent 944082f commit ecbde57

3 files changed

Lines changed: 23 additions & 3 deletions

File tree

source/source_esolver/esolver_ks_pw.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,9 @@ void ESolver_KS_PW<T, Device>::iter_finish(UnitCell& ucell, const int istep, int
287287
// DeltaP: compute gamma and update lambda after SCF iteration
288288
pw_deltap::deltap_iter_finish(ucell, this->drho,
289289
this->stp.psi_cpu, this->kv, this->pw_wfc, this->pw_rho, PARAM.inp);
290+
// Apply DeltaP constraint energy correction to f_en
291+
if (PARAM.inp.deltap_switch && PARAM.inp.deltap_corr)
292+
this->pelec->f_en.dp_escon = pw_deltap::get_deltap_pw_escon();
290293

291294
// the output quantities
292295
ModuleIO::ctrl_iter_pw(istep, iter, conv_esolver, this->stp.psi_cpu,

source/source_pw/module_pwdft/deltap_pw.cpp

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ namespace {
2121
std::vector<double> s_targets; // target per-atom gamma (rad)
2222
std::vector<int> s_constrain; // per-atom constrain flags
2323
double s_gamma_total = 0.0; // cached total gamma from last computation
24+
double s_dp_escon = 0.0; // cached dp_escon from last computation
2425
void* s_hamilt = nullptr; // stored HamiltPW pointer for inner loop
2526

2627
// Subspace data for inner lambda loop (saved once per SCF, reused across inner steps)
@@ -54,6 +55,11 @@ const std::vector<double>& get_deltap_pw_targets()
5455
return s_targets;
5556
}
5657

58+
double get_deltap_pw_escon()
59+
{
60+
return s_dp_escon;
61+
}
62+
5763
void set_deltap_pw_active(bool active)
5864
{
5965
s_active = active;
@@ -67,7 +73,8 @@ bool is_deltap_pw_active()
6773
void set_deltap_pw_hamilt(void* hamilt)
6874
{
6975
s_hamilt = hamilt;
70-
s_sub_saved = false; // reset subspace cache when hamilt changes (new SCF)
76+
s_sub_saved = false;
77+
s_lambda_set = false; // re-enable lambda update for new SCF cycle
7178
}
7279

7380
bool run_deltap_lambda_loop(const int iter,
@@ -245,7 +252,7 @@ void deltap_iter_finish(
245252

246253
set_deltap_pw_lambda(lambda, constrain);
247254

248-
// Compute final max_res for output
255+
// Compute final max_res and per-atom gamma for output
249256
std::vector<double> gamma_final(nat, 0.0);
250257
compute_per_atom_gamma_from_becp(ucell, nocc, gamma_total, gamma_final);
251258
double max_res = 0.0;
@@ -256,6 +263,14 @@ void deltap_iter_finish(
256263
max_res = std::max(max_res, std::abs(gamma_final[iat] - targets[iat]));
257264
}
258265

266+
// Compute dp_escon = -Σ λ_I · γ_I (constraint energy correction)
267+
// Subtracted from band energy to recover physical DFT energy
268+
// Follows same formula as DeltaSpin's escon = -Σ λ·M
269+
double dp_escon = 0.0;
270+
for (int iat = 0; iat < nat; iat++)
271+
dp_escon -= lambda[iat] * gamma_final[iat];
272+
s_dp_escon = dp_escon;
273+
259274
double lam_avg = 0.0;
260275
for (int iat = 0; iat < nat; iat++) lam_avg += lambda[iat];
261276
lam_avg /= nat;
@@ -265,7 +280,8 @@ void deltap_iter_finish(
265280
<< gamma_total << " rad λ_avg=";
266281
std::cout << std::scientific << std::setprecision(3) << lam_avg
267282
<< " |res|=" << max_res
268-
<< " γ/atom=(" << std::fixed << std::setprecision(4);
283+
<< " escon=" << std::fixed << std::setprecision(6) << dp_escon << " Ry"
284+
<< " γ/atom=(";
269285
for (int iat = 0; iat < nat; iat++)
270286
{
271287
if (iat > 0) std::cout << ", ";

source/source_pw/module_pwdft/deltap_pw.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ void set_deltap_pw_lambda(const std::vector<double>& lambda,
2121
const std::vector<double>& get_deltap_pw_lambda();
2222
const std::vector<int>& get_deltap_pw_constrain();
2323
const std::vector<double>& get_deltap_pw_targets();
24+
double get_deltap_pw_escon();
2425

2526
void set_deltap_pw_active(bool active);
2627
bool is_deltap_pw_active();

0 commit comments

Comments
 (0)