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)

0 commit comments

Comments
 (0)