Skip to content

Unify output directory structure with out_app_flag=2 - #8159

Open
mohanchen wants to merge 49 commits into
deepmodeling:developfrom
mohanchen:2026-10-16-b
Open

mohanchen wants to merge 49 commits into
deepmodeling:developfrom
mohanchen:2026-10-16-b

Conversation

@mohanchen

Copy link
Copy Markdown
Collaborator

Summary

Resolves #8151. This PR unifies the output directory structure by extending out_app_flag from bool to int with three modes, and routes all output files to consistent uppercase subdirectories when enabled.

Problem

In RT-TDDFT and MD calculations, output files (.cube charge densities, WFC files, matrices, etc.) accumulate in the OUT.<suffix>/ root directory, making it difficult to navigate and manage results.

Solution

out_app_flag semantics (backward compatible)

Value Behavior Directory
0 No append, files get step suffix Root OUT.xxx/
1 (default) Append to same file Root OUT.xxx/
2 (new) No append, files get step suffix Unified subdirectories

Unified subdirectories (only created when out_app_flag=2 and the output is requested)

Directory Contents
PSI/ Wave functions (PW and LCAO unified, replaces WFC/)
CHG/ Charge density (chg, tau)
POT/ Potential (pot, potes)
ELF/ Electron localization function
DOS/ DOS, PDOS, LDOS
DIP/ Dipole
MAT/ Matrices (replaces matrix/, includes dmk, lx/ly/lz, rr, tr)

Key changes

  • Parameter: out_app_flag changed from bool to int with validation {0,1,2}
  • Directory variables: 7 new System_para members (global_psi_dir, global_chg_dir, etc.) with MPI broadcast
  • On-demand creation: Subdirectories only created when the corresponding output flag is enabled
  • Path routing: All output paths updated to use the new directory variables
  • Backward compatibility: Default out_app_flag=1 preserves existing behavior (root directory, append mode)

Verification

  • Build: make -j 30 passes on build_max_para_test
  • Governance: Global dependency budget net decrease of 1 (no new PARAM/GlobalV cross-layer control)
  • Tests: Updated 4 unit test files and 1 integration test script for new semantics
  • Docs: Updated 4 documentation files describing out_app_flag behavior

Files changed

  • source/source_io/module_parameter/ — input parameter, read logic, global directory setup
  • source/source_io/module_ctrl/ — output path routing for chg/pot/elf/dos/dip/wfc
  • source/source_io/module_dm/ — dmk path routing
  • source/source_io/module_hs/ — matrix output path routing (hsr, pos_op, dhs, vxc)
  • source/source_base/module_out/ — filename_output signature update
  • tests/ — unit and integration test updates
  • docs/ — documentation updates

abacus_fixer added 8 commits October 16, 2026 14:47
…unified output directories

- Change out_app_flag from bool to int with three states:
  0: no append, no subdirectory (overwrite)
  1: append to same file (default, backward compatible)
  2: write to unified subdirectories
- Add new global directory variables in System_para:
  global_psi_dir, global_chg_dir, global_pot_dir,
  global_elf_dir, global_dos_dir, global_dip_dir, global_mat_dir
- Initialize directories in set_global_dir():
  out_app_flag==2 -> OUT.suffix/{PSI,CHG,POT,ELF,DOS,DIP,MAT}/
  otherwise -> all point to global_out_dir (backward compatible)
- Map legacy WFC->PSI, matrix->MAT
- Update all out_app_flag usages from bool to int semantics
- Broadcast new directory variables via Parallel_Common::bcast_string

Issue: deepmodeling#8151
- ctrl_output_fp.cpp: route chg/tau to global_chg_dir, pot/potes to
  global_pot_dir, ELF to global_elf_dir, dipole to global_dip_dir
- ctrl_output_pw.cpp: route wfc to global_psi_dir, dos to global_dos_dir,
  ldos to global_dos_dir
- ctrl_scf_lcao.cpp: route dos to global_dos_dir
- ctrl_runner_lcao.cpp: route ldos to global_dos_dir
- read_input.cpp: create subdirectories (PSI/CHG/POT/ELF/DOS/DIP/MAT)
  when out_app_flag==2
