|
1 | 1 | #include "cal_ldos.h" |
2 | 2 |
|
| 3 | +#include "cal_dos.h" |
3 | 4 | #include "cube_io.h" |
4 | 5 | #include "module_elecstate/module_dm/cal_dm_psi.h" |
5 | 6 | #include "module_hamilt_lcao/module_gint/temp_gint/gint_interface.h" |
|
8 | 9 |
|
9 | 10 | namespace ModuleIO |
10 | 11 | { |
11 | | -template <typename T> |
12 | | -void Cal_ldos<T>::cal_ldos_pw(const elecstate::ElecStatePW<std::complex<double>>* pelec, |
13 | | - const psi::Psi<std::complex<double>>& psi, |
14 | | - const Parallel_Grid& pgrid, |
15 | | - const UnitCell& ucell) |
16 | | -{ |
17 | | - for (int ie = 0; ie < PARAM.inp.stm_bias[2]; ie++) |
18 | | - { |
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); |
26 | | - |
27 | | - for (int ik = 0; ik < pelec->klist->get_nks(); ++ik) |
28 | | - { |
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++) |
34 | | - { |
35 | | - pelec->basis->recip2real(&psi(ib, 0), wfcr.data(), ik); |
36 | | - |
37 | | - const double eigenval = (pelec->ekb(ik, ib) - efermi) * ModuleBase::Ry_to_eV; |
38 | | - double weight = en > 0 ? pelec->klist->wk[ik] - pelec->wg(ik, ib) : pelec->wg(ik, ib); |
39 | | - weight /= ucell.omega; |
40 | | - |
41 | | - if (eigenval >= emin && eigenval <= emax) |
42 | | - { |
43 | | - for (int ir = 0; ir < pelec->basis->nrxx; ir++) |
44 | | - { |
45 | | - ldos[ir] += weight * norm(wfcr[ir]); |
46 | | - } |
47 | | - } |
48 | | - } |
49 | | - } |
50 | | - |
51 | | - std::stringstream fn; |
52 | | - fn << PARAM.globalv.global_out_dir << "LDOS_" << en << "eV" |
53 | | - << ".cube"; |
54 | | - |
55 | | - const int precision = PARAM.inp.out_ldos[1]; |
56 | | - ModuleIO::write_vdata_palgrid(pgrid, ldos.data(), 0, PARAM.inp.nspin, 0, fn.str(), 0, &ucell, precision, 0); |
57 | | - } |
58 | | -} |
59 | 12 |
|
60 | 13 | #ifdef __LCAO |
61 | 14 | template <typename T> |
@@ -147,4 +100,269 @@ void Cal_ldos<T>::cal_ldos_lcao(const elecstate::ElecStateLCAO<T>* pelec, |
147 | 100 |
|
148 | 101 | template class Cal_ldos<double>; // Gamma_only case |
149 | 102 | template class Cal_ldos<std::complex<double>>; // multi-k case |
150 | | -} // namespace ModuleIO |
| 103 | + |
| 104 | +// pw case |
| 105 | +void cal_ldos_pw(const elecstate::ElecStatePW<std::complex<double>>* pelec, |
| 106 | + const psi::Psi<std::complex<double>>& psi, |
| 107 | + const Parallel_Grid& pgrid, |
| 108 | + const UnitCell& ucell) |
| 109 | +{ |
| 110 | + if (PARAM.inp.out_ldos[0] == 1 || PARAM.inp.out_ldos[0] == 3) |
| 111 | + { |
| 112 | + ModuleIO::stm_mode_pw(pelec, psi, pgrid, ucell); |
| 113 | + } |
| 114 | + if (PARAM.inp.out_ldos[0] == 2 || PARAM.inp.out_ldos[0] == 3) |
| 115 | + { |
| 116 | + ModuleIO::ldos_mode_pw(pelec, psi, pgrid, ucell); |
| 117 | + } |
| 118 | +} |
| 119 | + |
| 120 | +void stm_mode_pw(const elecstate::ElecStatePW<std::complex<double>>* pelec, |
| 121 | + const psi::Psi<std::complex<double>>& psi, |
| 122 | + const Parallel_Grid& pgrid, |
| 123 | + const UnitCell& ucell) |
| 124 | +{ |
| 125 | + for (int ie = 0; ie < PARAM.inp.stm_bias[2]; ie++) |
| 126 | + { |
| 127 | + // energy range for ldos (efermi as reference) |
| 128 | + const double en = PARAM.inp.stm_bias[0] + ie * PARAM.inp.stm_bias[1]; |
| 129 | + const double emin = en < 0 ? en : 0; |
| 130 | + const double emax = en > 0 ? en : 0; |
| 131 | + |
| 132 | + std::vector<double> ldos(pelec->charge->nrxx); |
| 133 | + std::vector<std::complex<double>> wfcr(pelec->basis->nrxx); |
| 134 | + |
| 135 | + for (int ik = 0; ik < pelec->klist->get_nks(); ++ik) |
| 136 | + { |
| 137 | + psi.fix_k(ik); |
| 138 | + const double efermi = pelec->eferm.get_efval(pelec->klist->isk[ik]); |
| 139 | + const int nbands = psi.get_nbands(); |
| 140 | + |
| 141 | + for (int ib = 0; ib < nbands; ib++) |
| 142 | + { |
| 143 | + pelec->basis->recip2real(&psi(ib, 0), wfcr.data(), ik); |
| 144 | + |
| 145 | + const double eigenval = (pelec->ekb(ik, ib) - efermi) * ModuleBase::Ry_to_eV; |
| 146 | + double weight = en > 0 ? pelec->klist->wk[ik] - pelec->wg(ik, ib) : pelec->wg(ik, ib); |
| 147 | + weight /= ucell.omega; |
| 148 | + |
| 149 | + if (eigenval >= emin && eigenval <= emax) |
| 150 | + { |
| 151 | + for (int ir = 0; ir < pelec->basis->nrxx; ir++) |
| 152 | + { |
| 153 | + ldos[ir] += weight * norm(wfcr[ir]); |
| 154 | + } |
| 155 | + } |
| 156 | + } |
| 157 | + } |
| 158 | + |
| 159 | + std::stringstream fn; |
| 160 | + fn << PARAM.globalv.global_out_dir << "LDOS_" << en << "eV" |
| 161 | + << ".cube"; |
| 162 | + |
| 163 | + const int precision = PARAM.inp.out_ldos[1]; |
| 164 | + ModuleIO::write_vdata_palgrid(pgrid, ldos.data(), 0, PARAM.inp.nspin, 0, fn.str(), 0, &ucell, precision, 0); |
| 165 | + } |
| 166 | +} |
| 167 | + |
| 168 | +void ldos_mode_pw(const elecstate::ElecStatePW<std::complex<double>>* pelec, |
| 169 | + const psi::Psi<std::complex<double>>& psi, |
| 170 | + const Parallel_Grid& pgrid, |
| 171 | + const UnitCell& ucell) |
| 172 | +{ |
| 173 | + double emax = 0.0; |
| 174 | + double emin = 0.0; |
| 175 | + |
| 176 | + prepare_dos(GlobalV::ofs_running, |
| 177 | + pelec->eferm, |
| 178 | + pelec->ekb, |
| 179 | + pelec->klist->get_nks(), |
| 180 | + PARAM.inp.nbands, |
| 181 | + PARAM.inp.dos_edelta_ev, |
| 182 | + PARAM.inp.dos_scale, |
| 183 | + emax, |
| 184 | + emin); |
| 185 | + |
| 186 | + const int ndata = static_cast<int>((emax - emin) / PARAM.inp.dos_edelta_ev) + 1; |
| 187 | + const double sigma = sqrt(2.0) * PARAM.inp.dos_sigma; |
| 188 | + const double sigma2 = sigma * sigma; |
| 189 | + const double sigma_PI = sqrt(ModuleBase::PI) * sigma; |
| 190 | + |
| 191 | + std::vector<double> start = {PARAM.inp.ldos_line[0], PARAM.inp.ldos_line[1], PARAM.inp.ldos_line[2]}; |
| 192 | + std::vector<double> end = {PARAM.inp.ldos_line[3], PARAM.inp.ldos_line[4], PARAM.inp.ldos_line[5]}; |
| 193 | + const int npoints = PARAM.inp.ldos_line[6]; |
| 194 | + |
| 195 | + // calculate grid points |
| 196 | + std::vector<std::vector<int>> points(npoints, std::vector<int>(3, 0)); |
| 197 | + std::vector<std::vector<double>> shifts(npoints, std::vector<double>(3, 0)); |
| 198 | + get_grid_points(start, end, npoints, pgrid.nx, pgrid.ny, pgrid.nz, points, shifts); |
| 199 | + |
| 200 | + std::vector<std::vector<double>> ldos(npoints, std::vector<double>(ndata, 0)); |
| 201 | + |
| 202 | + // calculate ldos |
| 203 | + std::vector<double> tmp(pelec->charge->nrxx); |
| 204 | + std::vector<std::complex<double>> wfcr(pelec->basis->nrxx); |
| 205 | + for (int ik = 0; ik < pelec->klist->get_nks(); ++ik) |
| 206 | + { |
| 207 | + psi.fix_k(ik); |
| 208 | + const double efermi = pelec->eferm.get_efval(pelec->klist->isk[ik]); |
| 209 | + const int nbands = psi.get_nbands(); |
| 210 | + |
| 211 | + for (int ib = 0; ib < nbands; ib++) |
| 212 | + { |
| 213 | + pelec->basis->recip2real(&psi(ib, 0), wfcr.data(), ik); |
| 214 | + const double weight = pelec->klist->wk[ik] / ucell.omega; |
| 215 | + |
| 216 | + for (int ir = 0; ir < pelec->basis->nrxx; ir++) |
| 217 | + { |
| 218 | + tmp[ir] += weight * norm(wfcr[ir]); |
| 219 | + } |
| 220 | + |
| 221 | + std::vector<double> results(npoints, 0); |
| 222 | + trilinear_interpolate(points, shifts, pgrid, tmp, results); |
| 223 | + |
| 224 | + const double eigenval = pelec->ekb(ik, ib) * ModuleBase::Ry_to_eV; |
| 225 | + |
| 226 | + for (int ie = 0; ie < ndata; ++ie) |
| 227 | + { |
| 228 | + const double en = emin + ie * PARAM.inp.dos_edelta_ev; |
| 229 | + const double de = en - eigenval; |
| 230 | + const double de2 = de * de; |
| 231 | + const double gauss = exp(-de2 / sigma2) / sigma_PI; |
| 232 | + for (int ip = 0; ip < npoints; ++ip) |
| 233 | + { |
| 234 | + ldos[ip][ie] += results[ip] * gauss; |
| 235 | + } |
| 236 | + } |
| 237 | + } |
| 238 | + } |
| 239 | + |
| 240 | + std::ofstream ofs_ldos; |
| 241 | + std::stringstream fn; |
| 242 | + fn << PARAM.globalv.global_out_dir << "LDOS.txt"; |
| 243 | + if (GlobalV::MY_RANK == 0) |
| 244 | + { |
| 245 | + ofs_ldos.open(fn.str().c_str()); |
| 246 | + |
| 247 | + for (int ip = 0; ip < npoints; ++ip) |
| 248 | + { |
| 249 | + for (int ie = 0; ie < ndata; ++ie) |
| 250 | + { |
| 251 | + ofs_ldos << ldos[ip][ie] << " "; |
| 252 | + } |
| 253 | + ofs_ldos << std::endl; |
| 254 | + } |
| 255 | + ofs_ldos.close(); |
| 256 | + } |
| 257 | +} |
| 258 | + |
| 259 | +void get_grid_points(const std::vector<double>& start, |
| 260 | + const std::vector<double>& end, |
| 261 | + const int& npoints, |
| 262 | + const int& nx, |
| 263 | + const int& ny, |
| 264 | + const int& nz, |
| 265 | + std::vector<std::vector<int>>& points, |
| 266 | + std::vector<std::vector<double>>& shifts) |
| 267 | +{ |
| 268 | + std::vector<int> ndim = {nx, ny, nz}; |
| 269 | + auto grid_points = [](const std::vector<double>& coor, |
| 270 | + const std::vector<int>& ndim, |
| 271 | + std::vector<int>& points, |
| 272 | + std::vector<double>& shift) { |
| 273 | + for (int i = 0; i < 3; i++) |
| 274 | + { |
| 275 | + shift[i] = coor[i] * ndim[i]; |
| 276 | + while (shift[i] >= ndim[i]) |
| 277 | + { |
| 278 | + shift[i] -= ndim[i]; |
| 279 | + } |
| 280 | + while (shift[i] < 0) |
| 281 | + { |
| 282 | + shift[i] += ndim[i]; |
| 283 | + } |
| 284 | + points[i] = static_cast<int>(shift[i]); |
| 285 | + shift[i] -= points[i]; |
| 286 | + } |
| 287 | + }; |
| 288 | + |
| 289 | + if (npoints == 1) |
| 290 | + { |
| 291 | + grid_points(start, ndim, points[0], shifts[0]); |
| 292 | + } |
| 293 | + else |
| 294 | + { |
| 295 | + std::vector<double> delta = {end[0] - start[0], end[1] - start[1], end[2] - start[2]}; |
| 296 | + for (int i = 0; i < npoints; i++) |
| 297 | + { |
| 298 | + const double ratio = static_cast<double>(i) / (npoints - 1); |
| 299 | + std::vector<double> current = {0, 0, 0}; |
| 300 | + for (int j = 0; j < 3; j++) |
| 301 | + { |
| 302 | + current[j] = start[j] + ratio * delta[j]; |
| 303 | + } |
| 304 | + grid_points(current, ndim, points[i], shifts[i]); |
| 305 | + } |
| 306 | + } |
| 307 | +} |
| 308 | + |
| 309 | +void trilinear_interpolate(const std::vector<std::vector<int>>& points, |
| 310 | + const std::vector<std::vector<double>>& shifts, |
| 311 | + const Parallel_Grid& pgrid, |
| 312 | + const std::vector<double>& data, |
| 313 | + std::vector<double>& results) |
| 314 | +{ |
| 315 | + const int nx = pgrid.nx; |
| 316 | + const int ny = pgrid.ny; |
| 317 | + const int nz = pgrid.nz; |
| 318 | + const int nyz = ny * nz; |
| 319 | + const int nxyz = nx * ny * nz; |
| 320 | + |
| 321 | + // reduce |
| 322 | + std::vector<double> data_full(nxyz); |
| 323 | +#ifdef __MPI |
| 324 | + if (GlobalV::MY_POOL == 0 && GlobalV::MY_BNDGROUP == 0) |
| 325 | + { |
| 326 | + pgrid.reduce(data_full.data(), data.data()); |
| 327 | + } |
| 328 | + MPI_Barrier(MPI_COMM_WORLD); |
| 329 | +#else |
| 330 | + std::memcpy(data_full.data(), data.data(), nxyz * sizeof(double)); |
| 331 | +#endif |
| 332 | + |
| 333 | + auto grid_points = [&data_full, &nyz, &nz](const int& ix, const int& iy, const int& iz) { |
| 334 | + return data_full[ix * nyz + iy * nz + iz]; |
| 335 | + }; |
| 336 | + |
| 337 | + // trilinear interpolation |
| 338 | + const int npoints = points.size(); |
| 339 | + results.resize(npoints, 0.0); |
| 340 | + if (GlobalV::MY_RANK == 0) |
| 341 | + { |
| 342 | + for (int l = 0; l < npoints; ++l) |
| 343 | + { |
| 344 | + for (int i = 0; i < 2; ++i) |
| 345 | + { |
| 346 | + double weight = (i * shifts[l][0] + (1 - i) * (1 - shifts[l][0])); |
| 347 | + for (int j = 0; j < 2; ++j) |
| 348 | + { |
| 349 | + weight *= (j * shifts[l][1] + (1 - j) * (1 - shifts[l][1])); |
| 350 | + for (int k = 0; k < 2; ++k) |
| 351 | + { |
| 352 | + weight *= (k * shifts[l][2] + (1 - k) * (1 - shifts[l][2])); |
| 353 | + |
| 354 | + const int ix = points[l][0] + i; |
| 355 | + const int iy = points[l][1] + j; |
| 356 | + const int iz = points[l][2] + k; |
| 357 | + results[l] += weight * grid_points(ix, iy, iz); |
| 358 | + } |
| 359 | + } |
| 360 | + } |
| 361 | + } |
| 362 | + } |
| 363 | +#ifdef __MPI |
| 364 | + MPI_Bcast(results.data(), npoints, MPI_DOUBLE, 0, MPI_COMM_WORLD); |
| 365 | +#endif |
| 366 | +} |
| 367 | + |
| 368 | +} // namespace ModuleIO |
0 commit comments