Skip to content

Commit 512a3a7

Browse files
author
abacus_fixer
committed
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.
1 parent 5ff084e commit 512a3a7

6 files changed

Lines changed: 168 additions & 134 deletions

File tree

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/lambda_loop_helper.cpp

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@
44
#include <cmath>
55
#include <cstdio>
66
#include <iomanip>
7+
#include <string>
78
#include <utility>
9+
#include <vector>
810

911
#include "basic_funcs.h"
12+
#include "source_base/formatter.h"
1013

1114
/**
1215
* @file lambda_loop_helper.cpp
@@ -345,6 +348,116 @@ bool check_gradient_decay(const SpinConstrain<TK>& sc,
345348
return false;
346349
}
347350

351+
/**
352+
* @brief Print atomic magnetic moments Mi in a formatted table.
353+
*
354+
* @par Output format
355+
* - nspin=2: "Total Magnetism (uB)" with single z-component column
356+
* - nspin=4: three columns (Mx, My, Mz)
357+
*
358+
* Lifted from SpinConstrain<TK>::print_Mi; accesses state via getters.
359+
*/
360+
template <typename TK>
361+
void print_Mi(const SpinConstrain<TK>& sc, std::ostream& ofs_running)
362+
{
363+
sc.check_atomCounts();
364+
const int nat = sc.get_nat();
365+
const int nspin = sc.get_nspin();
366+
const auto& Mi = sc.get_Mi();
367+
const auto& atomLabel = sc.get_atomLabels();
368+
std::vector<double> mag_x(nat, 0.0);
369+
std::vector<double> mag_y(nat, 0.0);
370+
std::vector<double> mag_z(nat, 0.0);
371+
if (nspin == 2)
372+
{
373+
const std::vector<std::string> title = {"Total Magnetism (uB)", ""};
374+
const std::vector<std::string> fmts = {"%-26s", "%20.10f"};
375+
FmtTable table(/*titles=*/title,
376+
/*nrows=*/nat,
377+
/*formats=*/fmts,
378+
/*indent=*/0,
379+
/*align=*/{/*value*/FmtTable::Align::RIGHT, /*title*/FmtTable::Align::LEFT});
380+
for (int iat = 0; iat < nat; ++iat)
381+
{
382+
mag_z[iat] = Mi[iat].z;
383+
}
384+
table << atomLabel << mag_z;
385+
ofs_running << table.str() << std::endl;
386+
}
387+
else if (nspin == 4)
388+
{
389+
const std::vector<std::string> title = {"Total Magnetism (uB)", "", "", ""};
390+
const std::vector<std::string> fmts = {"%-26s", "%20.10f", "%20.10f", "%20.10f"};
391+
FmtTable table(/*titles=*/title,
392+
/*nrows=*/nat,
393+
/*formats=*/fmts,
394+
/*indent=*/0,
395+
/*align=*/{/*value*/FmtTable::Align::RIGHT, /*title*/FmtTable::Align::LEFT});
396+
for (int iat = 0; iat < nat; ++iat)
397+
{
398+
mag_x[iat] = Mi[iat].x;
399+
mag_y[iat] = Mi[iat].y;
400+
mag_z[iat] = Mi[iat].z;
401+
}
402+
table << atomLabel << mag_x << mag_y << mag_z;
403+
ofs_running << table.str() << std::endl;
404+
}
405+
}
406+
407+
/**
408+
* @brief Print the magnetic force (-lambda) per atom in eV/uB.
409+
*
410+
* Lifted from SpinConstrain<TK>::print_Mag_Force; accesses state via getters.
411+
* lambda is read via get_sc_lambda() and converted from Ry to eV on output.
412+
*/
413+
template <typename TK>
414+
void print_Mag_Force(const SpinConstrain<TK>& sc, std::ostream& ofs_running)
415+
{
416+
sc.check_atomCounts();
417+
const int nat = sc.get_nat();
418+
const int nspin = sc.get_nspin();
419+
const auto& lambda = sc.get_sc_lambda();
420+
const auto& atomLabel = sc.get_atomLabels();
421+
std::vector<double> mag_force_x(nat, 0.0);
422+
std::vector<double> mag_force_y(nat, 0.0);
423+
std::vector<double> mag_force_z(nat, 0.0);
424+
if (nspin == 2)
425+
{
426+
const std::vector<std::string> title = {"Magnetic force (eV/uB)", ""};
427+
const std::vector<std::string> fmts = {"%-26s", "%20.10f"};
428+
FmtTable table(/*titles=*/title,
429+
/*nrows=*/nat,
430+
/*formats=*/fmts,
431+
/*indent=*/0,
432+
/*align=*/{/*value*/FmtTable::Align::RIGHT, /*title*/FmtTable::Align::LEFT});
433+
for (int iat = 0; iat < nat; ++iat)
434+
{
435+
mag_force_z[iat] = lambda[iat].z * ModuleBase::Ry_to_eV;
436+
}
437+
table << atomLabel << mag_force_z;
438+
ofs_running << table.str() << std::endl;
439+
}
440+
else if (nspin == 4)
441+
{
442+
const std::vector<std::string> title = {"Magnetic force (eV/uB)", "", "", ""};
443+
const std::vector<std::string> fmts = {"%-26s", "%20.10f", "%20.10f", "%20.10f"};
444+
FmtTable table(/*titles=*/title,
445+
/*nrows=*/nat,
446+
/*formats=*/fmts,
447+
/*indent=*/0,
448+
/*align=*/{/*value*/FmtTable::Align::RIGHT, /*title*/FmtTable::Align::LEFT});
449+
for (int iat = 0; iat < nat; ++iat)
450+
{
451+
mag_force_x[iat] = lambda[iat].x * ModuleBase::Ry_to_eV;
452+
mag_force_y[iat] = lambda[iat].y * ModuleBase::Ry_to_eV;
453+
mag_force_z[iat] = lambda[iat].z * ModuleBase::Ry_to_eV;
454+
}
455+
table << atomLabel << mag_force_x << mag_force_y << mag_force_z;
456+
ofs_running << table.str() << std::endl;
457+
}
458+
}
459+
460+
348461
// Explicit instantiation for the only supported TK = std::complex<double>.
349462
// The double stub is provided by template_helpers.cpp via the existing
350463
// specialization mechanism (kept as a separate file to avoid duplicate symbols).
@@ -366,4 +479,14 @@ template bool check_gradient_decay<std::complex<double>>(const SpinConstrain<std
366479
std::vector<ModuleBase::Vector3<double>>,
367480
bool, std::ostream&);
368481