- Update docs: out_app_flag semantics from bool to int (0/1/2)

Issue: deepmodeling#8151
When out_app_flag defaults to 1 (not 2), all new unified directories
(PSI, CHG, POT, ELF, DOS, DIP, MAT) map to global_out_dir for
backward compatibility. Update io_sys_var_test.cpp expectations:
- global_matrix_dir: "OUT.test/matrix/" -> "OUT.test/"
- Add assertions for all 7 new directory variables
- read_input.cpp: change !out_app_flag to out_app_flag == 0 for
  matrix/WFC legacy directory decisions
- Update three unit tests to use int out_app_flag (0/1) instead of
  bool (false/true), matching the new function signatures:
  test_cal_dos.cpp, test_write_dos_pw.cpp, write_wfc_nao_test.cpp
- Update two comments to describe 0/1 semantics
Replace repeated PARAM.globalv.global_*_dir accesses with the local
const variables already declared at function top, eliminating the
net +4 PARAM global dependency introduced by the path routing change.
With out_app_flag changed from bool to int, the legacy WFC/ subdirectory
is no longer created when out_app_flag=0 (now maps to global_out_dir).
Update the multi-k wfc reference path accordingly.
- read_input.cpp: only create PSI/CHG/POT/ELF/DOS/DIP/MAT subdirectories
  when the corresponding output flag is enabled (out_app_flag=2)
- ctrl_scf_lcao.cpp: route write_dmk and angular momentum calculator
  output to global_mat_dir instead of global_out_dir
- hsr_legacy.cpp: route tr_nao.csr to global_matrix_dir
- pos_op_writer.cpp: route rr_nao.txt to global_matrix_dir
@mohanchen mohanchen added Input&Output Suitable for coders without knowing too many DFT details Refactor Refactor ABACUS codes labels Oct 16, 2026
@mohanchen

Copy link
Copy Markdown
Collaborator Author

@ABACUS-PR-BOT please help review the PR

@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.

Static review of 00ece15 with independent verification. Five implementation issues and three non-blocking suggestions are noted inline. Whitespace checks passed; the pinned governance check reported warnings only. No build or runtime tests were run, and CI diagnostics were unavailable.

Comment thread source/source_io/module_parameter/read_set_globalv.cpp
Comment thread source/source_io/module_parameter/read_input.cpp Outdated
Comment thread source/source_io/module_ctrl/ctrl_scf_lcao.cpp
Comment thread source/source_io/module_parameter/read_inp_out.cpp Outdated
Comment thread source/source_io/module_hs/hsk_writer.cpp
Comment thread source/source_io/module_parameter/read_inp_out.cpp Outdated
Comment thread source/source_io/test_serial/io_sys_var_test.cpp
Comment thread source/source_io/module_parameter/read_input.cpp Outdated
abacus_fixer and others added 18 commits October 18, 2026 08:10
- Remove md_no_append ternary in hsr_legacy.cpp, pos_op_writer.cpp,
  hterm_writer.cpp, dhs_sparse_writer.cpp: use global_matrix_dir
  unconditionally (it already equals global_out_dir when
  out_app_flag != 2, so no behavior change for legacy modes)
- write_dmr: add dmr_dir parameter, route DM(R) to MAT instead of
  hardcoded global_out_dir; drop parameter.h include
- read_input.cpp: add out_dmr/out_mat_l/out_mat_dh/out_mat_ds to
  MAT subdirectory creation flags

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- global_stru_dir now follows out_app_flag: STRU/ for flag 2,
  global_out_dir otherwise (consistent with MAT/PSI/CHG pattern)
- relax_driver: route STRU_NOW/STRU{step}/STRU_FINAL through
  global_stru_dir instead of global_out_dir
- run_md: drop _MD suffix, use STRU{step} naming consistent with
  relax
- global_file: remove unconditional STRU dir creation from
  make_dir_out; remove global_stru_dir parameter
