@@ -38,9 +38,9 @@ void Charge_Mixing::set_mixing(const std::string& mixing_mode_in,
3838 GlobalV::ofs_running<<" mixing_beta: " << this ->mixing_beta <<std::endl;
3939 GlobalV::ofs_running<<" mixing_gg0: " << this ->mixing_gg0 <<std::endl;
4040 GlobalV::ofs_running<<" mixing_gg0_min: " << GlobalV::MIXING_GG0_MIN <<std::endl;
41- if (GlobalV::NSPIN==2 )
41+ if (GlobalV::NSPIN==2 || GlobalV::NSPIN== 4 )
4242 {
43- GlobalV::ofs_running<<" mixing_beta_mag: " << GlobalV::MIXING_BETA_MAG <<std::endl;
43+ GlobalV::ofs_running<<" mixing_beta_mag: " << this -> mixing_beta_mag <<std::endl;
4444 GlobalV::ofs_running<<" mixing_gg0_mag: " << GlobalV::MIXING_GG0_MAG <<std::endl;
4545 }
4646 GlobalV::ofs_running<<" mixing_ndim: " << this ->mixing_ndim <<std::endl;
@@ -271,7 +271,6 @@ void Charge_Mixing::mix_rho_recip(Charge* chr)
271271
272272void Charge_Mixing::mix_rho_recip_new (Charge* chr)
273273{
274- // not support nspin=4 yet 2023/11/17
275274 // old support see mix_rho_recip()
276275 if (GlobalV::double_grid)
277276 {
@@ -281,7 +280,7 @@ void Charge_Mixing::mix_rho_recip_new(Charge* chr)
281280 std::complex <double >* rhog_in = nullptr ;
282281 std::complex <double >* rhog_out = nullptr ;
283282
284- if (GlobalV::NSPIN == 1 || GlobalV::NSPIN == 4 )
283+ if (GlobalV::NSPIN == 1 )
285284 {
286285 rhog_in = chr->rhog_save [0 ];
287286 rhog_out = chr->rhog [0 ];
@@ -316,8 +315,38 @@ void Charge_Mixing::mix_rho_recip_new(Charge* chr)
316315 };
317316 this ->mixing ->push_data (this ->rho_mdata , rhog_in, rhog_out, screen, twobeta_mix, true );
318317 }
318+ else if (GlobalV::NSPIN == 4 )
319+ {
320+ // I do not merge this part with nspin=2 because the method of nspin=2 is almost done,
321+ // while nspin=4 is not finished yet. I will try more methods for nspin=4 in the future.
322+ rhog_in = chr->rhog_save [0 ];
323+ rhog_out = chr->rhog [0 ];
324+ const int npw = this ->rhopw ->npw ;
325+ auto screen = std::bind (&Charge_Mixing::Kerker_screen_recip_new, this , std::placeholders::_1); // use old one
326+ auto twobeta_mix
327+ = [this , npw](std::complex <double >* out, const std::complex <double >* in, const std::complex <double >* sres) {
328+ #ifdef _OPENMP
329+ #pragma omp parallel for schedule(static, 256)
330+ #endif
331+ for (int i = 0 ; i < npw; ++i)
332+ {
333+ out[i] = in[i] + this ->mixing_beta * sres[i];
334+ }
335+ // magnetism, mx, my, mz
336+ #ifdef _OPENMP
337+ #pragma omp parallel for schedule(static, 256)
338+ #endif
339+ for (int i = npw; i < 4 * npw; ++i)
340+ {
341+ out[i] = in[i] + this ->mixing_beta_mag * sres[i];
342+ }
343+ };
344+ this ->mixing ->push_data (this ->rho_mdata , rhog_in, rhog_out, screen, twobeta_mix, true );
345+ }
319346
320347 // can choose inner_product_recip_new1 or inner_product_recip_new2
348+ // inner_product_recip_new1 is a simple sum
349+ // inner_product_recip_new2 is a hartree-like sum, unit is Ry
321350 auto inner_product_new
322351 = std::bind (&Charge_Mixing::inner_product_recip_new2, this , std::placeholders::_1, std::placeholders::_2);
323352 auto inner_product_old
@@ -326,7 +355,7 @@ void Charge_Mixing::mix_rho_recip_new(Charge* chr)
326355 {
327356 this ->mixing ->cal_coef (this ->rho_mdata , inner_product_new);
328357 }
329- else if (GlobalV::NSPIN == 1 || GlobalV::NSPIN == 4 )
358+ else if (GlobalV::NSPIN == 1 || GlobalV::NSPIN == 4 ) // nspin=4 can use old inner_product
330359 {
331360 this ->mixing ->cal_coef (this ->rho_mdata , inner_product_old);
332361 }
@@ -344,6 +373,8 @@ void Charge_Mixing::mix_rho_recip_new(Charge* chr)
344373 {
345374 chr->rhopw ->recip2real (chr->rhog [is], chr->rho [is]);
346375 }
376+
377+ // renormalize rho in R-space would induce a error in K-space
347378 // chr->renormalize_rho();
348379
349380 // For kinetic energy density
@@ -400,7 +431,7 @@ void Charge_Mixing::mix_rho_real(Charge* chr)
400431{
401432 double * rhor_in;
402433 double * rhor_out;
403- if (GlobalV::NSPIN == 1 || GlobalV::NSPIN == 4 )
434+ if (GlobalV::NSPIN == 1 )
404435 {
405436 rhor_in = chr->rho_save [0 ];
406437 rhor_out = chr->rho [0 ];
@@ -420,19 +451,47 @@ void Charge_Mixing::mix_rho_real(Charge* chr)
420451#ifdef _OPENMP
421452#pragma omp parallel for schedule(static, 256)
422453#endif
423- for (int i = 0 ; i < nrxx; ++i)
424- {
425- out[i] = in[i] + this ->mixing_beta * sres[i];
426- }
454+ for (int i = 0 ; i < nrxx; ++i)
455+ {
456+ out[i] = in[i] + this ->mixing_beta * sres[i];
457+ }
427458 // magnetism
428459#ifdef _OPENMP
429460#pragma omp parallel for schedule(static, 256)
430461#endif
431- for (int i = nrxx; i < 2 * nrxx; ++i)
432- {
433- out[i] = in[i] + this ->mixing_beta_mag * sres[i];
434- }
435- };
462+ for (int i = nrxx; i < 2 * nrxx; ++i)
463+ {
464+ out[i] = in[i] + this ->mixing_beta_mag * sres[i];
465+ }
466+ };
467+ this ->mixing ->push_data (this ->rho_mdata , rhor_in, rhor_out, screen, twobeta_mix, true );
468+ }
469+ else if (GlobalV::NSPIN == 4 )
470+ {
471+ // I do not merge this part with nspin=2 because the method of nspin=2 is almost done,
472+ // while nspin=4 is not finished yet. I will try more methods for nspin=4 in the future.
473+ rhor_in = chr->rho_save [0 ];
474+ rhor_out = chr->rho [0 ];
475+ const int nrxx = this ->rhopw ->nrxx ;
476+ auto screen = std::bind (&Charge_Mixing::Kerker_screen_real, this , std::placeholders::_1);
477+ auto twobeta_mix
478+ = [this , nrxx](double * out, const double * in, const double * sres) {
479+ #ifdef _OPENMP
480+ #pragma omp parallel for schedule(static, 256)
481+ #endif
482+ for (int i = 0 ; i < nrxx; ++i)
483+ {
484+ out[i] = in[i] + this ->mixing_beta * sres[i];
485+ }
486+ // magnetism, mx, my, mz
487+ #ifdef _OPENMP
488+ #pragma omp parallel for schedule(static, 256)
489+ #endif
490+ for (int i = nrxx; i < 4 * nrxx; ++i)
491+ {
492+ out[i] = in[i] + this ->mixing_beta_mag * sres[i];
493+ }
494+ };
436495 this ->mixing ->push_data (this ->rho_mdata , rhor_in, rhor_out, screen, twobeta_mix, true );
437496 }
438497
@@ -642,14 +701,18 @@ void Charge_Mixing::Kerker_screen_recip_new(std::complex<double>* drhog)
642701 for (int is = 0 ; is < GlobalV::NSPIN; ++is)
643702 {
644703 // new mixing method only support nspin=2 not nspin=4
645- if (is == 1 && GlobalV::NSPIN == 2 )
704+ if (is >= 1 )
646705 {
647706 if (GlobalV::MIXING_GG0_MAG <= 0.0001 || GlobalV::MIXING_BETA_MAG <= 0.1 )
648707 {
649- for (int ig = 0 ; ig < this ->rhopw ->npw ; ig++)
650- {
651- drhog[is * this ->rhopw ->npw + ig] *= 1 ;
652- }
708+ #ifdef __DEBUG
709+ assert (is == 1 ); // make sure break works
710+ #endif
711+ double is_mag = GlobalV::NSPIN - 1 ;
712+ // for (int ig = 0; ig < this->rhopw->npw * is_mag; ig++)
713+ // {
714+ // drhog[is * this->rhopw->npw + ig] *= 1;
715+ // }
653716 break ;
654717 }
655718 fac = GlobalV::MIXING_GG0_MAG;
@@ -692,13 +755,17 @@ void Charge_Mixing::Kerker_screen_real(double* drhor)
692755 for (int is = 0 ; is < GlobalV::NSPIN; is++)
693756 {
694757
695- if (is == 1 && GlobalV::NSPIN == 2 )
758+ if (is >= 1 )
696759 {
697760 if (GlobalV::MIXING_GG0_MAG <= 0.0001 || GlobalV::MIXING_BETA_MAG <= 0.1 )
698761 {
699- for (int ig = 0 ; ig < this ->rhopw ->npw ; ig++)
762+ #ifdef __DEBUG
763+ assert (is == 1 ); // make sure break works
764+ #endif
765+ double is_mag = GlobalV::NSPIN - 1 ;
766+ for (int ig = 0 ; ig < this ->rhopw ->npw * is_mag; ig++)
700767 {
701- drhog[is * this ->rhopw ->npw + ig] * = 0 ;
768+ drhog[is * this ->rhopw ->npw + ig] = 0 ;
702769 }
703770 break ;
704771 }
0 commit comments