Skip to content

Refactor DFT+U, step 4 - #7861

Open
mohanchen wants to merge 23 commits into
deepmodeling:developfrom
mohanchen:2026-08-25-U3
Open

Refactor DFT+U, step 4#7861
mohanchen wants to merge 23 commits into
deepmodeling:developfrom
mohanchen:2026-08-25-U3

Conversation

@mohanchen

Copy link
Copy Markdown
Collaborator

Refactor DFT+U, step 4

@mohanchen mohanchen added DFT+U Issues related to DFT plus U function Refactor Refactor ABACUS codes The Absolute Zero Reduce the "entropy" of the code to 0 labels Aug 26, 2026
@mohanchen
mohanchen requested a review from lanshuyue August 26, 2026 03:12
abacus_fixer added 14 commits August 26, 2026 16:17
Group the previously interleaved public/protected sections of
Plus_U_Base into a single public block followed by a single
protected block. No member is moved between access levels and no
signature or implementation is changed; this only consolidates the
layout so that follow-up changes to access permissions are easier
to review.
Move all public data members of Plus_U_Base to protected so that
external code is forced to go through accessors. This tightens
encapsulation of the U values, the DFT+U configuration flags, the
occ_mat state flag, and the occupation matrices themselves.

New public getters added for the existing external read sites:
- get_uramping()       replaces dftu.uramping reads in chgmixing.cpp
- get_occ_mat_ctrl()   replaces dftu.occ_mat_ctrl reads in
                       setup_dftu_pw.cpp and setup_dftu_lcao.cpp
- use_yukawa()         replaces dftu.use_yukawa reads in dftu_output.cpp

The data member use_yukawa is renamed to use_yukawa_ so the getter
can keep the natural name; the 9 internal bare-name accesses in
dftu_base.cpp / dftu_lcao.cpp / dftu_tools.cpp / dftu_yukawa.cpp
are updated accordingly.

External write access is limited to the unit-test fixture
DFTUTest::SetUp, which writes u_current, orbital_corr and resizes
occ_mat directly. Rather than exposing setters for these one-off
test scenarios, DFTUTest is declared as a friend of Plus_U_Base.

gtest TEST_F derives DFTUTest_xxx_Test whose TestBody does not
inherit the friend declaration, so a small const helper
occ_mat_c(iat, spin, icc) is added to DFTUTest itself; the three
affected EXPECT_NEAR sites in dftu_lcao_test.cpp call it instead
of touching dftu.occ_mat directly.

Two hamilt::DFTU<OperatorLCAO<TK, TR>> methods
(cal_v_of_u in dftu_lcao_op.cpp, cal_force_stress in dftu_fs.cpp)
read this->dftu->u_current[T0]; both are switched to the existing
get_u_current(T0) accessor.
将 fold_dSR_gamma 和 folding_matrix_k 中的重复代码抽取为两个
private 成员函数,消除重复逻辑并统一行为。

新增辅助函数(声明于 dftu_lcao.h,实现于 dftu_folding.cpp):
- is_adjacent_pair(): 原子对相邻性判断(直接截断 + 三体重叠桥接)
- get_linear_index(): 按 ks_solver 选择行/列主序的本地矩阵索引

主函数精简效果:
- fold_dSR_gamma: 113 行 -> 85 行
- folding_matrix_k: 156 行 -> 109 行
- 邻居判断逻辑副本数: 2 -> 1
- 矩阵索引逻辑副本数: 2 -> 1(且修复了 G 版写死列主序的不一致)

顺手清理:
- 删除 fold_dSR_gamma 中未使用的 iat0、start0 声明(死代码)
- 删除 folding_matrix_k 中冗余的 atom1 重复声明
- 删除两个函数中不再需要的 dtau/dtau1/dtau2/tau0 局部变量
- 统一了 G 版的矩阵索引判断(原本硬编码列主序,现在和 K 版一致)

公共 API 与调用点:
- fold_dSR_gamma / folding_matrix_k / folding_matrix_k_new 签名不变
- 调用方 dftu_force.cpp、dftu_occup.cpp 无需修改

验证:
- python3 tools/03_code_analysis/agent_governance_check.py --staged
  结果: no findings
- g++ -std=c++11 -fsyntax-only(针对 dftu_folding.cpp、dftu_lcao.h、
  dftu_force.cpp、dftu_occup.cpp)均通过,无错误无警告
- 未做完整 CMake build 与 ctest 运行时测试,因当前环境无 build 目录
  (仅有预编译的 abacus_max_para 可执行文件)
…iter param

The CPU and GPU branches of cal_occ_pw (formerly L32-110 and L113-188)
were near-verbatim duplicates, differing only in the device template
parameter of OnsiteProjector and Psi. Merge them into a single template
member function accumulate_occ_one_k<Device>, with explicit
instantiation controlling CPU always compiled and GPU only under
__CUDA/__ROCM.

Also drop the iter parameter from cal_occ_pw signature since it was
never used in the function body; update the call site in
setup_dftu_pw.cpp accordingly.

Files changed:
- source/source_pw/module_pwdft/dftu_base.h
    - drop const int iter param from cal_occ_pw declaration
    - add template member declaration accumulate_occ_one_k<Device>
- source/source_pw/module_pwdft/dftu_pw.cpp
    - drop iter param from cal_occ_pw implementation
    - replace ~80 lines of CPU/GPU duplicate code with two template calls
    - add accumulate_occ_one_k template definition and explicit
      instantiations at end of file
- source/source_pw/module_pwdft/setup_dftu_pw.cpp
    - drop iter argument at call site