- read_input: create STRU dir on demand (out_stru>0 or MD)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- run_md: use out_freq_ion (with md_restartfreq fallback) as the
  effective ionic-step output frequency for both STRU and restart
- run_md: gate STRU output on out_stru > 0, consistent with relax
- read_input: simplify STRU dir creation to out_stru > 0
- read_inp_out: update out_stru description to cover MD
- read_input_item_md: mark md_restartfreq as deprecated

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- commit 3a38485 made global_stru_dir follow out_app_flag (default 1
  maps it to the output dir), but the MD restart lookup still probed
  STRU_MD_{istep} there, so restart cases whose fixtures live in
  OUT.suffix/STRU/ (e.g. tests/04_FF/14_LJ_rescale_v) failed to start
- search the current global_stru_dir first, then fall back to the
  legacy OUT.suffix/STRU/ layout; accept both the new STRU{istep+1}
  naming (1-based, unified with relax) and the legacy STRU_MD_{istep}
- quit with a clear diagnostic when no restart structure file exists
- add unit test covering both naming schemes in a user read_file_dir
- add PSI/ candidate in read_wfc_nao so RT-TDDFT restart finds mode-2 snapshots
- route H(k) term outputs to MAT directory; add out_hsr_npz to MAT dir creation
  predicate; narrow DOS dir creation predicate to out_dos/out_ldos
- pass boolean append to save_mat in write_hk_common (was int out_app_flag)
- update out_app_flag/out_wfc_lcao INPUT metadata and position_matrix docs
- add mode-2 directory mapping and PSI layout roundtrip unit tests
Conflict resolutions:
- read_input_test.cpp: keep both added tests (OutAppFlagParsing ours,
  ExplicitNoccSurvivesUnresolvedElectronNumber upstream)
- relax_driver.cpp: identical condition; keep ours comment (md STRU
  output now handled by run_md.cpp, md_restartfreq removed)

Post-merge verification: make -j 30 in build_max_para_test, 100%
Built target abacus_max_para, 0 errors.
In append mode (out_app_flag=1), chg/tau/pot/potes/ELF cube outputs
now reuse a fixed filename (e.g. chgs1.cube, elftot.cube) so every
step overwrites the previous snapshot instead of accumulating
g{N}-suffixed files. Modes 0 and 2 keep the per-step g{N} suffix.
Add an explicit out_app_flag parameter to ModuleIO::write_dmk. In
append mode the geometry-step index is dropped from the filename
(istep_file = -1) so every ionic step overwrites the previous
snapshot, matching the fixed name that read_dmk already expects;
the file body still records the real ionic step.
Drop the g{N} suffix from tr_nao.csr and rr_nao.txt in append mode.
The filenames were changing every ionic step, which defeated the
existing MD append branches in save_sparse and the rr assemble path;
with fixed names those branches now accumulate all steps as designed.
Replace the hardcoded out_app_flag=0 in write_wfc_pw (a 2025-05-17
TODO) with an explicit parameter wired from inp.out_app_flag. In the
default append mode the PW wavefunction files now use fixed names
(wfk1_pw.dat), which finally matches what the restart reader
read_wf2rho_pw looks for; modes 0 and 2 keep the g{N} suffix.
write_chg_init/write_pot_init now keep the fixed _ini.cube names in
append mode so each snapshot overwrites the previous one, instead of
accumulating chgs1g{N}_ini.cube / potg{N}_ini.cube files. These
initial-density cubes are write-only snapshots; no reader consumes
them, so no restart path is affected.
Clarify that mode 1 reuses fixed filenames across steps (text records
append, cube snapshots overwrite), fix the remaining Boolean wording
in out_hsk, and note that out_chg=2/out_pot=3 initial-density cubes
omit the geometry-step index in append mode.
The fixed filename alone still truncated the file every ionic step.
Add a calculation parameter and open the stream with ios::app under
the same condition as open_sparse_file (calculation=="md" &&
out_app_flag==1 && istep>=0), so each MD step appends a new record
while other calculations start fresh.
Rule 22: user-facing output files print ionic steps starting from 1,
matching the g{N} filename suffix convention; zero-based counters such
as "STEP: 0" are not allowed.
Naming (mode 1 fixed name, modes 0/2 keep g{N}):
- DOS (LCAO+PW) and PDOS honor out_app_flag for the g{N} suffix
- lx/ly/lz matrices: Angmom_op::calculate takes out_app_flag

