Skip to content

Fix #8078: Refactor: remove the UnitCell Statistics layer and flattening reference members - #8080

Merged
mohanchen merged 22 commits into
deepmodeling:developfrom
mohanchen:2026-10-06-b
Oct 10, 2026
Merged

mohanchen merged 22 commits into
deepmodeling:developfrom
mohanchen:2026-10-06-b

Conversation

@mohanchen

Copy link
Copy Markdown
Collaborator

Fix #8078

Motivation

UnitCell stored its atom-count and index-map data in a nested Statistics st struct and re-exported every field as a reference member bound at
construction (int& nat = st.nat, int*& iat2it = st.iat2it, ...). This
design caused several concrete problems:

  1. Dual-view aliasing — every field is reachable under two names
    (ucell.nat and ucell.st.nat), both used interchangeably across the
    codebase, making the data flow hard to follow and grep-based refactoring
    unreliable.
  2. An invisible ownership rule — the four index arrays (iat2it,
    iat2ia, iwt2iat, iwt2iw) were raw int* owned by Statistics,
    whose destructor delete[]d them. Test fixtures had to new[] them but
    never delete[] them, a rule that was only documented in AGENTS.md;
    several unit tests double-freed as a result.
  3. A latent shallow-copy double-free — the reference members silently
    deleted the implicit copy assignment while leaving the implicit copy
    constructor available; that constructor shallow-copies the owning int*
    members, so copying a UnitCell would double-free.