Effects:
- ~80 lines of duplicate code removed from dftu_pw.cpp
- CPU/GPU inner loops (iat/ib/m1/m2 + nspin==4 Pauli block assembly)
  now maintained in a single template implementation
- psi::Psi visibility confirmed transitively via onsite_proj.h

Pending verification (build delegated to user):
- make module_pwdft incremental build
- DFT+U ctest (e.g. MODULE_DFTU label)
- GPU build path (__CUDA/__ROCM) explicit instantiation
…tions

The five private member functions of Plus_U defined in dftu_folding.cpp
(is_adjacent_pair, get_linear_index, fold_dSR_gamma, folding_matrix_k,
folding_matrix_k_new) were pure folding helpers that only read data
members without relying on class invariants. Extract them into free
functions declared in the new dftu_folding.h, removing them from the
Plus_U class API in dftu_lcao.h.

The free functions live in namespace dftu_folding and take the data they
need (orb_cutoff, ks_solver, npol, gamma_only_local, nspin) as direct
parameters instead of receiving a Plus_U reference. Since all callers
are Plus_U member functions, they read this->member directly and pass
the values in, so no getters or friendship are required. The function
names drop the dftu_ prefix since the namespace already qualifies them
(call sites read dftu_folding::folding_matrix_k(...)). No Plus_U members
are deleted: three of the five (npol, gamma_only_local, nspin) are still
read by other Plus_U member functions, and the other two (orb_cutoff_,
ks_solver) are kept to avoid PARAM coupling or cascading signature
changes through the public API.

Also rename the include guard of dftu_lcao.h from DFTU_H to DFTU_LCAO_H
to match the filename (consistent with the new dftu_folding.h guard
DFTU_FOLDING_H); confirmed no other translation unit references DFTU_H.

Files changed:
- source/source_lao/module_dftu/dftu_folding.h (NEW)
    - declare 5 free function prototypes under __LCAO, wrapped in
      namespace dftu_folding
- source/source_lao/module_dftu/dftu_folding.cpp
    - rewrite 5 member functions as free functions in namespace
      dftu_folding, taking data params
    - member access (this->orb_cutoff_ etc.) replaced by parameters
    - internal calls use unqualified names within the namespace
- source/source_lao/module_dftu/dftu_lcao.h
    - remove the 5 private member function declarations
    - rename include guard DFTU_H -> DFTU_LCAO_H
    - member variables and public API unchanged
- source/source_lao/module_dftu/dftu_force.cpp
    - include dftu_folding.h; update 3 call sites in
      cal_force_k / cal_stress_k / cal_stress_gamma to
      dftu_folding::folding_matrix_k / dftu_folding::fold_dSR_gamma
- source/source_lao/module_dftu/dftu_occup.cpp
    - include dftu_folding.h; update 1 call site in cal_occup_m_k to
      dftu_folding::folding_matrix_k_new

Effects:
- Plus_U class fully decoupled from folding details; dftu_lcao.h no
  longer mentions any folding function
- No getters, no friend declarations, no member-variable deletion
- TITLE/timer labels ("Plus_U", "fold_dSR_gamma" etc.) intentionally
  preserved to keep profiling tooling stable

Verification (partial, full build delegated to user):
- cmake --build build_std_para --target dftu  ->  [100%] Built target dftu
- full abacus build and DFTU ctest pending
The nspin==4 VU+energy calculation was split into two loops:
- block 0 (is=0, charge channel) with diag_coeff on the diagonal
- blocks 1-3 (is=1..3, spin channels sigma_x/y/z) with zero diagonal

These two loops have identical structure and only differ in the diagonal
coefficient. Merge them into a single is=0..3 loop with
  diag = (is == 0) ? diag_coeff : 0.0

Also add an English comment explaining the Pauli-block layout: VU is
stored as 4 contiguous blocks per atom, where is=0 is the charge
channel (Hubbard U contributes diag_coeff*delta on the diagonal) and
is=1,2,3 are spin channels (sigma_x/y/z, no U diagonal term). The
occupation matrix occ_mat[...][0][0].c packs all 4 blocks contiguously.

Physics unchanged:
- Hubbard U acts only on the charge channel (is=0), so diag_coeff is
  still applied only there; spin channels remain with zero diagonal.
- energy_u accumulation formula is identical for all 4 blocks.

Effect: ~25 lines -> ~12 lines (plus comment), removing the artificial
block-0 vs block-1-3 symmetry breaking.

Verification:
- semantic equivalence checked by inspection (start=0 + diag_coeff
  for is=0 matches the original block-0 loop; start=is*size + 0.0
  for is=1..3 matches the original block-1-3 loop)
- existing test VUPotNspin4_PauliTransform (dftu_pw_test.cpp) covers
  the Pauli->spin transform that follows this loop
- full build and ctest delegated to user
cal_occ_pw was doing three conceptually distinct jobs: (1) accumulate
occ_mat from psi, (2) reduce occ_mat across k-pools and sync to
uom_array, (3) compute effective potential VU and DFT+U energy. The
function name only reflects job (1), and the mixing step plus VU/energy
computation were tangled together at the end.

Extract job (3) into a protected member function
compute_eff_pot_and_energy(cell). This isolates the VU+energy
calculation (which reads occ_mat and writes eff_pot_pw / energy_u) from
the occupation-matrix accumulation and reduction logic.

The new function assumes occ_mat has already been reduced across
k-pools (documented in its doxygen comment), matching the current
calling order in cal_occ_pw.

Also add a doxygen comment block on the new function documenting:
- preconditions (occ_mat accumulated and reduced)
- outputs (eff_pot_pw layout for nspin=1/2/4, energy_u formula)

