Skip to content

Commit 9c49503

Browse files
committed
feat(deltaspin): opt-in subspace acceleration for LCAO spin-constrained DFT
- Add sc_acceleration_mode parameter: off/first_order/subspace - Add sc_acceleration_rms_thr parameter to control activation threshold - Restore full HSolverLCAO diagonalization as the default path for correctness - Subspace/first-order methods are now opt-in and only activate once RMS drops below the configured threshold - Pass acceleration parameters through init_sc chain to SpinConstrain class - Add comprehensive comments explaining i_step=-2 subspace build branch, acceleration activation logic, and the three execution paths in cal_mw_from_lambda - Fix critical bug where subspace diagonalization incorrectly replaced the full solver, causing convergence failure
1 parent 3706309 commit 9c49503

16 files changed

Lines changed: 1692 additions & 63 deletions

File tree

source/source_esolver/esolver_ks_lcao.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,7 +442,15 @@ void ESolver_KS_LCAO<TK, TR>::hamilt2rho_single(UnitCell& ucell, int istep, int
442442

443443
if (PARAM.inp.sc_lambda_strategy == "linear_scan")
444444
{
445+
sc.set_drho(this->drho);
445446
sc.run_lambda_linear_scan(iter - 1);
447+
448+
// Run subspace vs full diagnostic scan for nspin=2 LCAO
449+
if (PARAM.inp.nspin == 2 && PARAM.inp.sc_scan_steps > 0 && iter == 1)
450+
{
451+
sc.run_lambda_scan_diagnostic(iter - 1);
452+
}
453+
446454
skip_solve = true;
447455
}
448456
else if (PARAM.inp.sc_scf_thr_mode == "off")
@@ -468,6 +476,7 @@ void ESolver_KS_LCAO<TK, TR>::hamilt2rho_single(UnitCell& ucell, int istep, int
468476
// ================================================================
469477
if (iter <= PARAM.inp.sc_dir_phase1_steps)
470478
{
479+
sc.set_drho(this->drho);
471480
sc.set_direction_only(false);
472481
sc.run_lambda_loop(iter - 1);
473482
sc.set_direction_only(true);
@@ -508,6 +517,7 @@ void ESolver_KS_LCAO<TK, TR>::hamilt2rho_single(UnitCell& ucell, int istep, int
508517
{
509518
if (iter > 1)
510519
{
520+
sc.set_drho(this->drho);
511521
sc.run_lambda_loop(iter - 1);
512522
if (!sc.mag_converged()) { sc.set_mag_converged(true); }
513523
skip_solve = true;
@@ -517,12 +527,14 @@ void ESolver_KS_LCAO<TK, TR>::hamilt2rho_single(UnitCell& ucell, int istep, int
517527
{
518528
if (!sc.mag_converged() && this->drho > 0 && this->drho < PARAM.inp.sc_scf_thr)
519529
{
530+
sc.set_drho(this->drho);
520531
sc.run_lambda_loop(iter - 1);
521532
sc.set_mag_converged(true);
522533
skip_solve = true;
523534
}
524535
else if (sc.mag_converged())
525536
{
537+
sc.set_drho(this->drho);
526538
sc.run_lambda_loop(iter - 1);
527539
skip_solve = true;
528540
}
@@ -538,6 +550,7 @@ void ESolver_KS_LCAO<TK, TR>::hamilt2rho_single(UnitCell& ucell, int istep, int
538550
// available to compute initial magnetic moments.
539551
if (iter > 1)
540552
{
553+
sc.set_drho(this->drho);
541554
sc.run_lambda_loop(iter - 1);
542555
if (!sc.mag_converged()) { sc.set_mag_converged(true); }
543556
skip_solve = true;
@@ -549,12 +562,14 @@ void ESolver_KS_LCAO<TK, TR>::hamilt2rho_single(UnitCell& ucell, int istep, int
549562
// drho > 0 excludes iter=1 where drho has not been computed yet.
550563
if (!sc.mag_converged() && this->drho > 0 && this->drho < PARAM.inp.sc_scf_thr)
551564
{
565+
sc.set_drho(this->drho);
552566
sc.run_lambda_loop(iter - 1);
553567
sc.set_mag_converged(true);
554568
skip_solve = true;
555569
}
556570
else if (sc.mag_converged())
557571
{
572+
sc.set_drho(this->drho);
558573
sc.run_lambda_loop(iter - 1);
559574
skip_solve = true;
560575
}

source/source_esolver/lcao_others.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,8 @@ void ESolver_KS_LCAO<TK, TR>::others(UnitCell& ucell, const int istep)
155155
PARAM.inp.alpha_trial,
156156
PARAM.inp.sccut,
157157
PARAM.inp.sc_drop_thr,
158+
PARAM.inp.sc_acceleration_mode,
159+
PARAM.inp.sc_acceleration_rms_thr,
158160
ucell,
159161
PARAM.inp.sc_direction_only,
160162
&(this->pv),

source/source_io/module_parameter/input_parameter.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,8 @@ struct Input_para
609609
double sc_scan_lambda_start = 0.0; ///< start value for lambda scan (eV/uB)
610610
double sc_scan_lambda_end = 1.0; ///< end value for lambda scan (eV/uB)
611611
int sc_scan_steps = 20; ///< number of steps in lambda scan
612+
std::string sc_acceleration_mode = "off"; ///< acceleration mode: "off", "first_order", "subspace"
613+
double sc_acceleration_rms_thr = -1.0; ///< RMS threshold (uB) to activate acceleration, <0 disables
612614

613615
// ============== #Parameters (18.Quasiatomic Orbital analysis) =========
614616
///<==========================================================

source/source_io/module_parameter/read_input_item_other.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,41 @@ When false (default), both the direction and magnitude of the magnetic moment ar
292292
read_sync_int(input.sc_scan_steps);
293293
this->add_item(item);
294294
}
295+
{
296+
Input_Item item("sc_acceleration_mode");
297+
item.annotation = "acceleration mode for spin-constrained DFT";
298+
item.category = "Spin-Constrained DFT";
299+
item.type = "String";
300+
item.description = R"(Acceleration mode for converged lambda loop:
301+
* off: no acceleration, always use full HSolverLCAO diagonalization (default)
302+
* first_order: use first-order eigenvalue response (fastest, requires RMS < sc_acceleration_rms_thr)
303+
* subspace: use subspace diagonalization with wavefunction rotation (faster, requires RMS < sc_acceleration_rms_thr)
304+
305+
When enabled, the acceleration activates once RMS drops below sc_acceleration_rms_thr. The subspace is built using the wavefunctions at the current lambda when the threshold is first crossed.)";
306+
item.default_value = "off";
307+
item.unit = "";
308+
item.availability = "sc_mag_switch is true and basis_type=lcao";
309+
read_sync_string(input.sc_acceleration_mode);
310+
item.check_value = [](const Input_Item& item, const Parameter& para) {
311+
const std::string& mode = para.input.sc_acceleration_mode;
312+
if (mode != "off" && mode != "first_order" && mode != "subspace") {
313+
ModuleBase::WARNING_QUIT("ReadInput", "sc_acceleration_mode must be off, first_order, or subspace");
314+
}
315+
};
316+
this->add_item(item);
317+
}
318+
{
319+
Input_Item item("sc_acceleration_rms_thr");
320+
item.annotation = "RMS threshold for acceleration activation";
321+
item.category = "Spin-Constrained DFT";
322+
item.type = "Real";
323+
item.description = "RMS threshold (uB) to activate acceleration mode. Must be > 0 to enable. The acceleration activates once RMS < sc_acceleration_rms_thr. Typical value: 10 * sc_thr.";
324+
item.default_value = "-1.0";
325+
item.unit = "uB";
326+
item.availability = "sc_mag_switch is true and sc_acceleration_mode is not off";
327+
read_sync_double(input.sc_acceleration_rms_thr);
328+
this->add_item(item);
329+
}
295330

296331
// Quasiatomic Orbital analysis
297332
{

source/source_lcao/module_deltaspin/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ list(APPEND objects
1010
deltaspin_lcao.cpp
1111
sc_parse_json.cpp
1212
cal_mw_helper.cpp
13+
lcao_subspace.cpp
1314
)
1415

1516
add_library(

0 commit comments

Comments
 (0)