ABACUS develop
Atomic-orbital Based Ab-initio Computation at UStc
Loading...
Searching...
No Matches
get_pchg_pw.h
Go to the documentation of this file.
1#ifndef GET_PCHG_PW_H
2#define GET_PCHG_PW_H
3
4#include "cube_io.h"
5
6namespace ModuleIO
7{
8template <typename Device>
9void get_pchg_pw(const std::vector<int>& out_pchg,
10 const int nbands,
11 const int nspin,
12 const int nxyz,
13 const int chr_ngmc,
14 UnitCell* ucell,
15 const psi::Psi<std::complex<double>, Device>* kspw_psi,
16 const ModulePW::PW_Basis* pw_rhod,
17 const ModulePW::PW_Basis_K* pw_wfc,
18 const Device* ctx,
19 const Parallel_Grid& pgrid,
20 const std::string& global_out_dir,
21 const bool if_separate_k,
22 const K_Vectors& kv,
23 const int kpar,
24 const int my_pool,
25 const Charge* chr) // Charge class is needed for the charge density reduce
26{
27 // Get necessary parameters from kv
28 const int nks = kv.get_nks(); // current process pool k-point count
29 const int nkstot = kv.get_nkstot(); // total k-point count
30
31 // Loop over k-parallelism
32 for (int ip = 0; ip < kpar; ++ip)
33 {
34 if (my_pool != ip)
35 {
36 continue;
37 }
38
39 // bands_picked is a vector of 0s and 1s, where 1 means the band is picked to output
40 std::vector<int> bands_picked(nbands, 0);
41
42 // Check if length of out_pchg is valid
43 if (static_cast<int>(out_pchg.size()) > nbands)
44 {
45 ModuleBase::WARNING_QUIT("ModuleIO::get_pchg_pw",
46 "The number of bands specified by `out_pchg` in the "
47 "INPUT file exceeds `nbands`!");
48 }
49
50 // Check if all elements in bands_picked are 0 or 1
51 for (int value: out_pchg)
52 {
53 if (value != 0 && value != 1)
54 {
55 ModuleBase::WARNING_QUIT("ModuleIO::get_pchg_pw",
56 "The elements of `out_pchg` must be either 0 or 1. "
57 "Invalid values found!");
58 }
59 }
60
61 // Fill bands_picked with values from out_pchg
62 // Remaining bands are already set to 0
63 int length = std::min(static_cast<int>(out_pchg.size()), nbands);
64 for (int i = 0; i < length; ++i)
65 {
66 // out_pchg rely on function parse_expression
67 bands_picked[i] = static_cast<int>(out_pchg[i]);
68 }
69
70 // Allocate host memory
71 std::vector<std::complex<double>> wfcr(nxyz);
72 std::vector<std::vector<double>> rho_band(nspin, std::vector<double>(nxyz));
73
74 // Allocate device memory
75 std::complex<double>* wfcr_device = nullptr;
76 if (!std::is_same<Device, base_device::DEVICE_CPU>::value)
77 {
79 }
80
81 for (int ib = 0; ib < nbands; ++ib)
82 {
83 // Skip the loop iteration if bands_picked[ib] is 0
84 if (!bands_picked[ib])
85 {
86 continue;
87 }
88
89 for (int is = 0; is < nspin; ++is)
90 {
91 std::fill(rho_band[is].begin(), rho_band[is].end(), 0.0);
92 }
93
94 if (if_separate_k)
95 {
96 for (int ik = 0; ik < nks; ++ik)
97 {
98 const int ikstot = kv.ik2iktot[ik]; // global k-point index
99 const int spin_index = kv.isk[ik]; // spin index
100 const int k_number = ikstot % (nkstot / nspin) + 1; // k-point number, starting from 1
101
102 kspw_psi->fix_k(ik);
103
104 // FFT on device and copy result back to host
105 if (std::is_same<Device, base_device::DEVICE_CPU>::value)
106 {
107 pw_wfc->recip_to_real(ctx, &kspw_psi[0](ib, 0), wfcr.data(), ik);
108 }
109 else
110 {
111 pw_wfc->recip_to_real(ctx, &kspw_psi[0](ib, 0), wfcr_device, ik);
112
114 base_device::DEVICE_CPU,
115 Device>()(wfcr.data(), wfcr_device, nxyz);
116 }
117
118 // To ensure the normalization of charge density in multi-k calculation (if if_separate_k is true)
119 double wg_sum_k = 0.0;
120 if (nspin == 1)
121 {
122 wg_sum_k = 2.0;
123 }
124 else if (nspin == 2)
125 {
126 wg_sum_k = 1.0;
127 }
128 else
129 {
130 ModuleBase::WARNING_QUIT("ModuleIO::get_pchg_pw",
131 "Real space partial charge output currently do not support "
132 "noncollinear polarized calculation (nspin = 4)!");
133 }
134
135 double w1 = static_cast<double>(wg_sum_k / ucell->omega);
136
137 for (int i = 0; i < nxyz; ++i)
138 {
139 rho_band[spin_index][i] = std::norm(wfcr[i]) * w1;
140 }
141
142 std::stringstream ssc;
143 ssc << global_out_dir << "pchgi" << ib + 1 << "s" << spin_index + 1 << "k" << k_number << ".cube";
144
146 rho_band[spin_index].data(),
147 spin_index,
148 nspin,
149 0,
150 ssc.str(),
151 0.0,
152 ucell,
153 11,
154 1,
155 true); // reduce_all_pool is true
156 }
157 }
158 else
159 {
160 for (int ik = 0; ik < nks; ++ik)
161 {
162 const int ikstot = kv.ik2iktot[ik]; // global k-point index
163 const int spin_index = kv.isk[ik]; // spin index
164 const int k_number = ikstot % (nkstot / nspin) + 1; // k-point number, starting from 1
165
166 kspw_psi->fix_k(ik);
167
168 // FFT on device and copy result back to host
169 if (std::is_same<Device, base_device::DEVICE_CPU>::value)
170 {
171 pw_wfc->recip_to_real(ctx, &kspw_psi[0](ib, 0), wfcr.data(), ik);
172 }
173 else
174 {
175 pw_wfc->recip_to_real(ctx, &kspw_psi[0](ib, 0), wfcr_device, ik);
176
178 base_device::DEVICE_CPU,
179 Device>()(wfcr.data(), wfcr_device, nxyz);
180 }
181
182 double w1 = static_cast<double>(kv.wk[ik] / ucell->omega);
183
184 for (int i = 0; i < nxyz; ++i)
185 {
186 rho_band[spin_index][i] += std::norm(wfcr[i]) * w1;
187 }
188 }
189
190#ifdef __MPI
191 // Reduce the charge density across all pools if kpar > 1
192 if (kpar > 1 && chr != nullptr)
193 {
194 for (int is = 0; is < nspin; ++is)
195 {
196 chr->reduce_diff_pools(rho_band[is].data());
197 }
198 }
199#endif
200
201 // Symmetrize the charge density, otherwise the results are incorrect if the symmetry is on
202 // std::cout << " Symmetrizing band-decomposed charge density..." << std::endl;
203 Symmetry_rho srho;
204 for (int is = 0; is < nspin; ++is)
205 {
206 // Use vector instead of raw pointers
207 std::vector<double*> rho_save_pointers(nspin);
208 for (int s = 0; s < nspin; ++s)
209 {
210 rho_save_pointers[s] = rho_band[s].data();
211 }
212
213 std::vector<std::vector<std::complex<double>>> rhog(nspin,
214 std::vector<std::complex<double>>(chr_ngmc));
215
216 // Convert vector of vectors to vector of pointers
217 std::vector<std::complex<double>*> rhog_pointers(nspin);
218 for (int s = 0; s < nspin; ++s)
219 {
220 rhog_pointers[s] = rhog[s].data();
221 }
222
223 srho.begin(is,
224 rho_save_pointers.data(),
225 rhog_pointers.data(),
226 chr_ngmc,
227 nullptr,
228 pw_rhod,
229 ucell->symm);
230 }
231
232 for (int is = 0; is < nspin; ++is)
233 {
234 std::stringstream ssc;
235 ssc << global_out_dir << "pchgi" << ib + 1 << "s" << is + 1 << ".cube";
236
237 ModuleIO::write_vdata_palgrid(pgrid, rho_band[is].data(), is, nspin, 0, ssc.str(), 0.0, ucell);
238 }
239 } // else if_separate_k is false
240 } // end of ib loop over nbands
241 } // end of ip loop over kpar
242} // get_pchg_pw
243} // namespace ModuleIO
244
245#endif // GET_PCHG_PW_H
Definition charge.h:20
void reduce_diff_pools(double *array_rho) const
Reduce among different pools If NPROC_IN_POOLs are all the same, use GlobalV::KP_WORLD else,...
Definition charge_mpi.cpp:27
Definition klist.h:13
int get_nks() const
Definition klist.h:68
std::vector< int > ik2iktot
[nks] map ik to the global index of k points
Definition klist.h:128
std::vector< int > isk
ngk, number of plane waves for each k point
Definition klist.h:21
int get_nkstot() const
Definition klist.h:73
std::vector< double > wk
Direct coordinates of k points.
Definition klist.h:18
Special pw_basis class. It includes different k-points.
Definition pw_basis_k.h:57
void recip_to_real(const Device *ctx, const std::complex< FPTYPE > *in, std::complex< FPTYPE > *out, const int ik, const bool add=false, const FPTYPE factor=1.0) const
Definition xc3_mock.h:94
A class which can convert a function of "r" to the corresponding linear superposition of plane waves ...
Definition pw_basis.h:56
Definition parallel_grid.h:8
Definition symmetry_rho.h:9
void begin(const int &spin_now, const Charge &CHR, const ModulePW::PW_Basis *pw, ModuleSymmetry::Symmetry &symm) const
Definition symmetry_rho.cpp:13
Definition unitcell.h:16
ModuleSymmetry::Symmetry symm
Definition unitcell.h:55
double & omega
Definition unitcell.h:32
Definition psi.h:37
void WARNING_QUIT(const std::string &, const std::string &)
Combine the functions of WARNING and QUIT.
Definition test_delley.cpp:14
This class has two functions: restart psi from the previous calculation, and write psi to the disk.
Definition cal_dos.h:9
void get_pchg_pw(const std::vector< int > &out_pchg, const int nbands, const int nspin, const int nxyz, const int chr_ngmc, UnitCell *ucell, const psi::Psi< std::complex< double >, Device > *kspw_psi, const ModulePW::PW_Basis *pw_rhod, const ModulePW::PW_Basis_K *pw_wfc, const Device *ctx, const Parallel_Grid &pgrid, const std::string &global_out_dir, const bool if_separate_k, const K_Vectors &kv, const int kpar, const int my_pool, const Charge *chr)
Definition get_pchg_pw.h:9
void write_vdata_palgrid(const Parallel_Grid &pgrid, const double *const data, const int is, const int nspin, const int iter, const std::string &fn, const double ef, const UnitCell *const ucell, const int precision=11, const int out_fermi=1, const bool reduce_all_pool=false)
write volumetric data on the parallized grid into a .cube file
Definition write_cube.cpp:15
Definition memory_op.h:17