Files changed:
- source/source_pw/module_pwdft/dftu_base.h
    - add protected member declaration compute_eff_pot_and_energy(cell)
- source/source_pw/module_pwdft/dftu_pw.cpp
    - replace ~95 lines of VU+energy code in cal_occ_pw with a single call
    - add compute_eff_pot_and_energy definition containing the moved code
    - add doxygen comment on the new function

Effects:
- cal_occ_pw body shrinks from ~175 lines to ~80 lines (orchestration)
- VU+energy logic is now a self-contained unit that can be tested and
  evolved independently
- no behavior change: same code, same order, just moved

Verification:
- make module_pwdft incremental build passed (verified by user)
- DFT+U ctest not yet run (delegated to user)
…l_occ_pw

cal_occ_pw's middle section (formerly L42-L91) did two distinct jobs in
a single per-atom loop:
  (1) reduce occ_mat across k-pools (MPI AllReduce)
  (2) copy occ_mat to uom_array for mixing (plain data shuffle)

These have different natures (parallel communication vs local copy)
and interleaving them in one loop body made both harder to read. Split
them into two protected member functions so each is self-contained.

The new functions:
- reduce_occ_mat(cell): sums per-pool occ_mat contributions across pools.
  nspin-aware: nspin=1 reduces one channel, nspin=2 reduces two, nspin=4
  reduces all 4 Pauli blocks in one shot.
- sync_occ_to_uom(cell): flattens occ_mat into uom_array for mixing.
  nspin=2 uses the split layout [all_up | all_dn]. The uom_array.size()==0
  guard is hoisted to an early return at the function entry (equivalent
  to the previous in-loop check, but clearer).

Behavior unchanged: same code, same order
(reduce -> sync -> mixing -> compute_eff_pot_and_energy).

Note: GlobalV::NPROC_IN_POOL is still referenced inside reduce_occ_mat.
Isolating it there is a step toward removing the global dependency, but
the actual de-globalization is deferred to a separate governance PR.

Files changed:
- source/source_pw/module_pwdft/dftu_base.h
    - add protected declarations for reduce_occ_mat / sync_occ_to_uom
- source/source_pw/module_pwdft/dftu_pw.cpp
    - replace ~50 lines in cal_occ_pw with two calls
    - add reduce_occ_mat / sync_occ_to_uom definitions (code moved as-is)
    - add doxygen comments documenting nspin layout per function

Effects:
- cal_occ_pw body now ~30 lines of pure orchestration
- reduce and copy logic each isolated, nspin-aware layout documented
- existing test MultiAtomSplitLayout_Nspin2 (dftu_pw_test.cpp) covers
  the nspin=2 split layout used by sync_occ_to_uom

Verification:
- make module_pwdft incremental build passed (verified by user)
- DFT+U ctest not yet run (delegated to user)
Step 4a of the dftu_pw decoupling plan. Create a new header dftu_pw.h
declaring free functions in namespace dftu_pw, so the DFT+U PW kernels
can be unit-tested directly without going through Plus_U_Base.

First function: pauli_to_spin_basis(vu, m_size). This performs the
Pauli-to-spin-basis transform on VU for nspin==4, previously inlined
in compute_eff_pot_and_energy. The function is pure (no access to
Plus_U_Base members): it takes a raw std::complex<double>* pointer to
the per-atom VU block and m_size.

Files changed:
- source/source_pw/module_pwdft/dftu_pw.h (new)
    - declare namespace dftu_pw
    - declare pauli_to_spin_basis with doxygen comment documenting the
      4 Pauli blocks layout and the transform formula
- source/source_pw/module_pwdft/dftu_pw.cpp
    - include dftu_pw.h
    - replace ~18 lines of inlined Pauli transform in
      compute_eff_pot_and_energy with a single call
      dftu_pw::pauli_to_spin_basis(vu_iat, m_size)
    - add namespace dftu_pw block at end of file with the function
      definition (code moved as-is from the inlined version)

Effects:
- compute_eff_pot_and_energy nspin==4 branch shrinks by ~17 lines
- pauli_to_spin_basis is now independently testable
- no behavior change: same transform, same memory layout

Verification:
- make module_pwdft incremental build passed (verified by user)
- existing test VUPotNspin4_PauliTransform (dftu_pw_test.cpp) covers
  the transform; step 4d will rewire it to call the real function
…unctions

Step 4b of the dftu_pw decoupling plan. Extract the VU+energy per-atom
loops from compute_eff_pot_and_energy into two free functions in
namespace dftu_pw:
- compute_vu_spinor: nspin==4 case, writes 4 Pauli blocks of VU and
  returns the energy_u increment; internally calls pauli_to_spin_basis
  to convert VU to spin basis in-place (same order as before).
- compute_vu_scalar: nspin==1/2 case, writes one spin channel's VU
  and returns the energy_u increment.

Both functions are pure: they take raw pointers (vu, occ) and scalars
(u_value, diag_coeff, weight_eu, m_size), no access to Plus_U_Base
members. compute_eff_pot_and_energy now computes per-atom offsets
(vu_iat, occ pointer, u_value) and delegates the inner loop.

Files changed:
- source/source_pw/module_pwdft/dftu_pw.h
    - declare compute_vu_spinor / compute_vu_scalar with doxygen
      comments documenting pointer semantics and return value
- source/source_pw/module_pwdft/dftu_pw.cpp
    - replace ~40 lines of inlined VU+energy loops in
      compute_eff_pot_and_energy with 1 (nspin==4) or 1-2 (nspin==1/2)
      calls to the free functions; energy_u accumulates the return values
    - add compute_vu_spinor / compute_vu_scalar definitions in the
      namespace dftu_pw block (code moved as-is from the inlined version)

