@@ -407,6 +407,11 @@ void ESolver_KS_LCAO<TK, TR>::hamilt2rho_single(UnitCell& ucell, int istep, int
407407 sc.run_lambda_linear_scan (iter - 1 );
408408 skip_solve = true ;
409409 }
410+ else if (PARAM .inp .sc_direction_only )
411+ {
412+ // direction_only mode: skip the inner BFGS lambda loop.
413+ // Lambda projection is handled by the DeltaSpin operator.
414+ }
410415 else if (!sc.mag_converged () && this ->drho > 0 && this ->drho < PARAM .inp .sc_scf_thr )
411416 {
412417 sc.run_lambda_loop (iter - 1 );
@@ -480,6 +485,87 @@ void ESolver_KS_LCAO<TK, TR>::iter_finish(UnitCell& ucell, const int istep, int&
480485 // 3) for delta spin
481486 cal_mi_lcao_wrapper<TK >(iter, PARAM .inp );
482487
488+ // 3b) direction_only: constraint SCF annealing
489+ // Phase 1 (iter 1-5): strong lambda + tiny mixing_beta to lock spin direction
490+ // Phase 2 (iter 6+): decay lambda once aligned, restore mixing_beta
491+ if (PARAM .inp .sc_direction_only && PARAM .inp .sc_mag_switch )
492+ {
493+ spinconstrain::SpinConstrain<TK >& sc = spinconstrain::SpinConstrain<TK >::getScInstance ();
494+ const int nat = sc.get_nat ();
495+ const auto & Mi = sc.get_Mi ();
496+ const auto & target = sc.get_target_mag ();
497+ const auto & constrain = sc.get_constrain ();
498+ auto lambda = sc.get_sc_lambda ();
499+
500+ const double LAMBDA_STRONG_EV = 500.0 ; // strong constraint in eV/uB
501+ const double BETA_MIN = 0.02 ; // tiny mixing during guidance
502+ const int GUIDANCE_ITERS = 10 ; // guidance phase length
503+ const double DECAY = 0.5 ; // per-step decay after guidance
504+
505+ // Check if all atoms have correct spin direction
506+ bool all_aligned = true ;
507+ for (int ia = 0 ; ia < nat; ++ia)
508+ for (int ic = 0 ; ic < 3 ; ++ic)
509+ if (constrain[ia][ic] != 0 && Mi[ia][ic] * target[ia][ic] < 0 )
510+ all_aligned = false ;
511+
512+ if (iter <= GUIDANCE_ITERS )
513+ {
514+ // Phase 1: strong constraint, minimal mixing
515+ for (int ia = 0 ; ia < nat; ++ia)
516+ for (int ic = 0 ; ic < 3 ; ++ic)
517+ if (constrain[ia][ic] != 0 )
518+ lambda[ia][ic] = (target[ia][ic] > 0 ? LAMBDA_STRONG_EV : -LAMBDA_STRONG_EV ) / ModuleBase::Ry_to_eV;
519+ this ->p_chgmix ->set_mixing_beta (BETA_MIN );
520+ GlobalV::ofs_running << " [DS-dir] iter " << iter << " PHASE 1: guidance (lambda=" << LAMBDA_STRONG_EV
521+ << " eV/uB, beta=" << BETA_MIN << " )" << std::endl;
522+ std::cerr << " [DS-dir] iter " << iter << " PHASE 1: guidance (lambda=" << LAMBDA_STRONG_EV
523+ << " eV/uB, beta=" << BETA_MIN << " )" << std::endl;
524+ }
525+ else
526+ {
527+ // Phase 2: decay lambda, restore mixing_beta
528+ if (all_aligned)
529+ {
530+ for (int ia = 0 ; ia < nat; ++ia)
531+ for (int ic = 0 ; ic < 3 ; ++ic)
532+ if (constrain[ia][ic] != 0 )
533+ lambda[ia][ic] *= DECAY ;
534+ GlobalV::ofs_running << " [DS-dir] iter " << iter << " PHASE 2: decay (aligned)" << std::endl;
535+ std::cerr << " [DS-dir] iter " << iter << " PHASE 2: decay (aligned)" << std::endl;
536+ }
537+ else
538+ {
539+ GlobalV::ofs_running << " [DS-dir] iter " << iter << " PHASE 1: still guiding (MISMATCH)" << std::endl;
540+ std::cerr << " [DS-dir] iter " << iter << " PHASE 1: still guiding (MISMATCH)" << std::endl;
541+ // Keep strong constraint if not aligned yet
542+ for (int ia = 0 ; ia < nat; ++ia)
543+ for (int ic = 0 ; ic < 3 ; ++ic)
544+ if (constrain[ia][ic] != 0 )
545+ lambda[ia][ic] = (target[ia][ic] > 0 ? LAMBDA_STRONG_EV : -LAMBDA_STRONG_EV ) / ModuleBase::Ry_to_eV;
546+ }
547+ // Linearly restore mixing_beta to input value
548+ double beta_restore = std::min (1.0 , (iter - GUIDANCE_ITERS ) / (double )GUIDANCE_ITERS );
549+ this ->p_chgmix ->set_mixing_beta (BETA_MIN + (PARAM .inp .mixing_beta - BETA_MIN ) * beta_restore);
550+ }
551+ sc.set_lambda (lambda);
552+ // Print per-atom Mi/Target
553+ for (int ia = 0 ; ia < nat; ++ia)
554+ for (int ic = 0 ; ic < 3 ; ++ic)
555+ if (constrain[ia][ic] != 0 )
556+ {
557+ std::string status = (Mi[ia][ic] * target[ia][ic] < 0 ) ? " MISMATCH" : " OK" ;
558+ GlobalV::ofs_running << " Atom " << ia << " comp " << ic << " : Mi=" << Mi[ia][ic]
559+ << " T=" << target[ia][ic] << " [" << status
560+ << " ] lambda=" << lambda[ia][ic] * ModuleBase::Ry_to_eV << " eV/uB"
561+ << " beta=" << this ->p_chgmix ->get_mixing_beta () << std::endl;
562+ std::cerr << " Atom " << ia << " comp " << ic << " : Mi=" << Mi[ia][ic]
563+ << " T=" << target[ia][ic] << " [" << status
564+ << " ] lambda=" << lambda[ia][ic] * ModuleBase::Ry_to_eV << " eV/uB"
565+ << " beta=" << this ->p_chgmix ->get_mixing_beta () << std::endl;
566+ }
567+ }
568+
483569 // call iter_finish() of ESolver_KS, where band gap is printed,
484570 // eig and occ are printed, magnetization is calculated,
485571 // charge mixing is performed, potential is updated,
0 commit comments