Skip to content

Feature: Symmetry for DFT+U - #7969

Open
maki49 wants to merge 11 commits into
deepmodeling:developfrom
maki49:dftu-sym
Open

maki49 wants to merge 11 commits into
deepmodeling:developfrom
maki49:dftu-sym

Conversation

@maki49

@maki49 maki49 commented Sep 14, 2026

Copy link
Copy Markdown
Collaborator

Feature: DFT+U Symmetry

Fix #7950. The test results of the case provided by @liusss324 before and after this fix are as follows:

  IBZ-k Amag E/eV steps to converge
sym-1 324 1.23 -2343.98580 31
sym1 37 1.19 -2344.17853 51
sym1-fixed 37 1.23 -2343.98447 32

@dyzheng The symmetrization is done by rotating DM(k) before the Fourier transformation instead of rotating DM(R), just for the easier implementation.

Refactor

  • Move the EXX-irrelavant part of symmetry_rotation into module_symmetry and remove its LCAO+LibRI depencence (to make DFT+U not depend on module_ri), while EXX-relevant part remaining in module_ri.
  • nspin-as-parameter: remove the PARAM dependence in symmetry_rotation

Copilot AI lite review requested due to automatic review settings September 14, 2026 14:26

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Unresolved build, k-point handling, cache, and symmetry-restoration issues block approval.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Adds crystal-symmetry support for LCAO DFT+U by restoring full-BZ density matrices and accumulating occupations over k-point stars.

Changes:

  • Adds symmetry-based density and occupation-matrix restoration.
  • Defers spin-expanded k-point allocation.
  • Updates two DFT+U regression cases and references.
File summaries
File Summary
tests/17_DS_DFTU/04_LCAO_DFTU_S4_XY/result.ref Updates noncollinear symmetry results.
tests/17_DS_DFTU/04_LCAO_DFTU_S4_XY/INPUT Enables symmetry for the test case.
tests/17_DS_DFTU/03_LCAO_DFTU_S2_Z/result.ref Updates collinear symmetry results.
tests/17_DS_DFTU/03_LCAO_DFTU_S2_Z/INPUT Enables symmetry for the test case.
source/source_lcao/module_dftu/dftu_nao_op.h Adds k-vector and symmetry-rotation state.
source/source_lcao/module_dftu/dftu_nao_op.cpp Restores full-BZ density matrices.
source/source_lcao/module_dftu/dftu_nao_occ.cpp Accumulates occupations across k-point stars.
source/source_lcao/hamilt_lcao.cpp Supplies k-point data to DFT+U operators.
source/source_cell/reciprocal_grid.cpp Changes reciprocal-grid allocation.
source/source_cell/klist.cpp Defers spin expansion and changes k-point resizing.
Review details

Suppressed comments (9)

source/source_cell/klist.cpp:453

  • renew() also resizes ReciprocalGrid::kvec_c_full. At this point nkstot is the symmetry-reduced global count, while kvec_c_full must retain the original nkstot_nospin mesh; in MPI, using nkstot additionally allocates global-sized local containers on every rank. In a serial symmetry+LibRI run this truncates kvec_c_full, so later consumers such as Ewald_Vq iterate to nkstot_nospin past its end. Resize only the local spin-expanded arrays here and leave kvec_c_full untouched.
    this->renew(this->nkstot * this->spin_mult);

source/source_cell/klist.cpp:398

  • Rule: Preserve the established contract of public k-point readers.\nSeverity: error\nLocation: source/source_cell/klist.cpp:398\nReason: The same regression affects line-interpolated input: KlistTest.ReadKpointsLineCartesian directly calls read_kpoints() with spin_mult=2 and expects 102 entries, but this path now allocates only the 51 input points because set_kup_and_kdw() is not called.\nSuggested action: Preserve the spin-sized allocation for this direct reader path, or update the API/callers and the existing regression test together with an explicit expansion step.\nException: not allowed
    this->renew(this->nkstot); // mohan fix bug 2009-09-01; spin_mult doubling done later by set_kup_and_kdw()

source/source_lcao/module_dftu/dftu_nao_occ.cpp:53

  • Rule: Do not introduce new cross-layer control through GlobalV, GlobalC, or PARAM.
    Severity: error
    Location: source/source_lcao/module_dftu/dftu_nao_occ.cpp:53
    Reason: This adds a new PARAM.inp.nspin dependency inside the rotation helper even though cal_occ_mat_k already obtains the effective occupation-matrix spin count locally.
    Suggested action: Pass nspin (or an explicit nspin == 4 flag) into accumulate_occ_over_kstar and remove the new global read.
    Exception: not allowed
            if (PARAM.inp.nspin == 4)

source/source_lcao/module_dftu/dftu_nao_occ.cpp:159

  • ik is the index local to the current k-point pool, so it does not identify the same IBZ point on every MPI rank. For a pool whose startk_pool is nonzero, this modulo maps a local point to the wrong kstars entry and rotates/accumulates the wrong density matrix. Use the existing local-to-global mapping kv.ik2iktot[ik] before reducing modulo the IBZ star count.
            const int ik_ibz = ik % static_cast<int>(kv.kstars.size());

source/source_lcao/module_dftu/dftu_nao_occ.cpp:104

  • Checking only symm_flag == 1 does not guarantee that kstars exists: K_Vectors::set() skips IBZ reduction when berry_phase is enabled, so this branch can reach line 159 with an empty vector and divide by zero. Base the decision on actual k-star data (and apply the same guard in the operator path), or fall back to unsymmetrized accumulation when no IBZ expansion was built.
    const bool dftu_spacegroup_symmetry = (ModuleSymmetry::Symmetry::symm_flag == 1);

source/source_lcao/module_dftu/dftu_nao_occ.cpp:110

  • The vector is pool-local when mpi_k completes; the later global resize only adds zero padding and does not populate nonlocal entries. cal_Ms iterates the global kv.kstars and reads kv.kvec_d[ik_ibz], so with KPAR > 1 this old-DFT+U path also constructs rotation matrices for nonlocal stars from zero k-vectors. Use a gathered/global k-vector view or a correct local-to-global mapping.
        dftu_occ_symrot.cal_Ms(kv, ucell, *pv);

source/source_lcao/module_dftu/dftu_nao_op.cpp:146

  • The vector is pool-local when mpi_k completes; the new global resize at line 453 only adds zero padding and does not populate the nonlocal entries. cal_Ms iterates the global kv.kstars and reads kv.kvec_d[ik_ibz], so with KPAR > 1 it builds rotation matrices for nonlocal stars from zero k-vectors. Use a gathered/global k-vector view or a correct local-to-global mapping rather than relying on the padding.
            this->symrot_.cal_Ms(*this->kv_, *this->ucell, *pv);

tests/17_DS_DFTU/03_LCAO_DFTU_S2_Z/INPUT:18

  • Rule: Document INPUT behavior changes in both user-facing parameter references.\nSeverity: warning\nLocation: tests/17_DS_DFTU/03_LCAO_DFTU_S2_Z/INPUT:18\nReason: This change makes existing symmetry=1 produce different DFT+U magnetic results, but the PR does not update docs/parameters.yaml or docs/advanced/input_files/input-main.md, nor explain why those synchronized documentation updates are unnecessary. Users need the documented support/limitations for this combination.\nSuggested action: Update both symmetry parameter references with the DFT+U magnetic behavior, or add a clear no-update rationale to the PR.\nException: human approval required
symmetry    1

tests/17_DS_DFTU/04_LCAO_DFTU_S4_XY/INPUT:19

  • Rule: Focused tests for feature changes
    Severity: warning
    Location: tests/17_DS_DFTU/04_LCAO_DFTU_S4_XY/INPUT:19
    Reason: This nspin=4 regression case remains commented out in tests/17_DS_DFTU/CASES_CPU.txt, so the changed input/reference does not exercise the new symmetry path in CI; the enabled case covers only nspin=2.
    Suggested action: Add or enable a stable nspin=4 symmetry regression, or document a human-approved rationale and follow-up for the missing coverage.
    Exception: human approval required
symmetry    1
  • Files reviewed: 10/10 changed files
  • Comments generated: 7
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread source/source_cell/klist.cpp Outdated
Comment thread source/source_lcao/module_dftu/dftu_nao_occ.cpp Outdated
Comment thread source/source_lcao/module_dftu/dftu_nao_occ.cpp Outdated
Comment thread source/source_lcao/module_dftu/dftu_nao_op.cpp Outdated
Comment thread source/source_lcao/module_dftu/dftu_nao_op.cpp
Comment thread source/source_lcao/module_dftu/dftu_nao_op.cpp Outdated
Comment thread source/source_lcao/module_dftu/dftu_nao_op.h Outdated
@maki49
maki49 marked this pull request as draft September 14, 2026 15:31
@mohanchen mohanchen added Features Needed The features are indeed needed, and developers should have sophisticated knowledge DFT+U Issues related to DFT plus U function Refactor Refactor ABACUS codes labels Sep 15, 2026
maki49 added a commit to maki49/abacus-develop that referenced this pull request Sep 15, 2026
…xing, empty kstars, make_unique)

- accumulate_occ_over_kstar: take nspin as a parameter instead of reading
  the global PARAM.inp.nspin, matching the existing local nspin already
  computed in cal_occ_mat_k from dftu.occmat().nspin().
- cal_occ_mat_k: map the pool-local k index to the global one via
  kv.ik2iktot before reducing modulo kv.kstars.size(), since ik was only
  valid as a direct kstars index when KPAR==1.
- Guard the symmetry-restoration branches (contributeHR and cal_occ_mat_k)
  on kv.kstars being non-empty, since symm_flag==1 alone does not
  guarantee kstars was built (e.g. berry_phase skips IBZ reduction).
- Replace std::make_unique (C++14) with new + unique_ptr::reset (C++11).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019omhQohPCePyJnLiWnG6Fa
maki49 added a commit to maki49/abacus-develop that referenced this pull request Sep 15, 2026
Addresses the remaining PR deepmodeling#7969 review items:

- Build: DFT+U (built unconditionally) was pulling in
  source_lcao/module_ri/module_exx_symmetry/symm_rotation.h, which
  requires LibRI (module_exx_symmetry is entirely gated behind
  ENABLE_LIBRI) -- breaking any build with LibRI disabled.
  - Moved irreducible_sector.{h,cpp}/irred_sec_bvk.cpp to
    source_cell/module_symmetry/ (unconditionally built "symmetry"
    library): they have no RI::Tensor dependency at all, just were
    bundled into the wrong CMake target. TCdouble switched from
    Abfs::Vector3_Order<double> (module_ri) to plain
    ModuleBase::Vector3<double> -- its ordering was never actually used.
  - Extracted the LibRI-independent k-space AO-rotation machinery
    (cal_Ms/restore_dm/rot_matrix_ao/Wigner-D math/cal_rotmat_Slm/...)
    into a new ModuleSymmetry::Symmetry_rotation_k base class in the
    same module, storing rotmat_Slm_ as ModuleBase::ComplexMatrix
    instead of RI::Tensor. EXX's own Symmetry_rotation (module_ri) now
    inherits from it and keeps only what genuinely needs RI::Tensor
    (restore_HR, rotate_atompair_serial/parallel, ...); a small
    ComplexMatrix->RI::Tensor adapter bridges the two remaining call
    sites in symm_rotation_r.hpp. DFT+U now includes only
    symm_rotation_k.h, no module_ri header.
  - Verified against a LibRI-enabled build (build_libri/, LIBRI_DIR
    pointed at the local checkout): module_exx_symmetry builds clean,
    and all 9 MODULE_RI_EXX_SYMMETRY_rotation unit tests pass, matching
    their pre-refactor reference values bit-for-bit.
  - Fixed a handful of test CMakeLists that linked "symmetry" but not
    "parameter" (irreducible_sector.cpp reads PARAM.globalv, previously
    hidden because these files only ever built inside the
    already-PARAM-linked EXX target) and dftu_lcao_test, which compiles
    dftu_nao_op.cpp directly and needs "symmetry" now.

- K-point pools (KPAR>1): Symmetry_rotation_k::cal_Ms() read
  kv.kvec_d[ik_ibz] assuming a global array, but kv.kvec_d only holds
  the k-points owned by the current pool once mpi_k() has run. Gather
  the (small) global ibz-representative k-vector list once via
  MPI_Allreduce (mirroring Parallel_Kpoints::gatherkvec, inlined rather
  than called directly to avoid a new link dependency on
  parallel_kpoints.cpp for every "symmetry" consumer) before building
  the rotation matrices, so every pool computes correctly regardless of
  which pool actually owns a given ibz k-point.

- accumulate_occ_over_kstar takes nspin as an explicit parameter
  instead of reading the global PARAM.inp.nspin (matches the local
  nspin already computed in cal_occ_mat_k from dftu.occmat().nspin(),
  which is the same value).

Verified: full non-LibRI build (BUILD_TESTING=ON) compiles and links
clean; MODULE_CELL_{klist,reciprocal_grid,qlist,little_group,
unitcell,SYMMETRY_*} and dftu_{core,operator,lcao}_test all pass;
broader ctest run reached 361/367 with only one unrelated pre-existing
failure (LRI_CV_Tools.ReadCs, a missing test-data-file issue unrelated
to this change). 17_DS_DFTU/03_LCAO_DFTU_S2_Z with symmetry=1 gives the
same energy as before this refactor (-6771.6902262249250271 eV,
bit-identical), and with kpar=2 gives -6771.6902262249113846 eV
(matching to 12 significant figures, confirming the KPAR fix).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019omhQohPCePyJnLiWnG6Fa
maki49 added a commit to maki49/abacus-develop that referenced this pull request Sep 15, 2026
…xing, empty kstars, make_unique)

- accumulate_occ_over_kstar: take nspin as a parameter instead of reading
  the global PARAM.inp.nspin, matching the existing local nspin already
  computed in cal_occ_mat_k from dftu.occmat().nspin().
- cal_occ_mat_k: map the pool-local k index to the global one via
  kv.ik2iktot before reducing modulo kv.kstars.size(), since ik was only
  valid as a direct kstars index when KPAR==1.
- Guard the symmetry-restoration branches (contributeHR and cal_occ_mat_k)
  on kv.kstars being non-empty, since symm_flag==1 alone does not
  guarantee kstars was built (e.g. berry_phase skips IBZ reduction).
- Replace std::make_unique (C++14) with new + unique_ptr::reset (C++11).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019omhQohPCePyJnLiWnG6Fa
maki49 added a commit to maki49/abacus-develop that referenced this pull request Sep 15, 2026
Addresses the remaining PR deepmodeling#7969 review items:

- Build: DFT+U (built unconditionally) was pulling in
  source_lcao/module_ri/module_exx_symmetry/symm_rotation.h, which
  requires LibRI (module_exx_symmetry is entirely gated behind
  ENABLE_LIBRI) -- breaking any build with LibRI disabled.
  - Moved irreducible_sector.{h,cpp}/irred_sec_bvk.cpp to
    source_cell/module_symmetry/ (unconditionally built "symmetry"
    library): they have no RI::Tensor dependency at all, just were
    bundled into the wrong CMake target. TCdouble switched from
    Abfs::Vector3_Order<double> (module_ri) to plain
    ModuleBase::Vector3<double> -- its ordering was never actually used.
  - Extracted the LibRI-independent k-space AO-rotation machinery
    (cal_Ms/restore_dm/rot_matrix_ao/Wigner-D math/cal_rotmat_Slm/...)
    into a new ModuleSymmetry::Symmetry_rotation_k base class in the
    same module, storing rotmat_Slm_ as ModuleBase::ComplexMatrix
    instead of RI::Tensor. EXX's own Symmetry_rotation (module_ri) now
    inherits from it and keeps only what genuinely needs RI::Tensor
    (restore_HR, rotate_atompair_serial/parallel, ...); a small
    ComplexMatrix->RI::Tensor adapter bridges the two remaining call
    sites in symm_rotation_r.hpp. DFT+U now includes only
    symm_rotation_k.h, no module_ri header.
  - Verified against a LibRI-enabled build (build_libri/, LIBRI_DIR
    pointed at the local checkout): module_exx_symmetry builds clean,
    and all 9 MODULE_RI_EXX_SYMMETRY_rotation unit tests pass, matching
    their pre-refactor reference values bit-for-bit.
  - Fixed a handful of test CMakeLists that linked "symmetry" but not
    "parameter" (irreducible_sector.cpp reads PARAM.globalv, previously
    hidden because these files only ever built inside the
    already-PARAM-linked EXX target) and dftu_lcao_test, which compiles
    dftu_nao_op.cpp directly and needs "symmetry" now.

- K-point pools (KPAR>1): Symmetry_rotation_k::cal_Ms() read
  kv.kvec_d[ik_ibz] assuming a global array, but kv.kvec_d only holds
  the k-points owned by the current pool once mpi_k() has run. Gather
  the (small) global ibz-representative k-vector list once via
  MPI_Allreduce (mirroring Parallel_Kpoints::gatherkvec, inlined rather
  than called directly to avoid a new link dependency on
  parallel_kpoints.cpp for every "symmetry" consumer) before building
  the rotation matrices, so every pool computes correctly regardless of
  which pool actually owns a given ibz k-point.

- accumulate_occ_over_kstar takes nspin as an explicit parameter
  instead of reading the global PARAM.inp.nspin (matches the local
  nspin already computed in cal_occ_mat_k from dftu.occmat().nspin(),
  which is the same value).

Verified: full non-LibRI build (BUILD_TESTING=ON) compiles and links
clean; MODULE_CELL_{klist,reciprocal_grid,qlist,little_group,
unitcell,SYMMETRY_*} and dftu_{core,operator,lcao}_test all pass;
broader ctest run reached 361/367 with only one unrelated pre-existing
failure (LRI_CV_Tools.ReadCs, a missing test-data-file issue unrelated
to this change). 17_DS_DFTU/03_LCAO_DFTU_S2_Z with symmetry=1 gives the
same energy as before this refactor (-6771.6902262249250271 eV,
bit-identical), and with kpar=2 gives -6771.6902262249113846 eV
(matching to 12 significant figures, confirming the KPAR fix).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019omhQohPCePyJnLiWnG6Fa
@maki49
maki49 marked this pull request as ready for review September 15, 2026 15:31
maki49 and others added 10 commits September 15, 2026 22:23
…xing, empty kstars, make_unique)

- accumulate_occ_over_kstar: take nspin as a parameter instead of reading
  the global PARAM.inp.nspin, matching the existing local nspin already
  computed in cal_occ_mat_k from dftu.occmat().nspin().
- cal_occ_mat_k: map the pool-local k index to the global one via
  kv.ik2iktot before reducing modulo kv.kstars.size(), since ik was only
  valid as a direct kstars index when KPAR==1.
- Guard the symmetry-restoration branches (contributeHR and cal_occ_mat_k)
  on kv.kstars being non-empty, since symm_flag==1 alone does not
  guarantee kstars was built (e.g. berry_phase skips IBZ reduction).
- Replace std::make_unique (C++14) with new + unique_ptr::reset (C++11).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019omhQohPCePyJnLiWnG6Fa
…a6fc43

- read_listed_kpoints (Cartesian/Direct) and interpolate_k_between are
  public, independently-usable readers (KlistTest.ReadKpointsCartesian,
  ReadKpointsLineCartesian) that must produce spin-doubled containers
  immediately, without requiring a later set_kup_and_kdw() call; revert
  their allocation back to nkstot*spin_mult. Only Monkhorst_Pack (which
  triggered the original build_kstars crash and has no such contract)
  keeps the deferred, undoubled allocation.
- set_kup_and_kdw() now resizes only kvec_c/kvec_d/wk/ngk/isk for the
  down-spin copy it is about to append, instead of calling renew() (which
  also resizes kvec_c_full). kvec_c_full must keep holding the original,
  un-reduced full-BZ mesh for later consumers (e.g. Ewald_Vq); renew()
  was truncating it to the symmetry-reduced, spin-doubled size.

Verified: MODULE_CELL_klist_test (34/34), MODULE_CELL_reciprocal_grid_test
(10/10), MODULE_CELL_qlist_test (16/16), MODULE_CELL_klist_test_para1
(2/2) all pass; 17_DS_DFTU/03_LCAO_DFTU_S2_Z with symmetry=1 still
produces the same energy as before this fix.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019omhQohPCePyJnLiWnG6Fa
Addresses the remaining PR deepmodeling#7969 review items:

- Build: DFT+U (built unconditionally) was pulling in
  source_lcao/module_ri/module_exx_symmetry/symm_rotation.h, which
  requires LibRI (module_exx_symmetry is entirely gated behind
  ENABLE_LIBRI) -- breaking any build with LibRI disabled.
  - Moved irreducible_sector.{h,cpp}/irred_sec_bvk.cpp to
    source_cell/module_symmetry/ (unconditionally built "symmetry"
    library): they have no RI::Tensor dependency at all, just were
    bundled into the wrong CMake target. TCdouble switched from
    Abfs::Vector3_Order<double> (module_ri) to plain
    ModuleBase::Vector3<double> -- its ordering was never actually used.
  - Extracted the LibRI-independent k-space AO-rotation machinery
    (cal_Ms/restore_dm/rot_matrix_ao/Wigner-D math/cal_rotmat_Slm/...)
    into a new ModuleSymmetry::Symmetry_rotation_k base class in the
    same module, storing rotmat_Slm_ as ModuleBase::ComplexMatrix
    instead of RI::Tensor. EXX's own Symmetry_rotation (module_ri) now
    inherits from it and keeps only what genuinely needs RI::Tensor
    (restore_HR, rotate_atompair_serial/parallel, ...); a small
    ComplexMatrix->RI::Tensor adapter bridges the two remaining call
    sites in symm_rotation_r.hpp. DFT+U now includes only
    symm_rotation_k.h, no module_ri header.
  - Verified against a LibRI-enabled build (build_libri/, LIBRI_DIR
    pointed at the local checkout): module_exx_symmetry builds clean,
    and all 9 MODULE_RI_EXX_SYMMETRY_rotation unit tests pass, matching
    their pre-refactor reference values bit-for-bit.
  - Fixed a handful of test CMakeLists that linked "symmetry" but not
    "parameter" (irreducible_sector.cpp reads PARAM.globalv, previously
    hidden because these files only ever built inside the
    already-PARAM-linked EXX target) and dftu_lcao_test, which compiles
    dftu_nao_op.cpp directly and needs "symmetry" now.

- K-point pools (KPAR>1): Symmetry_rotation_k::cal_Ms() read
  kv.kvec_d[ik_ibz] assuming a global array, but kv.kvec_d only holds
  the k-points owned by the current pool once mpi_k() has run. Gather
  the (small) global ibz-representative k-vector list once via
  MPI_Allreduce (mirroring Parallel_Kpoints::gatherkvec, inlined rather
  than called directly to avoid a new link dependency on
  parallel_kpoints.cpp for every "symmetry" consumer) before building
  the rotation matrices, so every pool computes correctly regardless of
  which pool actually owns a given ibz k-point.

- accumulate_occ_over_kstar takes nspin as an explicit parameter
  instead of reading the global PARAM.inp.nspin (matches the local
  nspin already computed in cal_occ_mat_k from dftu.occmat().nspin(),
  which is the same value).

Verified: full non-LibRI build (BUILD_TESTING=ON) compiles and links
clean; MODULE_CELL_{klist,reciprocal_grid,qlist,little_group,
unitcell,SYMMETRY_*} and dftu_{core,operator,lcao}_test all pass;
broader ctest run reached 361/367 with only one unrelated pre-existing
failure (LRI_CV_Tools.ReadCs, a missing test-data-file issue unrelated
to this change). 17_DS_DFTU/03_LCAO_DFTU_S2_Z with symmetry=1 gives the
same energy as before this refactor (-6771.6902262249250271 eV,
bit-identical), and with kpar=2 gives -6771.6902262249113846 eV
(matching to 12 significant figures, confirming the KPAR fix).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019omhQohPCePyJnLiWnG6Fa
…otation

Symmetry_rotation_k (cal_Ms/restore_dm/contruct_2d_rot_mat_ao) and
Irreducible_Sector::write_irreducible_sector read PARAM.inp.nspin /
PARAM.globalv.global_out_dir directly, which pulled a module_parameter
link dependency into every target linking the unconditionally-built
"symmetry" library -- six test CMakeLists needed an extra "parameter"
LIBS entry just because of this.

- cal_Ms() now takes nspin as an explicit parameter and stores it in a
  new nspin_ member, read by restore_dm()/contruct_2d_rot_mat_ao()
  instead of PARAM.inp.nspin. Every existing caller (DFT+U, EXX, RPA,
  RDMFT) already has nspin in scope.
- find_irreducible_sector()/write_irreducible_sector() take an explicit
  output_dir string instead of reading PARAM.globalv.global_out_dir;
  DFT+U's two callers omit it (skipping the debug irreducible_sector.txt
  dump, consistent with dftu_nao_op.cpp/dftu_nao_occ.cpp already being
  PARAM-free), EXX/RPA/RDMFT pass PARAM.globalv.global_out_dir to keep
  their existing behavior.
- Dropped the now-unnecessary "parameter" LIBS entry from the 6 test
  targets that only needed it because of this transitive dependency.
- test_symm_rotation.cpp: pass nspin directly to
  set_density_rotations_for_testing() instead of overriding the global
  PARAM.inp.nspin via a RAII helper.

Verified: symmetry/dftu_lcao_test/MODULE_RI_EXX_SYMMETRY_rotation and
the MODULE_CELL_{SYMMETRY_*,klist,reciprocal_grid,qlist,little_group,
unitcell} suite all pass in both the non-LibRI and LibRI-enabled
builds; 17_DS_DFTU/03_LCAO_DFTU_S2_Z gives the same energy as before.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019omhQohPCePyJnLiWnG6Fa
Two independent bugs, both only visible with KPAR>1:

1. kv.kstars (needed by DFT+U's crystal-symmetry density-matrix
   restoration, not just EXX) was only ever built/broadcast when
   compiled with LibRI (#ifdef __EXX in K_Vectors::set()/mpi_k(),
   predating this branch). Without LibRI, kv.kstars stayed empty on
   every rank, so dftu_spacegroup_symmetry could never activate --
   silently, not a crash. Neither KListIO::build_kstars nor
   KListIO::bcast_kstars has any LibRI dependency, so removed the gate;
   the ModuleSymmetry::Symmetry::symm_flag==1 runtime check is unchanged.

2. Symmetry_rotation_k::restore_dm() indexed its input (dm_k_ibz =
   elecstate::DensityMatrix::_DMK) using the *global* irreducible-k
   count (kv.get_nkstot()/nspin), but _DMK only ever holds the
   k-points owned by the current pool (_nk = kv.get_nks()/nspin, see
   setup_dm.cpp) -- an out-of-bounds/wrong-slot read for any pool that
   doesn't own every irreducible k-point.

   Fixed by having restore_dm() operate on the local k-range and map
   each local slot to its global ibz index via kv.ik2iktot (mirroring
   the existing pattern in dftu_nao_occ.cpp's accumulate_occ_over_kstar),
   returning only the stars of this pool's own local irreducible
   k-points. This is exact, not an approximation: the k-summed
   Fourier transform D(k)->D(R) is linear, so each pool's partial
   contribution plus the caller's existing cross-pool reduction
   (compute_occ_from_dmr's Parallel_Reduce::reduce_all) gives the same
   total as if every pool held the complete global k-set -- no pool
   needs (or has to pay for gathering) the full D(k) data. Updated
   dftu_nao_op.cpp's kvec_d_full construction to match (one entry per
   star member of each local ibz-k, same local-to-global mapping).

   Note: EXX/RPA/RDMFT's own restore_dm() call sites still assume a
   global-sized result for their mix_DMk_2D mixing buffers
   (set_nks(kv.get_nkstot_nospin()*...)), so KPAR>1 support for their
   use of symmetry restoration is unchanged/still unverified -- out of
   scope here; flagging for whoever picks that up.

Verified: MODULE_CELL_{SYMMETRY_*,klist,klist_test_para4,
reciprocal_grid,qlist,little_group,unitcell} and dftu_{core,operator,
lcao,nao_ijr}_test / MODULE_RI_EXX_SYMMETRY_rotation all pass in both
builds; 17_DS_DFTU/03_LCAO_DFTU_S2_Z with KPAR=1 still gives the same
energy as before, and with KPAR=2 (4 MPI ranks, 2 pools) now gives the
same energy/magnetism as KPAR=1 to the run-to-run noise floor
(previously untested -- and, per bug 1, silently inert without LibRI).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019omhQohPCePyJnLiWnG6Fa
…udget

- symm_rotation_k.cpp: rot_matrix_ao()/trs_spin_rotate() unconditionally
  used ScalapackConnector::gemm and Parallel_2D::desc, both #ifdef __MPI
  only. This was previously masked because the code lived in module_ri
  (gated behind ENABLE_LIBRI, itself requiring MPI) before this branch's
  LibRI split moved it into the unconditionally-built "symmetry" library.
  Added a serial BlasConnector::gemm_cm fallback for #else __MPI (without
  MPI, Parallel_2D holds the whole dense matrix locally with leading
  dimension == nbasis, so the 2D-block-cyclic pgemm degenerates to a
  plain col-major gemm) -- fixes the CMake "Build without MPI" and
  "Build without LCAO and MPI" jobs.
- source/Makefile.Objects: OBJS_SYMMETRY was missing irreducible_sector.o,
  irred_sec_bvk.o and symm_rotation_k.o after this branch moved those
  files into source_cell/module_symmetry -- the legacy Makefile build
  (unlike CMake) has no glob, so new/moved files need an explicit object
  list entry. Fixes the "Build with Makefile & Intel compilers" job
  (undefined references wherever dftu_nao_op.cpp/dftu_nao_occ.cpp link).
- Reworded 4 doc comments that spelled out PARAM.inp.nspin /
  PARAM.globalv.global_out_dir in prose: the governance checker's global-
  dependency budget (tools/03_code_analysis/agent_governance_check.py)
  scans added/removed diff lines for the literal substring "PARAM." and
  blocks any PR with a net increase, with no code-vs-comment distinction.
  These 4 lines were pure documentation (the actual PARAM reads were
  already removed from this file by an earlier commit), so rewording them
  to describe the same thing without the literal token brings the PR's
  net delta negative without changing any code.

Verified locally: CMake build with -DENABLE_MPI=OFF and with
-DENABLE_MPI=OFF -DENABLE_LCAO=OFF both compile clean (previously failed
with "ScalapackConnector has not been declared" / "no member named
desc"); tools/03_code_analysis/agent_governance_check.py against this
branch's merge-base no longer reports any BLOCK-severity finding.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019omhQohPCePyJnLiWnG6Fa
Comment thread source/source_cell/module_symmetry/symm_rotation_k.h Outdated
Comment thread source/source_lcao/module_dftu/dftu_nao_occ.cpp Outdated
- symm_rotation_k.h: replace #pragma once with a standard ISO C++
  include guard, per review comment (pragma once is non-standard and
  can misbehave with hardlinked/symlinked build trees).
- symm_rotation_k.cpp, dftu_nao_op.cpp, dftu_nao_occ.cpp: spell out
  explicit types instead of auto for kv.kstars iteration/rotation
  results, per review comment (do not use auto unless necessary).
  Lambda-assigned locals are left as auto since their closure type
  has no nameable spelling.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019omhQohPCePyJnLiWnG6Fa
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 Features Needed The features are indeed needed, and developers should have sophisticated knowledge Refactor Refactor ABACUS codes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

symmetry has a strong effect on the band structure of magnetic systems

3 participants