Effects:
- compute_eff_pot_and_energy per-atom body shrinks from ~55 lines to
  ~20 lines of orchestration
- VU+energy kernels now independently testable
- no behavior change: same formula, same order (pauli_to_spin_basis
  still called after the 4 Pauli blocks are filled, inside compute_vu_spinor)

Verification:
- make module_pwdft incremental build passed (verified by user)
- existing tests VUPotNspin1_DiagonalLocale, VUPotNspin2_TwoSpinChannels,
  VUPotNspin4_PauliTransform (dftu_pw_test.cpp) cover the same formulas;
  step 4d will rewire them to call the real functions
…r free functions

Step 4c of the dftu_pw decoupling plan. Extract the per-atom-per-kpoint
occ_mat accumulation loops from accumulate_occ_one_k into two free
functions in namespace dftu_pw:
- accumulate_occ_spinor: nspin==4 case, accumulates 4 Pauli blocks from
  becp into occ_mat (npol=2 spinor layout).
- accumulate_occ_scalar: nspin==1/2 case, accumulates one spin channel
  from becp into occ_mat.

Both functions are pure: they take raw pointers (occ_mat_out, becp) and
scalars describing the per-atom/per-kpoint offsets, no access to
Plus_U_Base members. accumulate_occ_one_k now computes these offsets
and delegates the inner ib/m1/m2 loop.

Files changed:
- source/source_pw/module_pwdft/dftu_pw.h
    - add #include "source_base/matrix.h" (for ModuleBase::matrix wg param)
    - declare accumulate_occ_spinor / accumulate_occ_scalar with doxygen
      comments documenting pointer semantics and parameter meanings
- source/source_pw/module_pwdft/dftu_pw.cpp
    - replace ~45 lines of inlined accumulation loops in
      accumulate_occ_one_k with 1 call per branch (nspin==4 / nspin!=4)
    - add accumulate_occ_spinor / accumulate_occ_scalar definitions in
      the namespace dftu_pw block (code moved as-is)
    - use std::conj explicitly (no 'using namespace std')
    - drop unused 'is' parameter from accumulate_occ_scalar: the caller
      selects the spin channel by passing the corresponding occ_mat
      pointer (occ_mat[...][is].c); the function itself does not need is

Effects:
- accumulate_occ_one_k per-atom body shrinks from ~50 lines to ~15 lines
  of orchestration
- occ accumulation kernels now independently testable
- no behavior change: same becp indices, same Pauli-block packing,
  same weight handling

Verification:
- make module_pwdft incremental build passed (verified by user)
- existing tests LocaleAccumNspin12, LocaleAccumNspin4_PauliComponents
  (dftu_pw_test.cpp) cover the same formulas via arithmetic
  reimplementation; step 4d will rewire them to call the real functions
…pw.cpp

Step 4d-prerequisite of the dftu_pw decoupling plan. Enforce the
"header-implementation pairing" rule: the free-function declarations in
dftu_pw.h had their implementations stuffed at the bottom of dftu_pw.cpp
(alongside Plus_U_Base member functions), which is not a proper .h/.cpp
pair.

File structure after this commit:
- dftu_tools_pw.h      (renamed from dftu_pw.h)
    - declare 5 free functions in namespace dftu_pw
    - include guard DFTU_TOOLS_PW_H
- dftu_tools_pw.cpp    (new file)
    - implement the 5 free functions (pauli_to_spin_basis,
      compute_vu_spinor, compute_vu_scalar, accumulate_occ_spinor,
      accumulate_occ_scalar); depends only on <complex> and matrix.h
- dftu_cal_occ_pw.cpp  (renamed from dftu_pw.cpp via git mv)
    - Plus_U_Base member functions only (cal_occ_pw, accumulate_occ_one_k,
      reduce_occ_mat, sync_occ_to_uom, compute_eff_pot_and_energy)
    - includes dftu_tools_pw.h to call the free functions

namespace stays dftu_pw (not renamed) to avoid churning all call sites;
only filenames change.

Files changed:
- source/source_pw/module_pwdft/dftu_tools_pw.h (git mv from dftu_pw.h)
    - update include guard to DFTU_TOOLS_PW_H
- source/source_pw/module_pwdft/dftu_tools_pw.cpp (new)
    - body moved verbatim from the former dftu_pw.cpp namespace block
- source/source_pw/module_pwdft/dftu_cal_occ_pw.cpp (git mv from dftu_pw.cpp)
    - drop the namespace dftu_pw block (moved to dftu_tools_pw.cpp)
    - include "source_pw/module_pwdft/dftu_tools_pw.h" instead of dftu_pw.h
- source/source_pw/module_pwdft/CMakeLists.txt
    - replace dftu_pw.cpp with dftu_tools_pw.cpp + dftu_cal_occ_pw.cpp
- source/Makefile.Objects
    - replace dftu_pw.o with dftu_tools_pw.o + dftu_cal_occ_pw.o
- source/source_pw/module_pwdft/dftu_base.cpp
    - update the pointer comment to reflect new filenames

Effects:
- header/implementation properly paired for the free functions
- dftu_tools_pw.cpp has minimal dependencies, can be linked into
  unit tests without pulling in onsite_proj.h / parallel_reduce.h
- main implementation file (dftu_cal_occ_pw.cpp) retains its git history
  via git mv (rename similarity ~63%, above the 50% threshold)

Verification:
- make module_pwdft incremental build passed (verified by user)
- step 4d proper (rewire tests to call real functions) follows next
Step 4d of the dftu_pw decoupling plan. The 7 tests in dftu_pw_test.cpp
previously used arithmetic re-implementations of the VU/energy/occ
formulas, meaning they could not catch bugs in the real dftu_pw
implementations (test and production code were two independent copies).