482+
// print_Mi / print_Mag_Force are generic (no per-TK stub needed): the
483+
// template body works for both TK = std::complex<double> (real usage) and
484+
// TK = double (nspin=2 stub path instantiated by template_helpers_test).
485+
// We instantiate both so callers in PW/LCAO ESolvers that hold either TK
486+
// can link against a single definition.
487+
template void print_Mi<std::complex<double>>(const SpinConstrain<std::complex<double>>&, std::ostream&);
488+
template void print_Mag_Force<std::complex<double>>(const SpinConstrain<std::complex<double>>&, std::ostream&);
489+
template void print_Mi<double>(const SpinConstrain<double>&, std::ostream&);
490+
template void print_Mag_Force<double>(const SpinConstrain<double>&, std::ostream&);
491+
369492
} // namespace spinconstrain

source/source_lcao/module_deltaspin/lambda_loop_helper.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,32 @@ bool check_gradient_decay(const SpinConstrain<TK>& sc,
134134
bool print,
135135
std::ostream& ofs_running);
136136

137+
/**
138+
* @brief Print atomic magnetic moments Mi in a formatted table.
139+
*
140+
* @par Output format
141+
* - nspin=2: "Total Magnetism (uB)" with single z-component column
142+
* - nspin=4: three columns (Mx, My, Mz)
143+
*
144+
* @param sc SpinConstrain instance
145+
* @param ofs_running Log output stream
146+
*/
147+
template <typename TK>
148+
void print_Mi(const SpinConstrain<TK>& sc, std::ostream& ofs_running);
149+
150+
/**
151+
* @brief Print the magnetic force (-lambda) per atom in eV/uB.
152+
*
153+
* @par Physical meaning
154+
* Magnetic force = dL/dMi = -lambda. Large |lambda| means the system
155+
* strongly resists the target moment constraint.
156+
*
157+
* @param sc SpinConstrain instance
158+
* @param ofs_running Log output stream
159+
*/
160+
template <typename TK>
161+
void print_Mag_Force(const SpinConstrain<TK>& sc, std::ostream& ofs_running);
162+
137163
} // namespace spinconstrain
138164