Append (relax now appends like MD; was calculation=="md" only):
- open_sparse_file, rr/dH/dS writers, DM(k): condition relaxed to
  (out_app_flag == 1) && (istep >= 0); SCF passes istep=-1, unaffected
- PDOS and lx/ly/lz append per ionic step in mode 1
- DM(k) drops the calculation parameter again (no longer used)

Step indexing (governance rule 22, one-based):
- STEP: headers of sparse text files and the binary CSR step field
  now start from 1 (hs_sparse_io, pos_op_writer, dhs_sparse_writer,
  hsr_writer)

Build: make -j 30 verified by developer.
Instead of numbered STRU{N} files, out_app_flag=1 now writes one
fixed-name STRU file that accumulates one structure block per written
step, for both relax and MD:

- unitcell::print_stru_file and relax_stru_io::write_stru take a new
  append flag; relax writes "# Ionic Step N" headers (one-based,
  governance rule 22) via the existing build_stru_header
- mdcell::print_stru_file takes frame_comment + append; MD frames are
  prefixed with "# MD step N". The MPI path broadcasts a base offset
  (lseek SEEK_END) and keeps absolute pwrite offsets; O_APPEND is
  deliberately avoided since Linux pwrite ignores the offset with it
- CIF output keeps single-frame semantics: fixed-name STRU.cif is
  overwritten each written step
- modes 0/2 keep the numbered STRU{N} files unchanged
- CLI help of out_stru/out_app_flag documents the mode-1 behavior

Build: make -j 30 verified by developer.
The DM(k) writer emitted the row newline only before each group of
elements, so the file ended without a trailing newline. In append mode
(out_app_flag == 1) the next " --- Ionic Step N ---" record was glued to
the last value of the previous step. Add a trailing newline before
closing the file and cover it with a regression assertion.
abacus_fixer and others added 23 commits October 20, 2026 15:52
write_wfc_pw now mirrors write_wfc_nao's append_flag: the first
written step truncates the fixed-name wf*_pw.{txt,dat} files and later
ionic steps append one frame per step (all payload writes already use
append mode; only the per-step pre-clear is skipped). Modes 0/2 keep
per-step g{N} files unchanged.

Also terminate the DM(k) matrix body with a newline so appended
records start on a fresh line (developer fix), and document in
read_wf2rho_pw/out_wfc_pw help that multi-frame binary files are read
from their first frame only.

Build: make -j 30 verified by developer.
band.txt/bands1.txt/bands2.txt contained numeric rows only, so the k-point
blocks appended across ionic steps of a relax/md run were indistinguishable,
and a single-step run carried no version or timestamp. Print the STRU-style
header ("# ABACUS version", "# Written at", "# IONIC STEP n") in front of
every ionic step instead: write_bands now takes the step index, nscf_bands
takes the prepared header, and the step label is one-based with the collinear
spin-channel tag when nspin=2.

The integration comparison strips "#" lines before comparing band.txt, and
the unit test skips comment lines while parsing and asserts the header of
each appended block.
make_spin_tag pads "up" so that both collinear channels share the same width
wherever they are printed next to each other in the running log. The band
header instead ends up in a per-spin file (bands1.txt/bands2.txt), so the
padding only leaves a trailing blank before the closing parenthesis. The
header now uses " (spin up)" through a local band_spin_tag helper, while the
log line keeps make_spin_tag unchanged.
…nd semantics

Add focused unit tests exercising out_app_flag modes 0/1/2 across the
filename_output primitive and all major output writers:

- test_filename.cpp (new): filename_output three-mode matrix, iter/gamma/nspin
- write_dmk_test.cpp: Mode0PerStepFiles / Mode1FixedNameAppend / Mode2SameNamingAsMode0
- test_write_pdos_text.cpp: Mode1FixedNameAppend / Mode2SameNamingAsMode0
- test_cal_dos.cpp: Mode1Appends (two ionic step headers) / Mode2Overwrites
- test_print_cell.cpp: STRUAppend (two ATOMIC_SPECIES blocks accumulated)
- test_mdcell_reader.cpp: STRUAppendWithFrameComment (# MD step N markers)
- write_wfc_nao_test.cpp: OutAppFlagMode2SameNamingAsMode0 (completes 0/1/2)

Also sync out_dos CLI description to document the three-mode semantics.
Governance: net_delta=-9 (global dependency budget decreased).
- CMakeLists: MODULE_BASE_filename needs both `base` (filename.cpp) and
  `device` (kernel ops referenced by base) in its LIBS
- test_mdcell_reader: include gmock/gmock.h for HasSubstr matcher
- write_dmk_test: new three-mode tests were missing the K_Vectors
  construction and the precision parameter (third positional arg);
  sync with the WriteDMK precedent in the same file

Build verified by developer (make -j 30).
Follow-up to a658239 which moved the sparse/CSR STEP field to the
one-based convention (governance rule 22) without updating the tests:
- hs_sparse_io / dhs_sparse_writer / hsr_writer: expect istep+1 in the
  text STEP header and in the native binary step field
- write_dmk modes 0/1/2: resize kvec_d before calling write_dmk, which
  dereferences kv.kvec_d[ik] and segfaulted on the empty vector
- write_dmk mode 1: match the actual " --- Ionic Step N ---" header

Verified: the four test targets pass, including mpirun -np 2.
The sparse CSR writers emit std::max(istep, 0) + 1 in the STEP field
since a658239 (governance rule 22), but these integration references
still expected the zero-based value. Only the header line changes; all
matrix elements are byte-identical.

Affected cases: 02_NAO_Gamma/scf_out_hxc, 03_NAO_multik/scf_out_dh_t,
03_NAO_multik/get_s, 03_NAO_multik/nscf_out_hsr_tr_rr,
03_NAO_multik/scf_out_hsr_spin4.

Verified with Autotest.sh on a clean OUT.autotest: 36 test cases pass.
…ader

compare_hsr_binary.py still rejected any non-zero step in the native
binary record, so scf_out_hsr_binary_spin2 aborted after the sparse
writers moved to the one-based convention (a658239, rule 22). Accept
step 1 and describe the merged field as one-based in the out_hsr help
text and in the binary CSR format documentation.

Verified: scf_out_hsr_binary_spin2 passes; full 02_NAO_Gamma (35 cases)
and 03_NAO_multik (69 cases) rerun clean, with only the two
DFT-D4 cases failing because this build lacks -DENABLE_DFTD4=ON.
write_dh_perI had two relic caller-side branches that duplicated the
directory selection already performed by ReadInput::set_global_dir:

1. r_dir used a ternary keyed on calculation=="md" && out_app_flag!=1
2. the dense k-space dH(k) filename was hardcoded against global_out_dir
   instead of the r_dir variable

Both are replaced with a single mat_dir = PARAM.globalv.global_mat_dir,
so relax + out_app_flag=2 now lands CSR dH/dR and dense dH/dk in
OUT.suffix/MAT/ together with H(R), S(R), DM(k) and the H(k) term
matrices already routed in the fix commit. Modes 0 and 1 keep the exact
same output path because global_mat_dir aliases global_out_dir there.
The mode-2 subdir_flags OR chain for MAT/ covered the aggregate switches
(out_mat_hs2, out_mat_dh) and a handful of legacy flags (out_dmk, out_hsk,
out_mat_tk, ...) but none of the per-component switches that actually
write into MAT/:

  H(R) components: out_mat_h_t/vnl/vl/vh/vxc/exx
  dH components:   out_mat_dh_t/vl/vnl/vh/vxc

With only one of those per-component flags enabled in mode 2, MAT/
would not be created and the H(R)/dH component writers would fail to
open their output files. Append all 11 component switches to the OR
chain so MAT/ is created whenever any matrix output is requested.
…or out_app_flag

Two related fixes for the out_app_flag rework:

1. ctrl_output_pw.cpp — the last two PW-specific outputs that still wrote
   into OUT.root are now routed into their purpose-built mode-2
   subdirectories:
     out_pchg              -> global_chg_dir  (CHG/)
     out_wfc_norm / _re_im -> global_psi_dir  (PSI/)
   Every PW writer (wfc, DOS, chg, pot, ELF, dipole, pchg, wfc_norm)
   now honors mode-2 routing — no more OUT.root leakage from PW.

2. read_inp_out.cpp — out_app_flag's availability was
   "basis_type==lcao and gamma_only==0" even though the description
   said the routing applies to both LCAO and PW. Empty the availability
   expression so the flag is visible to every run type. The lcao
   restriction was never enforced in the code paths and PW users were
   only being hidden from the parameter — the PW writers above now back
   that description up.
Two regression guards for the review feedback asking for focused mode-2
coverage:

test_hs_dense_io.cpp :: AppendFalseOverwritesSameIstep
    save_mat must truncate on append=false even when the same istep is
    rewritten. The older BinaryAppend test cross-stepped istep 0 -> 1 -> 2
    and never caught the same-step overwrite case. This pairs append=true
    then append=false on the same file for istep=0 and asserts exactly one
    record remains.

test_hsk_writer.cpp :: Mode2OverwritesSameIstep
    write_hsk was passing the integer out_app_flag directly into save_mat's
    boolean append parameter before the fix, so out_app_flag=2 would append
    instead of truncating. The existing tests only exercised append=false
    implicit via k_out_app=0 (mode 0 behaviour). This test drives
    out_app_flag=2 for istep=0, swaps the FakeHamilt payload, writes again,
    and verifies the second payload replaced the first.

Governance: one new test file matches one source file, test_hsk_writer.cpp
was already in place so a new case joins the existing fixture.
out_app_flag == 1 writes one fixed-name "STRU" file, but a previous
release kept per-step STRU_MD_{step} files inside a STRU/ subdirectory
of the output directory. Restarting an MD from such output (14_LJ_-
rescale_v ships that layout) made open() hit the directory and abort
with "Unable to create MDCell restart STRU file: ... Is a directory".

Resolve the STRU output prefix once before the MD loop: when mode 1 is
requested and <out_dir>/STRU already exists as a directory, keep the
legacy numbered files inside that directory and skip accumulation.
Modes 0 and 2, and mode 1 without a legacy directory, are unchanged.

Also refresh the Mulliken output sample in the documentation: the file
now starts with " --- Ionic Step 1 ---" and uses the zeta/spin table
with sum m / sum mz / sum lmz labels.

Verified: make -j 30; 14_LJ_rescale_v 4/4; full 04_FF 78 checks;
02_NAO_Gamma md_*/relax_* (9 cases) 53 checks.
Two bugs in source/source_io/module_dipole/write_dipole.cpp caused
out_dipole=1 to abort under MPI:

1. Validation check rejected rhopw->nplane == 0, but nplane is a
   per-rank local count (number of z-planes owned by the current
   process). Some ranks legitimately hold zero z-planes under z-axis
   MPI decomposition; hitting WARNING_QUIT there made those ranks
   exit with code 1 while the others waited forever.

2. The dipole data line was written to 'ofs' on every rank, but the
   file is only opened on rank 0. Non-root ranks wrote to an
   unopened stream, which is undefined behaviour and corrupts output
   when it doesn't crash outright.

Fixes:
- Remove rhopw->nplane == 0 from the guard; keep only global
  dimensions nx/ny/nz/nxyz, which truly must be positive.
- Wrap the ofs << ... write inside an if (GlobalV::MY_RANK == 0)
  block, consistent with the existing file-open and file-close guards.
A rank can own zero real-space grid points (nrxx == 0) when the FFT grid
is decomposed across more processes than it has z-slabs. The asserts in
write_elf rejected that legitimate empty partition. Dropping the asserts
alone is not enough if the FFT body is skipped: real2recip/recip2real go
through PW_Basis::gatherp_scatters, which performs an MPI_Alltoallv that
requires every rank in POOL_WORLD to participate, so a rank that returns
early deadlocks the grid-owning ranks inside Alltoallv.

Run the same FFT path unconditionally on every rank (the per-grid-point
loops simply iterate zero times when nrxx == 0) and keep every rank in the
write_vdata_palgrid output section for the collective MPI_Gatherv in
Parallel_Grid::reduce. Add regression tests for the zero-length container
and zero-iteration invariants.

Verified with examples/17_relax/04_relax_with_output_lcao (out_elf 1):
OMP_NUM_THREADS=4 mpirun -np 4 abacus_max_para finishes in 4 s and writes
elfs1.cube, elfs2.cube and elftot.cube; MODULE_IO_write_elf_logic_test
passes 14/14.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com>
The 'Orbital' file only describes the NAO basis orbitals of the cell
(index, species, l, m, zeta, symmetry name) and is consumed by the
projected-band and Mulliken outputs. Rename it to 'nao.txt' so the
name states the basis type and does not collide conceptually with
plane-wave outputs.

Update both writers, the affected unit tests, the pband integration
comparison script and its golden reference, and the Mulliken docs.
wfk*_nao.txt now carries the same three-line header as bands1.txt
(version, timestamp, ionic step with spin tag) before the data block,
with one header per frame in append mode. The reader skips leading '#'
comment lines on the ASCII path only; the binary record layout is
untouched. Downstream Python consumers of the text format filter '#'
lines so they tolerate the new header.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com
Align test_lr_util.cpp with governance rule 22: hs_sparse_io writes
STEP: max(istep,0)+1, and LR_Util::save_HR passes istep = 0, so the
header is "STEP: 1". Fixes MODULE_LR_dm_regressions and
MODULE_LR_sparse_rank_keys.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
With out_app_flag = 1 the multi-step writers reuse a fixed filename, so
write_cube truncated the previous snapshot and only the last written step
survived in chg/tau/pot/elf cube files. Text outputs already append records
under the same flag, and out_wfc_lcao already truncates on the first step and
appends afterwards, so cube output was the remaining inconsistency.

Pass an explicit append flag down the writer chain instead of reading
PARAM inside the writers:
- write_cube / write_vdata_palgrid take a new append parameter and open the
  file with std::ios::app when it is set, otherwise truncate;
- write_elf and write_elecstat_pot forward it, and write_chg_init /
  write_pot_init compute it from inp.out_app_flag;
- ctrl_output_fp uses append = (out_app_flag == 1 && istep > 0), mirroring
  the out_wfc_lcao rule: the first written ionic step truncates, later
  written steps append one complete frame whose first comment line is
  Ionic_Step {#}, one-based. Single-point SCF/NSCF stays at istep == 0, so it
  keeps overwriting rather than stacking on a stale file from a rerun.
- every other call site (LDOS, LCAO/PW wavefunction cubes, partial charge,
  LR-TDDFT density, exciton density, DM2rho) passes false explicitly to keep
  its existing truncate behaviour.

Update the out_app_flag and out_elf help text, the output specification, and
add CubeIOTest.WriteCubeAppendFrames covering truncate-then-append-then-
truncate frame counting and the trailing newline contract.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com>
Rename vpp_local_out.dat, vpp_nonlocal_out.dat, vhartree_out.dat and
kinetic_out.dat to eband_vl.txt, eband_vnl.txt, eband_hart.txt and
eband_kin.txt, and prefix each file with version, timestamp, ionic step
and total energy, expectation-value formula, and unit comments. Write
the files on rank 0 only to avoid concurrent writes in MPI runs.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Is it possible to have the charge density files generated within a specific folder when performing an RT-TDDFT calculation?

2 participants