Now that the free functions live in dftu_tools_pw.{h,cpp} with minimal
dependencies (only <complex> and matrix.h), the tests can link against
the real implementations directly.

Tests rewired:
- VUPotNspin1_DiagonalLocale      -> compute_vu_scalar
- VUPotNspin2_TwoSpinChannels     -> compute_vu_scalar (twice, up/down)
- VUPotNspin4_PauliTransform      -> pauli_to_spin_basis (in-place)
- EnergyNspin12_DiagonalLocale    -> compute_vu_scalar (check return value)
- EnergyNspin4_WithOffDiagonal    -> compute_vu_spinor  (check return value)
- LocaleAccumNspin12              -> accumulate_occ_scalar
- LocaleAccumNspin4_PauliComponents -> accumulate_occ_spinor

Tests kept as arithmetic (out of dftu_tools_pw scope):
- EnergyWeightsAllNspin, BecpIndexNspin12vs4 (pure constants/arithmetic)
- MultiAtomSplitLayout_Nspin2 (Plus_U_Base member layout)
- OnsitePsOpKernel_Nspin2_Npol1 (onsite_op.cpp kernel)

Files changed:
- source/source_lcao/module_dftu/test/dftu_pw_test.cpp
    - add includes: <vector>, source_base/matrix.h,
      source_pw/module_pwdft/dftu_tools_pw.h
    - replace inlined arithmetic loops with calls to the real free
      functions; expected values unchanged
    - VUPotNspin4_PauliTransform: m_size 3 -> 1 (the test only fills a
      single (m1,m2) pair; m_size=1 matches the data layout)
    - EnergyNspin4_WithOffDiagonal: pass diag_coeff=1.0 (the nspin==4
      value used in cal_occ_pw)
- source/source_lcao/module_dftu/test/CMakeLists.txt
    - add ../../../source_pw/module_pwdft/dftu_tools_pw.cpp to
      dftu_pw_test SOURCES so the real implementations are linked

Effects:
- tests now exercise the same code path as cal_occ_pw
- arithmetic re-implementations removed (~80 lines of duplicated logic)
- any future change to the free functions is automatically covered

Verification:
- make dftu_pw_test build passed (verified by user)
- ctest -R dftu_pw_test passed (verified by user)
…TU_LCAO namespace

Extract the 5 force/stress member functions of Plus_U from dftu_force.cpp into free functions declared in a new dftu_force.h header, mirroring the existing dftu_folding pattern. The top-level force_stress takes a Plus_U& parameter because it still calls Plus_U::cal_VU_pot_mat_real/complex (defined in dftu_tools.cpp); the four inner functions (cal_force_k, cal_stress_k, cal_force_gamma, cal_stress_gamma) are fully decoupled and take their dependencies (npol, nlocal, ks_solver, orb_cutoff, iatlnmipol2iwt, orbital_corr) as explicit parameters, so they are unit-testable without a Plus_U instance.

Consolidate the two module-local namespaces dftu_force and dftu_folding into a single namespace DFTU_LCAO. The project-wide hamilt:: namespace (used by dftu_lcao_op.h/cpp, dftu_fs.cpp, dftu_lcao_op_legacy.h/cpp for operator classes inheriting from hamilt::OperatorLCAO<T>) is left untouched to avoid breaking the ABACUS hamilt operator framework. All callers updated: dftu_force:: and dftu_folding:: prefixes are replaced by DFTU_LCAO:: in dftu_force.cpp, dftu_occup.cpp, and force_stress_lcao.cpp; TITLE/timer/WARNING_QUIT identifier strings in dftu_force.cpp are renamed accordingly.

Plus_U_Base gains two public read-only accessors (get_iatlnmipol2iwt, get_orbital_corr_vec) so the free functions can receive the lookup table and orbital_corr vector as parameters. Plus_U gains 8 public getters (get_paraV, get_npol, get_nlocal, get_ks_solver, get_orb_cutoff, is_gamma_only_local, is_cal_force, is_cal_stress) and cal_VU_pot_mat_real/complex are promoted from private to public so the free function force_stress can call them via the Plus_U& parameter. get_onebody_eff_pot remains private.

Verification performed:
- cmake --build build_max_para_test -j 4: clean build, no errors, no warnings
- ./build_max_para_test/abacus_max_para --version: ABACUS version v3.11.0-beta8
- OMP_NUM_THREADS=1 ctest --test-dir build_max_para_test -R '^dftu_(pw_test|core_test|operator_test|lcao_test)$': 4/4 pass
- python3 tools/03_code_analysis/agent_governance_check.py --staged: only warnings (header deps, test evidence, doc sync), all Exception allowed: yes, no blockers
- 17_DS_DFTU: 45/50 sub-cases pass; the 5 PW Double-Spin failures are pre-existing baseline (verified via git stash + rerun with identical deviations), unrelated to this refactor
- dft_plus_u==2 + force/stress path remains disabled per the existing comment in force_stress_lcao.cpp:429-454; not end-to-end tested.
abacus_fixer added 9 commits August 26, 2026 16:49
Remove unused #include directives across 12 files in
source/source_lcao/module_dftu/. Each removal was verified by
symbol-usage grep against the file body (excluding the include lines
themselves) and by compiling the dftu + hamilt_lcao CMake targets.

Removed includes per file:
- dftu_lcao.cpp: parameter.h, constants.h, global_function.h,
  inverse_matrix.h, memory_recorder.h, magnetism.h, charge.h and
  unused <cstdint>/<cmath>/<cstdio>/<cstring>/<fstream>/<iomanip>/
  <iostream>/<sstream>; add focused matrix.h (for
  ModuleBase::matrix::operator() via occ_mat), tool_quit.h, tool_title.h
- dftu_folding.cpp: parameter.h, hcontainer.h, hcontainer_funcs.h
- dftu_force.cpp: parameter.h, constants.h, inverse_matrix.h,
  elecstate_lcao.h, magnetism.h, charge.h, <cmath>, <fstream>,
  <iomanip>, <iostream>, <sstream>, <stdio.h>, <string.h>
- dftu_hamilt.cpp: parameter.h
- dftu_lcao_op.cpp: hcontainer_funcs.h, <unordered_set>
- dftu_lcao_op_legacy.cpp: dftu_lcao.h (already provided by its own .h)
- dftu_occup.cpp: parameter.h
- dftu_tools.cpp: timer.h (no direct ModuleBase::timer use), parameter.h
- dftu_yukawa.cpp: parameter.h, <complex>, <fstream>, <iomanip>,
  <iostream>, <sstream>, <cstdio>, <cstring>
- dftu_lcao.h: charge_mixing.h (still provided transitively via
  dftu_base.h), force_stress_arrays.h (not directly used here)
- dftu_lcao_op.h: density_matrix.h (not directly used here)
- dftu_lcao_op_legacy.h: timer.h (not directly used here)

Note: scalapack_connector.h was kept in dftu_force.cpp / dftu_hamilt.cpp
/ dftu_occup.cpp -- these files call ScalapackConnector::gemm.

Verification: OMP_NUM_THREADS=1 make -C build_std_para dftu hamilt_lcao
=> EXIT=0, no errors, no warnings. Full abacus build deferred to user;
external modules that include dftu_lcao.h and use Charge_Mixing
(chgmixing.cpp, esolver_ks.cpp/h) should still resolve via
dftu_lcao.h -> dftu_base.h -> charge_mixing.h.
…_LCAO

Rename for consistency with the DFTU_LCAO free-function convention
established in dftu_force.h, and to disambiguate from the KS effective
potential V_eff:

* Plus_U::cal_eff_pot_mat_{complex,real} -> DFTU_LCAO::pot_uterm_{complex,real}
  Extracted from member functions to free functions taking Plus_U&.
  Internal this->paraV / this->nlocal replaced with dftu.get_paraV()
  / dftu.get_nlocal(); this->cal_VU_pot_mat_* replaced with
  dftu.pot_onsite_*.
