ABACUS develop
Atomic-orbital Based Ab-initio Computation at UStc
Loading...
Searching...
No Matches
get_wf_pw.h
Go to the documentation of this file.
1#ifndef GET_WF_PW_H
2#define GET_WF_PW_H
3
4namespace ModuleIO
5{
6template <typename Device>
7void get_wf_pw(const std::vector<int>& out_wfc_norm,
8 const std::vector<int>& out_wfc_re_im,
9 const int nbands,
10 const int nspin,
11 const int nxyz,
12 UnitCell* ucell,
13 const psi::Psi<std::complex<double>, Device>* kspw_psi,
14 const ModulePW::PW_Basis_K* pw_wfc,
15 const Device* ctx,
16 const Parallel_Grid& pgrid,
17 const std::string& global_out_dir,
18 const K_Vectors& kv,
19 const int kpar,
20 const int my_pool)
21{
22 // Get necessary parameters from kv
23 const int nks = kv.get_nks(); // current process pool k-point count
24 const int nkstot = kv.get_nkstot(); // total k-point count
25
26 // Loop over k-parallelism
27 for (int ip = 0; ip < kpar; ++ip)
28 {
29 if (my_pool != ip)
30 {
31 continue;
32 }
33
34 // bands_picked is a vector of 0s and 1s, where 1 means the band is picked to output
35 std::vector<int> bands_picked_norm(nbands, 0);
36 std::vector<int> bands_picked_re_im(nbands, 0);
37
38 // Check if length of out_wfc_norm and out_wfc_re_im is valid
39 if (static_cast<int>(out_wfc_norm.size()) > nbands || static_cast<int>(out_wfc_re_im.size()) > nbands)
40 {
41 ModuleBase::WARNING_QUIT("ModuleIO::get_wf_pw",
42 "The number of bands specified by `out_wfc_norm` or `out_wfc_re_im` in the "
43 "INPUT file exceeds `nbands`!");
44 }
45
46 // Check if all elements in bands_picked are 0 or 1
47 for (int value: out_wfc_norm)
48 {
49 if (value != 0 && value != 1)
50 {
51 ModuleBase::WARNING_QUIT("ModuleIO::get_wf_pw",
52 "The elements of `out_wfc_norm` must be either 0 or 1. "
53 "Invalid values found!");
54 }
55 }
56 for (int value: out_wfc_re_im)
57 {
58 if (value != 0 && value != 1)
59 {
60 ModuleBase::WARNING_QUIT("ModuleIO::get_wf_pw",
61 "The elements of `out_wfc_re_im` must be either 0 or 1. "
62 "Invalid values found!");
63 }
64 }
65
66 // Fill bands_picked with values from out_wfc_norm
67 // Remaining bands are already set to 0
68 int length = std::min(static_cast<int>(out_wfc_norm.size()), nbands);
69 for (int i = 0; i < length; ++i)
70 {
71 // out_wfc_norm rely on function parse_expression
72 bands_picked_norm[i] = static_cast<int>(out_wfc_norm[i]);
73 }
74 length = std::min(static_cast<int>(out_wfc_re_im.size()), nbands);
75 for (int i = 0; i < length; ++i)
76 {
77 bands_picked_re_im[i] = static_cast<int>(out_wfc_re_im[i]);
78 }
79
80 // Allocate host memory
81 std::vector<std::complex<double>> wfcr_norm(nxyz);
82 std::vector<std::vector<double>> rho_band_norm(nspin, std::vector<double>(nxyz));
83
84 // Allocate device memory
85 std::complex<double>* wfcr_norm_device = nullptr;
86 if (!std::is_same<Device, base_device::DEVICE_CPU>::value)
87 {
88 base_device::memory::resize_memory_op<std::complex<double>, Device>()(wfcr_norm_device, nxyz);
89 }
90
91 for (int ib = 0; ib < nbands; ++ib)
92 {
93 // Skip the loop iteration if bands_picked[ib] is 0
94 if (!bands_picked_norm[ib])
95 {
96 continue;
97 }
98
99 for (int is = 0; is < nspin; ++is)
100 {
101 std::fill(rho_band_norm[is].begin(), rho_band_norm[is].end(), 0.0);
102 }
103 for (int ik = 0; ik < nks; ++ik)
104 {
105 const int ikstot = kv.ik2iktot[ik]; // global k-point index
106 const int spin_index = kv.isk[ik]; // spin index
107 const int k_number = ikstot % (nkstot / nspin) + 1; // k-point number, starting from 1
108
109 kspw_psi->fix_k(ik);
110
111 // FFT on device and copy result back to host
112 if (std::is_same<Device, base_device::DEVICE_CPU>::value)
113 {
114 pw_wfc->recip_to_real(ctx, &kspw_psi[0](ib, 0), wfcr_norm.data(), ik);
115 }
116 else
117 {
118 pw_wfc->recip_to_real(ctx, &kspw_psi[0](ib, 0), wfcr_norm_device, ik);
119
120 base_device::memory::synchronize_memory_op<std::complex<double>, base_device::DEVICE_CPU, Device>()(
121 wfcr_norm.data(),
122 wfcr_norm_device,
123 nxyz);
124 }
125
126 // To ensure the normalization of charge density in multi-k calculation
127 double wg_sum_k = 0.0;
128 if (nspin == 1)
129 {
130 wg_sum_k = 2.0;
131 }
132 else if (nspin == 2)
133 {
134 wg_sum_k = 1.0;
135 }
136 else
137 {
138 ModuleBase::WARNING_QUIT("ModuleIO::get_wf_pw",
139 "Real space wavefunction output currently do not support noncollinear "
140 "polarized calculation (nspin = 4)!");
141 }
142
143 double w1 = static_cast<double>(wg_sum_k / ucell->omega);
144
145 for (int i = 0; i < nxyz; ++i)
146 {
147 rho_band_norm[spin_index][i] = std::abs(wfcr_norm[i]) * std::sqrt(w1);
148 }
149
150 std::stringstream ss_file;
151 ss_file << global_out_dir << "wfi" << ib + 1 << "s" << spin_index + 1 << "k" << k_number << ".cube";
152
154 rho_band_norm[spin_index].data(),
155 spin_index,
156 nspin,
157 0,
158 ss_file.str(),
159 0.0,
160 ucell,
161 11,
162 1,
163 true); // reduce_all_pool is true
164 }
165 }
166
167 // Allocate host memory
168 std::vector<std::complex<double>> wfc_re_im(nxyz);
169 std::vector<std::vector<double>> rho_band_re(nspin, std::vector<double>(nxyz));
170 std::vector<std::vector<double>> rho_band_im(nspin, std::vector<double>(nxyz));
171
172 // Allocate device memory
173 std::complex<double>* wfc_re_im_device = nullptr;
174 if (!std::is_same<Device, base_device::DEVICE_CPU>::value)
175 {
176 base_device::memory::resize_memory_op<std::complex<double>, Device>()(wfc_re_im_device, nxyz);
177 }
178
179 for (int ib = 0; ib < nbands; ++ib)
180 {
181 // Skip the loop iteration if bands_picked[ib] is 0
182 if (!bands_picked_re_im[ib])
183 {
184 continue;
185 }
186
187 for (int is = 0; is < nspin; ++is)
188 {
189 std::fill(rho_band_re[is].begin(), rho_band_re[is].end(), 0.0);
190 std::fill(rho_band_im[is].begin(), rho_band_im[is].end(), 0.0);
191 }
192 for (int ik = 0; ik < nks; ++ik)
193 {
194 const int ikstot = kv.ik2iktot[ik]; // global k-point index
195 const int spin_index = kv.isk[ik]; // spin index
196 const int k_number = ikstot % (nkstot / nspin) + 1; // k-point number, starting from 1
197
198 kspw_psi->fix_k(ik);
199
200 // FFT on device and copy result back to host
201 if (std::is_same<Device, base_device::DEVICE_CPU>::value)
202 {
203 pw_wfc->recip_to_real(ctx, &kspw_psi[0](ib, 0), wfc_re_im.data(), ik);
204 }
205 else
206 {
207 pw_wfc->recip_to_real(ctx, &kspw_psi[0](ib, 0), wfc_re_im_device, ik);
208
209 base_device::memory::synchronize_memory_op<std::complex<double>, base_device::DEVICE_CPU, Device>()(
210 wfc_re_im.data(),
211 wfc_re_im_device,
212 nxyz);
213 }
214
215 // To ensure the normalization of charge density in multi-k calculation
216 double wg_sum_k = 0.0;
217 if (nspin == 1)
218 {
219 wg_sum_k = 2.0;
220 }
221 else if (nspin == 2)
222 {
223 wg_sum_k = 1.0;
224 }
225 else
226 {
227 ModuleBase::WARNING_QUIT("ModuleIO::get_wf_pw",
228 "Real space wavefunction output currently do not support noncollinear "
229 "polarized calculation (nspin = 4)!");
230 }
231
232 double w1 = static_cast<double>(wg_sum_k / ucell->omega);
233
234 for (int i = 0; i < nxyz; ++i)
235 {
236 rho_band_re[spin_index][i] = std::real(wfc_re_im[i]) * std::sqrt(w1);
237 rho_band_im[spin_index][i] = std::imag(wfc_re_im[i]) * std::sqrt(w1);
238 }
239
240 std::stringstream ss_real;
241 ss_real << global_out_dir << "wfi" << ib + 1 << "s" << spin_index + 1 << "k" << k_number << "re.cube";
242
244 rho_band_re[spin_index].data(),
245 spin_index,
246 nspin,
247 0,
248 ss_real.str(),
249 0.0,
250 ucell,
251 11,
252 1,
253 true); // reduce_all_pool is true
254
255 std::stringstream ss_imag;
256 ss_imag << global_out_dir << "wfi" << ib + 1 << "s" << spin_index + 1 << "k" << k_number << "im.cube";
257
259 rho_band_im[spin_index].data(),
260 spin_index,
261 nspin,
262 0,
263 ss_imag.str(),
264 0.0,
265 ucell,
266 11,
267 1,
268 true); // reduce_all_pool is true
269 }
270 }
271 }
272}
273} // namespace ModuleIO
274
275#endif // GET_WF_PW_H
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
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
Definition parallel_grid.h:8
Definition unitcell.h:16
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_wf_pw(const std::vector< int > &out_wfc_norm, const std::vector< int > &out_wfc_re_im, const int nbands, const int nspin, const int nxyz, UnitCell *ucell, const psi::Psi< std::complex< double >, Device > *kspw_psi, const ModulePW::PW_Basis_K *pw_wfc, const Device *ctx, const Parallel_Grid &pgrid, const std::string &global_out_dir, const K_Vectors &kv, const int kpar, const int my_pool)
Definition get_wf_pw.h:7
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