Describe the Code Quality Issue
Summary
Three related issues / suggestions about the DFT+U occupation-matrix (occ_mat) handling.
1. Bug: E_plusU is always 0 in the PW basis output
Observed behavior
In a PW-basis DFT+U calculation, the E_plusU entry in the electronic-step energy table is always 0, even after the SCF has converged and the occupation matrix is non-trivial.
Likely cause
Plus_U_Base::energy_u is reset to 0 in init_base() and only updated through cal_occ_pw() (via dftu.energy_ref()). In esolver_ks_pw.cpp, pelec->set_dftu_energy(dftu_->get_energy()) is called inside iter_init(), but iter_init_dftu_pw() early-returns at iter == 1 && istep == 0 before cal_occ_pw runs, so the first step has energy_u == 0.
For subsequent steps, the call order needs to be verified: set_dftu_energy may be reading energy_u before cal_occ_pw of the current step updates it, so it always reports the previous step's value (and 0 on step 1).
Files involved
-
source/source_pw/module_pwdft/dftu_base.cpp (init_base resets energy_u)
-
source/source_pw/module_pwdft/dftu_pw.cpp (cal_occ_pw computes energy_u)
-
source/source_esolver/esolver_ks_pw.cpp (set_dftu_energy timing)
-
source/source_estate/elecstate_print.cpp (E_plusU printout)
The LCAO path has an explicit dftu->set_energy(u_energy) call (source/source_lcao/module_dftu/dftu_nao_op.cpp), so this appears to be PW-only.
2. Suggestion: unify the occupation-matrix output filename to occ_mat.txt
Currently the DFT+U occupation matrix is written to different filenames depending on the basis / version:
The name dm_onsite is misleading because the file holds the onsite occupation matrix, not the full density matrix. occ_mat.txt is clearer and is already used by the PW output.
Request: use occ_mat.txt consistently across PW and LCAO, and keep dm_onsite.txt only as a read-side fallback for backward compatibility.
3. Suggestion: decouple occ_mat output and input control; avoid out_dm ambiguity
DFT+U occupation-matrix I/O should have dedicated, basis-independent switches:
-
Output: out_occ_mat (already exists and works in both PW and LCAO). This should be the canonical switch; it should not be coupled to out_chg.
-
Input: init_occ_mat (Integer 0/1/2) controls whether and how the occ_mat is read from read_file_dir, with a fallback chain dm_onsite_ini.txt -> occ_mat.txt -> dm_onsite.txt.
Why this matters
-
out_dm / out_dmk (LCAO density matrix) and DFT+U occ_mat are conceptually different things; sharing or similar naming causes confusion, especially under PW where out_dm has no meaning.
-
Decoupling output from out_chg avoids unnecessary charge-density cube IO when the user only wants the occupation matrix.
-
A dedicated read switch (init_occ_mat) lets users load an occ_mat without also forcing a charge-density restart (init_chg=file), which is useful for broken-symmetry guiding and fixed-occupation-matrix studies.
Proposed acceptance criteria
Additional Context
No response
Task list for Issue attackers (only for developers)
Describe the Code Quality Issue
Summary
Three related issues / suggestions about the DFT+U occupation-matrix (occ_mat) handling.
1. Bug:
E_plusUis always 0 in the PW basis outputObserved behavior
In a PW-basis DFT+U calculation, the
E_plusUentry in the electronic-step energy table is always0, even after the SCF has converged and the occupation matrix is non-trivial.Likely cause
Plus_U_Base::energy_uis reset to0ininit_base()and only updated throughcal_occ_pw()(viadftu.energy_ref()). Inesolver_ks_pw.cpp,pelec->set_dftu_energy(dftu_->get_energy())is called insideiter_init(), butiter_init_dftu_pw()early-returns atiter == 1 && istep == 0beforecal_occ_pwruns, so the first step hasenergy_u == 0.For subsequent steps, the call order needs to be verified:
set_dftu_energymay be readingenergy_ubeforecal_occ_pwof the current step updates it, so it always reports the previous step's value (and 0 on step 1).Files involved
source/source_pw/module_pwdft/dftu_base.cpp(init_base resets energy_u)source/source_pw/module_pwdft/dftu_pw.cpp(cal_occ_pw computes energy_u)source/source_esolver/esolver_ks_pw.cpp(set_dftu_energy timing)source/source_estate/elecstate_print.cpp(E_plusU printout)The LCAO path has an explicit
dftu->set_energy(u_energy)call (source/source_lcao/module_dftu/dftu_nao_op.cpp), so this appears to be PW-only.2. Suggestion: unify the occupation-matrix output filename to
occ_mat.txtCurrently the DFT+U occupation matrix is written to different filenames depending on the basis / version:
PW develop:
occ_mat.txt(andocc_matg{istep}.txt)older versions / LCAO:
dm_onsite.txtThe name
dm_onsiteis misleading because the file holds the onsite occupation matrix, not the full density matrix.occ_mat.txtis clearer and is already used by the PW output.Request: use
occ_mat.txtconsistently across PW and LCAO, and keepdm_onsite.txtonly as a read-side fallback for backward compatibility.3. Suggestion: decouple occ_mat output and input control; avoid
out_dmambiguityDFT+U occupation-matrix I/O should have dedicated, basis-independent switches:
Output:
out_occ_mat(already exists and works in both PW and LCAO). This should be the canonical switch; it should not be coupled toout_chg.Input:
init_occ_mat(Integer 0/1/2) controls whether and how the occ_mat is read fromread_file_dir, with a fallback chaindm_onsite_ini.txt -> occ_mat.txt -> dm_onsite.txt.Why this matters
out_dm/out_dmk(LCAO density matrix) and DFT+Uocc_matare conceptually different things; sharing or similar naming causes confusion, especially under PW whereout_dmhas no meaning.Decoupling output from
out_chgavoids unnecessary charge-density cube IO when the user only wants the occupation matrix.A dedicated read switch (
init_occ_mat) lets users load an occ_mat without also forcing a charge-density restart (init_chg=file), which is useful for broken-symmetry guiding and fixed-occupation-matrix studies.Proposed acceptance criteria
E_plusUin the PW running log matches the actual DFT+U energy at every electronic step.Both PW and LCAO write the latest
Additional Context
No response
Task list for Issue attackers (only for developers)