Skip to content

Commit 125581b

Browse files
Feature: add so-called U-Ramping method to improve DFTU convergence (#3890)
* add a new input parameter uramping, default is -1.0 * add a new member uramping in dftu.h and value it in Input_conv::Convert() * add a new member U0 in dftu.h and value it in Input_conv::Convert() * set U zero if uramping > 0.1 in Input_conv::Convert() * add a new member function DFTU::uramping_update() to change U during SCF * add a new member function DFTU::U_converged() to check if U=U0 * add uramping in esolver_lcao::iter_init() and change conv_elec * make some minor changes * fix bug which only restart once * add a new member mixing_restart_count in Charge_Mixing * add U output at iter 1 * fix build error without LCAO * add some output of U value during U-Raming * add some docs about uramping * modify under some comments * add a space in output * add docs abouht DFTU in converge.md * add recommendations of mixing_restart in input-main.md * add some comment to explain why mixing_restart_count is int instead of bool * add ref & in mix_dmr() * add a new CI case 260_NO_DJ_PK_PU_AFM_URAMPING * rename chgmix->mixing_restart as mixing_restart_step to avoid misunderstanding between GlobalV::MIXING_RESTART * keep verbosity of judge in esolver to remind others mixing_dmr is only called in this case. --------- Co-authored-by: Mohan Chen <[email protected]>
1 parent 270b307 commit 125581b

File tree

22 files changed

+212
-22
lines changed

22 files changed

+212
-22
lines changed

docs/advanced/input_files/input-main.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,7 @@
276276
- [hubbard\_u](#hubbard_u)
277277
- [yukawa\_potential](#yukawa_potential)
278278
- [yukawa\_lambda](#yukawa_lambda)
279+
- [uramping](#uramping)
279280
- [omc](#omc)
280281
- [onsite\_radius](#onsite_radius)
281282
- [vdW correction](#vdw-correction)
@@ -2610,6 +2611,14 @@ These variables are used to control DFT+U correlated parameters
26102611
- **Description**: The screen length of Yukawa potential. If left to default, the screen length will be calculated as an average of the entire system. It's better to stick to the default setting unless there is a very good reason.
26112612
- **Default**: Calculated on the fly.
26122613

2614+
### uramping
2615+
2616+
- **Type**: Real
2617+
- **Unit**: eV
2618+
- **Availability**: DFT+U calculations with `mixing_restart > 0`.
2619+
- **Description**: Once `uramping` > 0.15 eV. DFT+U calculations will start SCF with U = 0 eV, namely normal LDA/PBE calculations. Once SCF restarts when `drho<mixing_restart`, U value will increase by `uramping` eV. SCF will repeat above calcuations until U values reach target defined in `hubbard_u`. As for `uramping=1.0 eV`, the recommendations of `mixing_restart` is around `5e-4`.
2620+
- **Default**: -1.0.
2621+
26132622
### omc
26142623

26152624
- **Type**: Integer

docs/advanced/scf/converge.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ For magnetic calculations, `mixing_beta_mag` and `mixing_gg0_mag` are activated.
1616

1717
An example showcasing different charge mixing methods can be found in our [repository](https://github.com/deepmodeling/abacus-develop/tree/develop/examples/charge_mixing/pw_Al). Four INPUT files are provided, with description given in README.
1818

19+
As for DFT+U calculations, where the hamiltonian is not only dependent on charge density, but also dependent on density matrix. You can try `mixing_restart>0` and `mixing_dmr=1` to improve convergence. For case extremely hard to converge, you can use so-called U-Ramping method by setting a finite positive `uramping` with `mixing_restart>0` and `mixing_dmr=1`.
20+
1921
## Smearing
2022

2123
Thermal smearing is an efficient tool for accelerating SCF convergence by allowing fractional occupation of molecular orbitals near the band edge. It is important for metallic systems.

source/module_elecstate/module_charge/charge_mixing.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -801,7 +801,7 @@ void Charge_Mixing::mix_dmr(elecstate::DensityMatrix<double, double>* DM)
801801
ModuleBase::timer::tick("Charge_Mixing", "mix_dmr");
802802
//
803803
std::vector<hamilt::HContainer<double>*> dmr = DM->get_DMR_vector();
804-
std::vector<std::vector<double>> dmr_save = DM->get_DMR_save();
804+
std::vector<std::vector<double>>& dmr_save = DM->get_DMR_save();
805805
//
806806
//const int dmr_nspin = (GlobalV::NSPIN == 2) ? 2 : 1;
807807
double* dmr_in;
@@ -900,7 +900,7 @@ void Charge_Mixing::mix_dmr(elecstate::DensityMatrix<std::complex<double>, doubl
900900
ModuleBase::timer::tick("Charge_Mixing", "mix_dmr");
901901
//
902902
std::vector<hamilt::HContainer<double>*> dmr = DM->get_DMR_vector();
903-
std::vector<std::vector<double>> dmr_save = DM->get_DMR_save();
903+
std::vector<std::vector<double>>& dmr_save = DM->get_DMR_save();
904904
//
905905
//const int dmr_nspin = (GlobalV::NSPIN == 2) ? 2 : 1;
906906
double* dmr_in;

source/module_elecstate/module_charge/charge_mixing.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,8 @@ class Charge_Mixing
101101
Base_Mixing::Mixing* get_mixing() const {return mixing;}
102102

103103
// for mixing restart
104-
int mixing_restart = 0; //which step to restart mixing during SCF
104+
int mixing_restart_step = 0; //which step to restart mixing during SCF
105+
int mixing_restart_count = 0; // the number of restart mixing during SCF. Do not set mixing_restart_count as bool since I want to keep some flexibility in the future
105106

106107
private:
107108

source/module_esolver/esolver_ks.cpp

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
//--------------Temporary----------------
1414
#include "module_base/global_variable.h"
1515
#include "module_hamilt_pw/hamilt_pwdft/global.h"
16+
#include "module_hamilt_lcao/module_dftu/dftu.h"
1617
//---------------------------------------
1718
#ifdef USE_PAW
1819
#include "module_cell/module_paw/paw_cell.h"
@@ -443,15 +444,23 @@ void ESolver_KS<T, Device>::run(const int istep, UnitCell& ucell)
443444
// mixing will restart at this->p_chgmix->mixing_restart steps
444445
if (drho <= GlobalV::MIXING_RESTART
445446
&& GlobalV::MIXING_RESTART > 0.0
446-
&& this->p_chgmix->mixing_restart > iter)
447+
&& this->p_chgmix->mixing_restart_step > iter)
447448
{
448-
this->p_chgmix->mixing_restart = iter + 1;
449+
this->p_chgmix->mixing_restart_step = iter + 1;
449450
}
450451

451452
// drho will be 0 at this->p_chgmix->mixing_restart step, which is not ground state
453+
bool not_restart_step = !(iter==this->p_chgmix->mixing_restart_step && GlobalV::MIXING_RESTART > 0.0);
454+
// SCF will continue if U is not converged for uramping calculation
455+
bool is_U_converged = true;
456+
// to avoid unnecessary dependence on dft+u, refactor is needed
457+
#ifdef __LCAO
458+
if (GlobalV::dft_plus_u) is_U_converged = GlobalC::dftu.u_converged();
459+
#endif
460+
//
452461
this->conv_elec = (drho < this->scf_thr
453-
&& !(iter==this->p_chgmix->mixing_restart
454-
&& GlobalV::MIXING_RESTART > 0.0));
462+
&& not_restart_step
463+
&& is_U_converged);
455464

456465
// If drho < hsolver_error in the first iter or drho < scf_thr, we do not change rho.
457466
if (drho < hsolver_error || this->conv_elec)
@@ -466,7 +475,7 @@ void ESolver_KS<T, Device>::run(const int istep, UnitCell& ucell)
466475
//----------charge mixing---------------
467476
// mixing will restart after this->p_chgmix->mixing_restart steps
468477
if (GlobalV::MIXING_RESTART > 0
469-
&& iter == this->p_chgmix->mixing_restart - 1)
478+
&& iter == this->p_chgmix->mixing_restart_step - 1)
470479
{
471480
// do not mix charge density
472481
}
@@ -529,10 +538,10 @@ void ESolver_KS<T, Device>::run(const int istep, UnitCell& ucell)
529538

530539
// notice for restart
531540
if (GlobalV::MIXING_RESTART > 0
532-
&& iter == this->p_chgmix->mixing_restart - 1
541+
&& iter == this->p_chgmix->mixing_restart_step - 1
533542
&& iter != GlobalV::SCF_NMAX)
534543
{
535-
std::cout<<"SCF restart after this step!"<<std::endl;
544+
std::cout<<" SCF restart after this step!"<<std::endl;
536545
}
537546
}
538547
#ifdef __RAPIDJSON

source/module_esolver/esolver_ks_lcao.cpp

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -552,13 +552,43 @@ void ESolver_KS_LCAO<TK, TR>::iter_init(const int istep, const int iter)
552552
if (iter == 1)
553553
{
554554
this->p_chgmix->init_mixing(); // init mixing
555-
this->p_chgmix->mixing_restart = GlobalV::SCF_NMAX + 1;
555+
this->p_chgmix->mixing_restart_step = GlobalV::SCF_NMAX + 1;
556+
this->p_chgmix->mixing_restart_count = 0;
557+
// this output will be removed once the feeature is stable
558+
if(GlobalC::dftu.uramping > 0.01)
559+
{
560+
std::cout << " U-Ramping! Current U = " ;
561+
for (int i = 0; i < GlobalC::dftu.U0.size(); i++)
562+
{
563+
std::cout << GlobalC::dftu.U[i] * ModuleBase::Ry_to_eV << " ";
564+
}
565+
std::cout << " eV " << std::endl;
566+
}
556567
}
557568
// for mixing restart
558-
if (iter == this->p_chgmix->mixing_restart
569+
if (iter == this->p_chgmix->mixing_restart_step
559570
&& GlobalV::MIXING_RESTART > 0.0)
560571
{
561572
this->p_chgmix->init_mixing();
573+
this->p_chgmix->mixing_restart_count++;
574+
if (GlobalV::dft_plus_u)
575+
{
576+
GlobalC::dftu.uramping_update(); // update U by uramping if uramping > 0.01
577+
if(GlobalC::dftu.uramping > 0.01)
578+
{
579+
std::cout << " U-Ramping! Current U = " ;
580+
for (int i = 0; i < GlobalC::dftu.U0.size(); i++)
581+
{
582+
std::cout << GlobalC::dftu.U[i] * ModuleBase::Ry_to_eV << " ";
583+
}
584+
std::cout << " eV " << std::endl;
585+
}
586+
if(GlobalC::dftu.uramping > 0.01
587+
&& !GlobalC::dftu.u_converged())
588+
{
589+
this->p_chgmix->mixing_restart_step = GlobalV::SCF_NMAX + 1;
590+
}
591+
}
562592
if (GlobalV::MIXING_DMR) // for mixing_dmr
563593
{
564594
// allocate memory for dmr_mdata
@@ -687,7 +717,9 @@ void ESolver_KS_LCAO<TK, TR>::hamilt2density(int istep, int iter, double ethr)
687717
// save input rho
688718
this->pelec->charge->save_rho_before_sum_band();
689719
// save density matrix for mixing
690-
if (GlobalV::MIXING_RESTART > 0 && GlobalV::MIXING_DMR && iter >= this->p_chgmix->mixing_restart)
720+
if (GlobalV::MIXING_RESTART > 0
721+
&& GlobalV::MIXING_DMR
722+
&& this->p_chgmix->mixing_restart_count > 0)
691723
{
692724
elecstate::DensityMatrix<TK, double>* dm
693725
= dynamic_cast<elecstate::ElecStateLCAO<TK>*>(this->pelec)->get_DM();
@@ -895,11 +927,13 @@ void ESolver_KS_LCAO<TK, TR>::iter_finish(int iter)
895927
{
896928
ModuleBase::TITLE("ESolver_KS_LCAO", "iter_finish");
897929

898-
// mix density matrix
899-
if (GlobalV::MIXING_RESTART > 0 && iter >= this->p_chgmix->mixing_restart && GlobalV::MIXING_DMR )
930+
// mix density matrix if mixing_restart + mixing_dmr + not first mixing_restart at every iter
931+
if (GlobalV::MIXING_RESTART > 0
932+
&& this->p_chgmix->mixing_restart_count > 0
933+
&& GlobalV::MIXING_DMR)
900934
{
901935
elecstate::DensityMatrix<TK, double>* dm
902-
= dynamic_cast<elecstate::ElecStateLCAO<TK>*>(this->pelec)->get_DM();
936+
= dynamic_cast<elecstate::ElecStateLCAO<TK>*>(this->pelec)->get_DM();
903937
this->p_chgmix->mix_dmr(dm);
904938
}
905939

source/module_esolver/esolver_ks_pw.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -587,10 +587,10 @@ void ESolver_KS_PW<T, Device>::iter_init(const int istep, const int iter)
587587
if (iter == 1)
588588
{
589589
this->p_chgmix->init_mixing();
590-
this->p_chgmix->mixing_restart = GlobalV::SCF_NMAX + 1;
590+
this->p_chgmix->mixing_restart_step = GlobalV::SCF_NMAX + 1;
591591
}
592592
// for mixing restart
593-
if (iter == this->p_chgmix->mixing_restart && GlobalV::MIXING_RESTART > 0.0)
593+
if (iter == this->p_chgmix->mixing_restart_step && GlobalV::MIXING_RESTART > 0.0)
594594
{
595595
this->p_chgmix->init_mixing();
596596
}

source/module_hamilt_lcao/module_dftu/dftu.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,36 @@ void DFTU::cal_energy_correction(const int istep)
355355
return;
356356
}
357357

358+
void DFTU::uramping_update()
359+
{
360+
// if uramping < 0.1, use the original U
361+
if(this->uramping < 0.01) return;
362+
// loop to change U
363+
for(int i = 0; i < this->U0.size(); i++)
364+
{
365+
if (this->U[i] + this->uramping < this->U0[i] )
366+
{
367+
this->U[i] += this->uramping;
368+
}
369+
else
370+
{
371+
this->U[i] = this->U0[i];
372+
}
373+
}
374+
}
375+
376+
bool DFTU::u_converged()
377+
{
378+
for(int i = 0; i < this->U0.size(); i++)
379+
{
380+
if (this->U[i] != this->U0[i])
381+
{
382+
return false;
383+
}
384+
}
385+
return true;
386+
}
387+
358388
void DFTU::set_dmr(const elecstate::DensityMatrix<std::complex<double>, double>* dmr)
359389
{
360390
this->dm_in_dftu_cd = dmr;

source/module_hamilt_lcao/module_dftu/dftu.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,13 @@ class DFTU
4444
// calculate the energy correction
4545
void cal_energy_correction(const int istep);
4646
double get_energy(){return EU;}
47+
void uramping_update(); // update U by uramping
48+
bool u_converged(); // check if U is converged
4749

4850
double* U; // U (Hubbard parameter U)
51+
std::vector<double> U0; // U0 (target Hubbard parameter U0)
4952
int* orbital_corr; //
53+
double uramping; // increase U by uramping, default is -1.0
5054
int omc; // occupation matrix control
5155
int mixing_dftu; //whether to mix locale
5256

source/module_io/input.cpp

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,7 @@ void Input::Default(void)
557557
yukawa_potential = false;
558558
yukawa_lambda = -1.0;
559559
omc = 0;
560+
uramping = -1.0; // -1.0 means no ramping
560561

561562
//==========================================================
562563
// DFT+DMFT Xin Qu added on 2020-08
@@ -2111,14 +2112,12 @@ bool Input::Read(const std::string& fn)
21112112
{
21122113
read_bool(ifs, test_skip_ewald);
21132114
}
2114-
//--------------
2115-
//----------------------------------------------------------------------------------
2116-
// Xin Qu added on 2020-10-29 for DFT+U
2117-
//----------------------------------------------------------------------------------
2115+
//----------------------------------------------------------
21182116
else if (strcmp("dft_plus_u", word) == 0)
21192117
{
21202118
read_value(ifs, dft_plus_u);
21212119
}
2120+
// ignore to avoid error
21222121
else if (strcmp("yukawa_potential", word) == 0)
21232122
ifs.ignore(150, '\n');
21242123
else if (strcmp("hubbard_u", word) == 0)
@@ -2129,6 +2128,10 @@ bool Input::Read(const std::string& fn)
21292128
ifs.ignore(150, '\n');
21302129
else if (strcmp("yukawa_lambda", word) == 0)
21312130
ifs.ignore(150, '\n');
2131+
else if (strcmp("uramping", word) == 0)
2132+
{
2133+
ifs.ignore(150, '\n');
2134+
}
21322135
//----------------------------------------------------------------------------------
21332136
// Xin Qu added on 2020-08 for DFT+DMFT
21342137
//----------------------------------------------------------------------------------
@@ -2471,6 +2474,11 @@ bool Input::Read(const std::string& fn)
24712474
{
24722475
ifs >> yukawa_lambda;
24732476
}
2477+
else if (strcmp("uramping", word) == 0)
2478+
{
2479+
read_value(ifs, uramping);
2480+
uramping /= ModuleBase::Ry_to_eV;
2481+
}
24742482
else if (strcmp("hubbard_u", word) == 0)
24752483
{
24762484
for (int i = 0; i < ntype; i++)
@@ -3633,6 +3641,7 @@ void Input::Bcast()
36333641
//-----------------------------------------------------------------------------------
36343642
Parallel_Common::bcast_int(dft_plus_u);
36353643
Parallel_Common::bcast_bool(yukawa_potential);
3644+
Parallel_Common::bcast_double(uramping);
36363645
Parallel_Common::bcast_int(omc);
36373646
Parallel_Common::bcast_double(yukawa_lambda);
36383647
if (GlobalV::MY_RANK != 0)

source/module_io/input.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,7 @@ class Input
492492
int omc; ///< whether turn on occupation matrix control method or not
493493
bool yukawa_potential; ///< default:false
494494
double yukawa_lambda; ///< default:-1.0, which means we calculate lambda
495+
double uramping; ///< default:-1.0, which means we do not use U-Ramping method
495496

496497
//==========================================================
497498
// DFT+DMFT Xin Qu added on 2021-08

source/module_io/input_conv.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,7 @@ void Input_Conv::Convert(void)
413413
GlobalC::dftu.Yukawa = INPUT.yukawa_potential;
414414
GlobalC::dftu.omc = INPUT.omc;
415415
GlobalC::dftu.orbital_corr = INPUT.orbital_corr;
416+
GlobalC::dftu.uramping = INPUT.uramping;
416417
GlobalC::dftu.mixing_dftu = INPUT.mixing_dftu;
417418
if (INPUT.yukawa_potential && INPUT.hubbard_u == nullptr)
418419
{
@@ -422,6 +423,11 @@ void Input_Conv::Convert(void)
422423
INPUT.hubbard_u = new double[GlobalC::ucell.ntype];
423424
}
424425
GlobalC::dftu.U = INPUT.hubbard_u;
426+
GlobalC::dftu.U0 = std::vector<double>(INPUT.hubbard_u, INPUT.hubbard_u + GlobalC::ucell.ntype);
427+
if (INPUT.uramping > 0.01)
428+
{
429+
ModuleBase::GlobalFunc::ZEROS(GlobalC::dftu.U, GlobalC::ucell.ntype);
430+
}
425431
}
426432
GlobalV::onsite_radius = INPUT.onsite_radius;
427433
#endif

source/module_io/test/input_test_para.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,7 @@ TEST_F(InputParaTest, Bcast)
317317
EXPECT_EQ(INPUT.dft_plus_u, 0);
318318
EXPECT_FALSE(INPUT.yukawa_potential);
319319
EXPECT_DOUBLE_EQ(INPUT.yukawa_lambda, -1.0);
320+
EXPECT_DOUBLE_EQ(INPUT.uramping, -1.0);
320321
EXPECT_EQ(INPUT.omc, 0);
321322
EXPECT_FALSE(INPUT.dft_plus_dmft);
322323
EXPECT_FALSE(INPUT.rpa);

source/module_io/test/write_input_test.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -839,6 +839,7 @@ TEST_F(write_input, DFTU20)
839839
testing::HasSubstr(
840840
"dft_plus_u 0 #1/2:new/old DFT+U correction method; 0: standard DFT calcullation(default)"));
841841
EXPECT_THAT(output, testing::HasSubstr("yukawa_lambda -1 #default:0.0"));
842+
EXPECT_THAT(output, testing::HasSubstr("uramping -1 #increasing U values during SCF"));
842843
EXPECT_THAT(output, testing::HasSubstr("yukawa_potential 0 #default: false"));
843844
EXPECT_THAT(output, testing::HasSubstr("omc 0 #the mode of occupation matrix control"));
844845
EXPECT_THAT(output, testing::HasSubstr("hubbard_u 0 #Hubbard Coulomb interaction parameter U(ev)"));

source/module_io/write_input.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,7 @@ ModuleBase::GlobalFunc::OUTP(ofs, "out_bandgap", out_bandgap, "if true, print ou
454454
ModuleBase::GlobalFunc::OUTP(ofs, "dft_plus_u", dft_plus_u, "1/2:new/old DFT+U correction method; 0: standard DFT calcullation(default)");
455455
ModuleBase::GlobalFunc::OUTP(ofs, "yukawa_lambda", yukawa_lambda, "default:0.0");
456456
ModuleBase::GlobalFunc::OUTP(ofs, "yukawa_potential", yukawa_potential, "default: false");
457+
ModuleBase::GlobalFunc::OUTP(ofs, "uramping", uramping, "increasing U values during SCF");
457458
ModuleBase::GlobalFunc::OUTP(ofs, "omc", omc, "the mode of occupation matrix control");
458459
ModuleBase::GlobalFunc::OUTP(ofs, "onsite_radius", onsite_radius, "radius of the sphere for onsite projection (Bohr)");
459460
ofs << std::setw(20) << "hubbard_u ";
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
INPUT_PARAMETERS
2+
suffix autotest
3+
nbands 40
4+
5+
calculation scf
6+
ecutwfc 20
7+
scf_thr 1.0e-4
8+
scf_nmax 500
9+
out_chg 0
10+
11+
smearing_method gaussian
12+
smearing_sigma 0.01
13+
14+
cal_force 1
15+
cal_stress 1
16+
17+
mixing_type broyden
18+
mixing_beta 0.4
19+
mixing_restart 5e-3
20+
mixing_dmr 1
21+
mixing_ndim 15
22+
23+
ks_solver genelpa
24+
basis_type lcao
25+
gamma_only 0
26+
symmetry 0
27+
nspin 2
28+
29+
#Parameter DFT+U
30+
dft_plus_u 1
31+
orbital_corr 2 -1
32+
hubbard_u 5.0 0.0
33+
uramping 2.5
34+
pseudo_dir ../../PP_ORB
35+
orbital_dir ../../PP_ORB

0 commit comments

Comments
 (0)