139165
#endif // LAMBDA_LOOP_HELPER_H

source/source_lcao/module_deltaspin/spin_constrain.cpp

Lines changed: 10 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ int SpinConstrain<TK>::get_ntype() const
287287
* - "number of atoms <= 0": some element type has no atoms
288288
*/
289289
template <typename TK>
290-
void SpinConstrain<TK>::check_atomCounts()
290+
void SpinConstrain<TK>::check_atomCounts() const
291291
{
292292
if (!this->atomCounts.size())
293293
{
@@ -297,7 +297,7 @@ void SpinConstrain<TK>::check_atomCounts()
297297
{
298298
ModuleBase::WARNING_QUIT("SpinConstrain::check_atomCounts", "nat <= 0");
299299
}
300-
for (std::map<int, int>::iterator it = this->atomCounts.begin(); it != this->atomCounts.end(); ++it)
300+
for (std::map<int, int>::const_iterator it = this->atomCounts.begin(); it != this->atomCounts.end(); ++it)
301301
{
302302
int itype = it->first;
303303
if (itype < 0 || itype >= this->get_ntype())
@@ -342,7 +342,7 @@ int SpinConstrain<TK>::get_iat(int itype, int atom_index)
342342
ModuleBase::WARNING_QUIT("SpinConstrain::get_iat", "atom index out of range [0, nat)");
343343
}
344344
int iat = 0;
345-
for (std::map<int, int>::iterator it = this->atomCounts.begin(); it != this->atomCounts.end(); ++it)
345+
for (std::map<int, int>::const_iterator it = this->atomCounts.begin(); it != this->atomCounts.end(); ++it)
346346
{
347347
if (it->first == itype)
348348
{
@@ -699,6 +699,13 @@ const std::vector<ModuleBase::Vector3<double>>& SpinConstrain<TK>::get_Mi() cons
699699
return this->Mi_;
700700
}
701701

702+
/// get human-readable atom labels for table printing
703+
template <typename TK>
704+
const std::vector<std::string>& SpinConstrain<TK>::get_atomLabels() const
705+
{
706+
return this->atomLabels_;
707+
}
708+
702709
/// get nsc
703710
template <typename TK>
704711
int SpinConstrain<TK>::get_nsc() const
@@ -765,127 +772,6 @@ void SpinConstrain<TK>::set_ParaV(Parallel_Orbitals* ParaV_in)
765772
}
766773
}
767774

768-
/**
769-
* @brief Print magnetic moments per atom in formatted table.
770-
*
771-
* @par Output format
772-
* - nspin=2: "ATOM 1 2.0000000000" (z-component only)
773-
* - nspin=4: "ATOM 1 0.0010000000 0.0020000000 1.9990000000" (x, y, z)
774-
*
775-
* @par Interpretation
776-
* - Positive Mi.z: spin aligned with z-axis (spin-up character)
777-
* - Negative Mi.z: spin anti-aligned with z-axis (spin-down character)
778-
* - Non-zero Mi.x/Mi.y: non-collinear spin components
779-
* - Mi close to target_mag: constraint is well-satisfied
780-
* - Mi far from target_mag: constraint is not yet converged
781-
*/
782-
template <typename TK>
783-
void SpinConstrain<TK>::print_Mi(std::ofstream& ofs_running)
784-
{
785-
this->check_atomCounts();
786-
int nat = this->get_nat();
787-
std::vector<double> mag_x(nat, 0.0);
788-
std::vector<double> mag_y(nat, 0.0);
789-
std::vector<double> mag_z(nat, 0.0);
790-
if (this->nspin_ == 2)
791-
{
792-
const std::vector<std::string> title = {"Total Magnetism (uB)", ""};
793-
const std::vector<std::string> fmts = {"%-26s", "%20.10f"};
794-
FmtTable table(/*titles=*/title,
795-
/*nrows=*/nat,
796-
/*formats=*/fmts,
797-
/*indent=*/0,
798-
/*align=*/{/*value*/FmtTable::Align::RIGHT, /*title*/FmtTable::Align::LEFT});
799-
for (int iat = 0; iat < nat; ++iat)
800-
{
801-
mag_z[iat] = Mi_[iat].z;
802-
}
803-
table << this->atomLabels_ << mag_z;
804-
ofs_running << table.str() << std::endl;
805-
}
806-
else if (this->nspin_ == 4)
807-
{
808-
const std::vector<std::string> title = {"Total Magnetism (uB)", "", "", ""};
809-
const std::vector<std::string> fmts = {"%-26s", "%20.10f", "%20.10f", "%20.10f"};
810-
FmtTable table(/*titles=*/title,
811-
/*nrows=*/nat,
812-
/*formats=*/fmts,
813-
/*indent=*/0,
814-
/*align=*/{/*value*/FmtTable::Align::RIGHT, /*title*/FmtTable::Align::LEFT});
815-
for (int iat = 0; iat < nat; ++iat)
816-
{
817-
mag_x[iat] = Mi_[iat].x;
818-
mag_y[iat] = Mi_[iat].y;
819-
mag_z[iat] = Mi_[iat].z;
820-
}
821-
table << this->atomLabels_ << mag_x << mag_y << mag_z;
822-
ofs_running << table.str() << std::endl;
823-
}
824-
}
825-
826-
/**
827-
* @brief Print the magnetic force (-lambda) per atom in eV/uB.
828-
*
829-
* @par Physical meaning
830-
* The "magnetic force" is the derivative of the constrained Lagrangian
831-
* with respect to the magnetic moment: dL/dMi = -lambda_i.
832-
* It represents how much energy would change if the constraint were relaxed.
833-
*
834-
* @par Interpretation
835-
* - Large |lambda|: The system strongly resists the target moment constraint
836-
* - lambda ≈ 0: The system naturally has the target moment (no constraint needed)
837-
* - Positive lambda.z: The constraint pushes the moment in the +z direction
838-
* - Negative lambda.z: The constraint pushes the moment in the -z direction
839-
*
840-
* @par Typical values
841-
* - Well-converged SCF: lambda ~ 0.01-1 eV/uB
842-
* - Strongly constrained: lambda ~ 1-10 eV/uB
843-
* - Diverging SCF: lambda growing without bound (check target_mag合理性)
844-
*/
845-
template <typename TK>
846-
void SpinConstrain<TK>::print_Mag_Force(std::ofstream& ofs_running)
847-
{
848-
this->check_atomCounts();
849-
int nat = this->get_nat();
850-
std::vector<double> mag_force_x(nat, 0.0);
851-
std::vector<double> mag_force_y(nat, 0.0);
852-
std::vector<double> mag_force_z(nat, 0.0);
853-
if (this->nspin_ == 2)
854-
{
855-
const std::vector<std::string> title = {"Magnetic force (eV/uB)", ""};
856-
const std::vector<std::string> fmts = {"%-26s", "%20.10f"};
857-
FmtTable table(/*titles=*/title,
858-
/*nrows=*/nat,
859-
/*formats=*/fmts,
860-
/*indent=*/0,
861-
/*align=*/{/*value*/FmtTable::Align::RIGHT, /*title*/FmtTable::Align::LEFT});
862-
for (int iat = 0; iat < nat; ++iat)
863-
{
864-
mag_force_z[iat] = lambda_[iat].z * ModuleBase::Ry_to_eV;
865-
}
866-
table << this->atomLabels_ << mag_force_z;
867-
ofs_running << table.str() << std::endl;
868-
}
869-
else if (this->nspin_ == 4)
870-
{
871-
const std::vector<std::string> title = {"Magnetic force (eV/uB)", "", "", ""};
872-
const std::vector<std::string> fmts = {"%-26s", "%20.10f", "%20.10f", "%20.10f"};
873-
FmtTable table(/*titles=*/title,
874-
/*nrows=*/nat,
875-
/*formats=*/fmts,
876-
/*indent=*/0,
877-
/*align=*/{/*value*/FmtTable::Align::RIGHT, /*title*/FmtTable::Align::LEFT});
878-
for (int iat = 0; iat < nat; ++iat)
879-
{
880-
mag_force_x[iat] = lambda_[iat].x * ModuleBase::Ry_to_eV;
881-
mag_force_y[iat] = lambda_[iat].y * ModuleBase::Ry_to_eV;
882-
mag_force_z[iat] = lambda_[iat].z * ModuleBase::Ry_to_eV;
883-
}
884-
table << this->atomLabels_ << mag_force_x << mag_force_y << mag_force_z;
885-
ofs_running << table.str() << std::endl;
886-
}
887-
}
888-
889775
/**
890776
* @brief Reset DeltaSpin operator initialization state.
891777
*

0 commit comments

Comments
 (0)