Skip to content

Unify ionic-step header keyword, cube channel suffixes, and Vxc(R) sparse output filename in IO outputs - #8293

Open
mohanchen wants to merge 37 commits into
deepmodeling:developfrom
mohanchen:2026-11-05-a
Open

mohanchen wants to merge 37 commits into
deepmodeling:developfrom
mohanchen:2026-11-05-a

Conversation

@mohanchen

Copy link
Copy Markdown
Collaborator

Summary

This PR consolidates a set of IO-output naming clean-ups that have grown
inconsistent across different writers. Three coordinated changes:

1. Unify ionic-step header keyword to Ionic_Step N

Output files written during geometry relaxations / MD previously used a
mix of header markers — RELAX STEP N, STEP: N, IONIC STEP N,
# istep: — across different writers. All text-based per-step outputs
now use the single form # Ionic_Step N (one-based), matching the
existing STRU-frame convention and the project-wide rule recorded in
AGENTS.md.

Files updated:

  • source_io/module_hs/* (HS/H(R)/S(R) dense + sparse writers)

  • source_io/module_dos/write_pdos_text.cpp

  • source_io/module_wfc/* (WFC / band header lines)

  • Related integration fixtures under tests/02_NAO_Gamma/**/*.ref

2. Disambiguate Libxc cube channel suffixes from real spin indices

write_libxc_r.cpp previously tagged every cube channel with _sN,
which collided with the real-spin convention used by rho / vrho
(s1 = spin-up, s2 = spin-down). Tensor quantities (sigma,
vsigma, v2rho2, v2rhosigma, v2sigma2, v3rho3, … v4sigma4)
now carry explicit Libxc channel-index tuples (_00, _01, _11, …)
and scalar quantities (exc, amag) drop the redundant _s1 suffix.

category before after
real spin rho_s1.cube, vrho_s2.cube unchanged (_sN is meaningful)
scalar exc_s1.cube, amag_s1.cube exc.cube, amag.cube
3-ch tensor sigma_s1/s2/s3.cube sigma_00/01/11.cube
6-ch tensor v2rhosigma_s1..s6.cube v2rhosigma_00_0 / 00_1 / … .cube
higher-order v3sigma3_s1..s10.cube v3sigma3_00_00_00 / … .cube

A small set of helper lambdas generates the suffix lists, so the
Libxc channel ordering stays consistent with libxc_tools.cpp
((00), (01), (11) for 3-channel tensors, symmetric-combination order
for higher ranks).

3. Rename Vxc(R) sparse CSR fixture to canonical form

source_io/module_hs/vxc_op_r.cpp was writing the Vxc(R) sparse matrix
as Vxc_R_spin0.ref in test fixtures. The file is now produced under
the canonical LCAO-matrix naming vxcrs{spin}_nao.csr, aligned with
hsr_writer / dsr_writer conventions. The fixture under
tests/02_NAO_Gamma/scf_out_hxc/ is renamed and its header assertion
updated accordingly.

Verification

  • make -j$(nproc) : full build passes, zero errors

  • source/source_io/module_chgpot/write_libxc_r.cpp compiles cleanly under __LIBXC

  • Integration references under tests/02_NAO_Gamma/, tests/03_NAO_multik/,
    and tests/08_RI/ have been updated to match the new header strings

Migration note for downstream users

Any post-processing scripts that parse the per-step header from
HS/H(R)/DOS/PDOS/WFC output files should look for Ionic_Step N
instead of STEP: N, RELAX STEP N, IONIC STEP N, or istep:.
Cube-filename consumers should switch from the _sN suffix pattern to
the new explicit index tuple for tensor quantities; real-spin files
(rho_s1, vrho_s2) are unaffected.

abacus_fixer added 12 commits November 5, 2026 15:08
…out_app_flag=2

The band output did not honor out_app_flag=2: the filename never received
a g{step} suffix and always wrote into global_out_dir, so multi-step runs
(MD/relax) would overwrite bands1.txt / bands2.txt and only keep the last
step.

Changes:
- Add global_band_dir to System_para, mapped to OUT/<suffix>/BANDS/ in mode 2
  and falling back to global_out_dir otherwise; includes MPI broadcast.
- write_bands: use global_band_dir as the output directory, add g{istep+1}
  suffix when out_app_flag==2, and lazily ensure the BANDS/ directory exists.
- Tests: sync io_sys_var_test directory assertions and test_write_bands
  TestParameters with the new global_band_dir.

