Skip to content

Commit 944082f

Browse files
committed
DeltaP PW force decomposition: add [DeltaP-F] diagnostic output
Split DeltaP constraint force into separate temp buffer before accumulating into total force, printing [DeltaP-F] to stdout. H2O force decomposition (z-component, λ=0 → 0.02 Ry): O: dF_corr/dλ = -14.7 eV/A/Ry dF_total/dλ = +11.9 relaxation = +26.6 H1: dF_corr/dλ = +11.9 dF_total/dλ = +11.9 relaxation ≈ 0 H2: dF_corr/dλ = +11.9 dF_total/dλ = +12.0 relaxation ≈ 0 For O: SCF relaxation dominates (opposite sign, 181% of F_corr magnitude). For H: F_corr ≈ total response (relaxation negligible). This confirms the force correction is correctly implemented as the Hellmann-Feynman gradient of the projector constraint operator.
1 parent f48e597 commit 944082f

1 file changed

Lines changed: 37 additions & 1 deletion

File tree

source/source_pw/module_pwdft/forces_onsite.cpp

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
#include "source_lcao/module_dftu/dftu.h"
99
#include "source_lcao/module_deltaspin/spin_constrain.h"
1010
#include "source_pw/module_pwdft/deltap_pw.h"
11+
#include "source_base/constants.h"
12+
#include <iomanip>
13+
#include <iostream>
1114

1215
template <typename FPTYPE, typename Device>
1316
void Forces<FPTYPE, Device>::cal_force_onsite(ModuleBase::matrix& force_onsite,
@@ -69,7 +72,40 @@ void Forces<FPTYPE, Device>::cal_force_onsite(ModuleBase::matrix& force_onsite,
6972
bool ok = (dp_constrain.empty() || static_cast<size_t>(iat) >= dp_constrain.size() || dp_constrain[iat] != 0);
7073
lam[iat].z = ok ? dp_lambda[iat] : 0.0;
7174
}
72-
onsite_p->cal_force_onsite_dspin(ik, npm, force, lam.data(), wg.c);
75+
76+
// Allocate temp force buffer for DeltaP contribution only
77+
FPTYPE* f_deltap = nullptr;
78+
resmem_var_op()(f_deltap, nat * 3);
79+
base_device::memory::set_memory_op<FPTYPE, Device>()(f_deltap, 0.0, nat * 3);
80+
onsite_p->cal_force_onsite_dspin(ik, npm, f_deltap, lam.data(), wg.c);
81+
82+
// Print DeltaP force contribution separately for verification
83+
std::cout << " [DeltaP-F] λ=(";
84+
for (int iat = 0; iat < nat; iat++)
85+
{
86+
double val = (dp_constrain.empty() || static_cast<size_t>(iat) >= dp_constrain.size() || dp_constrain[iat] != 0) ? dp_lambda[iat] : 0.0;
87+
if (iat > 0) std::cout << ", ";
88+
std::cout << std::scientific << std::setprecision(3) << val;
89+
}
90+
std::cout << ") Ry";
91+
for (int iat = 0; iat < nat; iat++)
92+
{
93+
std::cout << " F" << iat+1 << "=(";
94+
for (int ipol = 0; ipol < 3; ipol++)
95+
{
96+
if (ipol > 0) std::cout << ", ";
97+
double f_eV_A = f_deltap[iat * 3 + ipol] * ModuleBase::Ry_to_eV / ModuleBase::BOHR_TO_A;
98+
std::cout << std::fixed << std::setprecision(6) << f_eV_A;
99+
}
100+
std::cout << ")";
101+
}
102+
std::cout << " eV/A" << std::endl;
103+
104+
// Accumulate into total force
105+
for (int iat = 0; iat < nat; iat++)
106+
for (int ipol = 0; ipol < 3; ipol++)
107+
force[iat * 3 + ipol] += f_deltap[iat * 3 + ipol];
108+
delmem_var_op()(f_deltap);
73109
}
74110

75111
}

0 commit comments

Comments
 (0)