11#include " cal_ldos.h"
2+
23#include " cube_io.h"
3- #include " module_base/blas_connector .h"
4- #include " module_base/scalapack_connector .h"
4+ #include " module_elecstate/module_dm/cal_dm_psi .h"
5+ #include " module_hamilt_lcao/module_gint/temp_gint/gint_interface .h"
56
67#include < type_traits>
78
@@ -13,40 +14,43 @@ void Cal_ldos<T>::cal_ldos_pw(const elecstate::ElecStatePW<std::complex<double>>
1314 const Parallel_Grid& pgrid,
1415 const UnitCell& ucell)
1516{
16- // energy range for ldos (efermi as reference)
17- const double emin = PARAM.inp .stm_bias < 0 ? PARAM.inp .stm_bias : 0 ;
18- const double emax = PARAM.inp .stm_bias > 0 ? PARAM.inp .stm_bias : 0 ;
19-
20- std::vector<double > ldos (pelec->charge ->nrxx );
21- std::vector<std::complex <double >> wfcr (pelec->basis ->nrxx );
22-
23- for (int ik = 0 ; ik < pelec->klist ->get_nks (); ++ik)
17+ for (int ie = 0 ; ie < PARAM.inp .stm_bias [2 ]; ie++)
2418 {
25- psi.fix_k (ik);
26- const double efermi = pelec->eferm .get_efval (pelec->klist ->isk [ik]);
27- int nbands = psi.get_nbands ();
19+ // energy range for ldos (efermi as reference)
20+ const double en = PARAM.inp .stm_bias [0 ] + ie * PARAM.inp .stm_bias [1 ];
21+ const double emin = en < 0 ? en : 0 ;
22+ const double emax = en > 0 ? en : 0 ;
23+
24+ std::vector<double > ldos (pelec->charge ->nrxx );
25+ std::vector<std::complex <double >> wfcr (pelec->basis ->nrxx );
2826
29- for (int ib = 0 ; ib < nbands; ib++ )
27+ for (int ik = 0 ; ik < pelec-> klist -> get_nks (); ++ik )
3028 {
31- pelec->basis ->recip2real (&psi (ib, 0 ), wfcr.data (), ik);
32- const double eigenval = (pelec->ekb (ik, ib) - efermi) * ModuleBase::Ry_to_eV;
33- if (eigenval >= emin && eigenval <= emax)
29+ psi.fix_k (ik);
30+ const double efermi = pelec->eferm .get_efval (pelec->klist ->isk [ik]);
31+ int nbands = psi.get_nbands ();
32+
33+ for (int ib = 0 ; ib < nbands; ib++)
3434 {
35- for (int ir = 0 ; ir < pelec->basis ->nrxx ; ir++)
36- {
37- ldos[ir] += pelec->klist ->wk [ik] * norm (wfcr[ir]);
38- }
35+ pelec->basis ->recip2real (&psi (ib, 0 ), wfcr.data (), ik);
36+ const double eigenval = (pelec->ekb (ik, ib) - efermi) * ModuleBase::Ry_to_eV;
37+ if (eigenval >= emin && eigenval <= emax)
38+ {
39+ for (int ir = 0 ; ir < pelec->basis ->nrxx ; ir++)
40+ {
41+ ldos[ir] += pelec->klist ->wk [ik] * norm (wfcr[ir]);
42+ }
43+ }
3944 }
4045 }
41- }
4246
43- std::stringstream fn;
44- fn << PARAM.globalv .global_out_dir
45- << " LDOS_" << PARAM.inp .stm_bias << " eV"
46- << " .cube" ;
47+ std::stringstream fn;
48+ fn << PARAM.globalv .global_out_dir << " LDOS_" << en << " eV"
49+ << " .cube" ;
4750
48- const int precision = PARAM.inp .out_ldos [1 ];
49- ModuleIO::write_vdata_palgrid (pgrid, ldos.data (), 0 , PARAM.inp .nspin , 0 , fn.str (), 0 , &ucell, precision, 0 );
51+ const int precision = PARAM.inp .out_ldos [1 ];
52+ ModuleIO::write_vdata_palgrid (pgrid, ldos.data (), 0 , PARAM.inp .nspin , 0 , fn.str (), 0 , &ucell, precision, 0 );
53+ }
5054}
5155
5256#ifdef __LCAO
@@ -56,75 +60,83 @@ void Cal_ldos<T>::cal_ldos_lcao(const elecstate::ElecStateLCAO<T>* pelec,
5660 const Parallel_Grid& pgrid,
5761 const UnitCell& ucell)
5862{
59- // energy range for ldos (efermi as reference)
60- const double emin = PARAM.inp .stm_bias < 0 ? PARAM.inp .stm_bias : 0 ;
61- const double emax = PARAM.inp .stm_bias > 0 ? PARAM.inp .stm_bias : 0 ;
63+ for (int ie = 0 ; ie < PARAM.inp .stm_bias [2 ]; ie++)
64+ {
65+ // energy range for ldos (efermi as reference)
66+ const double en = PARAM.inp .stm_bias [0 ] + ie * PARAM.inp .stm_bias [1 ];
67+ const double emin = en < 0 ? en : 0 ;
68+ const double emax = en > 0 ? en : 0 ;
69+
70+ // calculate weight (for bands not in the range, weight is zero)
71+ ModuleBase::matrix weight (pelec->ekb .nr , pelec->ekb .nc );
72+ for (int ik = 0 ; ik < pelec->ekb .nr ; ++ik)
73+ {
74+ const double efermi = pelec->eferm .get_efval (pelec->klist ->isk [ik]);
6275
63- // calulate dm-like
64- const int nbands_local = psi.get_nbands ();
65- const int nbasis_local = psi.get_nbasis ();
76+ for (int ib = 0 ; ib < pelec->ekb .nc ; ib++)
77+ {
78+ const double eigenval = (pelec->ekb (ik, ib) - efermi) * ModuleBase::Ry_to_eV;
79+ if (eigenval >= emin && eigenval <= emax)
80+ {
81+ weight (ik, ib) = pelec->klist ->wk [ik];
82+ }
83+ }
84+ }
6685
67- // psi.T * wk * psi.conj()
68- // result[ik](iw1,iw2) = \sum_{ib} psi[ik](ib,iw1).T * wk(k) * psi[ik](ib,iw2).conj()
69- for (int ik = 0 ; ik < psi.get_nk (); ++ik)
70- {
71- psi.fix_k (ik);
72- const double efermi = pelec->eferm .get_efval (pelec->klist ->isk [ik]);
73-
74- // T* dmk_pointer = DM.get_DMK_pointer(ik);
75-
76- psi::Psi<T> wk_psi (1 , psi.get_nbands (), psi.get_nbasis (), psi.get_nbasis (), true );
77- const T* ppsi = psi.get_pointer ();
78- T* pwk_psi = wk_psi.get_pointer ();
79-
80- // #ifdef _OPENMP
81- // #pragma omp parallel for schedule(static, 1024)
82- // #endif
83- // for (int i = 0; i < wk_psi.size(); ++i)
84- // {
85- // pwk_psi[i] = my_conj(ppsi[i]);
86- // }
87-
88- // int ib_global = 0;
89- // for (int ib_local = 0; ib_local < nbands_local; ++ib_local)
90- // {
91- // while (ib_local != ParaV->global2local_col(ib_global))
92- // {
93- // ++ib_global;
94- // if (ib_global >= wg.nc)
95- // {
96- // ModuleBase::WARNING_QUIT("cal_ldos", "please check global2local_col!");
97- // }
98- // }
99-
100- // const double eigenval = (pelec->ekb(ik, ib_global) - efermi) * ModuleBase::Ry_to_eV;
101- // if (eigenval >= emin && eigenval <= emax)
102- // {
103- // for (int ir = 0; ir < pelec->basis->nrxx; ir++)
104- // ldos[ir] += pelec->klist->wk[ik] * norm(wfcr[ir]);
105- // }
106-
107- // double* wg_wfc_pointer = &(wk_psi(0, ib_local, 0));
108- // BlasConnector::scal(nbasis_local, pelec->klist->wk[ik], wg_wfc_pointer, 1);
109- // }
110-
111- // // C++: dm(iw1,iw2) = psi(ib,iw1).T * wk_psi(ib,iw2)
112- // #ifdef __MPI
113- // psiMulPsiMpi(wk_psi, psi, dmk_pointer, ParaV->desc_wfc, ParaV->desc);
114- // #else
115- // psiMulPsi(wk_psi, psi, dmk_pointer);
116- // #endif
117- }
118- }
86+ // calculate dm-like for ldos
87+ const int nspin_dm = PARAM.inp .nspin == 2 ? 2 : 1 ;
88+ elecstate::DensityMatrix<T, double > dm_ldos (pelec->DM ->get_paraV_pointer (),
89+ nspin_dm,
90+ pelec->klist ->kvec_d ,
91+ pelec->klist ->get_nks () / nspin_dm);
92+
93+ elecstate::cal_dm_psi (pelec->DM ->get_paraV_pointer (), weight, psi, dm_ldos);
94+ dm_ldos.init_DMR (*(pelec->DM ->get_DMR_pointer (1 )));
95+ dm_ldos.cal_DMR ();
96+
97+ // allocate ldos space
98+ std::vector<double > ldos_space (PARAM.inp .nspin * pelec->charge ->nrxx );
99+ double ** ldos = new double *[PARAM.inp .nspin ];
100+ for (int is = 0 ; is < PARAM.inp .nspin ; ++is)
101+ {
102+ ldos[is] = &ldos_space[is * pelec->charge ->nrxx ];
103+ }
119104
120- double my_conj (double x)
121- {
122- return x;
123- }
105+ // calculate ldos
106+ #ifndef __NEW_GINT
107+ ModuleBase::WARNING_QUIT (" Cal_ldos::dm2ldos" ,
108+ " do not support old grid integral, please recompile with __NEW_GINT" );
109+ #else
110+ ModuleGint::cal_gint_rho (dm_ldos.get_DMR_vector (), PARAM.inp .nspin , ldos);
111+ #endif
124112
125- std::complex <double > my_conj (const std::complex <double >& z)
126- {
127- return {z.real (), -z.imag ()};
113+ // I'm not sure whether ldos should be output for each spin or not
114+ // ldos[0] += ldos[1] for nspin_dm == 2
115+ if (nspin_dm == 2 )
116+ {
117+ BlasConnector::axpy (pelec->charge ->nrxx , 1.0 , ldos[1 ], 1 , ldos[0 ], 1 );
118+ }
119+
120+ // write ldos to cube file
121+ std::stringstream fn;
122+ fn << PARAM.globalv .global_out_dir << " LDOS_" << en << " eV"
123+ << " .cube" ;
124+
125+ const int precision = PARAM.inp .out_ldos [1 ];
126+ ModuleIO::write_vdata_palgrid (pgrid,
127+ ldos_space.data (),
128+ 0 ,
129+ PARAM.inp .nspin ,
130+ 0 ,
131+ fn.str (),
132+ 0 ,
133+ &ucell,
134+ precision,
135+ 0 );
136+
137+ // free memory
138+ delete[] ldos;
139+ }
128140}
129141
130142#endif
0 commit comments