Verified: MODULE_IO_write_bands (10/10), MODULE_IO_system_variable_test pass;
esolver builds cleanly; governance check has no new blockers.
Replace the legacy "RELAX STEP" keyword and pre-existing inconsistent
"Ionic Step" (with space) occurrences with "Ionic_Step" (underscore) to
match the established convention already used by write_cube.cpp and
related integration-test fixtures.

Production code:
- source_relax/relax_stru_io.cpp: STRU file provenance header
- source_io/module_output/print_info.cpp: stdout/ofs_running run logs
- source_io/module_hs/vxc_op_tools.cpp: eband decomposition energy header
- source_pw/module_pwdft/dftu_base_io.cpp: DFTU occ_mat provenance header
- source_io/module_dm/write_dmk.cpp: DM(k) frame header (historical)
- source_io/module_dm/write_dmr.cpp: DM(R) CSR frame header (historical)
- source_io/module_hs/hsr_writer.cpp: H(R)/S(R) CSR frame header (historical)
- source_io/module_mulliken/output_mulliken.cpp: Mulliken output frame header (historical)

Tests:
- source_relax/unittests/test_relax_stru_io.cpp
- source_io/unittests/test_print_info.cpp
- source_io/module_dm/test/write_dmk_test.cpp
- source_io/module_dm/test/test_write_dmr.cpp
- source_io/module_hs/unittests/test_hsr_writer.cpp

Comments / doc strings:
- source_base/module_out/csr_reader.h: CSR format example
- source_io/module_parameter/read_inp_out.cpp: out_stru parameter description

Verification:
- make -j 30 -> 100%
- ctest -R "(RELAX_relax_stru_io|IO_print_info|IO_vxc_op_tools|PW_dftu_base|
  IO_mulliken|IO_write_dmk|IO_write_dmr|IO_hsr_writer)" -> 10/10 PASSED
- grep -rn "RELAX STEP" / "Ionic Step " -> zero matches in source tree
Production code:
- source_io/module_wf/write_wfc_nao.cpp: wf{ki}s{spin}_nao.txt provenance header
- source_io/module_energy/write_bands.cpp: band eigenvalue provenance header

Tests:
- source_io/unittests/test_write_wfc_nao.cpp
- source_io/unittests/test_read_wfc_nao.cpp
- source_io/unittests/test_write_bands.cpp

Verification:
- make -j 30 -> 100%
- ctest -R "(IO_write_wfc_nao|IO_read_wfc_nao|IO_write_bands|
  RELAX_relax_stru_io|IO_print_info)" -> 8/8 PASSED
- grep -rn "RELAX STEP\|Ionic Step \|IONIC STEP" -> zero matches
Three source output files wrote "# ionic step" (or "X # ionic step") in
their per-ionic-step header comments, while STRU and cube outputs already
use "Ionic_Step". Rename to the unified keyword across:
- cal_dos.cpp      -> "X    # Ionic_Step" (doss*.txt / pdoss*.txt)
- write_eig_occ.cpp -> "X     # Ionic_Step" (eig_occ.txt)
- hs_dense_io.cpp  -> "# Ionic_Step X"  (HS dense matrix)

Sync test assertions and INPUT parameter description accordingly.
Also refines the INPUT file under examples/17_relax/04_relax_with_output_lcao
with end-of-line filename comments for each enabled out_* parameter.
The prior commit 4038796 unified "# ionic step" to "# Ionic_Step" in
hs_dense_io.cpp but missed test_hs_dense_io.cpp, causing TextHeaderContains
StepAndDimension and TextHeaderStepTwo to fail. Sync the EXPECT_NE find()
strings and a nearby comment.

Verification: MODULE_IO_hs_dense_io_test -> 11/11 PASSED.
Three writers produced per-frame headers as "STEP: N" or "IONIC_STEP: N":
- pos_op_csr.cpp       (rr_nao.csr, rx_nao.csr, ...)
- hs_sparse_io.cpp     (hrs*.csr, srg*.csr, trs*.csr, ...)
- dhs_sparse_writer.cpp (dhrx*.csr, dsrx*.csr, ...)
- overlap.cpp          (S_async(R) overlap)

Rename to "Ionic_Step N" (keyword-first, no colon) to match STRU cube,
doss, eig_occ, and HS dense-matrix headers unified in the previous commit.