* Plus_U::cal_VU_pot_mat_{complex,real} -> Plus_U::pot_onsite_{complex,real}
  Member, renamed only. The on-site Hubbard potential V_{mm'}.
* Plus_U::cal_occup_m_{k,gamma} -> Plus_U::cal_occ_mat_{k,gamma}
  Member, renamed only.
* dftu_cal_occup_m -> DFTU_LCAO::cal_occ_mat
  Moved into namespace DFTU_LCAO and renamed.

R-space variants Plus_U::cal_eff_pot_mat_R_double and
Plus_U::cal_eff_pot_mat_R_complex_double are intentionally left
untouched; they bind to the sparse R-space Hamiltonian path in
spar_u.cpp (force/stress) and will be addressed in a follow-up.

Timer and TITLE strings inside dftu_hamilt.cpp updated to match the
new function names for runtime log consistency.

No behavior change; pure rename + structural relocation.

Test directory source/source_lcao/module_dftu/test/ has no
references to any renamed function, so no test update is required.

Verification:
- rg confirms zero leftover references to the old names across the
  whole codebase, except the intentionally-preserved R-space variants.
- python3 tools/03_code_analysis/agent_governance_check.py --staged
  passes with only 2 PR-level WARNINGs (test/docs sync reminder),
  both addressed by this message.
…u_hamilt.h / dftu_occup.h

Previously dftu_lcao.h bundled the DFTU_LCAO namespace free-function
declarations together at the bottom of the Plus_U class header. Split
them into two focused headers mirroring dftu_force.h convention:

* dftu_hamilt.h: DFTU_LCAO::pot_uterm_complex / pot_uterm_real
  (implemented in dftu_hamilt.cpp)
* dftu_occup.h: DFTU_LCAO::cal_occ_mat template
  (specialized in dftu_lcao.cpp, delegates to Plus_U::cal_occ_mat_{k,
  gamma} in dftu_occup.cpp)

dftu_lcao.h no longer auto-includes the two new headers; each .cpp
that actually needs them includes the relevant one explicitly:

* dftu_hamilt.cpp      -> dftu_hamilt.h  (defines pot_uterm_*)
* dftu_lcao_op_legacy.cpp -> dftu_hamilt.h  (calls pot_uterm_*)
* dftu_lcao.cpp        -> dftu_occup.h  (specializes cal_occ_mat)
* setup_dftu_lcao.cpp  -> dftu_occup.h  (calls cal_occ_mat)

Both new headers are self-contained: they forward-declare
'class Plus_U;' instead of including dftu_lcao.h, so there is no
include cycle.

Plus_U member function declarations (cal_eff_pot_mat_R_*,
cal_occ_mat_{k,gamma}, pot_onsite_*, etc.) remain in dftu_lcao.h
because C++ does not support partial classes.

Verification:
- rg confirms the two new headers are only included by the four .cpp
  files listed above, with no remaining references via dftu_lcao.h.
- python3 tools/03_code_analysis/agent_governance_check.py --staged
  passes with only PR-level WARNINGs (test/docs sync reminder), all
  addressed by this message.
- The 'Confirm the declaration requires this include' reviewer note
  applies to the four added includes; all four are required because
  each .cpp either defines or calls the declared function and needs
  the full signature, not a forward declaration.
…ee functions

The two pot_uterm_{complex,real} functions were extracted into the
DFTU_LCAO namespace in a previous commit, but their ModuleBase::TITLE
and timer::start/end calls still used 'Plus_U' as the owner string.
This made the runtime log misleading: the entries appeared to come
from a Plus_U member function while they are actually DFTU_LCAO
namespace free functions.

Update the first TITLE/timer argument from 'Plus_U' to 'DFTU_LCAO'
for all 6 calls in dftu_hamilt.cpp so the log owner matches the
actual namespace hosting the function.

Plus_U member functions in dftu_tools.cpp (pot_onsite_*),
dftu_occup.cpp (cal_occ_mat_*), and dftu_lcao.cpp keep 'Plus_U'
as their TITLE/timer owner, since those are still class members.

OperatorDFTU::contributeHk in dftu_lcao_op_legacy.cpp keeps
'OperatorDFTU' as the owner, since it is a hamilt::OperatorDFTU
member, not a Plus_U member nor a DFTU_LCAO free function.

Verification:
- rg confirms 6 TITLE/timer calls in dftu_hamilt.cpp now use
  'DFTU_LCAO' as owner.
- python3 tools/03_code_analysis/agent_governance_check.py --staged
  passes with no findings.
…cross LCAO and PW bases

The codebase mixed variable naming conventions for the same physical
quantities: uppercase 'VU' (LCAO base) and lowercase 'vu' (PW base)
for the Hubbard on-site potential, 'eff_pot' for the LCAO-basis
U-term effective potential, and 'eff_pot_pw' for the PW counterpart.
This commit unifies them to 'pot_onsite' and 'pot_uterm[_pw]',
matching the function-name conventions introduced earlier.

Variable renames:
* VU / vu             -> pot_onsite  (Hubbard on-site potential V_{mm'})
* eff_pot             -> pot_uterm   (LCAO-basis U-term effective potential)
* eff_pot_pw          -> pot_uterm_pw (PW-basis U-term effective potential,
  Plus_U_Base member plus accessor names get_eff_pot_pw_* / get_size_eff_pot_pw_*
  get_pot_uterm_pw_* / get_size_pot_uterm_pw_*)
* eff_pot_pw_index    -> pot_uterm_pw_index
* VU_tmp / vu_tmp     -> pot_onsite_tmp
* vu_iat / vu_iat1    -> pot_onsite_iat / pot_onsite_iat1
* vu_ptr / vu_size / vu_host / vu_device -> pot_onsite_*
* vu_begin_iat        -> pot_onsite_begin_iat
* rho_VU              -> rho_pot_onsite
* dm_VU_dSm           -> dm_pot_onsite_dSm

Function renames (per user request 'names containing vu should also be renamed'):
* transfer_vu         -> transfer_pot_onsite
* cal_v_of_u          -> cal_pot_onsite
* compute_vu_spinor   -> compute_pot_onsite_spinor
* compute_vu_scalar   -> compute_pot_onsite_scalar
* cal_vu (test helper) -> cal_pot_onsite
* local static 'compute_vu' in dftu_core_test -> compute_pot_onsite

Test fixture renames:
* VUPotentialTest     -> PotOnsitePotentialTest
* VUPot* test names   -> PotOnsitePot*
* OffDiagonalVU       -> OffDiagonalPotOnsite

Scope (38 files):
* LCAO base: source/source_lcao/module_dftu/ (dftu_hamilt.{h,cpp},
  dftu_tools.cpp, dftu_force.cpp, dftu_fs.cpp, dftu_lcao.{h,cpp},
  dftu_lcao_op.{h,cpp}, dftu_lcao_op_legacy.cpp, test/dftu_*_test.cpp)
* PW base: source/source_pw/module_pwdft/ (dftu_base.{h,cpp},
  dftu_cal_occ_pw.cpp, dftu_tools_pw.{h,cpp}, op_pw_proj.cpp,
  onsite_proj.cpp, onsite_proj_tools.{h,cpp},
  kernels/{onsite,force,stress}_op.{h,cpp},
  kernels/cuda/{onsite,force,stress}_op.cu,
  kernels/rocm/{onsite,force,stress}_op.hip.cu,
  kernels/test/onsite_op_test.cpp)
* Cross-module callers: source/source_estate/module_charge/chgmixing.cpp
  and charge_mixing.cpp (eff_pot_pw -> pot_uterm_pw),
  source/source_esolver/esolver_ks_lcao.cpp (comment).

Out of scope (intentionally untouched):
* Non-DFTU files that happen to contain 'vu' as LAPACK/FORTRAN parameter
  names (lapack_connector.h, scalapack_connector.h, gather_math_lib_info.cpp,
  td_current_io_comm.cpp, base/module_container/*, etc.) -- these 'vu'
  strings are LAPACK interface parameters, not Hubbard potential, and
  renaming them would be incorrect.
* Plus_U_Base member 'uom_array' / 'uom_save' (occupation-related,
  different physical quantity, not renamed here).

Verification:
* rg '\bVU\b|\bvu\b|\beff_pot\b|cal_v_of_u|transfer_vu|compute_vu|eff_pot_pw'
  over source/source_lcao/module_dftu/, source/source_pw/module_pwdft/,
  chgmixing.cpp, charge_mixing.cpp, esolver_ks_lcao.cpp returns no matches.
* python3 tools/03_code_analysis/agent_governance_check.py --staged passes
  with only PR-level WARNINGs (test/docs sync reminder).

Test/Doc plan:
* Tests: pure rename, no semantic change; existing tests in
  source/source_lcao/module_dftu/test/ and
  source/source_pw/module_pwdft/kernels/test/ updated in lock-step.
* Docs: no INPUT parameter or user-facing behavior change; no
  documentation update required.
…missed in previous commit

The previous rename commit (3ac7790) used rg with word-boundary
patterns, which missed identifiers like 'vu_device', 'vu_begin_iat',
'vu_begin_iat0', 'vu_begin', 'vu_in' -- because underscore is a word
character, so '\bvu\b' does not match 'vu' followed by '_'.

Compile failure:
  op_pw_proj.cpp:47: error: 'class hamilt::OnsiteProj<...>' has no
  member named 'pot_onsite_device'
  op_pw_proj.cpp:263: error: ... has no member named 'pot_onsite_device'

This was because the member declaration in op_pw_proj.h:75 was still
'vu_device' while op_pw_proj.cpp called this->pot_onsite_device.

Files fixed (loose-pattern search 'vu' as substring):
* source/source_pw/module_pwdft/op_pw_proj.h:
  - vu_begin_iat -> pot_onsite_begin_iat (member)
  - vu_device    -> pot_onsite_device (member)
* source/source_pw/module_pwdft/op_pw_proj.cpp:
  - vu_begin_iat, vu_begin_iat0, vu_begin -> pot_onsite_*
* source/source_lcao/module_dftu/dftu_fs.cpp:
  - vu_in -> pot_onsite_in (function parameter, 14 occurrences)

Verification:
- rg 'vu' (substring, no word boundary) over DFTU scope returns no
  matches.
- python3 tools/03_code_analysis/agent_governance_check.py --staged
  passes with no findings.
… names

Commit 5ac6ca7 claimed 'R-space versions cal_eff_pot_mat_R_* kept
as-is for follow-up' in its message, but actually renamed the
function definitions in dftu_hamilt.cpp to cal_pot_uterm_mat_R_*.
The member declarations in dftu_lcao.h were not renamed, causing
header/implementation mismatch:

  dftu_hamilt.cpp:127: error: no declaration matches
    'void Plus_U::cal_pot_uterm_mat_R_double(int, double*, double*, int)'
  dftu_hamilt.cpp:157: error: no declaration matches
    'void Plus_U::cal_pot_uterm_mat_R_complex_double(...)'

Restore the original names cal_eff_pot_mat_R_double and
cal_eff_pot_mat_mat_R_complex_double in dftu_hamilt.cpp so they match
the declarations in dftu_lcao.h:80,82 and the call sites in
spar_u.cpp:76,195.

The R-space functions will be renamed in a follow-up commit that
also updates spar_u.cpp and the header in lock-step.

Verification:
- rg 'cal_pot_uterm_mat_R' returns no matches (no stale callers).
- rg 'cal_eff_pot_mat_R' shows consistent use across
  dftu_lcao.h (declarations), dftu_hamilt.cpp (definitions),
  spar_u.cpp (call sites).
… docs

The DFTU tests and input parameter docs used 'locale' as a variable
and annotation name for the occupation matrix. This is confusing
because 'locale' is also a C++ standard library concept
(std::locale, localization). The actual physical quantity is the
occupation matrix n_{mm'}, so rename to 'occ_mat' for clarity and
consistency with the existing Plus_U_Base member 'occ_mat' and
'get_occ_mat()' accessor.

Renames (variable scope limited to tests + comments):
* dftu_pw_test.cpp: locale_c / locale_up / locale_dn -> occ_mat_c /
  occ_mat_up / occ_mat_dn (flattened occupation matrix passed to
  compute_pot_onsite_scalar); comments updated.
* dftu_core_test.cpp: function parameters locale_up / locale_dn ->
  occ_mat_up / occ_mat_dn (Matrix2D per-atom occupation matrices).
* dftu_lcao_op.cpp:192 comment 'Reads locale ...' -> 'Reads occ_mat ...'
* input_parameter.h:115 annotation 'mix locale' -> 'mix occ_mat'
  (parameter name 'mixing_dftu' unchanged, no INPUT behavior change).
* read_inp_estruc.cpp:760 annotation 'mix locale' -> 'mix occ_mat'

Out of scope (intentionally untouched):
* Plus_U_Base::occ_mat member -- already named 'occ_mat', no change.
* Non-DFTU 'locale' occurrences (input_parameter.h is touched only for
  the DFT+U annotation line).

Verification:
- rg '\blocale\b' over DFTU scope + module_parameter returns no matches.
- python3 tools/03_code_analysis/agent_governance_check.py --staged
  passes with no findings.

Test/Doc plan:
* Tests: pure rename of test-local variables and comments; no
  semantic change; existing tests in dftu_pw_test.cpp and
  dftu_core_test.cpp updated in lock-step.
* Docs: no INPUT parameter name change (still 'mixing_dftu'); only
  the annotation string is reworded for clarity. parameters.yaml
  and input-main.md do not mention 'locale' so no update required
  there.
- dftu_base.h: drop klist.h (UnitCell from unitcell.h, matrix via charge_mixing.h)
- dftu_base.cpp: drop <cmath>/<complex>/<iomanip> (no usage)
- dftu_output.cpp: drop <cstring>/<sstream> (no usage); replace parameter.h with global_variable.h (GlobalV source, PARAM unused)
- dftu_cal_occ_pw.cpp: replace parameter.h with global_variable.h (GlobalV source, PARAM unused)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

DFT+U Issues related to DFT plus U function Refactor Refactor ABACUS codes The Absolute Zero Reduce the "entropy" of the code to 0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant