Skip to content

Commit 07dfb32

Browse files
mohanchenABACUS Devabacus_fixer
authored
Refactor output formats of deltaspin method (deepmodeling#7857)
* deltaspin: mirror print_header output into running_scf.log Include source_base/global_variable.h in lambda_loop_helper.cpp so the helper methods can reach GlobalV::ofs_running. For now only print_header is mirrored; subsequent commits will migrate the remaining helper functions one at a time so every step builds independently. stdout is preserved so interactive users and CaptureStdout-based unit tests (lambda_loop_hlp_test.cpp / deltaspin_core_test.cpp) keep observing the same terminal output they expect. * deltaspin: mirror print_termination footer output into running_scf.log Duplicate the two std::cout lines ("Inner optimization for lambda ends." and the closing separator) to GlobalV::ofs_running. The internal print_2d calls are left alone for now; they will be redirected in a separate commit that touches the shared helper so the change is centralized. The unit-test assertions for print_termination in lambda_loop_hlp_test.cpp are commented out, so there is no test drift to account for in this step. * deltaspin: mirror check_rms_stop output into running_scf.log Duplicate Step (Outer -- Inner) RMS/TIME line, both convergence exit messages, and both cumulative Total TIME lines into GlobalV::ofs_running alongside the existing std::cout stream. print_termination() at the exit point already emits duplicates thanks to the previous commit; no extra forwarding needed here. CaptureStdout-based tests in lambda_loop_hlp_test.cpp remain valid because stdout is preserved unmodified. * deltaspin: mirror check_restriction output into running_scf.log The two diagnostic lines emitted when the trial step is clipped ("alpha after restrict" and "boundary after") now also land in running_scf.log. The check_restriction signature stays untouched so ABACUS rule 5 (no default-argument additions to existing interfaces) is satisfied and lambda_loop.cpp does not need a call-site update. * deltaspin: mirror check_gradient_decay diagnostic output to ofs_running Duplicate the verbose debug block (print=true) and the early-exit "Reach limitation of current step" message into running_scf.log. Intentionally not touched in this commit: * printf-based [GRAD-DECAY] and [ALPHA-OPT] warnings inside check_gradient_decay and cal_alpha_opt — they are only triggered under guard conditions that do not fire for the reference 14_PW_DS_S4_XYZ test case and are addressed separately. * The print_2d call in the debug block — that helper has its own dedicated redirect commit next. * deltaspin: mirror print_2d tables into running_scf.log Include source_base/global_variable.h in basic_funcs.cpp and emit a duplicate copy of every print_2d line to GlobalV::ofs_running in addition to the caller-supplied ostream (which defaults to std::cout). All existing callers benefit from this single change: * lambda_loop.cpp : initial lambda, initial spin, target spin * lambda_loop_helper : after-optimization spin/lambda, diagonal gradient diagnostics in check_gradient_decay Formatting is preserved byte-for-byte by constructing each ATOM line into a local std::string before streaming to both sinks. MODULE_LCAO_deltaspin_basic_func_test keeps passing because stdout still contains the expected output lines. * deltaspin: mirror run_lambda_loop scalar diagnostics to ofs_running Include source_base/global_variable.h in lambda_loop.cpp and emit duplicate copies into running_scf.log for: * "Total TIME(s) = ..." (gradient-decay exit branch) * "Current RMS: ..." (post-inner-loop PW verification) * "Error: RMS error is too large, rerun the loop" The per-step check_rms_stop/print_termination outputs and the initial lambda/target spin tables already go to both sinks via earlier commits. No helper signatures changed (ABACUS rule 5 compliance) and no call-site updates are required. * deltaspin: mirror run_lambda_linear_scan [DS-DIAG] output into running_scf.log Duplicate every [DS-DIAG] line from run_lambda_linear_scan into GlobalV::ofs_running alongside std::cout, so the normally-off diagnostic lambda-scan helper also persists its findings to running_scf.log. Scope includes: scan-start banner and parameters, the auto-constrain notice, per-atom constrain/target dumps, per-step header and Mi output, consistency-check summary lines, and the completion banner. Only stdout (default) copies are tested; no unit-test modifications required because all CaptureStdout expectations remain satisfied. * elecstate: mirror SCF per-iter compact table to running_scf.log Append a copy of the per-SCF-iteration summary buffer produced by print_scf_iterinfo (the line with ITER, TMAGX/TMAGY/TMAGZ/AMAG, ETOT, EDIFF, DRHO, TIME) to GlobalV::ofs_running so users can get a compact convergence overview from running_scf.log without having to scroll back through the interactive terminal output. The std::flush is preserved on both sinks so large MPI jobs still see progress line by line during long runs. elecstate already includes source_base/global_variable.h so no new #include was necessary. * deltaspin: split output between screen and running_scf.log Replace previous dual-write (cout + ofs_running) with strict routing: information goes to either screen or log, not both. Screen keeps only: - SCF iteration compact table (ITER TMAGX ... DRHO TIME/s) - per-outer-step convergence summary (Meet/Reach criterion, Total TIME) - error/early-termination notices (Reach limitation, Error: RMS) Log receives (with leading-space style consistent with running_scf.log): - per-inner-step Step (Outer -- Inner) RMS = ... TIME(s) = ... - initial/after-optimization spin and lambda tables (per-atom info kept off screen to avoid flooding on large systems) - alpha after restrict / boundary after diagnostics - diagonal gradient / maximum gradient appears at / maximum gradient - Current RMS, Total TIME(s) - all [DS-DIAG] linear-scan debug lines print_2d now writes only to the stream passed by caller; no implicit dual output. Test assertion updated to expect leading space in ATOM rows. * deltaspin: add RMS column to SCF table, move converged summary to log Add a new RMS column to the SCF iteration table on screen, placed after DRHO (and DKIN if present) and before TIME. The column shows the most recent DeltaSpin lambda-loop RMS in scientific notation. Non-DeltaSpin calculations do not show this column. Implementation: - SpinConstrain: add last_rms_error_ member + get_last_rms_error() getter, set in run_lambda_loop when check_rms_stop returns true. - ESolver_KS: add ds_rms_ member, reset in iter_init to 0.0 when sc_mag_switch is on (column shown, value 0 before lambda loop runs) or -1.0 otherwise (column hidden). - ESolver_KS_PW / ESolver_KS_LCAO: after run_lambda_loop, fetch sc.get_last_rms_error() into ds_rms_. - print_etot / print_scf_iterinfo: add ds_rms parameter (default -1.0); when >= 0, append an RMS column (same width/format as DRHO) to both header and data rows. - Move the 'DeltaSpin: lambda loop converged' summary line from screen to running_scf.log (with leading space and trailing blank line). Abnormal summaries (max steps, early-termination, RMS too large) remain on screen so users see them immediately. * deltaspin: remove GlobalV::ofs_running dependency from module_deltaspin Pass ofs_running explicitly through function parameters instead of referencing the GlobalV::ofs_running global variable directly inside the deltaspin module. This follows ABACUS rule #1 (do not increase cross-layer control through GlobalV) and matches the existing design pattern used by print_Mi / print_Mag_Force. Changes: - spin_constrain.h: add std::ostream& ofs_running parameter to 7 functions (run_lambda_loop, run_lambda_linear_scan, print_header, print_termination, check_rms_stop, check_restriction, check_gradient_decay). Added <fstream> include. Removed default value for 'rerun' and 'print' parameters to keep call sites explicit (rule #5). - lambda_loop_helper.cpp: replace all GlobalV::ofs_running with the ofs_running parameter; remove #include source_base/global_variable.h. - lambda_loop.cpp: replace all GlobalV::ofs_running with the ofs_running parameter; remove #include source_base/global_variable.h (kept #include source_io/module_parameter/parameter.h since PARAM is still used). - basic_funcs.cpp: remove unused #include source_base/global_variable.h. - template_helpers.cpp: update TK=double stub signatures to match. - deltaspin_lcao.h/cpp: add ofs_running parameter to run_deltaspin_lambda_loop_lcao; add <iosfwd> include. - deltaspin_pw.h/cpp: add ofs_running parameter to run_deltaspin_lambda_loop; add <iosfwd> include. - esolver_ks_pw.cpp / esolver_ks_lcao.cpp: pass GlobalV::ofs_running at the call site (the esolver layer owns the dependency). - template_helpers_test.cpp: pass std::cout at test call sites. Result: module_deltaspin no longer references GlobalV::ofs_running. The only remaining GlobalV:: usages in the module are historical MPI constants (NPROC_IN_POOL, RANK_IN_POOL) in cal_mw*.cpp, untouched by this change. * deltaspin: add empty deltaspin_pw_impl.cpp in module_pwdft Create a placeholder file source/source_pw/module_pwdft/deltaspin_pw_impl.cpp that will host PW-specific SpinConstrain member function implementations in subsequent commits: - cal_mi_pw() - calculate_delta_hcc() - update_psi_charge_pw_cpu() - update_psi_charge_pw_gpu() Update source/source_pw/module_pwdft/CMakeLists.txt to include the new source file in the module_pwdft build list. The file currently contains only the spinconstrain namespace skeleton with a comment listing the functions to be moved. No functional change; the build produces an empty object file. Verified: make -j 30 in build_max_para_test compiles cleanly and generates deltaspin_pw_impl.cpp.o. * deltaspin: move cal_mi_pw implementation to module_pwdft Relocate the PW-specific SpinConstrain<std::complex<double>>::cal_mi_pw() member function from module_deltaspin/cal_mw.cpp to module_pwdft/deltaspin_pw_impl.cpp. cal_mi_pw() depends on projectors::OnsiteProjector (PW-side atomic projector) and psi::Psi<complex<double>, DEVICE_CPU/GPU> wavefunction container, which are PW-specific dependencies that should not be pulled into module_deltaspin. Changes: - module_pwdft/deltaspin_pw_impl.cpp: add cal_mi_pw() implementation with required includes (matrix.h, parallel_reduce.h, tool_title.h, timer.h, onsite_proj.h, spin_constrain.h, parameter.h). - module_deltaspin/cal_mw.cpp: remove cal_mi_pw() function body and its doxygen comment block; remove now-unused #include "source_pw/module_pwdft/onsite_proj.h"; leave a brief comment noting the function has been relocated. The function declaration stays in spin_constrain.h (no interface change). cal_mi_lcao() and set_operator() remain in cal_mw.cpp. Verified: make -j 30 in build_max_para_test compiles cleanly. * deltaspin: move calculate_delta_hcc to module_pwdft Relocate the PW-specific SpinConstrain<std::complex<double>>::calculate_delta_hcc() member function from module_deltaspin/cal_mw_from_lambda.cpp to module_pwdft/deltaspin_pw_impl.cpp. calculate_delta_hcc() builds the DeltaSpin correction to the subspace Hamiltonian (H += becp^d * delta_lambda * becp) using PW projector coefficients. It is only called by update_psi_charge_pw_cpu/gpu, which are PW-specific and will be moved in the next step. Changes: - module_pwdft/deltaspin_pw_impl.cpp: add calculate_delta_hcc() implementation; add #include "source_base/kernels/math_kernel_op.h" for ModuleBase::gemm_op used by the function. - module_deltaspin/cal_mw_from_lambda.cpp: remove calculate_delta_hcc() function body and its doxygen comment block; leave a brief comment noting the function has been relocated. All call sites within update_psi_charge_pw_cpu/gpu (which remain in this file for now) continue to work because the function declaration is still in spin_constrain.h. The PW includes (hsolver_pw.h, elecstate_pw.h, onsite_proj.h, math_kernel_op.h) are still needed by cal_mw_from_lambda.cpp for update_psi_charge_pw_cpu/gpu; they will be removed in step 4 once those functions are also relocated. Verified: make -j 30 in build_max_para_test compiles cleanly. * deltaspin: move update_psi_charge_pw_cpu/gpu to module_pwdft Relocate the PW-specific update_psi_charge_pw_cpu() and update_psi_charge_pw_gpu() member functions from module_deltaspin/cal_mw_from_lambda.cpp to module_pwdft/deltaspin_pw_impl.cpp. These functions depend on PW-specific types: - hsolver::HSolverPW (full plane-wave iterative solver) - elecstate::ElecStatePW (PW electronic state for psiToRho) - projectors::OnsiteProjector (PW atomic projector for becp) - hsolver::DiagoIterAssist (subspace diagonalization) Changes: - module_pwdft/deltaspin_pw_impl.cpp: add update_psi_charge_pw_cpu() and update_psi_charge_pw_gpu() implementations; add includes for diago_iter_assist.h, hsolver_pw.h, elecstate_pw.h, elecstate_tools.h. - module_deltaspin/cal_mw_from_lambda.cpp: remove the two function bodies and their doxygen comment blocks; remove now-unused includes (hsolver_pw.h, elecstate_pw.h, math_kernel_op.h); remove duplicate elecstate_tools.h include; leave a brief comment noting the functions have been relocated. After this change, cal_mw_from_lambda.cpp no longer includes hsolver_pw.h, elecstate_pw.h, or math_kernel_op.h. The PW-specific HSolverPW and ElecStatePW dependencies are now fully contained within module_pwdft. Note: onsite_proj.h and diago_iter_assist.h are still needed by cal_mw_from_lambda.cpp because the main cal_mw_from_lambda() function internally uses OnsiteProjector and DiagoIterAssist for the PW subspace setup path. These remain as the LCAO/PW dispatch logic in the main entry point. The update_psi_charge() dispatch entry and cal_mw_from_lambda() main function remain in cal_mw_from_lambda.cpp; they call the relocated PW functions via the class member function declarations in spin_constrain.h. Verified: make -j 30 in build_max_para_test compiles cleanly. * deltaspin: finalize PW code relocation and clean up includes Clean up unused includes in module_deltaspin/cal_mw.cpp that were left behind after cal_mi_pw() was moved to module_pwdft in step 2. Removed includes (verified unused after relocation): - <iostream> - source_base/matrix.h - source_base/name_angular.h - source_base/parallel_reduce.h - source_io/module_parameter/parameter.h The remaining includes (tool_title.h, timer.h, spin_constrain.h, and the __LCAO block) are all still used by cal_mi_lcao() and set_operator(). Final state after the 5-step relocation: - module_deltaspin/cal_mw.cpp: only LCAO-specific code (cal_mi_lcao, set_operator) - module_deltaspin/cal_mw_from_lambda.cpp: main entry points (cal_mw_from_lambda, update_psi_charge) + LCAO dispatch; no longer includes hsolver_pw.h, elecstate_pw.h, math_kernel_op.h - module_pwdft/deltaspin_pw_impl.cpp: all PW-specific implementations (cal_mi_pw, calculate_delta_hcc, update_psi_charge_pw_cpu/gpu) - module_pwdft/deltaspin_pw.cpp: PW wrapper (unchanged) Verification: - make -j 30 in build_max_para_test compiles cleanly. - All 5 deltaspin unit tests pass: MODULE_ESTATE_elecstate_print, MODULE_LCAO_deltaspin_basic_func_test, MODULE_LCAO_deltaspin_template_helpers, deltaspin_pw_test, deltaspin_core_test. - grep confirms module_deltaspin/*.cpp no longer include hsolver_pw.h, elecstate_pw.h, or math_kernel_op.h. - onsite_proj.h is still included by cal_mw_from_lambda.cpp because the main cal_mw_from_lambda() function uses OnsiteProjector for the PW subspace setup path; this is the LCAO/PW dispatch logic that stays in the main entry point. * deltaspin: lift 6 lambda-loop helpers out of SpinConstrain class Phase 1 of god-class slimming: lift six lambda-loop helper methods (check_rms_stop, check_restriction, check_gradient_decay, cal_alpha_opt, print_header, print_termination) out of the SpinConstrain<TK> class template and into free function templates in the spinconstrain namespace. Motivation ---------- spin_constrain.h is a god class with 7+ mixed responsibilities. The lambda-loop workflow helpers are pure algorithms / I/O routines that do not need to be part of the class interface; lifting them shrinks the public API surface and clarifies the boundary between state (SpinConstrain) and algorithm (free functions). Changes ------- - New header lambda_loop_helper.h declares 6 free function templates taking 'const SpinConstrain<TK>&' as first parameter. - lambda_loop_helper.cpp: 6 explicit specializations on SpinConstrain<std::complex<double>> rewritten as free function templates with explicit instantiation for std::complex<double>. - template_helpers.cpp: 6 corresponding no-op stubs for SpinConstrain<double> re-expressed as free function explicit specializations (preserves linker surface for the nspin=2 stub). - spin_constrain.h: removed 6 member-function declarations; added public getters get_Mi() and get_current_sc_thr() so helpers can read internal state without friendship. - spin_constrain.cpp: get_nat/get_ntype/get_decay_grad(itype)/ get_decay_grad() promoted to const (required for const ref parameter); get_decay_grad(itype) uses map::find instead of operator[] to remain const-correct. - lambda_loop.cpp: 7 call sites switched from 'this->helper(...)' to 'helper(*this, ...)'. - test/template_helpers_test.cpp: call sites updated. - test/CMakeLists.txt: MODULE_LCAO_deltaspin_template_helpers now links lambda_loop_helper.cpp and basic_funcs.cpp (transitive deps of the new free function implementations). Verification ------------ - 'make -j 30' in build_max_para_test: clean build, abacus + abacus_basic_para + all MODULE_LCAO_deltaspin_* targets linked. - 'ctest -R deltaspin --output-on-failure': 5/5 tests passed (basic_func, spin_constrain, template_helpers, pw, core). Out of scope ------------ PW-specific methods (cal_mi_pw, update_psi_charge_pw_*, calculate_delta_hcc) and LCAO-specific helpers (cal_mi_lcao, convert, calculate_MW, collect_MW) remain as member functions for now; they will be lifted in subsequent phases. * deltaspin: lift print_Mi / print_Mag_Force out of SpinConstrain class Phase 2 of god-class slimming: lift the two table-printing member functions print_Mi and print_Mag_Force out of SpinConstrain<TK> and into free function templates in the spinconstrain namespace, alongside the lambda-loop helpers landed in phase 1. Motivation ---------- print_Mi / print_Mag_Force are pure formatting routines (FmtTable output) that read Mi_ and lambda_ via the existing getters. They do not belong on the class interface; lifting them further shrinks the public API and consolidates all deltaspin printing in lambda_loop_helper.{h,cpp}. Changes ------- - lambda_loop_helper.{h,cpp}: add print_Mi / print_Mag_Force free function templates. Both are generic (no per-TK stub needed); instantiated for std::complex<double> (real path) and double (nspin=2 stub path) so callers holding either TK can link. - spin_constrain.{h,cpp}: remove print_Mi / print_Mag_Force member declarations and definitions; add get_atomLabels() getter so helpers can read the per-atom label vector. - spin_constrain.{h,cpp}: promote check_atomCounts() to const (it only reads atomCounts and calls get_nat, both safe). Replaces std::map::iterator with const_iterator in two loops. - ctrl_output_pw.cpp / ctrl_scf_lcao.cpp: update call sites from 'sc.print_Mag_Force(ofs_running)' / 'sc.print_Mi(ofs_running)' to 'spinconstrain::print_Mag_Force(sc, ofs_running)' / 'spinconstrain::print_Mi(sc, ofs_running)'; add lambda_loop_helper.h include. Verification ------------ - 'make -j 30' in build_max_para_test: clean build of abacus + abacus_basic_para + all MODULE_LCAO_deltaspin_* test targets. - 'ctest -R deltaspin --output-on-failure': 5/5 tests passed. Out of scope ------------ PW-specific methods (cal_mi_pw, update_psi_charge_pw_*, calculate_delta_hcc), LCAO-specific helpers (cal_mi_lcao, convert, calculate_MW, collect_MW) and accumulate_Mi_from_becp remain as member functions for subsequent phases. * Refactor: extract accumulate_Mi_from_becp as free function in mi_tools Why: - SpinConstrain<TK>::accumulate_Mi_from_becp does not depend on TK or any singleton state beyond Mi_ and get_spin_sign(ik); keeping it as a member unnecessarily couples it to the class template and singleton lifecycle. - Factoring it out as a free function lets both LCAO and PW DeltaSpin paths call it without going through the SpinConstrain<TK> instantiation, and makes it independently unit-testable. What changed: - New files source/source_lcao/module_deltaspin/mi_tools.{h,cpp}: - pauli_to_moment moved here as inline free function (was inline in header) - accumulate_Mi_from_becp reimplemented as free function; Mi_ becomes an in/out reference parameter 'mi', ik replaced by caller-precomputed spin_sign (npol==2 callers pass 1), TK template parameter dropped. - Entry validates becp/wg_ik/nh_iat non-null, nkb/nbands positive, npol in {1,2}, spin_sign in {-1,1} via ModuleBase::WARNING_QUIT. - ModuleBase::ZERO replaced with local const std::complex<double> zero(0.0, 0.0), removing the source_base/constants.h include. - spin_constrain.h: removed pauli_to_moment inline definition and the accumulate_Mi_from_becp member declaration. - spin_constrain.cpp: removed the member function definition; get_spin_sign kept as member (it still reads npol_ and isk). - cal_mw_from_lambda.cpp, deltaspin_pw_impl.cpp (3 call sites total): updated to precompute spin_sign and call the free function with mi. - CMakeLists.txt: added mi_tools.cpp to the deltaspin OBJECT library. Verification: - cmake --build build_std_para -j4 : deltaspin OBJECT lib + abacus_std_para executable built successfully. - Functional/ctest runs not executed (compile-only verification). * deltaspin: remove redundant sc_parse_json.cpp sc_parse_json.cpp contained only two explicit template instantiations (template class spinconstrain::SpinConstrain<std::complex<double>> and the double specialization) at global scope. The same instantiations already exist at the end of spin_constrain.cpp (inside namespace spinconstrain, lines 733-734), making this file dead code. History: the file predates the instantiations being added to spin_constrain.cpp; once those landed, sc_parse_json.cpp became redundant but was never cleaned up. The misleading filename (suggests JSON parsing) is also retired. Verification: cmake --build build_std_para --target deltaspin -j4 built successfully; SpinConstrain<TK> symbols still resolve via the in-file instantiations in spin_constrain.cpp. * remove some PARAM usage --------- Co-authored-by: ABACUS Dev <abacus-dev@example.com> Co-authored-by: abacus_fixer <mohanchen@pku.eud.cn>
1 parent 0484e5b commit 07dfb32

31 files changed

Lines changed: 1390 additions & 1075 deletions

source/source_esolver/esolver_ks.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,10 @@ void ESolver_KS::iter_init(UnitCell& ucell, const int istep, const int iter)
190190

191191
iter_time = ModuleBase::get_time();
192192

193+
// Reset DeltaSpin RMS for this SCF iteration. If DeltaSpin is enabled, use 0
194+
// (meaning "lambda loop not yet run this iteration"); otherwise -1 (no RMS column).
195+
this->ds_rms_ = this->inp_->sc_mag_switch ? 0.0 : -1.0;
196+
193197
if (this->inp_->esolver_type == "ksdft")
194198
{
195199
diag_ethr = hsolver::set_diagethr_ks(this->inp_->basis_type, this->inp_->esolver_type,
@@ -279,8 +283,8 @@ void ESolver_KS::iter_finish(UnitCell& ucell, const int istep, int& iter, bool &
279283
double duration = ModuleBase::get_duration(iter_time, ModuleBase::get_time());
280284

281285
// print energies
282-
elecstate::print_etot(ucell.magnet, *pelec, conv_esolver, iter, drho,
283-
dkin, duration, diag_ethr);
286+
elecstate::print_etot(ucell.magnet, *pelec, conv_esolver, iter, drho,
287+
dkin, duration, diag_ethr, 0, true, this->ds_rms_);
284288

285289

286290
#ifdef __RAPIDJSON

source/source_esolver/esolver_ks.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ class ESolver_KS : public ESolver_FP
7070
double scf_ene_thr; //! scf energy threshold
7171
double drho; //! the difference between rho_in (before HSolver) and rho_out (After HSolver)
7272
double hsolver_error; //! the error of HSolver
73+
/// DeltaSpin RMS from the most recent lambda optimization loop; -1.0 means no DeltaSpin.
74+
/// Set by ESolver_KS_LCAO after run_lambda_loop, read by ESolver_KS::iter_finish when calling print_etot.
75+
double ds_rms_ = -1.0;
7376
int maxniter; //! maximum iter steps for scf
7477
int niter; //! iter steps actually used in scf
7578
bool oscillate_esolver = false; // whether esolver is oscillated

source/source_esolver/esolver_ks_lcao.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -430,18 +430,20 @@ void ESolver_KS_LCAO<TK, TR>::hamilt2rho_single(UnitCell& ucell, int istep, int
430430
spinconstrain::SpinConstrain<TK>& sc = spinconstrain::SpinConstrain<TK>::getScInstance();
431431
if (this->inp_->sc_lambda_strategy == "linear_scan")
432432
{
433-
sc.run_lambda_linear_scan(iter - 1);
433+
sc.run_lambda_linear_scan(iter - 1, GlobalV::ofs_running);
434434
skip_solve = true;
435435
}
436436
else if (!sc.mag_converged() && this->drho > 0 && this->drho < this->inp_->sc_scf_thr)
437437
{
438-
sc.run_lambda_loop(iter - 1);
438+
sc.run_lambda_loop(iter - 1, true, GlobalV::ofs_running);
439+
this->ds_rms_ = sc.get_last_rms_error();
439440
sc.set_mag_converged(true);
440441
skip_solve = true;
441442
}
442443
else if (sc.mag_converged())
443444
{
444-
sc.run_lambda_loop(iter - 1);
445+
sc.run_lambda_loop(iter - 1, true, GlobalV::ofs_running);
446+
this->ds_rms_ = sc.get_last_rms_error();
445447
skip_solve = true;
446448
}
447449
}

source/source_esolver/esolver_ks_pw.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "source_hamilt/module_xc/general_exx_info.h" // for General_Exx_Info type used via general_exx_info_
2020
#include "source_io/module_ctrl/ctrl_output_pw.h" // mohan add 20250927
2121
#include "source_pw/module_pwdft/deltaspin_pw.h" // mohan add 20250309
22+
#include "source_lcao/module_deltaspin/spin_constrain.h"
2223
#include "source_pw/module_pwdft/setup_pot.h" // mohan add 20250929
2324
#include "source_pw/module_pwdft/update_cell_pw.h" // mohan add 20250309
2425
#include "source_pw/module_pwdft/setup_dftu_pw.h" // mohan add 20250309
@@ -227,7 +228,14 @@ void ESolver_KS_PW<T, Device>::hamilt2rho_single(UnitCell& ucell, const int iste
227228
bool skip_charge = this->inp_->calculation == "nscf" ? true : false;
228229

229230
// run the inner lambda loop to contrain atomic moments with the DeltaSpin method
230-
bool skip_solve = pw::run_deltaspin_lambda_loop(iter - 1, this->drho, *this->inp_);
231+
bool skip_solve = pw::run_deltaspin_lambda_loop(iter - 1, this->drho, *this->inp_, GlobalV::ofs_running);
232+
if (skip_solve)
233+
{
234+
// Fetch the most recent DeltaSpin RMS for display in the SCF iteration table.
235+
spinconstrain::SpinConstrain<std::complex<double>>& sc
236+
= spinconstrain::SpinConstrain<std::complex<double>>::getScInstance();
237+
this->ds_rms_ = sc.get_last_rms_error();
238+
}
231239

232240
if (!skip_solve)
233241
{

source/source_esolver/lcao_others.cpp

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ void ESolver_KS_LCAO<TK, TR>::others(BaseCell& basecell, const int istep)
3838
ModuleBase::timer::start("ESolver_KS_LCAO", "others");
3939

4040
const std::string cal_type = this->inp_->calculation;
41+
const std::string global_out_dir = PARAM.globalv.global_out_dir;
42+
const bool gamma_only_local = PARAM.globalv.gamma_only_local;
4143

4244
if (cal_type == "test_memory")
4345
{
@@ -78,7 +80,7 @@ void ESolver_KS_LCAO<TK, TR>::others(BaseCell& basecell, const int istep)
7880
this->inp_->out_level,
7981
orb_.get_rcutmax_Phi(),
8082
ucell.infoNL->get_rcutmax_Beta(),
81-
PARAM.globalv.gamma_only_local);
83+
gamma_only_local);
8284

8385
atom_arrange::search(PARAM.globalv.search_pbc,
8486
GlobalV::ofs_running,
@@ -108,7 +110,7 @@ void ESolver_KS_LCAO<TK, TR>::others(BaseCell& basecell, const int istep)
108110
// (2)For each atom, calculate the adjacent atoms in different cells
109111
// and allocate the space for H(R) and S(R).
110112
// If k point is used here, allocate HlocR after atom_arrange.
111-
this->RA.for_2d(ucell, this->gd, this->pv, PARAM.globalv.gamma_only_local, orb_.cutoffs());
113+
this->RA.for_2d(ucell, this->gd, this->pv, gamma_only_local, orb_.cutoffs());
112114

113115
// 2. density matrix extrapolation
114116

@@ -175,14 +177,14 @@ void ESolver_KS_LCAO<TK, TR>::others(BaseCell& basecell, const int istep)
175177

176178
// pelec should be initialized before these calculations
177179
elecstate::init_scf(ucell, this->Pgrid, this->sf.strucFac, this->locpp.numeric,
178-
istep, PARAM.globalv.global_out_dir, *this->inp_, this->pelec);
180+
istep, global_out_dir, *this->inp_, this->pelec);
179181

180182
// self consistent calculations for electronic ground state
181183
if (cal_type == "get_pchg")
182184
{
183185
std::cout << FmtCore::format("\n * * * * * *\n << Start %s.\n", "getting partial charge");
184186
Get_pchg_lcao get_pchg(this->psi, &(this->pv));
185-
if (PARAM.globalv.gamma_only_local)
187+
if (gamma_only_local)
186188
{
187189
get_pchg.begin(this->chr.rho,
188190
this->pelec->wg,
@@ -196,7 +198,7 @@ void ESolver_KS_LCAO<TK, TR>::others(BaseCell& basecell, const int istep)
196198
this->Pgrid,
197199
&this->gd,
198200
this->kv,
199-
PARAM.globalv.global_out_dir,
201+
global_out_dir,
200202
GlobalV::ofs_running);
201203
}
202204
else
@@ -215,7 +217,7 @@ void ESolver_KS_LCAO<TK, TR>::others(BaseCell& basecell, const int istep)
215217
this->Pgrid,
216218
&this->gd,
217219
this->kv,
218-
PARAM.globalv.global_out_dir,
220+
global_out_dir,
219221
GlobalV::ofs_running,
220222
this->inp_->if_separate_k,
221223
this->chr.ngmc);
@@ -226,7 +228,7 @@ void ESolver_KS_LCAO<TK, TR>::others(BaseCell& basecell, const int istep)
226228
{
227229
std::cout << FmtCore::format("\n * * * * * *\n << Start %s.\n", "getting wave function");
228230
Get_wf_lcao get_wf(this->pelec);
229-
if (PARAM.globalv.gamma_only_local)
231+
if (gamma_only_local)
230232
{
231233
get_wf.begin(ucell,
232234
this->psi,
@@ -241,7 +243,7 @@ void ESolver_KS_LCAO<TK, TR>::others(BaseCell& basecell, const int istep)
241243
this->inp_->nbands,
242244
this->inp_->nspin,
243245
PARAM.globalv.nlocal,
244-
PARAM.globalv.global_out_dir,
246+
global_out_dir,
245247
GlobalV::ofs_running);
246248
}
247249
else
@@ -259,7 +261,7 @@ void ESolver_KS_LCAO<TK, TR>::others(BaseCell& basecell, const int istep)
259261
this->inp_->nbands,
260262
this->inp_->nspin,
261263
PARAM.globalv.nlocal,
262-
PARAM.globalv.global_out_dir,
264+
global_out_dir,
263265
GlobalV::ofs_running);
264266
}
265267
std::cout << FmtCore::format(" >> Finish %s.\n * * * * * *\n", "getting wave function");

source/source_estate/elecstate_print.cpp

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ void print_scf_iterinfo(const std::string& ks_solver,
4444
const std::vector<double>& drho,
4545
const int& wrho,
4646
const double& time,
47-
const int& wtime)
47+
const int& wtime,
48+
const double& ds_rms)
4849
{
4950
std::map<std::string, std::string> iter_header_dict
5051
= {{"cg", "CG"},
@@ -91,6 +92,12 @@ void print_scf_iterinfo(const std::string& ks_solver,
9192
{
9293
td_fmt.emplace_back(" %" + std::to_string(wrho) + ".4e");
9394
}
95+
// DeltaSpin RMS column (optional, same width/format as DRHO/DKIN)
96+
if (ds_rms >= 0)
97+
{
98+
th_fmt.emplace_back(" %" + std::to_string(wrho) + "s");
99+
td_fmt.emplace_back(" %" + std::to_string(wrho) + ".4e");
100+
}
94101
// time column, trivial
95102
th_fmt.emplace_back(" %" + std::to_string(wtime) + "s\n");
96103
td_fmt.emplace_back(" %" + std::to_string(wtime) + ".2f\n");
@@ -132,6 +139,13 @@ void print_scf_iterinfo(const std::string& ks_solver,
132139
titles.push_back(FmtCore::center("DKIN", wrho));
133140
values.push_back(drho[1]);
134141
}
142+
// DeltaSpin RMS column: shown only when a valid RMS value is provided (>= 0).
143+
// Placed after DKIN (if any) and before TIME.
144+
if (ds_rms >= 0)
145+
{
146+
titles.push_back(FmtCore::center("RMS", wrho));
147+
values.push_back(ds_rms);
148+
}
135149
titles.push_back(FmtCore::center("TIME/s", wtime));
136150
values.push_back(time);
137151
std::string buf;
@@ -168,7 +182,8 @@ void print_etot(const Magnetism& magnet,
168182
const double& duration,
169183
const double& pw_diag_thr,
170184
const double& avg_iter,
171-
const bool print)
185+
const bool print,
186+
const double& ds_rms)
172187
{
173188
ModuleBase::TITLE("energy", "print_etot");
174189
const int iter = iter_in;
@@ -395,7 +410,8 @@ void print_etot(const Magnetism& magnet,
395410
drho,
396411
12,
397412
duration,
398-
6);
413+
6,
414+
ds_rms);
399415
}
400416
return;
401417
}

source/source_estate/elecstate_print.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ namespace elecstate
1717
const double& duration,
1818
const double& pw_diag_thr = 0,
1919
const double& avg_iter = 0,
20-
bool print = true);
20+
bool print = true,
21+
const double& ds_rms = -1.0);
2122
}
2223
#endif

source/source_io/module_ctrl/ctrl_output_pw.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "../module_wf/get_wf_pw.h"
1111
#include "../module_wf/write_wfc_pw.h" // use write_wfc_pw
1212
#include "source_base/formatter.h"
13+
#include "source_lcao/module_deltaspin/lambda_loop_helper.h"
1314
#include "source_lcao/module_deltaspin/spin_constrain.h"
1415
#include "source_pw/module_pwdft/elecond.h"
1516
#include "source_pw/module_pwdft/onsite_proj.h" // use projector
@@ -214,7 +215,7 @@ void ModuleIO::ctrl_scf_pw(const int istep,
214215
{
215216
spinconstrain::SpinConstrain<std::complex<double>>& sc = spinconstrain::SpinConstrain<std::complex<double>>::getScInstance();
216217
sc.cal_mi_pw();
217-
sc.print_Mag_Force(GlobalV::ofs_running);
218+
spinconstrain::print_Mag_Force(sc, GlobalV::ofs_running);
218219
}
219220

220221
//------------------------------------------------------------------

source/source_io/module_ctrl/ctrl_scf_lcao.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "../module_dm/write_dmr.h" // use ModuleIO::write_dmr()
2626
#include "../module_dos/write_dos_lcao.h" // use ModuleIO::write_dos_lcao()
2727
#include "../module_wf/write_wfc_nao.h" // use ModuleIO::write_wfc_nao()
28+
#include "source_lcao/module_deltaspin/lambda_loop_helper.h" // print_Mi / print_Mag_Force free functions
2829
#include "source_lcao/module_deltaspin/spin_constrain.h" // use spinconstrain::SpinConstrain<TK>
2930
#include "source_lcao/module_operator_lcao/ekinetic.h" // use hamilt::EKinetic
3031
#ifdef __MLALGO
@@ -554,8 +555,8 @@ void ModuleIO::ctrl_scf_lcao(UnitCell& ucell,
554555
{
555556
spinconstrain::SpinConstrain<TK>& sc = spinconstrain::SpinConstrain<TK>::getScInstance();
556557
sc.cal_mi_lcao(istep);
557-
sc.print_Mi(GlobalV::ofs_running);
558-
sc.print_Mag_Force(GlobalV::ofs_running);
558+
spinconstrain::print_Mi(sc, GlobalV::ofs_running);
559+
spinconstrain::print_Mag_Force(sc, GlobalV::ofs_running);
559560
}
560561

561562
//------------------------------------------------------------------

source/source_lcao/module_deltaspin/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ list(APPEND objects
88
cal_mw_from_lambda.cpp
99
template_helpers.cpp
1010
deltaspin_lcao.cpp
11-
sc_parse_json.cpp
1211
cal_mw_helper.cpp
12+
mi_tools.cpp
1313
)
1414

1515
add_library(

0 commit comments

Comments
 (0)