Sync test assertions, fixture SR.csr, and comments accordingly.
PDOS text output (write_pdos_text.cpp) used "# istep:" as its per-step
header keyword while all other outputs had already been unified to
"Ionic_Step". This was the last remaining non-Ionic_Step keyword in
production output.

Production code:
- source_io/module_dos/write_pdos_text.cpp

Tests:
- source_io/module_dos/unittests/test_write_pdos_text.cpp (5 assertions)

Docs:
- docs/advanced/elec_properties/dos.md (PDOS format example and description)

Verification:
- make -j 30 -> 100%
- MODULE_DOS_write_pdos_text -> 5/5 PASSED
hs_dense_io.cpp writes "# Ionic_Step N" since the keyword unification, but
the hk/sk/vxc/dH reference files still contained "# ionic step". CompareFile.py
compares comment lines token by token, so those matrix comparisons would fail.
Update 31 references under tests/; value data is unchanged.
out_mat_r writes a single rr_nao.txt (or MAT/rrg{step}_nao.txt when
out_app_flag = 2) rather than separate rxrs/ryrs/rzrs CSR files. Update
the INPUT description, the position-matrix guide, and the example INPUT
comment, and align the documented frame header with the emitted
Ionic_Step keyword.
Tensor quantities (sigma, vsigma, v2rho2, v2rhosigma, v2sigma2, v3rho3,
v3rho2sigma, v3rhosigma2, v3sigma3, v4rho4, v4rho3sigma, v4rho2sigma2,
v4rhosigma3, v4sigma4) previously used _s1/_s2/_s3 suffixes that collide
with the real spin-index convention used by rho and vrho.  Replace them
with explicit Libxc-channel index tuples (_00, _01, _11 for 3-channel
tensors, etc.).  Scalar quantities (exc, amag) no longer carry a
redundant _s1 suffix.  Rho and vrho keep _sN since those map to actual
spin indices.  A set of small helper lambdas generates the suffix lists
so the channel ordering stays consistent with Libxc throughout.
Follow the repository NAO sparse-matrix naming convention: one-based
spin index, "_nao.csr" suffix, and the g{step} suffix plus append
behavior driven by out_app_flag in mode 2. Pass the ionic step and
out_app_flag explicitly into write_Vxc_R instead of hard-coding
istep = -1. Update the out_mat_xc2 help text, the example INPUT
comment, and the scf_out_hxc reference fixture (including its
Ionic_Step header).
@mohanchen mohanchen added Input&Output Suitable for coders without knowing too many DFT details Refactor Refactor ABACUS codes The Absolute Zero Reduce the "entropy" of the code to 0 Solve before 3.11 labels Nov 5, 2026

@ABACUS-PR-BOT ABACUS-PR-BOT left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The output changes introduce mismatched derivative labels, a CSR step-reader regression, stale Vxc records on reruns, and unmigrated integration headers. The global-dependency budget and three non-blocking documentation/test items also need attention. Static source and API-contract review of 63431111; no builds or tests were run.

auto make_v2rhosigma_suffixes = [](int num_spin) -> std::vector<std::string>
{
if (num_spin == 1) { return {"00_00"}; }
return {"00_0", "00_1", "01_0", "01_1", "11_0", "11_1"};

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P2] Match mixed-derivative labels to Libxc packing

For polarized GGA output (out_xc_r >= 2), v2rhosigma component 1 is (rho0,sigma01), but this table labels it 00_1; several files therefore identify the wrong derivative. v3rho2sigma and v4rho3sigma also encode one extra rho index. Generate the mixed suffix tables from Libxc’s ordered tuples, pass them through named locals, and add a field-to-filename test. Audit v4rho2sigma2 too: its existing allocation/stride is 15 rather than Libxc’s 18, so expanding the new labels alone would be insufficient.

}

ofs << " --- Ionic Step " << istep + 1 << " ---" << std::endl;
ofs << " --- Ionic_Step " << istep + 1 << " ---" << std::endl;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P2] Update the CSR step reader with the header

csrFileReader::parseFile() still skips three strings before reading the step. With --- Ionic_Step 1 ---, it discards 1 and attempts to parse the trailing --- as an integer, so getStep() loses the recorded step. Support both header spellings with checked extraction and assert a nontrivial step in the writer-to-reader test.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The valid-header regression is addressed in ef9764dc: the reader now recognizes bare/decorated Ionic_Step and legacy Ionic Step. Non-blocking: the new extraction still silently defaults malformed or missing step values to zero; require a recognized marker and successful integer extraction. When reconciling the newer develop parser, retain both valid spellings and invalid-header tests. This is source inspection, not an executed parser test.

os << std::setprecision(4);
/// step info
os << " --- Ionic Step " << istep+1 << " ---" << std::endl;
os << " --- Ionic_Step " << istep+1 << " ---" << std::endl;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P2] Migrate the remaining integration reference headers

Live references such as tests/02_NAO_Gamma/scf_out_mul/mulliken.txt.ref and tests/03_NAO_multik/scf_out_hsr/hrs1_nao.csr.ref still contain --- Ionic Step 1 ---. Their comparison paths retain this line, and CompareFile.py rejects the changed token count before comparing numerical data. Update the affected reference headers while preserving numerical values and tolerances.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The reference-header mismatch is addressed in 6703379c. The updated references match the current writers, including the one-based cube step, while preserving numerical payloads and tolerances. This is a static source comparison; integration tests were not run.

Comment thread source/source_io/module_hs/vxc_op_r.cpp Outdated
options.binary = false;
options.istep = -1;
options.istep = istep;
options.out_app_flag = out_app_flag;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P2] Truncate the first Vxc write of a fresh run

With out_app_flag=1, a fresh LCAO relaxation ending at istep>0 now appends to an existing vxcrs1_nao.csr. Vxc is written only from after_all_runners, so open_sparse_file() never receives a step-zero write to clear the previous run. Separate first-write truncation from the final geometry index and cover a rerun with a seeded output file.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Addressed in 574e84f3: write_Vxc_R() now forces overwrite for its fixed-name final snapshot while retaining the actual ionic step in the header. By source inspection, a fresh run ending after step zero therefore cannot append stale frames from an earlier run; the rerun case was not executed.

if (inp.out_band[0])
{
// Mode-2 BANDS/ subdirectory is created lazily at write time.
ModuleBase::ensure_directory(PARAM.globalv.global_band_dir);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P2] Keep the global-dependency budget non-increasing

This additional PARAM read leaves the full production diff at four added global references versus three removed, exceeding the project’s non-increasing budget. Capture the band directory once and reuse it for directory creation and filename construction, or pass it explicitly.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The global-reference increase is addressed in 1021fac3: the solver passes the band directory once, and the writer reuses it for directory creation and filenames. Static source review only; builds and tests were not run.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The earlier band-directory fix remains intact, but the full diff at af5a0e66 again exceeds the global-reference budget: the baseline governance checker reports 21 added references and 17 removed (net +4). The eight new GlobalV::MY_RANK guards in test_hsr_writer.cpp contribute to this increase. Factor repeated rank access through a test helper or otherwise restore the non-increasing budget.

out_xc_r 1 # CHG/rho*.cube, vrho*.cube, etc. (Libxc real-space XC derivs.)

out_freq_ion 2
out_app_flag 1

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Non-blocking: this example selects out_app_flag 1, but most new comments describe mode-2 subdirectories and g{step} filenames. Align the comments with the selected mode (or select mode 2); out_xc_r also writes xc_*.cube in the output root rather than CHG/rho*.cube.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The new layout comments now distinguish modes 0/1 from mode-2 subdirectories. Non-blocking: remove pbands from the line-26 list that says final snapshots drop g{step}; the writer and the detailed out_proj_band row retain pbands{spin}g{last}.xml in mode 2.