Changes

  • Repoint the only consumers of the Statistics type. The
    symmetry-related modules (source_cell/module_symmetry/* and
    source_lcao/module_ri/module_exx_symmetry/*) previously took
    const Statistics& in ~20 function signatures; they now take
    const UnitCell& (forward-declared where the header only declares).
    All call sites pass ucell (or *ucell where ucell is a pointer).
  • Move the nine fields into UnitCell as direct members under the
    existing top-level names, so the many ucell.nat-style call sites are
    unchanged. The st member, the nine reference members, and the
    Statistics struct are deleted.
  • Convert iat2it/iat2ia/iwt2iat/iwt2iw from raw int* to
    std::vector<int>.
    The ~100 allocation sites (production:
    unitcell.cpp, cal_wfc.cpp; the rest in test fixtures) migrate from
    new int[]/delete[] to resize()/assign(). The two device-upload
    call sites in force_pw.cpp now use .data(). Element access X[i] is
    unchanged everywhere.
  • Delete UnitCell copy constructor/assignment and default the move
    operations
    , so accidental copies fail at compile time instead of
    double-freeing at runtime. No existing code copies a UnitCell
    (verified by grep), so this changes no behavior.
  • Update AGENTS.md: replace the obsolete fixture note ("do not
    delete[] iat2it") with the new ownership/vector rule.

Scope / non-goals

  • The Lattice lat block follows the same flattening-reference pattern but
    is intentionally out of scope. Unlike Statistics, Lattice is a
    genuinely cohesive type passed by value/reference to many consumers
    (bcast_Lattice, remake_cell, update_pos_tau, analy_sys,
    pyabacus), so the struct should be kept; only its reference aliases need
    removal. That is a larger, independent change left for a follow-up PR.
  • No INPUT parameter or user-facing behavior change.

Verification

  • Full build succeeds with no compile errors.
  • OMP_NUM_THREADS=1 ctest -R "unitcell|CELL_SYMMETRY|symmetry|hcontainer| dftu|operator_lcao|module_dm|pdos|hsr|restart_exx|gint|relax|esolver":
    33/33 passed. (Full ctest is not runnable in this sandbox — GPU
    device tests and tests that write to absolute paths fail with
    process_reader/code=11 environment noise; the related-test subset is
    green.)
  • tools/03_code_analysis/agent_governance_check.py --base HEAD~1 --head HEAD:
    4 warnings, all benign and explained below; no blockers.
    • irreducible_sector.h:99-100 "new default parameters" — false positive:
      the default arguments pre-date this change; the lines only appear in the
      diff because the parameter was renamed st → ucell.
    • unitcell.h adds <vector> — required: the new members are value-type
      std::vector<int> and need the complete type.
    • symm_rotation.h adds unitcell.h — required: the header directly
      includes two .hpp implementation files whose inline templates
      dereference ucell.iat2it, so it must hold the complete type.
    • "docs sync review" — no INPUT/user-facing change, so
      docs/parameters.yaml and docs/advanced/input_files/input-main.md are
      intentionally untouched.
  • Final greps: no Statistics, no ucell.st / ->st (in the UnitCell
    sense), no remaining new int[] / delete[] for the four index arrays.

Notes for reviewers

  • The large file count is almost entirely the mechanical
    new int[] → resize() migration in test fixtures; each per-file diff is
    small.
  • One non-mechanical change worth a look:
    source_lcao/module_dftu/unittests/test_dftu_nao_ijr.cpp previously bound
    the index arrays to fixture-owned buffer vectors via raw pointers
    (ucell.iat2it = iat2it_buf.data()) and reset them to nullptr in
    TearDown — a workaround for the old pointer-ownership model. Now that the
    members are vectors, it uses assign()/resize() directly and the buffer
    members and reset logic are removed. Semantically equivalent and simpler.

…ce members

UnitCell stored its atom-count and index-map data in a nested `Statistics`
struct and re-exported every field as a reference member (`int& nat = st.nat`,
`int*& iat2it = st.iat2it`, ...). This created dual-view aliasing, an
invisible raw-pointer ownership rule (fixtures had to `new[]` but never
`delete[]`, and several unit tests double-freed as a result), and a latent
shallow-copy double-free since the implicit copy constructor remained
available while copy assignment was silently deleted by the reference members.

Changes:
- Repoint the only consumers of the `Statistics` type: module_symmetry and
  module_exx_symmetry interfaces now take `const UnitCell&` instead of
  `const Statistics&`; all call sites pass `ucell` (or `*ucell`).
- Move the nine fields into UnitCell as direct members under the existing
  top-level names, so `ucell.nat`-style call sites are unchanged. Delete the
  `st` member, the reference members, and the `Statistics` struct.
- Convert iat2it/iat2ia/iwt2iat/iwt2iw from raw int* to std::vector<int>;
  migrate the ~100 test/support allocation sites from `new int[]` to
  resize()/assign(). Production sites (unitcell.cpp, cal_wfc.cpp) and the
  two force_pw.cpp device-upload call sites use .data().
- Delete UnitCell copy constructor/assignment and default the move
  operations, so accidental copies fail at compile time.
- Update AGENTS.md: replace the obsolete fixture note with the new
  ownership/vector rule.

Verification:
- Full build succeeds (no compile errors).
- ctest -R "unitcell|CELL_SYMMETRY|symmetry|hcontainer|dftu|operator_lcao|
  module_dm|pdos|hsr|restart_exx|gint|relax|esolver": 33/33 passed.
- agent_governance_check: no issues.

No INPUT parameter or user-facing behavior change; docs/parameters.yaml
unaffected. The Lattice lat reference-member block is intentionally out of
scope and can follow the same recipe in a later PR.
@mohanchen
mohanchen requested a review from 19hello October 6, 2026 01:16
The Statistics refactor converted UnitCell::iat2it from int* to
std::vector<int>. The CUDA-only translation unit gint_gpu_vars.cpp was not
compiled by the local CPU build, so this call site was missed: cudaMemcpy
expects a const void* source but received the vector object. Pass
ucell.iat2it.data() instead, matching the force_pw.cpp device-upload sites.
@mohanchen mohanchen added Refactor Refactor ABACUS codes The Absolute Zero Reduce the "entropy" of the code to 0 labels Oct 6, 2026
@mohanchen
mohanchen requested a review from Critsium-xy October 8, 2026 00:53
Comment thread source/source_cell/unitcell.h Outdated
Comment thread source/source_cell/unitcell.h Outdated
Comment thread source/source_cell/unitcell.h Outdated
Comment thread AGENTS.md Outdated
Comment thread source/source_cell/module_symmetry/symmetry.h Outdated
Comment thread source/source_cell/module_symmetry/irreducible_sector.h Outdated
Comment thread source/source_lcao/module_ri/module_exx_symmetry/symm_rotation.h Outdated
Comment thread source/source_cell/test/unitcell_test.cpp
abacus_fixer and others added 18 commits October 9, 2026 13:09
The defaulted move constructor shallow-copied the owning raw pointer
'atoms' together with 'set_atom_flag' without resetting the source, so
both the moved-to and moved-from objects ran delete[] on the same Atom
array. The defaulted move assignment was implicitly deleted because the
reference aliases into 'lat' (Coordinate, a1, latvec, ...) cannot be
re-bound, triggering -Wdefaulted-function-deleted. Explicitly delete
both move operations so any accidental move fails at compile time;
correct move semantics require an owning container for 'atoms' and
removal of the reference aliases in later refactoring steps.
Add static_asserts on std::is_copy/move_constructible/assignable so that
re-enabling either operation during future UnitCell refactoring fails the
translation unit at compile time instead of reintroducing the double
free and dangling 'lat' reference aliases.
Replace the const UnitCell& parameter of analy_sys (and its three private
helpers is_all_movable, analyze_magnetic_group,
analyze_magnetic_group_nspin4) with only the index data they actually
read: nat, ntype, iat2it, iat2ia, itia2iat. This breaks the
UnitCell <-> Symmetry type-level dependency cycle: symmetry.h no longer
names UnitCell at all, and the three implementation files drop their
unitcell.h includes. The two other classes in the module that still need
UnitCell (Irreducible_Sector, Symmetry_rotation_k) carry their own
forward declaration now. All production and test call sites pass the
five data members explicitly; behavior is unchanged.
Replace the const UnitCell& parameters of find_irred_sector,
cal_return_lattice_all, gen_symm_bvk (Irred_Sector) and cal_Ms /
contruct_2d_rot_mat_ao (Symmetry_rotation_k) with the data they
actually read: nat, ntype, the iat2it/iat2ia maps, and explicit
symm/atoms/lat/latvec/lmax arguments. This removes the possibility of
passing mismatched atoms/lat alongside one cell's index maps and makes
both headers free of any UnitCell name; the three implementation files
drop their unitcell.h includes. Drop the unused get_aRb_direct helpers
(no callers anywhere in the tree).

Rename for brevity: Irreducible_Sector -> Irred_Sector,
irreducible_sector.{h,cpp} -> irred_sec.{h,cpp} (matching the existing
irred_sec_bvk.cpp and the irs_ member),
find/get_irreducible_sector -> find/get_irred_sector, and
gen_symmetry_BvK -> gen_symm_bvk. Comments, log strings and the output
file name keep the standard "BvK" spelling. All three production call
sites (DFTU x2, RDMFT) and the EXX info printer are updated; behavior
is unchanged.
The EXX/RPA/RDMFT rotation templates only consume the atom index maps,
so pass iat2it/iat2ia explicitly instead of const UnitCell&, and remove
the unitcell.h include from symm_rotation.h (forward-declare UnitCell
for the non-template print_symrot_info_k). TUs that dereference UnitCell
now include unitcell.h directly.

Delete unreachable helpers: test_HR_rotation (both overloads),
test_Cs_rotation, get_Rs_from_adjacent_list, get_Rs_from_BvK.

Also fix the three missed .hpp call sites of the Irred_Sector rename
(exx_lri_interface.hpp, exx_lri.hpp, rpa_lri.hpp).

Verified: make -j 30 builds abacus_max_para with 0 warnings;
MODULE_RI_EXX_SYMMETRY_rotation test target also builds.
Set the ABACUS executable in Autotest.sh and general_info to the local
build_max_para_test/abacus_max_para binary for local test runs.
Makefile.Objects still listed irreducible_sector.o, which no longer
exists after renaming irreducible_sector.{h,cpp} to irred_sec.{h,cpp};
update it to irred_sec.o so the mpiicpx Makefile build links again.
The upstream merge brought in a test that assigned new int[nat] to
ucell.iat2it/iat2ia, but these are std::vector<int> members on this
branch. Use resize() instead, matching the other fixtures in this file
and removing the leaked allocation.

Verified: MODULE_RELAX_relax_sync_test target builds with 0 errors.
Resolve conflict in symm_rot_out.cpp: keep both includes --
unitcell.h is needed to dereference UnitCell members (nat, atoms,
iat2it) after the header was forward-declared in symm_rotation.h,
and parameter.h is needed for PARAM.globalv.global_out_dir from
upstream.
The local absolute build path broke CUDA CI jobs that do not have
this directory; restore the upstream default of resolving abacus
from PATH.
Complete the partial revert in b6be72d: the hardcoded local path
build_max_para_test/abacus_max_para was still set in Autotest.sh, so
CUDA CI jobs (which lack that local CPU build) failed to launch every
integration test case. Restore the upstream default and resolve the
executable via PATH, ABACUS_EXE, or the -a option for local runs.
Resolve the conflict with deepmodeling#8115, which split unitcell.cpp into
unitcell_index.cpp, unitcell_stats.cpp and unitcell_setup.cpp: take the
upstream unitcell.cpp and port this branch's std::vector resize() change
for iat2it/iat2ia into unitcell_index.cpp. Update the stale ownership
comments in test_unitcell_index.cpp accordingly.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ng#8099

The previous merge of upstream/develop brought in deepmodeling#8099, whose code still
used the pre-refactor API and broke every CI build:

- symm_rotation_k.cpp: reset_symmetry() assigned Irreducible_Sector(),
  renamed to Irred_Sector on this branch.
- symm_test_analysis.cpp and test_symm_rotation.cpp: replace ucell.st,
  find_irreducible_sector() and cal_Ms(kv, cell, ...) with the new
  explicit nat/ntype/iat2it/iat2ia/itia2iat signatures, and assign the
  index maps as std::vector instead of new int[].

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
mohanchen and others added 2 commits October 10, 2026 17:19
…d::vector

deepmodeling#8068 added a test that assigned `new int[1]` to ucell.iat2it, which no
longer compiles now that UnitCell owns iat2it as std::vector<int>. Use
resize() as the other test in this file already does.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@mohanchen
mohanchen merged commit 6fb3af3 into deepmodeling:develop Oct 10, 2026
17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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.

Refactor: Remove the Statistics struct layer and flattening reference members in UnitCell

2 participants