Refactor klist, fix a few bugs - #7897
Open
mohanchen wants to merge 22 commits into
Open
Conversation
added 2 commits
September 3, 2026 08:34
Rename the private member K_Vectors::nspin -> spin_mult (together with get_nspin/set_nspin -> get_spin_mult/set_spin_mult). The old name collided semantically with PARAM.inp.nspin: the member holds the k-point spin multiplicity (1 or 2; nspin=4 is mapped to 1 at set() time), not the physical spin index (1/2/4). The new name matches the inherited ReciprocalGrid::spin_factor() override and the member's actual role as a k-point doubling factor. Fix two bugs surfaced by the rename: - K_Vectors::set() now maps spin_mult directly from the input nspin_in (print -> validate -> map) instead of the previous "assign first, then remap itself" flow that also left the member written before validation. - K_Vectors::set_after_vc() no longer accepts an nspin argument and no longer calls set_spin_mult(): the spin multiplicity is fixed by set() and never changes during a run. The old code passed the raw, unmapped input nspin (e.g. 4 for non-collinear) and wrote it into spin_mult, silently overwriting the correct mapped value in nspin=4 vc-relax calculations. The remaining work in set_after_vc is purely a Cartesian coordinate refresh (kvec_d2c) plus logging. Remove the now-unused set_spin_mult() setter (the only external caller was set_after_vc itself). Update production and test call sites (esolver_fp, klist_test, klist_test_para, print_info_test, write_dmk_test) accordingly. API surface: K_Vectors::set() and the data members exposed through isk/nks/ nkstot remain unchanged. No INPUT or PARAM behavior is altered.
added 19 commits
September 3, 2026 09:05
After the rename of K_Vectors::nspin -> spin_mult, two kinds of latent misuses in the tests became visible and are corrected here: 1. In klist_test_para.cpp, set() calls had been passing kv->spin_mult as the nspin_in argument. That was only working by accident (both sides happened to be 1). Since set() takes the *physical* nspin (1/2/4, which it then maps to spin_mult internally), replace the member argument with explicit physical-nspin literals, and remove the now- redundant pre-set of the member (set() overwrites it anyway). 2. In klist_test.cpp (SetKupKdown test), the non-collinear case had been written as kv->spin_mult = 4, which is not a legal spin_mult value (only 1 and 2 are). K_Vectors maps nspin=4 -> 1 (non- collinear does not double the k-point list); the 4 was only masking a coincidentally matching renew(nkstot*4) size and a set_kup_and_kdw default branch that did nothing. Change it to the correct mapped value (1), add case A/B/C comments explaining the physical spin source for each case, and remove the bogus isk[ik+5/10/15] checks that relied on the accidentally oversized container. All production call sites already pass the physical nspin correctly (inp.nspin / inp_->nspin), so no source changes are needed there.
…ctions
Step 1 of the klist.cpp quality refactor. Move the two IBZ reduction
table builders out of K_Vectors::reduce_by_symmetry into this-free
helpers KListSymm::ibz_kpt_table / KListSymm::ibz_wk_table defined at
the top of klist.cpp (deliberately not static, not in an anonymous
namespace). This cuts the function's cyclomatic complexity from 22 to
20 and isolates pure string formatting from the symmetry logic.
The helpers live in klist.cpp rather than a new TU because dozens of
test targets across the tree compile klist.cpp alone; a separate TU
would need registering in every one of them. File splitting into
self-contained TUs happens in later steps.
Also fix a pre-existing build break in write_dmk_test.cpp: the
'#define private public' placed before write_dmk.h corrupted <sstream>
("__xfer_bufptrs redeclared with different access"). Pre-include the
standard headers so their include guards are set before the macro.
Verified: full build (BUILD_EXIT=0) and
ctest -R "MODULE_CELL_(klist|reciprocal_grid|qlist)" -> 5/5 passed in
build_max_para_test (MPI build, GNU 11, ENABLE_MPI=ON).
The previous commit pre-included <sstream>/<fstream>/... before '#define private public', but write_dmk.h reaches <sstream> indirectly through global_variable.h -> <iomanip> -> bits/quoted_string.h. Without <iomanip> pre-included, quoted_string.h is first parsed while the 'private'/'public' macro is active, corrupting libstdc++ and failing CI with "'...__xfer_bufptrs' redeclared with different access". Pre-include <iomanip> as well so the whole chain is guard-protected before the macro is defined. Verified: cmake --build --target MODULE_IO_write_dmk (exit 0) and ctest -R MODULE_IO_write_dmk -> 2/2 passed in build_max_para_test.
Move the IBZ table formatters and line-mode interpolation out of
klist.cpp into a new source_cell/klist_io.{h,cpp} (namespace KListIO):
- ibz_kpt_table / ibz_wk_table: pure string formatting, unchanged output.
- interp_line: this-free line-mode interpolation returning LineK
{kpts, segids, nks_total}; K_Vectors::interpolate_k_between becomes a
thin wrapper that sizes members and copies results back.
klist.cpp: 926 -> 830 lines, quality score 6 -> 12; klist_io.cpp scores
100. reduce_by_symmetry and parse_kfile lose their largest this-free
blocks.
CMake: klist_io.cpp added to the cell library; 16 test targets that
compile klist.cpp without linking cell_info also register klist_io.cpp.
Verified: cmake --build build_max_para_test -j30 (exit 0) and
ctest -R "MODULE_CELL_(klist|reciprocal_grid|qlist)|MODULE_IO_...|
MODULE_ESTATE_...|MODULE_HSOLVER_pw|MODULE_LCAO_deltaspin" -> 27/27.
Move the this-free triple loop that groups k points into EXX k-stars out of K_Vectors::reduce_by_symmetry into KListIO::build_kstars. The symmetry comparison is passed in as a std::function so klist_io.cpp does not depend on the Symmetry header; k restriction uses ModuleCell::restrict_kpt. Behavior is unchanged for symm_flag==1 (the only path that reaches this code). klist.cpp drops ~20 lines; the loop is now isolated and testable. Verified: cmake --build build_max_para_test -j30 (exit 0, __EXX on) and ctest -R "MODULE_CELL_(klist|reciprocal_grid|qlist)" -> 5/5.
The this-free helpers extracted into source_cell/klist_io.cpp are referenced by klist.cpp, but the Makefile object list was not updated when the CMake build gained the new TU, breaking the Makefile link with undefined references to KListIO::ibz_kpt_table/ibz_wk_table/interp_line.
Move the this-free flatten/scatter loops in K_Vectors::mpi_k into KListIO::pack_kpts (rank-0 -> contiguous broadcast buffers) and KListIO::unpack_kpts (broadcast buffers -> this pool's k-point slice). mpi_k keeps the broadcast calls and the renew/distribute orchestration. pack_kpts sizes the kvec_c_full copy from the vector length so the full grid is handled independently of nkstot. Verified: cmake --build build_max_para_test -j30 (exit 0, __MPI on) and ctest -R "MODULE_CELL_(klist|reciprocal_grid|qlist)" -> 5/5 (covers the para1/para4 mpi_k paths).
Remove the GlobalV::ofs_warning dependency from K_Vectors::generate_kfile by taking the stream as a parameter; the single caller (read_kpoints) passes GlobalV::ofs_warning. Private signature only, no public interface change. global_dependency count in klist.cpp drops by 2. Verified: cmake --build build_max_para_test -j30 (exit 0) and ctest -R "MODULE_CELL_(klist|reciprocal_grid|qlist)" -> 5/5.
Remove the GlobalV::MY_RANK/MY_POOL dependency from K_Vectors::mpi_k by taking them as parameters; the single caller (set()) passes the GlobalV values. Private signature only, no public interface change. global_dependency count in klist.cpp drops by 5. Verified: cmake --build build_max_para_test -j30 (exit 0, __MPI on) and ctest -R "MODULE_CELL_(klist|reciprocal_grid|qlist)" -> 5/5.
… KListIO Move the K_POINTS header scan loop and the Cartesian/Direct explicit k-point read loop out of K_Vectors::parse_kfile into this-free KListIO::find_kpoints_header / read_kpt_list. parse_kfile keeps the renew() sizing calls as a thin member shell. Cyclomatic complexity of parse_kfile drops 26 -> 20; klist.cpp 802 -> 775 lines.
Move the nkstot == 0 branch of parse_kfile (Gamma/MP keyword dispatch, mesh size and offset reading, Monkhorst_Pack call) into a private K_Vectors::read_mp_mesh member. parse_kfile now only records success and keeps the nkstot > 0 explicit-list branch; its cyclomatic complexity drops 20 -> 16.
…d_kpoints Move the nkstot > 0 dispatch of parse_kfile into a private read_listed_kpoints member, and merge the duplicated Line_Cartesian/ Line_Direct handling into setup_line_kpoints (symmetry check, line interpolation, unit weights, coordinate-done flag). parse_kfile is now a thin header/count reader plus two dispatch calls; its cyclomatic complexity drops 16 -> 7, removing the -16 complexity penalty.
Pass ofs_warning explicitly into read_kpoints/parse_kfile/read_mp_mesh/ read_listed_kpoints and my_rank into read_kpoints (following the mpi_k/generate_kfile pattern), removing 8 GlobalV references from the k-point reading path. set() now reads MY_RANK/MY_POOL once into locals and reuses them. Update the 30+ private-access call sites in klist_test and print_info_test accordingly. Also wrap three >120-char lines and reword a WARNING_QUIT message whose "nspin = 1" text tripped the default-parameter heuristic.
Move the rank-0 -> all kstars broadcast loop out of K_Vectors::mpi_k into a this-free KListIO helper. The wrappers compile to no-ops in serial builds, so the helper is guarded only by __EXX at the call site like the original block.
Move the inversion check and the time-reversal operation expansion (Theta*g antiunitary coset for magnetic nspin=4, -g doubling otherwise) out of K_Vectors::reduce_by_symmetry into the this-free KListIO::append_time_reversal_ops. The physics comment moves with the logic. reduce_by_symmetry cyclomatic complexity drops 13 -> 7 and the file loses the Matrix3 'inv' local (brace-initialized in the helper), removing a 9-parameter false positive; klist.cpp 793 -> 763 lines.
…ng from K_Vectors::set Move the full k-point Cartesian-coordinate completion (kc/kd branches) into KListIO::fill_full_kvec and the reciprocal/real lattice mismatch handling (symmetry_autoclose retry vs WARNING_QUIT) into a private K_Vectors::handle_symmetry_mismatch member. This drops the set() cyclomatic complexity penalty; klist.cpp score rises 45 -> 50.
…ate_kfile to KListIO - cal_ik_global: inlined as KListIO::build_ik2iktot free function (6 params), called directly from set(); the private member declaration is removed. - set_kup_and_kdw: logic body (switch/case 1 and 2) moved to KListIO::expand_spin_kpoints free function; the public member shell keeps TITLE() plus the spin=2 OUT log lines so existing 5 call sites and tests remain source-compatible. - generate_kfile: this-free body renamed KListIO::write_auto_kfile with a UnitCell fwd-decl in klist_io.h (header dep rule 3); private declaration is removed from klist.h. klist.cpp shrinks 771 -> 673 lines; file_too_long deduction drops from -12 to -8; score raises 50 -> 54.
bee21a3 changed the kvec_c_full loop in pack_kpts from `nkstot` to `kvec_c_full.size()`, but the aux buffer is still allocated as `nkstot_nospin * 3` (which equals `nkstot * 3` at the assignment point in klist.cpp:291, before spin doubling). For nspin=2 cases (spin_mult=2), kvec_c_full has been resized to `nkstot * 2` by renew(), so the new loop writes 2x past the end of kvec_c_full_aux, corrupting the heap and causing `free(): invalid pointer` when ESolver_FP is destroyed. Restore the original `nkstot` bound so the behavior matches the pre-refactor code exactly. The aux buffer (allocated as `nkstot_nospin * 3`) and bcast length (`nkstot_nospin * 3`) are unchanged; only the loop upper bound is restored. Verified: 12 failed 01_PW tests (003, 007, 028, 030, 034, 036, 037, 050, 055, 063, 078, 079, 097x2, 206, 815, scf_deltaspin2) all pass again; valgrind reports no Invalid write from ABACUS code.
…arning through klist API Three intertwined changes that must ship together to keep the build green: 1. Rename `nkstot_full` -> `nkstot_nospin` (member, getter, setter) across all consumers (source_cell, source_lcao/module_ri, module_bse, module_lr, module_rdmft, source_pw/module_pwdft, source_io). The old name was ambiguous: EXX/RI/LR code already treats it as "physical k-point count WITHOUT spin multiplicity" (see e.g. ri_2d_comm.hpp: `ik_full + is_k * nkstot_full`), so the new name makes the convention explicit. Comments in reciprocal_grid.h now document both: - nkstot: INCLUDING spin multiplicity (after set_kup_and_kdw) - nkstot_nospin: physical k-points, WITHOUT spin multiplicity 2. Thread `std::ostream& ofs_warning` through K_Vectors::set, setup_line_kpoints, set_both_kvec, update_use_ibz, reduce_by_symmetry, handle_symmetry_mismatch, and read_mp_mesh so they no longer read `GlobalV::ofs_warning` directly. Internal ModuleBase::WARNING calls are replaced with `ofs_warning <<` to keep behavior consistent. The klist module itself no longer references GlobalV::ofs_warning; outer callers (esolver_fp, esolver_gets, esolver_lr_lcao_tddft, deepks_test_prep) pass `GlobalV::ofs_warning` at the boundary. 3. Thread `int my_rank` through update_use_ibz, reduce_by_symmetry, handle_symmetry_mismatch to remove `GlobalV::MY_RANK` reads inside the klist module. Also included: dftu_base static-member cleanup (mark_occ_mat_initialized -> this->occ_mat_initialized = true) which was already in the working tree and is consistent with the project rule "no static members in dftu_base.h". Behavior is unchanged. Build passes with `cmake --build build_max_para_test -j 30`. All 12 previously-failing 01_PW tests (003, 007, 028, 030, 034, 036, 037, 050, 055, 063, 078, 079, 097x2, 206, 815, scf_deltaspin2) pass with identical etot; valgrind reports no ABACUS-side Invalid write.
mohanchen
requested review from
Flying-dragon-boxing
and removed request for
AsTonyshment
September 3, 2026 22:19
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.
Refactor klist, fix a few bugs