if (inp.out_app_flag == 2)
{
ss << "g" << istep + 1;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Non-blocking: document the new mode-2 paths BANDS/bandgN.txt and BANDS/bandsSgN.txt in the out_band and out_app_flag INPUT help, with one-based geometry index N and spin index S. The authoritative directory list currently omits BANDS/.

void set_output(const std::string& directory, bool append)
{
parameter_.sys.global_out_dir = directory;
parameter_.sys.global_band_dir = directory;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Non-blocking: the current writer cases never select out_app_flag=2. Add a focused case for lazy BANDS/ creation and two steps of the spin-resolved gN files, checking exact names and independent contents. Set mode 2 in both the passed Input_para and the lower-level output configuration.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Non-blocking: for the new band_dir argument, have the mode-2 test pass a directory different from the global one. The current fixture aliases them, so it would still pass if the writer reverted to reading the global directory. Static test-source review; tests were not run.

abacus_fixer added 3 commits November 6, 2026 14:44
The earlier commit 91465ba updated 31 .txt.ref files under tests/ for
the Ionic_Step unification, but left .csr.ref, rr_nao.txt.ref,
mulliken.txt.ref and cube.ref fixtures still carrying the legacy
"--- Ionic Step N ---", "STEP: N" or "IONIC_STEP: N" headers.
CompareFile.py does a token-by-token compare and those mismatches cause
the integrating tests (md_out_hk_syns, scf_out_hk_spin2, scf_out_mul,
scf_out_mul_spin2, ...) to fail. Update 41 remaining reference files
under tests/02_NAO_Gamma/ and tests/03_NAO_multik/ to the new unified
"Ionic_Step N" keyword. Data values are untouched.
The eig_occ.txt per-ionic-step header was unified from "X     # ionic
step" to "X     # Ionic_Step", but the ASE reader still counted frames
with endswith('# ionic step'), yielding nframe = 0 and failing the
assertion len(ik) == nframe * nspin * nk in read_band_from_eig_occ.

Match the header with a case-insensitive regex that accepts both the
old and the new spelling, and sync the nspin4-gamma-eigocc fixture to
the current format.
The out_band BANDS/ change read PARAM.globalv.global_band_dir inside
write_bands, which pushed the PR over the global dependency budget
(added=4, removed=3, net_delta=1) and blocked CI.

Resolve the directory once in ESolver_KS::after_scf and pass it as an
explicit argument, following the existing write_eig_file /
output_mat_sparse convention. This keeps the band writer free of PARAM
and brings the PR-wide delta to zero.

Verified: MODULE_IO_write_bands 2/2 passed; abacus_basic_para target
builds; governance diff counting gives net_delta=0.

@ABACUS-PR-BOT ABACUS-PR-BOT left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The reader now accepts both step-header spellings. The suggestion below covers the legacy format. Static incremental review; builds and tests were not run.

nframe = len([l for l in raw if l.endswith('# ionic step')])
# The per-ionic-step header is ``X # Ionic_Step`` in the latest output,
# while older outputs wrote ``X # ionic step``. Accept both spellings.
step_header_pat = r'\d+\s+#\s+ionic[ _]step$'

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Non-blocking: the updated fixture covers only Ionic_Step, although this reader also promises support for ionic step. Run the same fixture through both spellings and compare the parsed frames, energies and occupations so a later change cannot silently drop compatibility with existing eig_occ.txt files.

abacus_fixer added 8 commits November 7, 2026 11:33
The non-MPI-specific tests in test_hsr_writer.cpp performed file I/O
on all MPI ranks simultaneously, causing file corruption and race
conditions when the test binary was launched with mpirun -np 2.

- For the 7 tests that call the non-collective write_hcontainer_csr /
  write_hcontainer_csr_binary directly, add an early return on
  non-zero ranks so only rank 0 writes/reads/removes the files.
- For WriteHsrTextCsrCarriesPerSpinFermiFromEfermi, keep the collective
  write_hsr call (which internally uses gatherParallels) on all ranks,
  but guard the file read-back, assertions, and cleanup to rank 0 only.

Verified: single-process (21 passed, 1 skipped) and mpirun -np 2
(22 passed on both ranks), plus ctest serial+parallel both pass.
The MO-basis Vxc matrix written by out_mat_xc reused the "vxc" property,
which resolved to the same vxck{ik}s{spin}_nao.txt filename as the
NAO-basis matrix from out_mat_vxck; with out_app_flag 0/1 the later
writer silently overwrote the former. Give the MO-basis matrix its own
"vxcmo" property and pass the real ionic step and out_app_flag into
write_Vxc instead of locally shadowed constants, which restores the
one-based Ionic_Step header and the mode-2 g{step} suffix. Update the
two integration fixtures and props_mat.sh accordingly.
write_Vxc_R is called from ctrl_runner_lcao, which runs once at the end
of the whole calculation, so out_app_flag=2 only ever produced a single
vxcrs{spin}g{N}_nao.csr file. Drop the per-step suffix and always
truncate, matching the documented vxcrs{spin}_nao.csr name, and remove
the now unused out_app_flag parameter.
write_h_term looped both spin channels while write_hk_common enumerated
only the spin-up k indices, so Vnl(k)/Vl(k)/Vh(k) were written twice
into s1 files, and Vxc(k), which is spin dependent, placed both channels
in the same s1 file. Enumerate the local k points of each spin through
K_Vectors::isk as write_hsk does, pass nspin=1 to filename_output for
spin-independent terms so they carry no spin suffix, and apply the same
enumeration to the EXX writer and to T(k).
Emit the column header only once per file and stamp each frame with
"# Ionic_Step <1-based step>" so the angular-momentum matrices match the
step labelling of the other matrix outputs. Appending frames no longer
repeats the full header.
Mode 0 previously kept every written frame and mode 2 ignored the step
number. Open the file per the selected mode: overwrite for mode 0, append
after the first step for mode 1, and write mullikeng{step}.txt in mode 2.
write_eig_file always appended after the first step and ignored the ionic
output frequency, so mode 0 kept every frame and mode 2 had no step suffix.
Gate the write by out_freq_ion and open the file per out_app_flag: overwrite
in mode 0, append after the first step in mode 1, and write eig_occg{step}.txt
in mode 2.
out_band was dumped on every ionic step regardless of out_freq_ion, so a
run with out_freq_ion = 2 produced five band frames while the other
step-scoped outputs produced three. Gate write_bands with the same
frequency used by eig_occ.txt; a non-positive frequency still writes
every step.
abacus_fixer added 14 commits November 7, 2026 12:33
The band-decomposed energy files were emitted only from ctrl_runner_lcao,
which runs once at the end, so a multi-step run produced a single frame and
mode 2 had no step suffix. Move the write_Vxc/write_eband_terms calls to
ctrl_scf_lcao and honour out_app_flag in the file name and open mode:
mode 0 overwrites, mode 1 appends after the first step, mode 2 writes
eband_*g{step}.txt. The CMake-listed signature of ctrl_scf_lcao now takes a
non-const Structure_Factor because the potential builders need its address.
The pbands{spin}.xml files ignored out_app_flag, so mode 2 produced the
same fixed name as the other modes, and the document carried no ionic-step
annotation. Write pbands{spin}g{step}.xml in mode 2 (XML cannot be appended,
so mode 1 keeps overwriting the fixed name) and add an Ionic_Step XML
comment that parsers ignore.
out_xc_r wrote xc_*.cube files into the output root with a fixed name in
every mode. Build the name from the charge-density directory (CHG/ in
mode 2, matching the other cube writers) and apply out_app_flag: append
after the first written step in mode 1 and append g{step} in mode 2.
mulliken used " --- Ionic_Step N ---" and doss used "N    # Ionic_Step",
so the same ionic step was annotated in two more shapes. Both now emit the
"# Ionic_Step N" comment line already used by bands, pdos and the eband
files, which also lets comment-aware plotters skip the line. eig_occ keeps
its "N     # Ionic_Step" form because
interfaces/ASE_interface/abacuslite/io/latestio.py parses exactly that
pattern.
…trices

hcontainer CSR, dmk and dmr files prefixed the step with
" --- Ionic_Step N ---" while the other sparse writers already used
"Ionic_Step N". Emit the bare spelling everywhere and teach csrFileReader
to also accept the old wrapped spelling (and the older "Ionic Step N"
form) so restart files written before this change stay readable.
Several comments still advertised the pre-fix naming: out_mat_xc pointed
at the eband files, out_eband omitted kin/vl/vnl/hart, vnlk/vlk/vhk/tk
still showed a spin suffix, out_mat_xc2 was not marked as a final
snapshot, out_xc_r missed the CHG/ directory, and mulliken/band/dos/
proj-band/out_stru did not spell out the out_app_flag mode behaviour.
Comment-only change; no input value is touched.
dH(k)/dT(k)/d*V(k) files were named with neither the spin channel nor the
ionic step, so nspin=2 wrote both spins to one file and out_app_flag=2
overwrote the same fixed name on every step. Mirror the other MAT outputs:
append s{spin} for nspin=2 and g{step} for mode 2.
cal_ldos_lcao passed a hard-coded 0 as the iteration to write_vdata_palgrid,
so the LDOS cube always claimed "Ionic_Step 1" even though it is written once
by after_all_runners for the final step. Thread the runner's ionic step through
the writer instead.
The libxc files contained only the raw grid values, so they were not
readable as Gaussian cube files and appended frames had no separator.
Reuse the regular cube header (Ionic_Step line, grid geometry and atom
list) before the data block; mode 1 now appends complete frames.
Sync the INPUT reference and the relax example comments with the recent
output changes: out_ldos and out_proj_band are written once for the final
ionic step, out_xc_r files now carry a full cube header including the
one-based ionic step, and out_mat_dh/k-space naming replaces the stale
dH(R) description.
Get_pchg_lcao passed a hard-coded 0 as the iteration to write_vdata_palgrid,
so every pchg cube claimed "Ionic_Step 1". Thread the runner's ionic step
through begin_gamma/begin_k.
cal_ldos_pw (and its ldos_mode_pw / stm_mode_pw helpers) passed a hard-coded
0 as the iteration to write_vdata_palgrid, so every PW cube claimed
"Ionic_Step 1". Store the last ionic step in ESolver_KS_PW and thread it
through ctrl_runner_pw down to the cube writer.
The ionic step in matrix output headers is now 1-based, but the
vxcmo_nao.txt and vxcmok2_nao.txt references still carried Ionic_Step 0,
so scf_out_hxc (02_NAO_Gamma) and scf_out_xc_multik (08_RI) failed
during property validation.

Verified with build_max_para_test: both categories pass
(02_NAO_Gamma 28s, 08_RI 24s).
Add a layout convention block to the 04_relax_with_output_lcao INPUT so
the SUB/ prefixes and g{step} suffixes are understood as mode-2 behaviour,
with mode 0 truncating and mode 1 appending fixed files in OUT.${suffix}.

Also correct the out_stru, out_elf, out_mat_ds and out_mat_t descriptions
so they match the produced file names, and switch the example to
out_app_flag=0.

@ABACUS-PR-BOT ABACUS-PR-BOT left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The new output modes break the bundled ASE reader for multi-step or numbered eigenvalue files, and mode 1 discards earlier MO Vxc matrices. The inline comments identify the required consumer and append changes.

Static incremental review of af5a0e66: source/caller inspection and whitespace/governance checks only; no builds or runtime tests. CI diagnostics are unavailable. The newer develop tip 27c3e106 also has CSR merge conflicts with this head; the integrated revision remains unverified.

|| (inp.calculation == "md" && inp.mdp.md_restart);
// A restart of an MD run keeps the records of the previous run in
// mode 1; every other first-step write truncates the fixed file.
const bool restart_append = (inp.calculation == "md" && inp.mdp.md_restart);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P2] Update the ASE consumer for the new eigenvalue output modes

A multi-step relax/MD run with the default out_app_flag=0 now keeps one eigenvalue frame, but latestio.read_abacus_out() still opens eig_occ.txt and asserts one eigenvalue frame per trajectory frame before selecting the requested image. Mode 2 instead leaves that filename missing, and out_freq_ion>1 can also break frame alignment. Update file discovery and step-based alignment in the bundled ASE reader, with multi-step, numbered-file, and skipped-step coverage.

const bool append_vxc = (out_app_flag == 1);
// This MO-basis matrix is a single-snapshot output, so the file is
// always truncated. Only mode 2 adds the g{istep+1} suffix.
const bool append_vxc = false;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P2] Append the now per-step MO Vxc matrices in mode 1

