Repository navigation
Fix #8078: Refactor: remove the UnitCell Statistics layer and flattening reference members - #8080
Merged
Merged
Conversation
…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.
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.
Critsium-xy
reviewed
Oct 8, 2026
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>
Critsium-xy
approved these changes
Oct 10, 2026
…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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fix #8078
Motivation
UnitCellstored its atom-count and index-map data in a nestedStatistics ststruct and re-exported every field as a reference member bound atconstruction (
int& nat = st.nat,int*& iat2it = st.iat2it, ...). Thisdesign caused several concrete problems:
(
ucell.natanducell.st.nat), both used interchangeably across thecodebase, making the data flow hard to follow and grep-based refactoring
unreliable.
iat2it,iat2ia,iwt2iat,iwt2iw) were rawint*owned byStatistics,whose destructor
delete[]d them. Test fixtures had tonew[]them butnever
delete[]them, a rule that was only documented inAGENTS.md;several unit tests double-freed as a result.
deleted the implicit copy assignment while leaving the implicit copy
constructor available; that constructor shallow-copies the owning
int*members, so copying a
UnitCellwould double-free.Changes
Statisticstype. Thesymmetry-related modules (
source_cell/module_symmetry/*andsource_lcao/module_ri/module_exx_symmetry/*) previously tookconst Statistics&in ~20 function signatures; they now takeconst UnitCell&(forward-declared where the header only declares).All call sites pass
ucell(or*ucellwhereucellis a pointer).UnitCellas direct members under theexisting top-level names, so the many
ucell.nat-style call sites areunchanged. The
stmember, the nine reference members, and theStatisticsstruct are deleted.iat2it/iat2ia/iwt2iat/iwt2iwfrom rawint*tostd::vector<int>. The ~100 allocation sites (production:unitcell.cpp,cal_wfc.cpp; the rest in test fixtures) migrate fromnew int[]/delete[]toresize()/assign(). The two device-uploadcall sites in
force_pw.cppnow use.data(). Element accessX[i]isunchanged everywhere.
UnitCellcopy constructor/assignment and default the moveoperations, 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.
AGENTS.md: replace the obsolete fixture note ("do notdelete[] iat2it") with the new ownership/vector rule.Scope / non-goals
Lattice latblock follows the same flattening-reference pattern butis intentionally out of scope. Unlike
Statistics,Latticeis agenuinely 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.
Verification
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
ctestis not runnable in this sandbox — GPUdevice tests and tests that write to absolute paths fail with
process_reader/code=11environment noise; the related-test subset isgreen.)
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.hadds<vector>— required: the new members are value-typestd::vector<int>and need the complete type.symm_rotation.haddsunitcell.h— required: the header directlyincludes two
.hppimplementation files whose inline templatesdereference
ucell.iat2it, so it must hold the complete type.docs/parameters.yamlanddocs/advanced/input_files/input-main.mdareintentionally untouched.
Statistics, noucell.st/->st(in the UnitCellsense), no remaining
new int[]/delete[]for the four index arrays.Notes for reviewers
new int[]→resize()migration in test fixtures; each per-file diff issmall.
source_lcao/module_dftu/unittests/test_dftu_nao_ijr.cpppreviously boundthe index arrays to fixture-owned buffer vectors via raw pointers
(
ucell.iat2it = iat2it_buf.data()) and reset them tonullptrinTearDown— a workaround for the old pointer-ownership model. Now that themembers are vectors, it uses
assign()/resize()directly and the buffermembers and reset logic are removed. Semantically equivalent and simpler.