Skip to content

Commit 478b972

Browse files
committed
DeltaP Phase B3: per-atom gamma via becp weights from OnsiteProjector
compute_per_atom_gamma_from_becp(): - Reads becp = <alpha|psi_n(k)> from OnsiteProjector singleton - Accumulates per-atom weights: w[I] = Σ_n Σ_{α∈I} |becp(α,n)|^2 - gamma[I] = w[I] * gamma_total / Σ w[J] - Fallback to equal division if becp unavailable deltap_iter_finish() now uses becp decomposition instead of equal partition. Per-atom gamma output in the console log. Test (H2O Gamma-only): gamma_total = -0.2307 rad per-atom: O=(-0.1510, 65.5%), H1=(-0.0399, 17.3%), H2=(-0.0399, 17.3%) Weights evolve with wavefunctions as lambda converges. BN LCAO regression passes.
1 parent 13197cb commit 478b972

2 files changed

Lines changed: 69 additions & 19 deletions

File tree

source/source_pw/module_pwdft/deltap_pw.cpp

Lines changed: 63 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "source_basis/module_pw/pw_basis_k.h"
66
#include "source_cell/klist.h"
77
#include "source_cell/unitcell.h"
8+
#include "source_pw/module_pwdft/onsite_proj.h"
89
#include <iomanip>
910
#include <iostream>
1011

@@ -141,25 +142,9 @@ void deltap_iter_finish(
141142
if (gamma_total == 0.0)
142143
return; // no valid k-strings (Gamma-only grid)
143144

144-
// For Phase B2: assign gamma equally to constrained atoms
145-
// Phase B3 will add proper per-atom decomposition via becp weights
146-
int nconstrained = 0;
147-
for (int iat = 0; iat < nat; iat++)
148-
{
149-
bool ok = (constrain.empty() || static_cast<size_t>(iat) >= constrain.size() || constrain[iat] != 0);
150-
if (ok) nconstrained++;
151-
}
152-
if (nconstrained == 0) return;
153-
154-
double gamma_per_atom = gamma_total / nconstrained;
155-
156-
// Build per-atom gamma and update lambda via gradient descent
145+
// Phase B3: decompose total gamma per atom via becp weights
157146
std::vector<double> gamma_1d(nat, 0.0);
158-
for (int iat = 0; iat < nat; iat++)
159-
{
160-
bool ok = (constrain.empty() || static_cast<size_t>(iat) >= constrain.size() || constrain[iat] != 0);
161-
gamma_1d[iat] = ok ? gamma_per_atom : 0.0;
162-
}
147+
compute_per_atom_gamma_from_becp(ucell, nocc, gamma_total, gamma_1d);
163148

164149
// Target values (fixed, from STRU at initialization)
165150
const std::vector<double>& targets = get_deltap_pw_targets();
@@ -189,7 +174,66 @@ void deltap_iter_finish(
189174
for (int iat = 0; iat < nat; iat++) lam_avg += lambda[iat];
190175
lam_avg /= nat;
191176
std::cout << std::scientific << std::setprecision(3) << lam_avg
192-
<< " |res|=" << max_res << std::endl;
177+
<< " |res|=" << max_res
178+
<< " γ/atom=(" << std::fixed << std::setprecision(4);
179+
for (int iat = 0; iat < nat; iat++)
180+
{
181+
if (iat > 0) std::cout << ", ";
182+
std::cout << gamma_1d[iat];
183+
}
184+
std::cout << ")" << std::endl;
185+
}
186+
187+
void compute_per_atom_gamma_from_becp(
188+
const UnitCell& ucell,
189+
int nocc,
190+
double gamma_total,
191+
std::vector<double>& gamma_per_atom)
192+
{
193+
int nat = ucell.nat;
194+
gamma_per_atom.assign(nat, 0.0);
195+
196+
auto* onsite_p = projectors::OnsiteProjector<double, base_device::DEVICE_CPU>::get_instance();
197+
if (onsite_p == nullptr) return;
198+
199+
int tot_nproj = onsite_p->get_tot_nproj();
200+
if (tot_nproj == 0) return;
201+
202+
const std::complex<double>* becp = onsite_p->get_becp();
203+
if (becp == nullptr) return;
204+
205+
// Compute per-atom weights: w[I] = Σ_n Σ_{α∈I} |<alpha|psi_n>|^2
206+
std::vector<double> w(nat, 0.0);
207+
int iproj = 0;
208+
for (int iat = 0; iat < nat; iat++)
209+
{
210+
int nh = onsite_p->get_nh(iat);
211+
for (int ip = 0; ip < nh; ip++)
212+
{
213+
double w_ip = 0.0;
214+
for (int ib = 0; ib < nocc; ib++)
215+
{
216+
std::complex<double> b = becp[ib * tot_nproj + iproj];
217+
w_ip += b.real() * b.real() + b.imag() * b.imag();
218+
}
219+
w[iat] += w_ip;
220+
iproj++;
221+
}
222+
}
223+
224+
double w_total = 0.0;
225+
for (int iat = 0; iat < nat; iat++) w_total += w[iat];
226+
227+
if (w_total < 1e-30)
228+
{
229+
// Fallback: equal division
230+
for (int iat = 0; iat < nat; iat++)
231+
gamma_per_atom[iat] = gamma_total / nat;
232+
return;
233+
}
234+
235+
for (int iat = 0; iat < nat; iat++)
236+
gamma_per_atom[iat] = gamma_total * w[iat] / w_total;
193237
}
194238

195239
} // namespace pw_deltap

source/source_pw/module_pwdft/deltap_pw.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,12 @@ void deltap_iter_finish(
8383
const ModulePW::PW_Basis* rhopw,
8484
const Input_para& inp);
8585

86+
void compute_per_atom_gamma_from_becp(
87+
const UnitCell& ucell,
88+
int nocc,
89+
double gamma_total,
90+
std::vector<double>& gamma_per_atom);
91+
8692
} // namespace pw_deltap
8793

8894
#endif // DELTAP_PW_H

0 commit comments

Comments
 (0)