write_Vxc() now runs from ctrl_scf_lcao() on each selected ionic step, so this is no longer a single final snapshot. With out_mat_xc=1 and out_app_flag=1, append_vxc=false truncates the same vxcmo*.txt at every write, losing earlier matrices while the associated energy files append. Honor mode-1 append after the first step and cover two distinct frames plus fresh-run truncation.

// Modes 0 and 1 reuse the fixed name; only mode 2 numbers the frames.
if (out_app_flag == 2)
{
name += "g" + std::to_string(istep + 1);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Non-blocking: update the out_eband and out_mat_xc Input_Item descriptions for their new output cadence, mode-2 eband_*gN.txt filenames, and vxcmo matrix names. The current descriptions still list only fixed energy names and omit the changed matrix naming contract.

remove("eig_occ.txt");

// Mode 2: one g{step} file per written step.
ModuleIO::write_eig_file(ekb, wg, *kv, nbands, nspin, out_dir, 1, 2);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Non-blocking: derive this new mode-2 output path, its readback, and cleanup from testing::TempDir(). out_dir is still "./", so the added eig_occg2.txt fixture is written into the working directory, contrary to the test scratch-file convention.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Input&Output Suitable for coders without knowing too many DFT details Refactor Refactor ABACUS codes Solve before 3.11 The Absolute Zero Reduce the "entropy" of the code to 0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants