Line data Source code
1 : !!****m* ABINIT/m_gwr
2 : !! NAME
3 : !! m_gwr
4 : !!
5 : !! FUNCTION
6 : !! Objects and procedures implementing the GW method in real-space and imaginary time.
7 : !!
8 : !! NOTES
9 : !! Memory and workload are distributed using a 4D cartesian grid: (g/r, tau, k-points, spin).
10 : !!
11 : !! Inside the g/r communicator, we use PBLAS matrices to store G, tchi and W
12 : !! using a 1D processor grid and block distribution along columns.
13 : !! A 2D grid, indeed, would require MPI-FFT or some communication before performing the FFTs along columns.
14 : !!
15 : !! Let's assume for simplicity that we have only two MPI procs in the g/r communicator.
16 : !! Matrices in (g,g') space are distributed along columns so that the g-index is local
17 : !! and we can use sequential zero-padded FFTs to transform from g to r in the unit cell:
18 : !!
19 : !! g'-axis
20 : !! |--------------------
21 : !! | | |
22 : !! g-axis | P0 | P1 |
23 : !! | | |
24 : !! |--------------------
25 : !!
26 : !! The results of the FFT transform along g are stored in another PBLAS matrix with the same layout:
27 : !!
28 : !! g'-axis
29 : !! |--------------------
30 : !! | | |
31 : !! r-axis | P0 | P1 |
32 : !! | | |
33 : !! |--------------------
34 : !!
35 : !! At this point, we call ptrans to MPI transpose the (r, g') matrix, and we end up with:
36 : !!
37 : !! r-axis
38 : !! |--------------------
39 : !! | | |
40 : !! g'-axis | P0 | P1 |
41 : !! | | |
42 : !! |--------------------
43 : !!
44 : !! Differences with respect to the quartic GW code formulated in frequency-domain (real axis)
45 : !!
46 : !! - in GWR, the k-mesh must be Gamma-centered when the supercell-method is used.
47 : !! Convolutions can use shifted k-meshes, although this part should be tests.
48 : !! - All the two-point functions are defined on k/q-centered g-spheres while GW uses a single Gamma-centered sphere.
49 : !! - The frequency/tau meshes are automatically defined by gwr_ntau and the KS energies up to nband (minimax meshes).
50 : !!
51 : !! Technical problems:
52 : !!
53 : !! - it's not clear to me that one can use vc(Sq, SG) when a cutoff is used as the cutoff breaks
54 : !! the spherical symmetry of vc(r). Besides, when symmetries are used to reconstruct the term for q in the BZ,
55 : !! one might have to take into account umklapps. Use cache?
56 : !!
57 : !! - Treatment of the anisotropic behaviour of Wc. This part is badly coded in GW, in the sense that
58 : !! we use a finite small q when computing Wc for q --> 0. This breaks the symmetry of the system
59 : !! and QP degeneracies. The equations needed to express the angular dependency of W(q) for q --> 0
60 : !! are well known but one has to pass through the Adler-Wiser expression.
61 : !! Possible solution: Compute heads and wings using a WFK_fine wavefunction file with dense k-mesh and less bands.
62 : !! The dipole matrix elements are computed with the DFPT routines, still we need to
63 : !! recode a lot of stuff that is already done in cchi0q0, especially symmetries.
64 : !! Note, however, that tchi is Hermitian along the imaginary axis, expect for omega = 0 in metals
65 : !! but I don't think the minmax grids contain omega = 0.
66 : !!
67 : !! - In principle, it's possible to compute QP correction along a k-path if a new WFK file is provided.
68 : !! The correlated part is evaluated in real-space in the super-cell.
69 : !! For Sigma_x, we need a specialized routine that can handle arbitrary q, especially at the level of v(q, G)
70 : !! but I don't know if this approach will give smooth bands
71 : !! as we don't have q --> 0 when k does not belong to the k-mesh.
72 : !!
73 : !! - New routine to compute oscillator matrix elements with NC/PAW and PBLAS matrices.
74 : !! It can be used to compute tchi head/wings as well as Sigma_x + interface with coupled-cluster codes.
75 : !!
76 : !! - Decide whether we should use VASP conventions for G and the analytic continuation or the "standard" ones by Godby.
77 : !! The standard ones are consistent with Hedin's notations and correspond to the ones used in the legacy GW code.
78 : !! On the other hand, VASP notations make life easier if one has to implement PAW as all the equations
79 : !! have been already derived.
80 : !!
81 : !! - Address nspinor = 2 and PBLAS distribution as MPI proc can have both spinors in memory
82 : !! In other words, we should store the first/last index in gvec for each spinor
83 : !!
84 : !! - Optimization for Gamma-only. Memory and c -> r FFTs
85 : !!
86 : !! - Need to extend FFT API to avoid scaling if isign = -1. Also fft_ug and fft_ur should accept isign
87 : !! optional argument. Refactoring of all the FFT routines used in the GW code is needed
88 : !! in order to exploit R2C, C2R (e.g. chi0(q=0) and GPU version.
89 : !!
90 : !! - Use round-robin distribution instead of blocked-distribution to improve load balance?
91 : !!
92 : !! - For nspinor = 2, we use 4 Scalapack matrices to store G^k_ab(g,g') instead of a single matrix of shape (2*npw, 2*npw)
93 : !!
94 : !! - Memory peaks:
95 : !!
96 : !! (env3.9) [magianto@uan01 /scratch/project_465000061/magianto/DDIAGO_ZnO]
97 : !! $~/git_repos/abinit/tests/Scripts/abimem.py peaks abimem_rank0.mocc
98 : !! [0] <var=gt_scbox, A@m_gwr.F90:3395, addr=0x14aa53673010, size_mb=379.688>
99 : !! [1] <var=xsum, A@xmpi_sum.finc:2551, addr=0x14aa2fce9010, size_mb=379.688>
100 : !! [2] <var=gt_scbox, A@m_gwr.F90:4338, addr=0x14aa4f64f010, size_mb=379.688>
101 : !! [3] <var=allcg_k, A@m_wfd.F90:4631, addr=0x14aa56b57010, size_mb=217.865>
102 : !! [5] <var=wct_scbox, A@m_gwr.F90:4339, addr=0x14aa43876010, size_mb=189.844>
103 : !! [6] <var=xsum, A@xmpi_sum.finc:2476, addr=0x14aa31bb0010, size_mb=189.844>
104 : !! [7] <var=cg_k, A@m_wfd.F90:4623, addr=0x14aa64535010, size_mb=108.932>
105 : !!
106 : !! TODO
107 : !! - Remove cryst%timrev, use kptopt and qptopt
108 : !! - Sig_c breaks QP degeneracies due to fixed q0.
109 : !!
110 : !! NOTES:
111 : !!
112 : !! 1) _slk_mat_t is a CPP macro defined in abi_common.h that allows us to use PBLAS in single/double precision
113 : !! Be careful when using c_f_pointer because there's no type checking.
114 : !!
115 : !! COPYRIGHT
116 : !! Copyright (C) 1999-2026 ABINIT group (MG)
117 : !! This file is distributed under the terms of the
118 : !! GNU General Public License, see ~abinit/COPYING
119 : !! or http://www.gnu.org/copyleft/gpl.txt .
120 : !!
121 : !! SOURCE
122 :
123 : #if defined HAVE_CONFIG_H
124 : #include "config.h"
125 : #endif
126 :
127 : #include "abi_common.h"
128 :
129 : ! nvtx related macro definition
130 : #include "nvtx_macros.h"
131 :
132 : module m_gwr
133 :
134 : use, intrinsic :: iso_c_binding
135 : use defs_basis
136 : use m_abicore
137 : use m_errors
138 : use m_xmpi
139 : use m_xomp
140 : use m_hdr
141 : use m_ebands
142 : use netcdf
143 : use m_nctk
144 : use m_dtfil
145 : use m_yaml
146 : use m_sigtk
147 : use m_hide_blas
148 : #if defined(HAVE_GPU_MARKERS)
149 : use m_nvtx_data
150 : #endif
151 :
152 : use defs_datatypes, only : pseudopotential_type
153 : use defs_abitypes, only : mpi_type
154 : use m_gwdefs, only : GW_TOL_DOCC, GW_TOLQ0, GW_TOL_W0, GW_Q0_DEFAULT, cone_gw, czero_gw, j_gw, sigijtab_t, &
155 : sigijtab_free, g0g0w
156 : use m_time, only : cwtime, cwtime_report, sec2str, timab
157 : use m_io_tools, only : iomode_from_fname, get_unit, file_exists, open_file, write_units
158 : use m_pstat, only : pstat_proc
159 : use m_numeric_tools, only : blocked_loop, get_diag, isdiagmat, arth, print_arr, imin_loc, imax_loc, &
160 : c2r, linfit, bisect, hermitianize
161 : use m_copy, only : alloc_copy
162 : use m_geometry, only : normv, vdotw, spinrot_cmat
163 : use m_fstrings, only : sjoin, itoa, strcat, ktoa, ltoa, ftoa, string_in, yesno
164 : use m_sort, only : sort_rvals, sort_gvecs, sort_dp
165 : use m_krank, only : krank_t, get_ibz2bz, star_from_ibz_idx
166 : use m_crystal, only : crystal_t
167 : use m_dtset, only : dataset_type
168 : use m_cplxtools, only : cplx_mat_plus_bc
169 : use m_fftcore, only : get_kg, sphereboundary, getng, print_ngfft, fftcore_set_mixprec, ngfft_seq
170 : use m_cgtk, only : cgtk_rotate
171 : use m_cgtools, only : cg_zdotc
172 : use m_mpinfo, only : initmpi_seq, destroy_mpi_enreg
173 : use m_kg, only : getcut
174 : use m_fft, only : fftbox_plan3_t, uplan_t, fft_ug, fft_ur, fourdp
175 : use m_fft_mesh, only : calc_ceikr, calc_ceigr
176 : use m_kpts, only : kpts_ibz_from_kptrlatt, kpts_timrev_from_kptopt, kpts_map, kpts_map_print, kpts_pack_in_stars
177 : use m_bz_mesh, only : littlegroup_t, findqg0, kmesh_t
178 : use m_gsphere, only : kg_map, gsphere_t
179 : use m_melemts, only : melements_t
180 : use m_ioarr, only : fftdatar_write
181 : use m_slk, only : slkmat_dp_t, slkmat_sp_t, slk_processor_t, slk_array_free, slk_array_set_zero, slk_array_gpu_set_zero,&
182 : slk_array_locmem_mb, block_dist_1d, slk_pgemm
183 : use m_wfk, only : wfk_read_ebands, wfk_t
184 : use m_wfd, only : wfd_t, wfdgw_t
185 : use m_ddk, only : ddkop_t
186 : use m_pawtab, only : pawtab_type
187 : use m_pawcprj, only : pawcprj_type
188 : use m_vcoul, only : vcgen_t
189 : use m_vkbr, only : vkbr_t, vkbr_free, vkbr_init, nc_ihr_comm
190 : use m_chi0tk, only : chi0_bbp_mask, accumulate_head_wings_imagw, symmetrize_afm_chi0
191 : use m_sigx, only : sigx_symmetrize
192 : use m_dyson_solver, only : sigma_pade_t
193 : use minimax_grids, only : gx_minimax_grid
194 : use m_occ, only : get_fact_spin_tol_empty
195 :
196 : implicit none
197 :
198 : private
199 : !!***
200 :
201 : !!****t* m_gwr/desc_t
202 : !! NAME
203 : !! desc_t
204 : !!
205 : !! FUNCTION
206 : !! Parameters related to a two-point function such as
207 : !! gvectors, tables used for zero padded FFTs and matrix elements of the Coulomb interaction.
208 : !!
209 : !! SOURCE
210 :
211 : type,public :: desc_t
212 :
213 : integer :: istwfk = 1
214 : ! Storage mode for this k/q point.
215 :
216 : integer :: npw = -1
217 : ! Total number of plane-waves for this k/q-point.
218 :
219 : integer :: ig0 = -1
220 : ! Index of g=0 in gvec.
221 :
222 : logical :: kin_sorted
223 : ! True if gvec are sorted by |k+g|^2/2
224 :
225 : integer,allocatable :: gvec(:,:)
226 : ! (3, npw)
227 : ! G-vectors in reduced coordinates.
228 : ! Note that this array is global i.e. it is not MPI-distributed inside the PBLAS communicator.
229 :
230 : integer,allocatable :: gbound(:,:)
231 : ! (2*mgfft+8, 2)
232 : ! sphere boundary info for zero-padded FFT
233 :
234 : integer,allocatable :: g2box(:)
235 : ! (npw)
236 : ! Index of gvec in the supercell FFT box.
237 :
238 : integer :: cached_sc_ngfft(6) = -1
239 :
240 : complex(gwp),allocatable :: vc_sqrt_eps(:)
241 : ! (npw)
242 : ! Square root of the Coulomb interaction in reciprocal space.
243 : ! Allocated and computed for tchi/W descriptors.
244 : ! A Coulomb cutoff might be applied but NOT the MC technique
245 :
246 : complex(gwp),allocatable :: vc_sqrt_sigma(:)
247 : ! (npw)
248 : ! Square root of the Coulomb interaction in reciprocal space.
249 : ! Allocated and computed for Sigma descriptors.
250 : ! A Coulomb cutoff might be applied. MC technique can be used here
251 :
252 : integer,allocatable :: rottb(:,:,:)
253 : ! rottb(ng,timrev,nsym)
254 : ! rottb(G,I,S) is the index of (SI) G in the array gvec
255 : ! where I is either the identity or the inversion.
256 :
257 : integer,allocatable :: rottbm1(:,:,:)
258 : ! rottb(ng,timrev,nsym)
259 : ! rottbm1(G,I,S) is the index of IS{^-1} G in the array gvec
260 :
261 : complex(gwp),allocatable :: phmGt(:,:)
262 : ! phmGt(ng,nsym)
263 : ! Phase factor e^{-i2\pi(G.\tau)} where $\tau$ is the fractional translation associated to isym.
264 :
265 : complex(gwp),allocatable :: phmSGt(:,:)
266 : ! phmSGt(ng,nsym)
267 : ! Phase factor e^{-i2\pi(SG.\tau)} where S is one of the symmetry properties in reciprocal space.
268 :
269 : contains
270 :
271 : procedure :: init => desc_init
272 : ! Initialize the object
273 :
274 : procedure :: copy => desc_copy
275 : ! Copy object.
276 :
277 : procedure :: to_scbox => desc_to_scbox
278 : ! Insert cg_k array defined on the k-centered g-sphere with npw vectors inside the FFT box.
279 :
280 : procedure :: get_vc_sqrt => desc_get_vc_sqrt
281 : ! Compute square root of vc(q,g).
282 :
283 : procedure :: free => desc_free
284 : ! Free memory.
285 : end type desc_t
286 :
287 : interface desc_array_free
288 : module procedure desc_array1_free
289 : end interface desc_array_free
290 : !!***
291 :
292 : !----------------------------------------------------------------------
293 :
294 : !!****t* m_gwr/est_t
295 : !! NAME
296 : !! est_t
297 : !!
298 : !! FUNCTION
299 : !! Memory is given in Mb
300 : !!
301 : !! SOURCE
302 :
303 : type, public :: est_t
304 :
305 : real(dp) :: mem_green_gg = zero
306 : real(dp) :: mem_green_rg = zero
307 : real(dp) :: mem_chi_gg = zero
308 : real(dp) :: mem_chi_rg = zero
309 : real(dp) :: mem_ugb = zero
310 : real(dp) :: mem_total = zero
311 : real(dp) :: efficiency = zero
312 : real(dp) :: speedup = zero
313 :
314 : contains
315 : procedure :: print => est_print
316 : end type est_t
317 : !!***
318 :
319 : !----------------------------------------------------------------------
320 :
321 : !!****t* m_gwr/gwr_t
322 : !! NAME
323 : !! gwr_t
324 : !!
325 : !! FUNCTION
326 : !! This object provides the high-level API used to perform the different steps of the GWR algorithm.
327 : !!
328 : !! SOURCE
329 :
330 : type, public :: gwr_t
331 :
332 : integer :: nsppol = 1, nspinor = -1, nsig_ab = -1, nspden = -1
333 : ! Number of independent spin polarizations, number of spinor components and spin densities.
334 :
335 : integer :: natom = -1
336 : ! Number of atoms
337 :
338 : integer :: usepaw = -1
339 : ! 0 if NC pseudos. 1 if PAW is used (not yet supported).
340 :
341 : integer :: my_nspins = -1
342 : ! Number of independent spin polarizations treated by this MPI proc
343 :
344 : integer :: nkbz = -1, nkibz = -1
345 : ! Number of k-points in the BZ/IBZ
346 :
347 : integer :: my_nkibz = -1, my_nkbz = -1
348 : ! Number of k-points in the IBZ/BZ stored by this MPI proc.
349 :
350 : integer :: uc_batch_size = -1
351 : ! Max number of unit cell FFT-transforms done in batch mode.
352 :
353 : integer :: sc_batch_size = -1
354 : ! Max number of supercell-cell FFT-transforms done in batch mode.
355 :
356 : integer,allocatable :: my_kbz_inds(:)
357 : ! (my_nkbz)
358 : ! List of k-BZ indices treated by this proc.
359 :
360 : integer,allocatable :: my_kibz_inds(:)
361 : ! (my_nkibz)
362 : ! List of k-IBZ indices treated by this proc.
363 :
364 : integer :: nqbz = -1, nqibz = -1
365 : ! Number of q-points in the BZ/IBZ
366 :
367 : integer :: my_nqibz = -1, my_nqbz = -1
368 : ! Number of q-points in the IBZ/BZ stored by this MPI proc.
369 :
370 : integer,allocatable :: my_qibz_inds(:)
371 : ! (my_nqibz)
372 : ! List of q-IBZ indices treated by this proc.
373 :
374 : integer,allocatable :: my_qbz_inds(:)
375 : ! (my_nqbz)
376 : ! List of q-IBZ indices treated by this proc.
377 :
378 : integer :: ntau = -1
379 : ! Total number of imaginary time points.
380 :
381 : integer :: my_ntau = -1
382 : ! Number of imaginary time/frequency points treated by this MPI rank.
383 :
384 : integer :: nkcalc
385 : ! Number of Sigma_nk k-points computed
386 : ! TODO: Should be spin dependent + max_nkcalc
387 :
388 : integer :: max_nbcalc
389 : ! Maximum number of bands computed (max over nkcalc and spin).
390 :
391 : integer :: nwr = -1
392 : ! Number of frequency points along the real axis for Sigma(w) and spectral function A(w)
393 : ! Odd number so that the mesh is centered on the KS energy.
394 :
395 : !real(dp) :: i_sz = huge(one)
396 : ! Value of the integration of the Coulomb singularity 4\pi/V_BZ \int_BZ d^3q 1/q^2
397 :
398 : real(dp) :: wr_step = -one
399 : ! Step of the linear mesh along the real axis (Ha units).
400 :
401 : real(dp) :: q0(3) = GW_Q0_DEFAULT
402 : ! The small q for the treatment of q --> 0
403 :
404 : real(dp),allocatable :: kcalc(:,:)
405 : ! kcalc(3, nkcalc)
406 : ! List of k-points where the self-energy is computed.
407 :
408 : logical :: idle_proc = .False.
409 : ! True if there are idle procs i.e. if processes in the input_comm have been excluded.
410 :
411 : !logical :: use_shmem_for_k = .False.
412 : !logical :: use_mpi_for_k = .False.
413 :
414 : integer,allocatable :: bstart_ks(:,:)
415 : ! bstart_ks(nkcalc, nsppol)
416 : ! Initial KS band index included in self-energy matrix elements for each k-point in kcalc.
417 : ! Depends on spin because all degenerate states should be included when symsigma /= 0 is used.
418 :
419 : integer,allocatable :: bstop_ks(:,:)
420 : ! bstop_ks(nkcalc, nsppol)
421 :
422 : integer,allocatable :: nbcalc_ks(:,:)
423 : ! nbcalc_ks(nkcalc, nsppol)
424 : ! Number of bands included in self-energy matrix elements for each k-point in kcalc.
425 : ! Depends on spin because all degenerate states should be included when symsigma /= 0 is used.
426 :
427 : integer,allocatable :: kcalc2ibz(:,:)
428 : !kcalc2ibz(nkcalc, 6))
429 : ! Mapping ikcalc --> IBZ as reported by listkk.
430 :
431 : logical :: use_supercell_for_tchi = .True.
432 : ! True if we are using the supercell formalism for tchi
433 : ! False if we are using the mixed-space approach with convolutions in k-space.
434 :
435 : logical :: use_supercell_for_sigma = .True.
436 : ! True if we are using the supercell formalism for sigma
437 : ! False if we are using the mixed-space approach with convolutions in k-space.
438 :
439 : integer :: ngkpt(3) = -1, ngqpt(3) = -1
440 : ! Number of divisions in k/q meshes.
441 :
442 : integer,allocatable :: my_spins(:)
443 : ! (my_nspins)
444 : ! Indirect table giving the spin indices treated by this MPI rank.
445 : ! Used only in the collinear case with nsppol = 2.
446 :
447 : integer,allocatable :: my_itaus(:)
448 : ! (my_ntau)
449 : ! Indirect table giving the tau indices treated by this MPI rank.
450 :
451 : integer,allocatable :: tau_master(:)
452 : ! (ntau)
453 : ! The rank of the MPI proc in tau_comm treating itau.
454 :
455 : integer, allocatable :: np_qibz(:)
456 : ! (nqibz)
457 : ! Number of processors in kpt_comm treating iq_ibz
458 :
459 : integer, allocatable :: np_kibz(:)
460 : ! (nkibz)
461 : ! Number of processors in kpt_comm treating ik_ibz
462 :
463 : logical, allocatable :: itreat_ikibz(:)
464 : ! (nkibz)
465 : ! True if this MPI rank treats ik_ibz
466 :
467 : logical, allocatable :: itreat_iqibz(:)
468 : ! (nqibz)
469 : ! True if this MPI rank treats iq_ibz
470 :
471 : real(dp),allocatable :: tau_mesh(:), tau_wgs(:)
472 : ! (ntau)
473 : ! Imaginary tau mesh and integration weights.
474 :
475 : real(dp),allocatable :: iw_mesh(:), iw_wgs(:)
476 : ! (ntau)
477 : ! Imaginary frequency mesh and integration weights
478 :
479 : real(dp),allocatable :: cosft_wt(:,:)
480 : ! (ntau, ntau)
481 : ! weights for cosine transform. (i tau --> i omega)
482 :
483 : real(dp),allocatable :: cosft_tw(:,:)
484 : ! (ntau, ntau)
485 : ! weights for sine transform (i iomega --> i tau)
486 :
487 : real(dp),allocatable :: sinft_wt(:,:)
488 : ! (ntau, ntau)
489 : ! weights for sine transform (i tau --> i omega)
490 :
491 : real(dp) :: te_min = -one, te_max = one
492 : ! min and Max transition energy in Ha.
493 :
494 : real(dp) :: ft_max_error(3) = -one
495 : ! Max error due to inhomogenous FT.
496 :
497 : real(dp) :: cosft_duality_error = -one
498 : ! Max_{ij} |CT CT^{-1} - I|
499 :
500 : integer :: green_mpw = -1
501 : ! Max number of g-vectors for Green's function over k-points.
502 :
503 : integer :: tchi_mpw = -1
504 : ! Max number of g-vectors for tchi over q-points.
505 :
506 : !integer :: sigma_mpw = -1
507 : ! Max number of g-vectors for Sigma over q-points.
508 :
509 : integer :: g_ngfft(18) = -1, g_mgfft = -1, g_nfft = -1
510 : ! FFT mesh for the Green's function.
511 :
512 : !integer :: chi_ngfft(18) = -1, chi_mgfft = -1, chi_nfft = -1
513 : !integer :: sig_ngfft(18) = -1, sig_mgfft = -1, sig_nfft = -1
514 :
515 : integer :: mg0(3) = [2, 2, 2]
516 : ! Max shifts to account for umklapps.
517 :
518 : type(desc_t),allocatable :: green_desc_kibz(:)
519 : ! (nkibz)
520 : ! Descriptor for Green's functions
521 :
522 : type(desc_t),allocatable :: tchi_desc_qibz(:)
523 : ! (nqibz)
524 : ! Descriptor for tchi. NB: The g-vectors are sorted by |q+g|^2/2
525 :
526 : integer,allocatable :: chinpw_qibz(:)
527 : ! Number of PWs in tchi for each q-point in the IBZ (available on all procs)
528 :
529 : !type(desc_t),allocatable :: sigma_desc_kibz(:)
530 : ! (nkibz)
531 : ! Descriptor for self-energy
532 :
533 : integer :: coords_stgk(4) = 0
534 : ! Cartesian coordinates of this processor in the Cartesian grid.
535 :
536 : type(xcomm_t) :: comm
537 : ! Communicator with all MPI procs involved in the computation
538 : ! NB: gwr%comm%value is not necessarly the same as the input_comm
539 : ! we may decide to remove some procs from input_comm before createring the Cartesian grid.
540 :
541 : type(xcomm_t) :: spin_comm
542 : ! MPI communicator over spins.
543 :
544 : type(xcomm_t) :: kpt_comm
545 : ! MPI communicator for k/q-point distribution.
546 :
547 : type(xcomm_t) :: g_comm
548 : ! MPI communicator for g/r distribution
549 :
550 : type(xcomm_t) :: tau_comm
551 : ! MPI communicator for imag time distribution
552 :
553 : type(xcomm_t) :: gtau_comm
554 : ! MPI communicator for g/tau 2D subgrid.
555 :
556 : type(xcomm_t) :: kg_comm
557 : ! MPI communicator for g/g 2D subgrid.
558 :
559 : type(xcomm_t) :: kts_comm
560 : ! MPI communicator for tau/kpoint/spin 3D grid
561 :
562 : type(xcomm_t) :: kgt_comm
563 : ! MPI communicator for g/tau/kpoint 3D grid
564 :
565 : type(dataset_type), pointer :: dtset => null()
566 : ! Input variables.
567 :
568 : type(datafiles_type), pointer :: dtfil => null()
569 : ! Names of input/output files and prefixes.
570 :
571 : type(crystal_t), pointer :: cryst => null()
572 : ! Crystal structure.
573 :
574 : integer :: scf_iteration = 1
575 : ! Internal counter used to implement self-consistency
576 : ! For the time being, only self-consistency in energies is supported.
577 :
578 : integer,allocatable :: ks_vbik(:,:)
579 : ! (gwr%ks_ebands%nkpt, gwr%ks_ebands%nsppol)
580 : ! KS valence band indices.
581 :
582 : type(ebands_t), pointer :: ks_ebands => null()
583 : ! initial KS energies
584 :
585 : type(gaps_t) :: ks_gaps
586 : ! Info on the KS gaps.
587 :
588 : type(ebands_t) :: qp_ebands
589 : ! QP energies
590 :
591 : type(ebands_t) :: qp_ebands_prev
592 : ! QP energies of the previous iteration. Used if self-consistency.
593 :
594 : type(pseudopotential_type), pointer :: psps => null()
595 : ! NC Pseudos data
596 :
597 : type(pawtab_type), pointer :: pawtab(:) => null()
598 : ! PAW data
599 :
600 : type(mpi_type),pointer :: mpi_enreg => null()
601 : ! Sequential mpi_type needed to invoke ABINIT routines requiring it.
602 :
603 : type(slk_processor_t) :: g_slkproc
604 : ! 1D PBLAS grid to block-distribute matrices along columns inside gcomm.
605 :
606 : type(__slkmat_t),allocatable :: gt_kibz(:,:,:,:,:)
607 : ! (2, nkibz, ntau, nsppol, nsig_ab)
608 : ! Occupied/Empty Green's function G_k(g,g')
609 :
610 : type(__slkmat_t),allocatable :: tchi_qibz(:,:,:)
611 : ! (nqibz, ntau, nsppol)
612 : ! Irreducible polarizability tchi_q(g,g')
613 :
614 : character(len=10) :: tchi_space = "none"
615 : ! Defines if the tchi_qibz matrix stores Chi in tau or iomega domain.
616 : ! "none", "itau", "iomega"
617 :
618 : type(__slkmat_t),allocatable :: wc_qibz(:,:,:)
619 : ! (nqibz, ntau, nsppol)
620 : ! Correlated screened Coulomb interaction summed over collinear spins
621 : ! Replicated across spin_comm if nsppol == 2.
622 :
623 : character(len=10) :: wc_space = "none"
624 : ! Defines if the wc_qibz matrix stores W in tau or iomega domain.
625 : ! "none", "itau", "iomega"
626 :
627 : !type(__slkmat_t),allocatable :: em1_qibz(:,:,:)
628 : ! Inverse dielectric matrix at omega = 0
629 : ! (nqibz, nsppol)
630 : ! Replicated across the tau comm and the spin comm if nsppol == 2.
631 :
632 : type(__slkmat_t),allocatable :: sigc_kibz(:,:,:,:,:)
633 : ! (2, nkibz, ntau, nsppol, nsig_ab)
634 :
635 : character(len=10) :: sigc_space = "none"
636 : ! Defines if the sigc_kibz matrix stores Sigma in tau or iomega domain.
637 : ! "none", "itau", "iomega"
638 :
639 : type(__slkmat_t),allocatable :: ugb(:,:) !, nato_ugb(:,:)
640 : ! (nkibz, nsppol)
641 : ! Fourier components of the KS wavefunctions stored in a PBLAS matrix
642 : ! Bands are distributed in the g_comm communicator in a round-robin fashion.
643 : ! hence they are REPLICATED over tau_comm as this leads to better scalability in terms of flops.
644 : ! Distributing bands inside the 2D gtau_comm, indeed, allows one to reduce memory further
645 : ! but then the pzgemm used to build G explodes. Also. tau parallelism is high-level in GWR so it's not a good idea
646 : ! to mix it with low-level just to make memory for ugb scale better.
647 : ! The size of ugb is negligible when compared to G and Chi.
648 :
649 : type(slk_processor_t) :: gtau_slkproc
650 : ! Scalapack grid with (g,tau) processors
651 :
652 : integer :: ugb_nband = -1
653 : ! Number of bands in ugb.
654 :
655 : type(vcgen_t) :: vcgen_eps
656 : ! Object used to compute Coulomb term vc(q,g) in epsilon.
657 :
658 : type(vcgen_t) :: vcgen_sigma
659 : ! Object used to compute Coulomb term vc(q,g) in Sigma
660 :
661 : logical :: has_vcgen_sigma = .False.
662 : ! True if vcgen_sigma is allocated
663 :
664 : character(len=fnlen) :: gwrnc_path = ABI_NOFILE
665 : ! Path to the GWR.nc file with output results.
666 :
667 : logical :: gwrnc_write = .True.
668 : ! Activate/deactivate the output of the GWR.nc file.
669 :
670 : real(dp),allocatable :: kbz(:,:)
671 : ! (3, nkbz)
672 : ! Reduced coordinates of the k-points in the full BZ.
673 :
674 : real(dp), contiguous, pointer :: kibz(:,:) => null()
675 : ! (3, nkibz)
676 : ! Reduced coordinates of the k-points in the IBZ
677 :
678 : integer,allocatable :: kbz2ibz(:,:)
679 : ! (6, nkbz)
680 : ! Mapping kBZ to IBZ (symrec conventions)
681 :
682 : integer,allocatable :: kbz2ibz_symrel(:,:)
683 : ! (6, nkbz)
684 : ! Mapping kBZ to IBZ (symrel conventions)
685 :
686 : real(dp), contiguous, pointer :: wtk(:) => null()
687 : ! (nkibz)
688 : ! Weights of the k-points in the IBZ (normalized to one).
689 :
690 : real(dp),allocatable :: qbz(:,:)
691 : ! (3, nqbz)
692 : ! Reduced coordinates of the q-points in the full BZ.
693 :
694 : integer,allocatable :: qbz2ibz(:,:)
695 : ! (6, nqbz)
696 : ! Mapping qBZ to IBZ (symrec conventions)
697 :
698 : real(dp),allocatable :: qibz(:,:)
699 : ! (3, nqibz)
700 : ! Reduced coordinates of the q-points in the IBZ (full symmetry of the system).
701 :
702 : real(dp),allocatable :: wtq(:)
703 : ! (nqibz)
704 : ! Weights of the q-points in the IBZ (normalized to one).
705 :
706 : complex(dp),allocatable :: chi0_head_myw(:,:,:)
707 : ! (3,3,my_ntau)
708 : ! Head of the irred. polarizability in i.omega space.
709 : ! Note that spins have been summed over.
710 :
711 : complex(dp),allocatable :: chi0_uwing_myw(:,:,:), chi0_lwing_myw(:,:,:)
712 : ! (3, npw_chi_gamma, my_ntau)
713 : ! Upper wings of the irred. polarizability in i omega space.
714 : ! Note that spins have been summed over.
715 :
716 : type(wfdgw_t) :: kcalc_wfd
717 : ! wavefunction descriptor with the KS states where QP corrections are wanted.
718 :
719 : type(hdr_type) :: wfk_hdr
720 : ! header of the WFK file
721 : ! IMPORTANT: Don't use wkf_hdr%npwarr to get the number of PW as we might have used ecutwfn < ecut.
722 :
723 : type(melements_t) :: ks_me !, qp_me
724 : ! Matrix elements of the different potentials in the KS basis set.
725 :
726 : type(degtab_t),allocatable :: degtab(:,:)
727 : ! (nkcalc, nsppol)
728 : ! Table used to average QP results in the degenerate subspace if symsigma == 1
729 :
730 : integer :: b1gw = -1, b2gw = -1
731 : ! b1gw = minval(gwr%bstart_ks); b2gw = maxval(gwr%bstop_ks)
732 :
733 : logical :: sig_diago
734 : ! True if Sigma_ matrices are diagonal in the band indices (default)
735 :
736 : complex(dp),allocatable :: sigx_mat(:,:,:,:)
737 : ! (b1gw:b2gw, ?, nkcalc, nsppol)
738 : ! Matrix elements of <i|\Sigma_x|j>. The second dimension depends on sig_diago
739 :
740 : !complex(dp),allocatable :: sigc_it_mat(:,:,:,:,:)
741 : ! (2, ntau, max_nbcalc, nkcalc, nsppol*nsig_ab))
742 : ! Matrix elements of <i|\Sigma_c(itau)|j>. The second dimension depends on sig_diago
743 :
744 : complex(dp),allocatable :: sigc_iw_mat(:,:,:,:,:)
745 : ! Matrix elements of <i|\Sigma_c(i omega)|j>
746 : ! (ntau, b1gw:b2gw, ?, nkcalc, nsppol). The second dimension depends on sig_diago
747 :
748 : contains
749 :
750 : procedure :: init => gwr_init
751 : ! Initialize the object.
752 :
753 : procedure :: rotate_gpm => gwr_rotate_gpm
754 : ! Reconstruct the Green's functions in the BZ from the IBZ.
755 :
756 : procedure :: gk_to_scbox => gwr_gk_to_scbox
757 : ! Insert G_k(g',r) in the FFT box of the supercell: k+g' index.
758 :
759 : procedure :: wcq_to_scbox => gwr_wcq_to_scbox
760 : ! Insert W_q(g',r) in the FFT box of the supercell: q+g' index.
761 :
762 : procedure :: get_myk_green_gpr => gwr_get_myk_green_gpr
763 : ! G_k(g,g') --> G_k(g',r) for each k in the BZ treated by this MPI proc for given spin and tau.
764 :
765 : procedure :: get_gkbz_rpr_pm => gwr_get_gkbz_rpr_pm
766 : ! Compute G_k(r',r) with (r, r') in the unit cell and k in the full BZ.
767 :
768 : procedure :: rotate_wc => gwr_rotate_wc
769 : ! Reconstruct Wc(q) in the BZ from the IBZ.
770 :
771 : procedure :: get_myq_wc_gpr => gwr_get_myq_wc_gpr
772 : ! W_q(g,g') --> W_q(g',r) for each q in the BZ treated by this MPI procs for given spin and tau.
773 :
774 : procedure :: get_wc_rpr_qbz => gwr_get_wc_rpr_qbz
775 : ! Compute Wc_q(r',r') with q in the BZ
776 :
777 : procedure :: rpr_to_ggp => gwr_rpr_to_ggp
778 : ! F_{r',r} --> F_{g,g'}
779 :
780 : procedure :: cos_transform => gwr_cos_transform
781 : ! Inhomogeneous cosine transform.
782 :
783 : procedure :: malloc_free_mats => gwr_malloc_free_mats
784 : ! Allocate/Deallocate matrices for G/tchi/Sigma
785 :
786 : procedure :: free => gwr_free
787 : ! Free memory.
788 :
789 : procedure :: print => gwr_print
790 : ! Print info on the object.
791 :
792 : procedure :: print_mem => gwr_print_mem
793 : ! Print memory required by PBLAS matrices.
794 :
795 : procedure :: print_trace => gwr_print_trace
796 : ! Print trace of matrices for testing purposes.
797 :
798 : procedure :: load_kcalc_wfd => gwr_load_kcalc_wfd
799 : ! Load the KS states for Sigma_nk from the WFK file
800 :
801 : procedure :: read_ugb_from_wfk => gwr_read_ugb_from_wfk
802 : ! Read wavefunctions from WFK file.
803 :
804 : procedure :: build_green => gwr_build_green
805 : ! Build Green's functions in imaginary time from the %ugb matrices stored in memory.
806 :
807 : procedure :: build_tchi => gwr_build_tchi
808 : ! Build the irreducible polarizability
809 :
810 : procedure :: redistrib_gt_kibz => gwr_redistrib_gt_kibz
811 : ! Redistribute/deallocate G_k
812 :
813 : procedure :: redistrib_mats_qibz => gwr_redistrib_mats_qibz
814 : ! Redistribute/deallocate tchi_q or Wc_q
815 :
816 : procedure :: build_wc => gwr_build_wc
817 : ! Build the correlated part of the screened interaction.
818 :
819 : procedure :: build_sigmac => gwr_build_sigmac
820 : ! Build the correlated part of the self-energy GWc
821 : ! and compute matrix elements in the KS representation.
822 :
823 : procedure :: rpa_energy => gwr_rpa_energy
824 : ! Compute RPA energy.
825 :
826 : procedure :: gamma_gw => gwr_gamma_gw
827 : ! TODO: Work in progress.
828 :
829 : procedure :: build_chi0_head_and_wings => gwr_build_chi0_head_and_wings
830 : ! Compute head and wings of chi0
831 :
832 : procedure :: build_sigxme => gwr_build_sigxme
833 : ! Compute matrix elements of the exchange part.
834 :
835 : procedure :: get_u_ngfft => gwr_get_u_ngfft
836 : ! Compute FFT mesh from boxcutmin
837 :
838 : procedure :: run_g0w0 => gwr_run_g0w0
839 : ! Compute QP corrections with one-shot G0W0.
840 :
841 : procedure :: run_chi0 => gwr_run_chi0
842 : ! Compute CHI0 only.
843 :
844 : procedure :: run_energy_scf => gwr_run_energy_scf
845 : ! Compute QP corrections with energy-only self-consistent GW
846 :
847 : procedure :: check_scf_cycle => gwr_check_scf_cycle
848 : ! Check SCF cycle for convergence.
849 :
850 : procedure :: ncwrite_tchi_wc => gwr_ncwrite_tchi_wc
851 : ! Write tchi or wc to netcdf file
852 :
853 : end type gwr_t
854 : !!***
855 :
856 : ! Handy named costants (private stuff)
857 : integer,private,parameter :: LOG_MODR = 500, LOG_MODK = 5
858 : integer,private,parameter :: istwfk1 = 1, ndat1 = 1, me_fft0 = 0, paral_fft0 = 0, nproc_fft1 = 1
859 : integer,private,parameter :: OP_COPY = 0, OP_ACC = 1
860 : integer,private,parameter :: CHI_FIT = 1, SIGMA_FIT = 2
861 :
862 : contains
863 : !!***
864 :
865 : !----------------------------------------------------------------------
866 :
867 : !!****f* m_gwr/gwr_init
868 : !! NAME
869 : !! gwr_init
870 : !!
871 : !! FUNCTION
872 : !! Initialize the gwr object.
873 : !!
874 : !! INPUTS
875 : !! dtset<dataset_type>=All input variables for this dataset.
876 : !! dtfil<datafiles_type>=Variables related to files.
877 : !! cryst=Crystalline structure
878 : !! psps<pseudopotential_type>=Variables related to pseudopotentials.
879 : !! pawtab(ntypat*usepaw)<pawtab_type>=Paw tabulated starting data.
880 : !! ke_ebands=KS energies
881 : !! mpi_enreg=information about MPI parallelization (FAKE one as GWR has its own MPI algo)
882 : !! input_comm=MPI communicator
883 : !!
884 : !! OUTPUT
885 : !!
886 : !! SOURCE
887 :
888 0 : subroutine gwr_init(gwr, dtset, dtfil, cryst, psps, pawtab, ks_ebands, mpi_enreg, input_comm)
889 :
890 : !Arguments ------------------------------------
891 : !scalars
892 : class(gwr_t),target,intent(out) :: gwr
893 : type(dataset_type),target,intent(in) :: dtset
894 : type(datafiles_type),target,intent(in) :: dtfil
895 : type(crystal_t),target,intent(in) :: cryst
896 : type(pseudopotential_type),target,intent(in) :: psps
897 : type(pawtab_type),target,intent(in) :: pawtab(psps%ntypat*psps%usepaw)
898 : type(ebands_t),target,intent(in) :: ks_ebands
899 : type(mpi_type),target,intent(in) :: mpi_enreg
900 : integer,intent(inout) :: input_comm
901 :
902 : !Local variables-------------------------------
903 : !scalars
904 : integer,parameter :: qptopt1 = 1, master = 0, ndims = 4
905 : integer :: my_it, my_ikf, ii, kptopt, my_iki, my_iqi, itau, spin, my_iqf
906 : integer :: my_nshiftq, iq_bz, iq_ibz, npw_, ncid, smat_bsize1, smat_bsize2
907 : integer :: comm_cart, me_cart, ierr, all_nproc, my_rank, qprange_, gap_err, ncerr, omp_nt
908 : integer :: cnt, ikcalc, ndeg, mband, bstop, nbsum, jj, gw_icutcoul_
909 : integer :: ik_ibz, ik_bz, isym_k, trev_k, g0_k(3)
910 : integer :: ip_g, ip_k, ip_t, ip_s, np_g, np_k, np_t, np_s, isym, itim
911 : real(dp) :: cpu, wall, gflops, wmax, vc_ecut, delta, abs_rerr, exact_int, eval_int, drude_plasmon_freq
912 : real(dp) :: prev_efficiency, prev_speedup, regterm, prev_dual_error
913 : logical :: isirr_k, changed, q_is_gamma, reorder, can_use_kshifts
914 : character(len=5000) :: msg
915 0 : type(krank_t) :: qrank, krank_ibz
916 : type(est_t) :: est
917 0 : type(kmesh_t) :: Kmesh, Qmesh
918 : !arrays
919 : integer :: qptrlatt(3,3), dims_kgts(ndims), try_dims_kgts(ndims), indkk_k(6,1), units(2)
920 0 : integer,allocatable :: gvec_(:,:),degblock(:,:), degblock_all(:,:,:,:), ndeg_all(:,:), iwork(:,:), got(:)
921 : real(dp) :: my_shiftq(3,1), kk_ibz(3), kk_bz(3), qq_bz(3), qq_ibz(3), kk(3), tsec(2), qbz(3), sq(3)
922 0 : real(dp),allocatable :: wtk(:), kibz(:,:)
923 : logical :: periods(ndims), keepdim(ndims)
924 : ! *************************************************************************
925 :
926 0 : call cwtime(cpu, wall, gflops, "start")
927 0 : call timab(1920, 1, tsec)
928 :
929 0 : all_nproc = xmpi_comm_size(input_comm); my_rank = xmpi_comm_rank(input_comm)
930 0 : units = [std_out, ab_out]
931 :
932 : ! Keep a reference to other objects to simplify the internal API.
933 0 : gwr%dtset => dtset; gwr%dtfil => dtfil; gwr%cryst => cryst; gwr%psps => psps; gwr%pawtab => pawtab
934 0 : gwr%ks_ebands => ks_ebands; gwr%kibz => ks_ebands%kptns; gwr%wtk => ks_ebands%wtk; gwr%mpi_enreg => mpi_enreg
935 :
936 : ! Initialize qp_ebands with KS values.
937 0 : call ks_ebands%copy(gwr%qp_ebands)
938 0 : call ks_ebands%copy(gwr%qp_ebands_prev)
939 :
940 0 : ABI_MALLOC(gwr%ks_vbik, (gwr%ks_ebands%nkpt, gwr%ks_ebands%nsppol))
941 0 : gwr%ks_vbik(:,:) = gwr%ks_ebands%get_valence_idx()
942 :
943 : ! Useful dimensions.
944 0 : gwr%nspinor = dtset%nspinor; gwr%nsppol = dtset%nsppol; gwr%nspden = dtset%nspden
945 0 : gwr%nsig_ab = gwr%nspinor ** 2 !! TODO HT: One day we only need 3
946 0 : gwr%natom = dtset%natom; gwr%usepaw = dtset%usepaw
947 0 : gwr%sig_diago = .True.
948 0 : if (string_in(gwr%dtset%gwr_task, "GAMMA_GW")) gwr%sig_diago = .False.
949 :
950 : ! Decide whether one should use supercells or convolutions in the BZ.
951 0 : gwr%use_supercell_for_tchi = .True.
952 0 : if (gwr%dtset%gwr_chi_algo == 0) then
953 : ! Automatic selection
954 0 : ABI_ERROR("Not implemented Error")
955 : else
956 0 : gwr%use_supercell_for_tchi = gwr%dtset%gwr_chi_algo == 1
957 : end if
958 :
959 0 : if (gwr%dtset%gwr_sigma_algo == 0) then
960 : ! Automatic selection
961 0 : ABI_ERROR("Not implemented Error")
962 : else
963 0 : gwr%use_supercell_for_sigma = gwr%dtset%gwr_sigma_algo == 1
964 : end if
965 :
966 : ! Set q0 for long-wavelength limit
967 0 : if (dtset%gw_nqlwl /= 0) gwr%q0 = dtset%gw_qlwl(:, 1)
968 :
969 0 : mband = ks_ebands%mband; nbsum = dtset%nband(1)
970 0 : ABI_CHECK_IRANGE(nbsum, 1, mband, "Invalid nbsum")
971 :
972 : ! Define frequency mesh for sigma(w_real) and spectral functions.
973 : ! Note that in GWR computing quantities on the real-axis is really cheap
974 : ! so we can use very dense meshes without affecting performance.
975 : ! The default for nfresp and freqspmax is zero.
976 : ! Here we compute wr_step and nwrt so that we have e0 +- the expected plasmom frequency
977 0 : drude_plasmon_freq = sqrt(four_pi * ks_ebands%nelect / cryst%ucvol)
978 0 : wmax = dtset%freqspmax; if (abs(wmax) < tol6) wmax = two * drude_plasmon_freq
979 0 : gwr%nwr = dtset%nfreqsp
980 0 : if (gwr%nwr == 0) gwr%nwr = nint(wmax / (0.05_dp * eV_Ha))
981 0 : if (mod(gwr%nwr, 2) == 0) gwr%nwr = gwr%nwr + 1
982 0 : gwr%wr_step = wmax / (gwr%nwr - 1)
983 :
984 : ! =======================
985 : ! Setup k-mesh and q-mesh
986 : ! =======================
987 :
988 : ! Get full kBZ associated to ks_ebands
989 : call kpts_ibz_from_kptrlatt(cryst, ks_ebands%kptrlatt, ks_ebands%kptopt, ks_ebands%nshiftk, ks_ebands%shiftk, &
990 0 : gwr%nkibz, kibz, wtk, gwr%nkbz, gwr%kbz) !, bz2ibz=bz2ibz)
991 : !new_kptrlatt=gwr%kptrlatt, new_shiftk=gwr%kshift,
992 : !bz2ibz=new%ind_qbz2ibz) # FIXME
993 0 : ABI_FREE(wtk)
994 :
995 : ! In principle kibz should be equal to ks_ebands%kptns.
996 0 : ABI_CHECK_IEQ(gwr%nkibz, ks_ebands%nkpt, "nkibz != ks_ebands%nkpt")
997 0 : ABI_CHECK(all(abs(ks_ebands%kptns - kibz) < tol12), "ks_ebands%kibz != kibz")
998 :
999 0 : can_use_kshifts = .not. gwr%use_supercell_for_tchi .and. .not. gwr%use_supercell_for_sigma
1000 : !can_use_kshifts = .False.
1001 :
1002 0 : if (.not. (isdiagmat(ks_ebands%kptrlatt) .and. ks_ebands%nshiftk == 1) .and. .not. can_use_kshifts) then
1003 0 : ABI_ERROR("GWR code requires ngkpt with one shift!")
1004 : end if
1005 0 : gwr%ngkpt = get_diag(ks_ebands%kptrlatt)
1006 :
1007 : ! Note symrec convention here.
1008 0 : kptopt = ks_ebands%kptopt
1009 0 : call krank_ibz%from_kptrlatt(gwr%nkibz, kibz, ks_ebands%kptrlatt, compute_invrank=.False.)
1010 :
1011 0 : ABI_MALLOC(gwr%kbz2ibz, (6, gwr%nkbz))
1012 0 : if (kpts_map("symrec", kptopt, cryst, krank_ibz, gwr%nkbz, gwr%kbz, gwr%kbz2ibz) /= 0) then
1013 0 : ABI_ERROR("Cannot map kBZ to IBZ!")
1014 : end if
1015 :
1016 : ! Order kbz by stars and rearrange entries in kbz2ibz table.
1017 0 : call kpts_pack_in_stars(gwr%nkbz, gwr%kbz, gwr%kbz2ibz)
1018 0 : if (my_rank == master) then
1019 0 : call kpts_map_print(units, " Mapping kBZ --> kIBZ", "symrec", gwr%kbz, kibz, gwr%kbz2ibz, gwr%dtset%prtvol)
1020 : end if
1021 :
1022 : !call get_ibz2bz(gwr%nkibz, gwr%nkbz, gwr%kbz2ibz, kibz2bz, msg, ierr)
1023 : !ABI_CHECK(ierr == 0, sjoin("Something wrong in symmetry tables for k-points", ch10, msg))
1024 :
1025 : ! Table with symrel conventions for the symmetrization of the wfs.
1026 0 : ABI_MALLOC(gwr%kbz2ibz_symrel, (6, gwr%nkbz))
1027 0 : if (kpts_map("symrel", kptopt, cryst, krank_ibz, gwr%nkbz, gwr%kbz, gwr%kbz2ibz_symrel) /= 0) then
1028 0 : ABI_ERROR("Cannot map kBZ to IBZ!")
1029 : end if
1030 :
1031 : ! Here we set up the q-mesh for chi and w and the corresponding symmetry tables.
1032 : ! Supercell algos require Gamma-centered meshes with ngqpt so that we can easily insert q+G in the FFT box
1033 : ! Convolution algos can handle multiple shifts in the k-mesh.
1034 : ! After this block we should know IBZ, BZ, weights and qbz2ibz mapping
1035 0 : if (.not. can_use_kshifts) then
1036 :
1037 : ! Setup IBZ q-points, weights and BZ. Always use q --> -q symmetry even in systems without inversion
1038 0 : my_nshiftq = 1; my_shiftq = zero; qptrlatt = ks_ebands%kptrlatt
1039 : call kpts_ibz_from_kptrlatt(cryst, qptrlatt, qptopt1, my_nshiftq, my_shiftq, & ! in
1040 0 : gwr%nqibz, gwr%qibz, gwr%wtq, gwr%nqbz, gwr%qbz) ! out
1041 :
1042 0 : ABI_CHECK(all(abs(gwr%qibz(:,1)) < tol16), "First qpoint in qibz should be Gamma!")
1043 0 : gwr%ngqpt = get_diag(qptrlatt)
1044 :
1045 : ! Table with symrec conventions for the symmetrization of chi.
1046 0 : ABI_MALLOC(gwr%qbz2ibz, (6, gwr%nqbz))
1047 :
1048 0 : call qrank%from_kptrlatt(gwr%nqibz, gwr%qibz, qptrlatt, compute_invrank=.False.)
1049 0 : if (kpts_map("symrec", qptopt1, cryst, qrank, gwr%nqbz, gwr%qbz, gwr%qbz2ibz) /= 0) then
1050 0 : ABI_ERROR("Cannot map qBZ to IBZ!")
1051 : end if
1052 0 : call qrank%free()
1053 :
1054 : else
1055 : ! === Create basic data types for the calculation ===
1056 : ! Kmesh defines the k-point sampling for the wavefunctions.
1057 : ! Qmesh defines the q-point sampling for chi0, all possible differences k1-k2 reduced to the IBZ.
1058 : ! TODO Kmesh%bz should be in [-half, half[ but this modification is painful!
1059 0 : call Kmesh%init(cryst, gwr%nkibz, kibz, dtset%kptopt, wrap_1zone=.FALSE.)
1060 :
1061 : ! Some required information are not filled up inside kmesh_init. So doing it here, even though it is not clean
1062 0 : Kmesh%kptrlatt(:,:) = Dtset%kptrlatt(:,:)
1063 0 : Kmesh%nshift = Dtset%nshiftk
1064 0 : ABI_MALLOC(Kmesh%shift, (3, Kmesh%nshift))
1065 0 : Kmesh%shift(:,:) = Dtset%shiftk(:,1:Dtset%nshiftk)
1066 : !call Kmesh%print(units, header="K-mesh for the wavefunctions", prtvol=Dtset%prtvol)
1067 :
1068 : ! === Find Q-mesh ===
1069 : ! Stop if a nonzero umklapp is needed to reconstruct the BZ.
1070 : ! epsilon^-1(Sq) indeed should be symmetrized in csigme using a different expression (G-G_o is needed)
1071 0 : call qmesh%find_qmesh(cryst, Kmesh)
1072 : !call qmesh%print(units, "Q-mesh for the screening function", prtvol=dtset%prtvol)
1073 :
1074 : ! Transfer data from qmesh to gwr.
1075 0 : gwr%nqibz = qmesh%nibz
1076 0 : gwr%nqbz = qmesh%nbz
1077 :
1078 0 : call alloc_copy(qmesh%ibz, gwr%qibz)
1079 0 : call alloc_copy(qmesh%wt, gwr%wtq)
1080 0 : call alloc_copy(qmesh%bz, gwr%qbz)
1081 :
1082 0 : ABI_CHECK(all(abs(gwr%qibz(:,1)) < tol16), "First qpoint in qibz should be Gamma!")
1083 0 : gwr%ngqpt = -1
1084 :
1085 : ! Table with symrec conventions for the symmetrization of chi.
1086 0 : ABI_MALLOC(gwr%qbz2ibz, (6, gwr%nqbz))
1087 :
1088 0 : do iq_bz=1,Qmesh%nbz
1089 0 : call qmesh%get_bz_item(iq_bz, qbz, iq_ibz, isym, itim)
1090 0 : gwr%qbz2ibz(1, iq_bz) = iq_ibz
1091 0 : gwr%qbz2ibz(2, iq_bz) = isym
1092 0 : gwr%qbz2ibz(3:5, iq_bz) = zero
1093 : ! Note different conventions from itim between the Qmesh routines used in conventional GW and Abinit routines.
1094 0 : gwr%qbz2ibz(6, iq_bz) = merge(0, 1, itim == 1)
1095 0 : sq = (3-2*itim) * MATMUL(cryst%symrec(:,:,isym), qmesh%ibz(:,iq_ibz))
1096 0 : if (ANY(ABS(qbz-sq) > 1.0d-4)) then
1097 : write(msg,'(a,3f6.3,a,3f6.3,2a,9i3,a,i2,2a)')&
1098 0 : ' qpoint ',qbz,' is the symmetric of ',qmesh%ibz(:,iq_ibz),ch10,&
1099 0 : ' through operation ',cryst%symrec(:,:,isym),' and itim ',itim,ch10,&
1100 0 : ' however a non zero umklapp G_o vector is required and this is not yet allowed'
1101 0 : ABI_ERROR(msg)
1102 : end if
1103 : end do
1104 0 : call kmesh%free(); call qmesh%free()
1105 : end if
1106 :
1107 : ! Order qbz by stars and rearrange entries in qbz2ibz table.
1108 0 : call kpts_pack_in_stars(gwr%nqbz, gwr%qbz, gwr%qbz2ibz)
1109 0 : if (my_rank == master) then
1110 0 : call kpts_map_print(units, " Mapping qBZ --> qIBZ", "symrec", gwr%qbz, gwr%qibz, gwr%qbz2ibz, gwr%dtset%prtvol)
1111 : end if
1112 :
1113 : ! ==========================
1114 : ! Setup k-points in Sigma_nk
1115 : ! ==========================
1116 0 : gwr%ks_gaps = ks_ebands%get_gaps(gap_err)
1117 :
1118 0 : if (my_rank == master) call gwr%ks_gaps%print(units, header="Kohn-Sham gaps and band edges from IBZ mesh")
1119 :
1120 : ! TODO: nkcalc should be spin dependent.
1121 : ! This piece of code is taken from m_sigmaph.
1122 : ! In principle one should use the same algorithm in setup_sigma (legacy GW code).
1123 0 : if (dtset%nkptgw /= 0) then
1124 : ! Treat the k-points and bands specified in the input file via kptgw and bdgw.
1125 0 : call sigtk_kcalc_from_nkptgw(dtset, mband, gwr%nkcalc, gwr%kcalc, gwr%bstart_ks, gwr%nbcalc_ks)
1126 :
1127 : else
1128 0 : if (any(abs(dtset%sigma_erange) > zero)) then
1129 : ! Use sigma_erange and (optionally) sigma_ngkpt
1130 : call sigtk_kcalc_from_erange(dtset, cryst, ks_ebands, gwr%ks_gaps, &
1131 0 : gwr%nkcalc, gwr%kcalc, gwr%bstart_ks, gwr%nbcalc_ks, input_comm)
1132 :
1133 : else
1134 : ! Use qp_range to select the interesting k-points and the corresponding bands.
1135 : !
1136 : ! 0 --> Compute the QP corrections only for the fundamental and the direct gap.
1137 : ! +num --> Compute the QP corrections for all the k-points in the irreducible zone and include `num`
1138 : ! bands above and below the Fermi level.
1139 : ! -num --> Compute the QP corrections for all the k-points in the irreducible zone.
1140 : ! Include all occupied states and `num` empty states.
1141 :
1142 0 : qprange_ = dtset%gw_qprange
1143 0 : if (gap_err /= 0 .and. qprange_ == 0) then
1144 0 : ABI_WARNING("Cannot compute fundamental and direct gap (likely metal). Will replace qprange 0 with qprange 1")
1145 0 : qprange_ = 1
1146 : end if
1147 :
1148 0 : if (qprange_ /= 0) then
1149 0 : call sigtk_kcalc_from_qprange(dtset, cryst, ks_ebands, qprange_, gwr%nkcalc, gwr%kcalc, gwr%bstart_ks, gwr%nbcalc_ks)
1150 : else
1151 : ! qprange is not specified in the input.
1152 : ! Include direct and fundamental KS gap or include states depending on the position wrt band edges.
1153 0 : call sigtk_kcalc_from_gaps(dtset, ks_ebands, gwr%ks_gaps, gwr%nkcalc, gwr%kcalc, gwr%bstart_ks, gwr%nbcalc_ks)
1154 : end if
1155 : end if
1156 :
1157 : end if ! nkptgw /= 0
1158 :
1159 : ! Include all degenerate states and map kcalc to the IBZ. NB: This part is copied from sigmaph.
1160 :
1161 : ! The k-point and the symmetries connecting the BZ k-point to the IBZ.
1162 0 : ABI_MALLOC(gwr%kcalc2ibz, (gwr%nkcalc, 6))
1163 :
1164 : ! Workspace arrays used to compute degeneracy tables.
1165 0 : ABI_ICALLOC(degblock_all, (2, mband, gwr%nkcalc, gwr%nsppol))
1166 0 : ABI_ICALLOC(ndeg_all, (gwr%nkcalc, gwr%nsppol))
1167 :
1168 0 : ierr = 0
1169 0 : do ikcalc=1,gwr%nkcalc
1170 : ! Note symrel and use_symrel.
1171 : ! These are the conventions for the symmetrization of the wavefunctions used in cgtk_rotate.
1172 0 : kk = gwr%kcalc(:, ikcalc)
1173 :
1174 0 : if (kpts_map("symrel", kptopt, cryst, krank_ibz, 1, kk, indkk_k) /= 0) then
1175 : write(msg, '(5a)' ) &
1176 0 : "The WFK file cannot be used to compute self-energy corrections at k-point: ",trim(ktoa(kk)),ch10,&
1177 0 : "The k-point cannot be generated from a symmetrical one.", ch10
1178 0 : ABI_ERROR(msg)
1179 : end if
1180 :
1181 : ! TODO: Invert dims and update abipy
1182 0 : gwr%kcalc2ibz(ikcalc, :) = indkk_k(:, 1)
1183 :
1184 0 : ik_ibz = indkk_k(1,1); isym_k = indkk_k(2,1)
1185 0 : trev_k = indkk_k(6,1); g0_k = indkk_k(3:5,1)
1186 0 : isirr_k = (isym_k == 1 .and. trev_k == 0 .and. all(g0_k == 0))
1187 : !kk_ibz = ks_ebands%kptns(:,ik_ibz)
1188 : if (.not. isirr_k) then
1189 0 : ABI_WARNING(sjoin("The k-point in Sigma_{nk} must be in the IBZ but got:", ktoa(kk)))
1190 0 : ierr = ierr + 1
1191 : end if
1192 :
1193 : ! We will have to average the QP corrections over degenerate states if symsigma=1 is used.
1194 : ! Here we make sure that all the degenerate states are included.
1195 : ! Store also band indices of the degenerate sets, used to average final results.
1196 0 : if (abs(gwr%dtset%symsigma) == 1) then
1197 0 : cnt = 0
1198 0 : do spin=1,gwr%nsppol
1199 0 : bstop = gwr%bstart_ks(ikcalc, spin) + gwr%nbcalc_ks(ikcalc, spin) - 1
1200 : call ks_ebands%enclose_degbands(ik_ibz, spin, gwr%bstart_ks(ikcalc, spin), bstop, changed, gwr%dtset%symsigma_de, &
1201 0 : degblock=degblock)
1202 0 : if (changed) then
1203 0 : gwr%nbcalc_ks(ikcalc, spin) = bstop - gwr%bstart_ks(ikcalc, spin) + 1
1204 0 : cnt = cnt + 1
1205 0 : if (cnt < 5) then
1206 : write(msg,'(2(a,i0),2a,2(1x,i0))') &
1207 0 : "Not all the degenerate states for ikcalc: ",ikcalc,", spin: ",spin,ch10, &
1208 0 : "were included in the bdgw set. bdgw has been automatically changed to: ",gwr%bstart_ks(ikcalc, spin), bstop
1209 0 : ABI_COMMENT(msg)
1210 : end if
1211 : write(msg,'(2(a,i0),2a)') &
1212 0 : "The number of included states: ", bstop, &
1213 0 : " is larger than the number of bands in the input ",dtset%nband(ik_ibz + (spin-1)*ks_ebands%nkpt),ch10,&
1214 0 : "Action: Increase nband."
1215 0 : ABI_CHECK(bstop <= dtset%nband(ik_ibz + (spin-1)*ks_ebands%nkpt), msg)
1216 : end if
1217 :
1218 : ! Store band indices used for averaging (shifted by bstart_ks)
1219 0 : ndeg = size(degblock, dim=2)
1220 0 : ndeg_all(ikcalc, spin) = ndeg
1221 0 : degblock_all(:, 1:ndeg, ikcalc, spin) = degblock(:, 1:ndeg)
1222 :
1223 0 : ABI_FREE(degblock)
1224 : end do
1225 : end if ! symsigma
1226 : end do ! ikcalc
1227 :
1228 0 : ABI_CHECK(ierr == 0, "kptgw wavevectors must be in the IBZ read from the WFK file.")
1229 :
1230 : ! Build degtab tables to average self-energy matrix element if symsigma /= 0
1231 0 : if (abs(gwr%dtset%symsigma) == 1) then
1232 0 : ABI_MALLOC(gwr%degtab, (gwr%nkcalc, gwr%nsppol))
1233 0 : do ikcalc=1,gwr%nkcalc
1234 0 : do spin=1,gwr%nsppol
1235 0 : ndeg = ndeg_all(ikcalc, spin)
1236 0 : ABI_MALLOC(gwr%degtab(ikcalc, spin)%bids, (ndeg))
1237 0 : do ii=1,ndeg
1238 0 : cnt = degblock_all(2, ii, ikcalc, spin) - degblock_all(1, ii, ikcalc, spin) + 1
1239 0 : ABI_MALLOC(gwr%degtab(ikcalc, spin)%bids(ii)%vals, (cnt))
1240 : ! Note that we start to count bands from bstart_ks(ikcalc, spin)
1241 : gwr%degtab(ikcalc, spin)%bids(ii)%vals = [(jj, jj= &
1242 0 : degblock_all(1, ii, ikcalc, spin), degblock_all(2, ii, ikcalc, spin))]
1243 : end do
1244 : end do
1245 : end do
1246 : end if
1247 :
1248 0 : ABI_FREE(degblock_all)
1249 0 : ABI_FREE(ndeg_all)
1250 :
1251 : ! Now we can finally compute max_nbcalc.
1252 0 : gwr%max_nbcalc = maxval(gwr%nbcalc_ks)
1253 0 : ABI_MALLOC(gwr%bstop_ks, (gwr%nkcalc, gwr%nsppol))
1254 0 : gwr%bstop_ks = gwr%bstart_ks + gwr%nbcalc_ks - 1
1255 0 : gwr%b1gw = minval(gwr%bstart_ks); gwr%b2gw = maxval(gwr%bstop_ks)
1256 :
1257 0 : call krank_ibz%free()
1258 0 : ABI_FREE(kibz) ! Deallocate kibz here because krank_ibz keeps a reference to this array.
1259 :
1260 : ! ================================
1261 : ! Setup tau/omega mesh and weights
1262 : ! ================================
1263 : ! Compute min/max transition energy taking into account nsppol if any.
1264 0 : gwr%te_min = minval(gwr%ks_gaps%cb_min - gwr%ks_gaps%vb_max)
1265 0 : gwr%te_max = maxval(ks_ebands%eig(nbsum,:,:) - ks_ebands%eig(1,:,:))
1266 0 : if (gwr%te_min <= tol6) then
1267 0 : gwr%te_min = tol6
1268 0 : ABI_ERROR("System is metallic or with a very small fundamental gap! Check energies in WFK file!")
1269 : end if
1270 0 : gwr%ntau = dtset%gwr_ntau
1271 :
1272 0 : regterm = dtset%gwr_regterm
1273 0 : if (regterm > -tol16) then
1274 0 : call wrtout(std_out, sjoin("Computing minimax grid with user-provided regterm:", ftoa(regterm)))
1275 : call gx_minimax_grid(gwr%ntau, gwr%te_min, gwr%te_max, & ! in
1276 : gwr%tau_mesh, gwr%tau_wgs, gwr%iw_mesh, gwr%iw_wgs, & ! out args allocated by the routine.
1277 : gwr%cosft_wt, gwr%cosft_tw, gwr%sinft_wt, &
1278 0 : gwr%ft_max_error, gwr%cosft_duality_error, ierr, regterm=regterm)
1279 0 : ABI_CHECK(ierr == 0, "Error in gx_minimax_grid")
1280 : else
1281 0 : regterm = zero
1282 0 : call wrtout(std_out, sjoin("Computing minimax grid with user-provided regterm:", ftoa(regterm)))
1283 : call gx_minimax_grid(gwr%ntau, gwr%te_min, gwr%te_max, & ! in
1284 : gwr%tau_mesh, gwr%tau_wgs, gwr%iw_mesh, gwr%iw_wgs, & ! out args allocated by the routine.
1285 : gwr%cosft_wt, gwr%cosft_tw, gwr%sinft_wt, &
1286 0 : gwr%ft_max_error, gwr%cosft_duality_error, ierr, regterm=regterm)
1287 0 : ABI_CHECK(ierr == 0, "Error in gx_minimax_grid")
1288 :
1289 : ! If duality error is big, use regterm = 1e-6
1290 0 : if (gwr%cosft_duality_error > half) then
1291 0 : ABI_SFREE(gwr%tau_mesh)
1292 0 : ABI_SFREE(gwr%tau_wgs)
1293 0 : ABI_SFREE(gwr%iw_mesh)
1294 0 : ABI_SFREE(gwr%iw_wgs)
1295 0 : ABI_SFREE(gwr%cosft_wt)
1296 0 : ABI_SFREE(gwr%cosft_tw)
1297 0 : ABI_SFREE(gwr%sinft_wt)
1298 0 : regterm = tol6
1299 0 : call wrtout(std_out, sjoin("LARGE duality error -> recomputing minimax grid with regterm:", ftoa(regterm)))
1300 0 : prev_dual_error = gwr%cosft_duality_error
1301 : call gx_minimax_grid(gwr%ntau, gwr%te_min, gwr%te_max, & ! in
1302 : gwr%tau_mesh, gwr%tau_wgs, gwr%iw_mesh, gwr%iw_wgs, & ! out args allocated by the routine.
1303 : gwr%cosft_wt, gwr%cosft_tw, gwr%sinft_wt, &
1304 0 : gwr%ft_max_error, gwr%cosft_duality_error, ierr, regterm=regterm)
1305 0 : ABI_CHECK(ierr == 0, "Error in gx_minimax_grid")
1306 :
1307 0 : if (gwr%cosft_duality_error > prev_dual_error) then
1308 0 : ABI_WARNING("Using regterm didn't decrease the duality error")
1309 : end if
1310 : end if
1311 : end if
1312 :
1313 0 : if (gwr%comm%me == 0) then
1314 : ! Print some info on errors.
1315 0 : write(std_out, "(3a)")ch10, " Computing F(delta) = \int_0^{\infty} dw / (w^2 + delta^2) = pi/2/delta ", ch10
1316 0 : write(std_out, "(*(a12,2x))")"delta", "numeric", "exact", "abs_rerr (%)"
1317 0 : do ii=1,10
1318 0 : delta = (ii * gwr%te_min)
1319 0 : eval_int = sum(gwr%iw_wgs(:) / (gwr%iw_mesh(:)**2 + delta**2))
1320 0 : exact_int = pi / (two * delta)
1321 0 : abs_rerr = 100 * abs(eval_int - exact_int) / exact_int
1322 0 : write(std_out, "(*(es12.5,2x))") delta, eval_int, exact_int, abs_rerr
1323 : end do
1324 :
1325 0 : write(std_out, "(3a)")ch10," Computing F(w) = \int_0^{\infty} e^{-w tau} dtau", ch10
1326 0 : write(std_out, "(*(a12,2x))")"w", "numeric", "exact", "abs_rerr (%)"
1327 0 : do itau=1,gwr%ntau
1328 0 : eval_int = sum(gwr%tau_wgs(:) * exp(-gwr%tau_mesh(:) * gwr%iw_mesh(itau)))
1329 0 : exact_int = one / gwr%iw_mesh(itau)
1330 0 : abs_rerr = 100 * abs(eval_int - exact_int) / exact_int
1331 0 : write(std_out, "(*(es12.5,2x))") gwr%iw_mesh(itau), eval_int, exact_int, abs_rerr
1332 : end do
1333 0 : write(std_out, "(a)")
1334 : end if
1335 :
1336 : ! =========================================
1337 : ! Find FFT mesh and max number of g-vectors
1338 : ! =========================================
1339 : ! Note the usage of gwr_boxcutmin and the loops over the full BZ.
1340 0 : gwr%g_ngfft = gwr%dtset%ngfft; gwr%g_ngfft(1:6) = 0 ! Allow user to specify fftalg
1341 :
1342 0 : gwr%green_mpw = -1
1343 0 : do ik_bz=1,gwr%nkbz
1344 0 : kk_bz = gwr%kbz(:, ik_bz)
1345 0 : call get_kg(kk_bz, istwfk1, dtset%ecutwfn, gwr%cryst%gmet, npw_, gvec_)
1346 0 : ABI_FREE(gvec_)
1347 : call getng(dtset%gwr_boxcutmin, dtset%chksymtnons, dtset%ecutwfn, cryst%gmet, &
1348 : kk_bz, me_fft0, gwr%g_mgfft, gwr%g_nfft, gwr%g_ngfft, nproc_fft1, cryst%nsym, paral_fft0, &
1349 0 : cryst%symrel, cryst%tnons, gpu_option=gwr%dtset%gpu_option, unit=dev_null)
1350 0 : gwr%green_mpw = max(gwr%green_mpw, npw_)
1351 : end do
1352 :
1353 0 : gwr%tchi_mpw = -1
1354 0 : do iq_bz=1,gwr%nqbz
1355 0 : qq_bz = gwr%qbz(:, iq_bz)
1356 0 : call get_kg(qq_bz, istwfk1, dtset%ecuteps, gwr%cryst%gmet, npw_, gvec_)
1357 0 : ABI_FREE(gvec_)
1358 : call getng(dtset%gwr_boxcutmin, dtset%chksymtnons, dtset%ecuteps, cryst%gmet, &
1359 : qq_bz, me_fft0, gwr%g_mgfft, gwr%g_nfft, gwr%g_ngfft, nproc_fft1, cryst%nsym, &
1360 0 : paral_fft0, cryst%symrel, cryst%tnons, gpu_option=gwr%dtset%gpu_option, unit=dev_null)
1361 0 : gwr%tchi_mpw = max(gwr%tchi_mpw, npw_)
1362 0 : if (iq_bz == 1) then
1363 0 : ABI_CHECK(all(abs(qq_bz) < tol16), "First qpoint in the qbz should be Gamma!")
1364 : end if
1365 : end do
1366 :
1367 : ! No augmentation of workspace arrays.
1368 0 : gwr%g_ngfft(4:6) = gwr%g_ngfft(1:3)
1369 :
1370 : ! ========================
1371 : ! === MPI DISTRIBUTION ===
1372 : ! ========================
1373 : !
1374 : ! Here we define the following quantities:
1375 : ! - np_k, np_g, np_t, np_s
1376 : ! - gwr%comm and gwr%idle_proc
1377 : !
1378 : ! NB: Do not use input_comm after this section as idle processors return immediately.
1379 :
1380 0 : if (any(dtset%gwr_np_kgts /= 0)) then
1381 : ! Use grid from input file.
1382 0 : np_k = dtset%gwr_np_kgts(1); np_g = dtset%gwr_np_kgts(2); np_t = dtset%gwr_np_kgts(3); np_s = dtset%gwr_np_kgts(4)
1383 : !call xmpi_comm_multiple_of(product(dtset%gwr_np_kgts), input_comm, gwr%idle_proc, gwr%comm)
1384 : !if (gwr%idle_proc) return
1385 0 : gwr%comm = xcomm_from_mpi_int(input_comm)
1386 0 : all_nproc = gwr%comm%nproc
1387 :
1388 : else
1389 : ! Automatic grid generation.
1390 : !
1391 : ! Priorities | MPI Scalability | Memory
1392 : ! ==================================================================================================
1393 : ! spin (if any) | excellent | scales
1394 : ! g/r (PBLAS) | network-intensive ! scales
1395 : ! tau | excellent | scales
1396 : ! kbz | newtwork-intensive | scales (depends on the BZ -> IBZ mapping)
1397 :
1398 0 : gwr%comm = xcomm_from_mpi_int(input_comm)
1399 0 : all_nproc = gwr%comm%nproc
1400 : !call xmpi_comm_multiple_of(gwr%ntau * gwr%dtset%nsppol, input_comm, gwr%idle_proc, gwr%comm)
1401 : !if (gwr%idle_proc) return
1402 : !all_nproc = xmpi_comm_size(gwr%comm)
1403 :
1404 : ! Start from a configuration that minimizes memory i.e use all procs for g-parallelism,
1405 : ! then check whether it's possible to move some procs to the other levels
1406 : ! without spoiling parallel efficiency and/or increasing memory per MPI proc.
1407 : ! Only master rank works here for consistency reasons.
1408 0 : if (my_rank == master) then
1409 0 : dims_kgts = [1, all_nproc, 1, 1]
1410 0 : est = estimate(gwr, dims_kgts)
1411 0 : prev_efficiency = est%efficiency; prev_speedup = est%speedup
1412 0 : call wrtout(units, sjoin("- Optimizing MPI grid with mem_per_cpu_mb:", ftoa(mem_per_cpu_mb), "[Mb]"), pre_newlines=1)
1413 0 : call wrtout(units, "- Use `abinit run.abi --mem-per-cpu=4G` to set mem_per_cpu_mb in the submission script")
1414 0 : write(msg, "(a,4(a4,2x),3(a12,2x))") "- ", "np_k", "np_g", "np_t", "np_s", "memb_per_cpu", "efficiency", "speedup"
1415 0 : call wrtout(units, msg)
1416 0 : ip_k = dims_kgts(1); ip_g = dims_kgts(2); ip_t = dims_kgts(3); ip_s = dims_kgts(4)
1417 0 : write(msg, "(a,4(i4,2x),3(es12.5,2x))") "- ", ip_k, ip_g, ip_t, ip_s, est%mem_total, est%efficiency, est%speedup
1418 0 : call wrtout(units, msg)
1419 :
1420 0 : do ip_s=1,gwr%nsppol
1421 0 : do ip_t=1,gwr%ntau
1422 0 : if (mod(gwr%ntau, ip_t) /= 0) cycle ! ip_t should divide gwr%ntau.
1423 0 : do ip_k=1,gwr%nkbz
1424 0 : if (mod(gwr%nkbz, ip_k) /= 0) cycle ! ip_k is should divide gwr%nkbz.
1425 0 : do ip_g=1,gwr%green_mpw
1426 0 : try_dims_kgts = [ip_k, ip_g, ip_t, ip_s]
1427 0 : if (product(try_dims_kgts) /= all_nproc .or. all(try_dims_kgts == dims_kgts)) cycle
1428 : !ABI_CHECK(block_dist_1d(gwr%green_mpw, ip_g, col_bsize, msg), msg)
1429 0 : est = estimate(gwr, try_dims_kgts)
1430 : !if (est%mem_total < mem_per_cpu_mb * 0.8_dp .and. est%efficiency > prev_efficiency) then
1431 0 : if (est%mem_total < mem_per_cpu_mb * 0.8_dp .and. est%speedup > prev_speedup) then
1432 0 : prev_efficiency = est%efficiency; prev_speedup = est%speedup; dims_kgts = try_dims_kgts
1433 : end if
1434 0 : write(msg,"(a,4(i4,2x),3(es12.5,2x))")"- ", ip_k, ip_g, ip_t, ip_s, est%mem_total, est%efficiency, est%speedup
1435 0 : call wrtout(units, msg)
1436 : end do
1437 : end do
1438 : end do
1439 : end do
1440 : end if ! master
1441 :
1442 0 : call xmpi_bcast(dims_kgts, master, gwr%comm%value, ierr)
1443 0 : np_k = dims_kgts(1); np_g = dims_kgts(2); np_t = dims_kgts(3); np_s = dims_kgts(4)
1444 :
1445 0 : if (my_rank == master) then
1446 0 : est = estimate(gwr, dims_kgts)
1447 0 : call wrtout(units, "-")
1448 0 : call wrtout(units, "- Selected MPI grid:")
1449 0 : ip_k = dims_kgts(1); ip_g = dims_kgts(2); ip_t = dims_kgts(3); ip_s = dims_kgts(4)
1450 0 : write(msg, "(a,4(a4,2x),3(a12,2x))") "- ", "np_k", "np_g", "np_t", "np_s", "memb_per_cpu", "efficiency", "speedup"
1451 0 : call wrtout(units, msg)
1452 0 : write(msg, "(a,4(i4,2x),3(es12.5,2x))")"- ", ip_k, ip_g, ip_t, ip_s, est%mem_total, est%efficiency, est%speedup
1453 0 : call wrtout(units, msg, newlines=1)
1454 0 : call est%print(units)
1455 : end if
1456 : end if
1457 :
1458 : ! ================================
1459 : ! Build MPI grid and communicators
1460 : ! ================================
1461 0 : dims_kgts = [np_k, np_g, np_t, np_s]
1462 0 : gwr%dtset%gwr_np_kgts = dims_kgts
1463 0 : periods(:) = .False.; reorder = .False.
1464 :
1465 : ! Consistency check.
1466 0 : if (product(dims_kgts) /= all_nproc) then
1467 : write(msg, "(a,i0,3a, 5(a,1x,i0))") &
1468 0 : "Cannot create 4D Cartesian grid with total nproc: ", all_nproc, ch10, &
1469 0 : "Idle MPI processes are not supported. The product of the `nproc_*` vars should be equal to nproc while is it:", ch10, &
1470 0 : "k_nproc (", np_k, ") x g_nproc (", np_g, ") x tau_nproc (", np_t,") x spin_nproc (", np_s, ") == ", product(dims_kgts)
1471 0 : ABI_ERROR(msg)
1472 : end if
1473 :
1474 : !!! FIXME HT: rewrite spin logic in redistribution routines
1475 0 : if (gwr%nspinor == 2 .and. np_s == 2) then
1476 0 : ABI_ERROR("Spin parallelism is not supported for nspinor=2 for now!")
1477 : end if
1478 :
1479 : #ifdef HAVE_MPI
1480 : block
1481 : !integer,parameter :: k=1, g=2, t=3, s=4 ! Bad placement
1482 : integer,parameter :: k=4, g=3, t=2, s=1 ! Much better placement
1483 0 : dims_kgts = dims_kgts(4:1:-1)
1484 0 : call MPI_CART_CREATE(gwr%comm%value, ndims, dims_kgts, periods, reorder, comm_cart, ierr)
1485 :
1486 : ! Find the index and coordinates of the current processor
1487 0 : call MPI_COMM_RANK(comm_cart, me_cart, ierr)
1488 0 : call MPI_CART_COORDS(comm_cart, me_cart, ndims, gwr%coords_stgk, ierr)
1489 :
1490 : ! k-point communicator
1491 0 : keepdim = .False.; keepdim(k) = .True.; call gwr%kpt_comm%from_cart_sub(comm_cart, keepdim)
1492 : ! g-communicator
1493 0 : keepdim = .False.; keepdim(g) = .True.; call gwr%g_comm%from_cart_sub(comm_cart, keepdim)
1494 : ! tau-communicator
1495 0 : keepdim = .False.; keepdim(t) = .True.; call gwr%tau_comm%from_cart_sub(comm_cart, keepdim)
1496 : ! spin-communicator
1497 0 : keepdim = .False.; keepdim(s) = .True.; call gwr%spin_comm%from_cart_sub(comm_cart, keepdim)
1498 : ! Communicator for the g-tau 2D grid.
1499 0 : keepdim = .False.; keepdim(g) = .True.; keepdim(t) = .True.; call gwr%gtau_comm%from_cart_sub(comm_cart, keepdim)
1500 : ! Communicator for the k-g 2D grid.
1501 0 : keepdim = .False.; keepdim(k) = .True.; keepdim(g) = .True.; call gwr%kg_comm%from_cart_sub(comm_cart, keepdim)
1502 : ! Communicator for the k-g-tau 3D subgrid.
1503 0 : keepdim = .True.; keepdim(s) = .False.; call gwr%kgt_comm%from_cart_sub(comm_cart, keepdim)
1504 : ! Communicator for the k-tau-spin 3D subgrid.
1505 0 : keepdim = .True.; keepdim(g) = .False.; call gwr%kts_comm%from_cart_sub(comm_cart, keepdim)
1506 0 : call xmpi_comm_free(comm_cart)
1507 : end block
1508 : #endif
1509 :
1510 0 : call wrtout(units, sjoin("P kpt_comm can use shmem:", yesno(gwr%kpt_comm%can_use_shmem())))
1511 0 : call wrtout(units, sjoin("P g_comm can use shmem:", yesno(gwr%g_comm%can_use_shmem())))
1512 0 : call wrtout(units, sjoin("P tau_comm can use shmem:", yesno(gwr%tau_comm%can_use_shmem())))
1513 0 : call wrtout(units, sjoin("P spin_comm can use shmem", yesno(gwr%spin_comm%can_use_shmem())))
1514 : !call gwr%kpt_comm%print_names(); call gwr%g_comm%print_names()
1515 :
1516 : ! Define batch sizes for FFT transforms taking into account k-point parallelism, OpenMP threads and GPUs.
1517 0 : omp_nt = xomp_get_num_threads(open_parallel=.True.)
1518 :
1519 0 : if (gwr%dtset%gwr_ucsc_batch(1) > 0) then
1520 : ! Take it from input file (user is always right)
1521 0 : gwr%uc_batch_size = gwr%dtset%gwr_ucsc_batch(1) * omp_nt
1522 : else
1523 : ! Automatic detection
1524 0 : gwr%uc_batch_size = 1 * omp_nt
1525 0 : if (gwr%dtset%gpu_option /= ABI_GPU_DISABLED) then
1526 : ! TODO: Optimize
1527 0 : gwr%uc_batch_size = 4 * omp_nt
1528 : !gwr%uc_batch_size = 1
1529 : end if
1530 : end if
1531 :
1532 0 : if (gwr%dtset%gwr_ucsc_batch(2) > 0) then
1533 : ! Take it from input file (user is always right)
1534 0 : gwr%sc_batch_size = gwr%dtset%gwr_ucsc_batch(2) * omp_nt
1535 : else
1536 : ! Automatic detection
1537 0 : gwr%sc_batch_size = 1 * omp_nt
1538 0 : if (gwr%dtset%gpu_option /= ABI_GPU_DISABLED) then
1539 : ! TODO: Optimize
1540 0 : gwr%sc_batch_size = 4 * omp_nt
1541 : !gwr%sc_batch_size = 1
1542 : end if
1543 : end if
1544 :
1545 : ! Make sure all procs agree.
1546 : !call xmpi_min_ip(gwr%sc_batch_size, gwr%comm%value, ierr)
1547 : !call xmpi_min_ip(gwr%uc_batch_size, gwr%comm%value, ierr)
1548 :
1549 0 : if (my_rank == master) then
1550 0 : call print_ngfft([std_out], gwr%g_ngfft, header="FFT mesh for Green's function")
1551 0 : call wrtout(units, sjoin("- FFT uc_batch_size:", itoa(gwr%uc_batch_size)))
1552 0 : call wrtout(units, sjoin("- FFT sc_batch_size:", itoa(gwr%sc_batch_size)))
1553 : end if
1554 :
1555 : ! Block-distribute dimensions and allocate redirection table local index --> global index.
1556 0 : call xmpi_split_block(gwr%ntau, gwr%tau_comm%value, gwr%my_ntau, gwr%my_itaus)
1557 0 : ABI_CHECK(gwr%my_ntau > 0, "my_ntau == 0, decrease number of procs for tau level")
1558 :
1559 : ! Store the rank of the MPI proc in tau_comm treating the itau index.
1560 0 : ABI_MALLOC(gwr%tau_master, (gwr%ntau))
1561 0 : gwr%tau_master = -1
1562 0 : do my_it=1,gwr%my_ntau
1563 0 : itau = gwr%my_itaus(my_it); gwr%tau_master(itau) = gwr%tau_comm%me
1564 : end do
1565 0 : call xmpi_max_ip(gwr%tau_master, gwr%tau_comm%value, ierr)
1566 0 : ABI_CHECK(all(gwr%tau_master > -1), "tau_master!")
1567 :
1568 0 : call xmpi_split_block(gwr%nsppol, gwr%spin_comm%value, gwr%my_nspins, gwr%my_spins)
1569 0 : ABI_CHECK(gwr%my_nspins > 0, "my_nspins == 0, decrease number of MPI procs for spin level")
1570 :
1571 : ! Distribute k-points in the full BZ and build redirection tables.
1572 : ! Finally, find the number of IBZ k-points treated by this MPI rank.
1573 0 : call xmpi_split_block(gwr%nkbz, gwr%kpt_comm%value, gwr%my_nkbz, gwr%my_kbz_inds)
1574 0 : ABI_CHECK(gwr%my_nkbz > 0, "my_nkbz == 0, decrease number of MPI procs for k-point level")
1575 :
1576 : ! Compute np_kibz
1577 0 : ABI_ICALLOC(gwr%np_kibz, (gwr%nkibz))
1578 0 : do my_ikf=1,gwr%my_nkbz
1579 0 : ik_bz = gwr%my_kbz_inds(my_ikf); ik_ibz = gwr%kbz2ibz(1, ik_bz)
1580 0 : gwr%np_kibz(ik_ibz) = 1
1581 : end do
1582 :
1583 0 : gwr%my_nkibz = count(gwr%np_kibz > 0)
1584 0 : ABI_MALLOC(gwr%my_kibz_inds, (gwr%my_nkibz))
1585 0 : ii = 0
1586 0 : do ik_ibz=1,gwr%nkibz
1587 0 : if (gwr%np_kibz(ik_ibz) > 0) then
1588 0 : ii = ii + 1; gwr%my_kibz_inds(ii) = ik_ibz
1589 : end if
1590 : end do
1591 :
1592 0 : call xmpi_sum(gwr%np_kibz, gwr%kpt_comm%value, ierr)
1593 :
1594 : ! Build table to distribute iterations over ik_ibz as kIBZ might be replicated across MPI procs.
1595 0 : ABI_ICALLOC(iwork, (gwr%kpt_comm%nproc, gwr%nkibz))
1596 0 : ABI_ICALLOC(got, (gwr%kpt_comm%nproc))
1597 0 : do my_iki=1,gwr%my_nkibz
1598 0 : ik_ibz = gwr%my_kibz_inds(my_iki)
1599 0 : iwork(gwr%kpt_comm%me + 1, ik_ibz) = 1
1600 : end do
1601 0 : call xmpi_sum(iwork, gwr%kpt_comm%value, ierr)
1602 :
1603 0 : ABI_MALLOC(gwr%itreat_ikibz, (gwr%nkibz))
1604 0 : gwr%itreat_ikibz = .False.
1605 0 : do ik_ibz=1,gwr%nkibz
1606 0 : ii = imin_loc(got, mask=iwork(:, ik_ibz) /= 0); got(ii) = got(ii) + 1
1607 0 : if (ii == gwr%kpt_comm%me + 1) gwr%itreat_ikibz(ik_ibz) = .True.
1608 : end do
1609 0 : ABI_FREE(got)
1610 0 : ABI_FREE(iwork)
1611 :
1612 : ! Distribute q-points in full BZ, transfer symmetry tables.
1613 : ! Finally find the number of my IBZ q-points that should be stored in memory.
1614 0 : call xmpi_split_block(gwr%nqbz, gwr%kpt_comm%value, gwr%my_nqbz, gwr%my_qbz_inds)
1615 :
1616 : ! Compute np_qibz
1617 0 : ABI_ICALLOC(gwr%np_qibz, (gwr%nqibz))
1618 0 : do my_iqf=1,gwr%my_nqbz
1619 0 : iq_bz = gwr%my_qbz_inds(my_iqf); iq_ibz = gwr%qbz2ibz(1, iq_bz)
1620 0 : gwr%np_qibz(iq_ibz) = 1
1621 : end do
1622 :
1623 0 : gwr%my_nqibz = count(gwr%np_qibz > 0)
1624 0 : ABI_MALLOC(gwr%my_qibz_inds, (gwr%my_nqibz))
1625 0 : ii = 0
1626 0 : do iq_ibz=1,gwr%nqibz
1627 0 : if (gwr%np_qibz(iq_ibz) > 0) then
1628 0 : ii = ii + 1; gwr%my_qibz_inds(ii) = iq_ibz
1629 : end if
1630 : end do
1631 :
1632 0 : call xmpi_sum(gwr%np_qibz, gwr%kpt_comm%value, ierr)
1633 :
1634 : ! Build table to distribute iterations over iq_ibz as qIBZ might be replicated.
1635 0 : ABI_ICALLOC(iwork, (gwr%kpt_comm%nproc, gwr%nqibz))
1636 0 : ABI_ICALLOC(got, (gwr%kpt_comm%nproc))
1637 0 : do my_iqi=1,gwr%my_nqibz
1638 0 : iq_ibz = gwr%my_qibz_inds(my_iqi)
1639 0 : iwork(gwr%kpt_comm%me + 1, iq_ibz) = 1
1640 : end do
1641 0 : call xmpi_sum(iwork, gwr%kpt_comm%value, ierr)
1642 :
1643 0 : ABI_MALLOC(gwr%itreat_iqibz, (gwr%nqibz))
1644 0 : gwr%itreat_iqibz = .False.
1645 0 : do iq_ibz=1,gwr%nqibz
1646 0 : ii = imin_loc(got, mask=iwork(:, iq_ibz) /= 0); got(ii) = got(ii) + 1
1647 0 : if (ii == gwr%kpt_comm%me + 1) gwr%itreat_iqibz(iq_ibz) = .True.
1648 : end do
1649 0 : ABI_FREE(got)
1650 0 : ABI_FREE(iwork)
1651 :
1652 : ! Initialize Coulomb interaction.
1653 : ! Note: MC integration should not be used when computing epsilon, only when integrating in q-space.
1654 0 : vc_ecut = max(dtset%ecutsigx, dtset%ecuteps)
1655 0 : gw_icutcoul_ = dtset%gw_icutcoul
1656 :
1657 0 : gwr%has_vcgen_sigma = .False.
1658 0 : if (any(gw_icutcoul_ == [14, 15, 16])) then
1659 0 : gw_icutcoul_ = mod(gw_icutcoul_, 10); gwr%has_vcgen_sigma = .True.
1660 : end if
1661 :
1662 : call gwr%vcgen_eps%init(cryst, ks_ebands%kptrlatt, gwr%nkbz, gwr%nqibz, gwr%nqbz, gwr%qbz, &
1663 0 : dtset%gw_rcut, gw_icutcoul_, dtset%vcutgeo, vc_ecut, gwr%comm%value)
1664 :
1665 0 : if (gwr%has_vcgen_sigma) then
1666 : ! Note dtset%gw_icutcoul here.
1667 : call gwr%vcgen_sigma%init(cryst, ks_ebands%kptrlatt, gwr%nkbz, gwr%nqibz, gwr%nqbz, gwr%qbz, &
1668 0 : dtset%gw_rcut, dtset%gw_icutcoul, dtset%vcutgeo, vc_ecut, gwr%comm%value)
1669 : end if
1670 :
1671 : ! Now we know the value of g_ngfft. Setup tables for zero-padded FFTs.
1672 : ! Build descriptors for Green's functions and tchi and setup tables for zero-padded FFTs.
1673 0 : ABI_MALLOC(gwr%green_desc_kibz, (gwr%nkibz))
1674 :
1675 0 : do my_iki=1,gwr%my_nkibz
1676 0 : ik_ibz = gwr%my_kibz_inds(my_iki); kk_ibz = gwr%kibz(:, ik_ibz)
1677 0 : call gwr%green_desc_kibz(ik_ibz)%init(kk_ibz, istwfk1, dtset%ecutwfn, gwr, kin_sorted=.False.)
1678 : end do
1679 :
1680 0 : ABI_MALLOC(gwr%tchi_desc_qibz, (gwr%nqibz))
1681 0 : ABI_ICALLOC(gwr%chinpw_qibz, (gwr%nqibz))
1682 :
1683 0 : do my_iqi=1,gwr%my_nqibz
1684 0 : iq_ibz = gwr%my_qibz_inds(my_iqi); qq_ibz = gwr%qibz(:, iq_ibz)
1685 : ! Note ecuteps instead of ecut. Also, sort the g-vectors by |q+g|^2/2 when q is in the IBZ to facilitate
1686 : ! the extrapolation of the RPA energy as a function of ecut_chi
1687 0 : call gwr%tchi_desc_qibz(iq_ibz)%init(qq_ibz, istwfk1, dtset%ecuteps, gwr, kin_sorted=.True., rot=.True.)
1688 :
1689 : ! Compute sqrt(vc(q,G))
1690 0 : associate (desc_q => gwr%tchi_desc_qibz(iq_ibz))
1691 0 : if (gwr%itreat_iqibz(iq_ibz)) gwr%chinpw_qibz(iq_ibz) = desc_q%npw
1692 0 : q_is_gamma = (normv(qq_ibz, gwr%cryst%gmet, "G") < GW_TOLQ0)
1693 0 : call desc_q%get_vc_sqrt(qq_ibz, q_is_gamma, gwr, "epsilon", gwr%gtau_comm%value)
1694 0 : if (gwr%has_vcgen_sigma) then
1695 0 : call desc_q%get_vc_sqrt(qq_ibz, q_is_gamma, gwr, "sigma", gwr%gtau_comm%value)
1696 : end if
1697 : end associate
1698 : end do
1699 :
1700 : ! Collect npwq on all procs
1701 0 : call xmpi_sum(gwr%chinpw_qibz, gwr%comm%value, ierr)
1702 :
1703 : ! Init 1D PBLAS grid to block-distribute matrices along columns.
1704 0 : call gwr%g_slkproc%init(gwr%g_comm%value, grid_dims=[1, gwr%g_comm%nproc])
1705 0 : call gwr%gtau_slkproc%init(gwr%gtau_comm%value, grid_dims=[1, gwr%gtau_comm%nproc])
1706 :
1707 : ! ==================================
1708 : ! Allocate arrays of PBLAS matrices
1709 : ! ==================================
1710 0 : ABI_MALLOC(gwr%gt_kibz, (2, gwr%nkibz, gwr%ntau, gwr%nsppol, gwr%nsig_ab))
1711 0 : ABI_MALLOC(gwr%tchi_qibz, (gwr%nqibz, gwr%ntau, gwr%nsppol))
1712 0 : ABI_MALLOC(gwr%sigc_kibz, (2, gwr%nkibz, gwr%ntau, gwr%nsppol, gwr%nsig_ab))
1713 :
1714 : ! ====================================
1715 : ! Create netcdf file to store results
1716 : ! ====================================
1717 0 : gwr%gwrnc_write = .True.
1718 : !gwr%gwrnc_write = .False.
1719 0 : gwr%gwrnc_path = strcat(dtfil%filnam_ds(4), "_GWR.nc")
1720 :
1721 0 : if (my_rank == master .and. gwr%gwrnc_write) then
1722 0 : call gwr%print(units)
1723 0 : NCF_CHECK(nctk_open_create(ncid, gwr%gwrnc_path, xmpi_comm_self))
1724 : ! Write structure and ebands
1725 0 : NCF_CHECK(cryst%ncwrite(ncid))
1726 0 : NCF_CHECK(ks_ebands%ncwrite(ncid))
1727 :
1728 : ! Add GWR dimensions.
1729 0 : smat_bsize1 = gwr%b2gw - gwr%b1gw + 1
1730 0 : smat_bsize2 = merge(1, gwr%b2gw - gwr%b1gw + 1, gwr%sig_diago)
1731 : ncerr = nctk_def_dims(ncid, [ &
1732 : nctkdim_t("nsppol", gwr%nsppol), &
1733 : nctkdim_t("nspin_channel", gwr%nsppol*gwr%nsig_ab),&
1734 : nctkdim_t("nsig_ab", gwr%nsig_ab),&
1735 : nctkdim_t("ntau", gwr%ntau), &
1736 : nctkdim_t("nwr", gwr%nwr), &
1737 : nctkdim_t("chi_mpw", gwr%tchi_mpw), &
1738 : nctkdim_t("nqibz", gwr%nqibz), &
1739 : nctkdim_t("nqbz", gwr%nqbz), &
1740 : nctkdim_t("nkcalc", gwr%nkcalc), &
1741 : nctkdim_t("max_nbcalc", gwr%max_nbcalc), &
1742 : nctkdim_t("smat_bsize1", smat_bsize1), &
1743 : nctkdim_t("smat_bsize2", smat_bsize2) &
1744 0 : ], defmode=.True.)
1745 0 : NCF_CHECK(ncerr)
1746 :
1747 : ncerr = nctk_def_iscalars(ncid, [character(len=nctk_slen) :: &
1748 : "gwr_completed", "sig_diago", "b1gw", "b2gw", "symsigma", "symchi", "scf_iteration" &
1749 0 : ])
1750 0 : NCF_CHECK(ncerr)
1751 :
1752 : ncerr = nctk_def_dpscalars(ncid, [character(len=nctk_slen) :: &
1753 : "wr_step", "ecuteps", "ecut", "ecutwfn", "ecutsigx", "gwr_boxcutmin", &
1754 : "gwr_max_hwtene", "min_transition_energy_eV", "max_transition_energy_eV", &
1755 : "eratio", "ft_max_err_t2w_cos", "ft_max_err_w2t_cos", "ft_max_err_t2w_sin", &
1756 : "cosft_duality_error", "regterm" &
1757 0 : ])
1758 0 : NCF_CHECK(ncerr)
1759 :
1760 : ! Define arrays with results.
1761 : ncerr = nctk_def_arrays(ncid, [ &
1762 : nctkarr_t("gwr_task", "char", "character_string_length"), &
1763 : nctkarr_t("tau_mesh", "dp", "ntau"), &
1764 : nctkarr_t("tau_wgs", "dp", "ntau"), &
1765 : nctkarr_t("iw_mesh", "dp", "ntau"), &
1766 : nctkarr_t("iw_wgs", "dp", "ntau"), &
1767 : nctkarr_t("cosft_wt", "dp", "ntau, ntau"), &
1768 : nctkarr_t("cosft_tw", "dp", "ntau, ntau"), &
1769 : nctkarr_t("sinft_wt", "dp", "ntau, ntau"), &
1770 : !nctkarr_t("ngqpt", "int", "three"), &
1771 : nctkarr_t("bstart_ks", "int", "nkcalc, nsppol"), &
1772 : nctkarr_t("bstop_ks", "int", "nkcalc, nsppol"), &
1773 : nctkarr_t("kcalc", "dp", "three, nkcalc"), &
1774 : nctkarr_t("kcalc2ibz", "int", "nkcalc, six") &
1775 0 : ])
1776 0 : NCF_CHECK(ncerr)
1777 :
1778 : ! ======================================================
1779 : ! Write data that do not depend on the (kpt, spin) loop.
1780 : ! ======================================================
1781 0 : NCF_CHECK(nctk_set_datamode(ncid))
1782 : ncerr = nctk_write_iscalars(ncid, [character(len=nctk_slen) :: &
1783 : "gwr_completed", "sig_diago", "b1gw", "b2gw", "symsigma", "symchi", "scf_iteration"], &
1784 0 : [0, merge(1, 0, gwr%sig_diago), gwr%b1gw, gwr%b2gw, gwr%dtset%symsigma, dtset%symchi, gwr%scf_iteration])
1785 0 : NCF_CHECK(ncerr)
1786 :
1787 : ncerr = nctk_write_dpscalars(ncid, [character(len=nctk_slen) :: &
1788 : "wr_step", "ecuteps", "ecut", "ecutwfn", "ecutsigx", "gwr_boxcutmin", &
1789 : "gwr_max_hwtene", "min_transition_energy_eV", "max_transition_energy_eV", &
1790 : "eratio", "ft_max_err_t2w_cos", "ft_max_err_w2t_cos", "ft_max_err_t2w_sin", &
1791 : "cosft_duality_error", "regterm"], &
1792 : [gwr%wr_step, dtset%ecuteps, dtset%ecut, dtset%ecutwfn, dtset%ecutsigx, dtset%gwr_boxcutmin, &
1793 : dtset%gwr_max_hwtene, gwr%te_min, gwr%te_max, gwr%te_max / gwr%te_min, &
1794 : gwr%ft_max_error(1), gwr%ft_max_error(2), gwr%ft_max_error(3), gwr%cosft_duality_error, regterm &
1795 0 : ])
1796 0 : NCF_CHECK(ncerr)
1797 :
1798 0 : NCF_CHECK(nf90_put_var(ncid, vid("gwr_task"), trim(dtset%gwr_task)))
1799 0 : NCF_CHECK(nf90_put_var(ncid, vid("tau_mesh"), gwr%tau_mesh))
1800 0 : NCF_CHECK(nf90_put_var(ncid, vid("tau_wgs"), gwr%tau_wgs))
1801 0 : NCF_CHECK(nf90_put_var(ncid, vid("iw_mesh"), gwr%iw_mesh))
1802 0 : NCF_CHECK(nf90_put_var(ncid, vid("iw_wgs"), gwr%iw_wgs))
1803 0 : NCF_CHECK(nf90_put_var(ncid, vid("cosft_wt"), gwr%cosft_wt))
1804 0 : NCF_CHECK(nf90_put_var(ncid, vid("cosft_tw"), gwr%cosft_tw))
1805 0 : NCF_CHECK(nf90_put_var(ncid, vid("sinft_wt"), gwr%sinft_wt))
1806 0 : NCF_CHECK(nf90_put_var(ncid, vid("bstart_ks"), gwr%bstart_ks))
1807 0 : NCF_CHECK(nf90_put_var(ncid, vid("bstop_ks"), gwr%bstop_ks))
1808 0 : NCF_CHECK(nf90_put_var(ncid, vid("kcalc"), gwr%kcalc))
1809 0 : NCF_CHECK(nf90_put_var(ncid, vid("kcalc2ibz"), gwr%kcalc2ibz))
1810 0 : NCF_CHECK(nf90_close(ncid))
1811 : end if ! master
1812 :
1813 0 : call cwtime_report(" gwr_init:", cpu, wall, gflops)
1814 0 : call timab(1920, 2, tsec)
1815 :
1816 : contains
1817 0 : integer function vid(vname)
1818 : character(len=*),intent(in) :: vname
1819 0 : vid = nctk_idname(ncid, vname)
1820 : end function vid
1821 :
1822 : end subroutine gwr_init
1823 : !!***
1824 :
1825 : !----------------------------------------------------------------------
1826 :
1827 : !!****f* m_gwr/estimate
1828 : !! NAME
1829 : !! estimate
1830 : !!
1831 : !! FUNCTION
1832 : !! Estimate memory requirements and the parallel speedup of a given `np_kgts` configuration.
1833 : !!
1834 : !! SOURCE
1835 :
1836 0 : type(est_t) pure function estimate(gwr, np_kgts) result(est)
1837 :
1838 : !Arguments ------------------------------------
1839 : class(gwr_t),intent(in) :: gwr
1840 : integer,intent(in) :: np_kgts(4)
1841 :
1842 : !Local variables-------------------------------
1843 : real(dp) :: np_k, np_g, np_t, np_s, w_k, w_g, w_t, w_s, np_tot
1844 : ! *************************************************************************
1845 :
1846 : ! Use real quantities to avoid integer division
1847 0 : np_k = np_kgts(1); np_g = np_kgts(2); np_t = np_kgts(3); np_s = np_kgts(4)
1848 0 : np_tot = product(real(np_kgts))
1849 :
1850 : ! NB: array dimensioned with nkibz and nqibz do not scale as 1/np_k as we distribute the BZ, IBZ points might be replicated.
1851 :
1852 : !!! FIXME HT: Here we should recalculate with nsig_ab
1853 : ! Resident memory in Mb for G(g,g',+/-tau) and chi(g,g',tau)
1854 0 : est%mem_green_gg = two * two * (one*gwr%nspinor*gwr%green_mpw)**2 * two*gwr%ntau * gwr%nkibz * gwr%nsppol * gwp*b2Mb / np_tot
1855 0 : est%mem_chi_gg = two * (one*gwr%tchi_mpw)**2 * gwr%ntau * gwr%nqibz * gwp*b2Mb / (np_g * np_t * np_k)
1856 0 : est%mem_ugb = two * gwr%green_mpw * gwr%nspinor * gwr%dtset%nband(1) * gwr%nkibz * gwr%nsppol * gwp*b2Mb / np_tot
1857 :
1858 : ! Temporary memory allocated inside the tau loops.
1859 : ! This is the chunck we have to minimize by increasing np_g and/or np_k to avoid going OOM.
1860 0 : est%mem_green_rg = two * two * gwr%nspinor**2 * gwr%green_mpw * gwr%g_nfft * gwr%nkbz * gwr%nsppol * gwp*b2Mb / (np_g * np_k)
1861 0 : est%mem_chi_rg = two * gwr%tchi_mpw * gwr%g_nfft * gwr%nqbz * gwp*b2Mb / (np_g * np_k)
1862 :
1863 0 : est%mem_total = est%mem_green_gg + est%mem_chi_gg + est%mem_ugb + est%mem_green_rg + est%mem_chi_rg
1864 :
1865 : ! Estimate speedup and parallel efficiency using heuristic weights. Note g_nfft instead of green_mpw.
1866 0 : w_k = 0.799_dp; w_g = 0.899_dp; w_t = 1.1_dp; w_s = 1.2_dp
1867 :
1868 : ! Promote kpt parallelism under particular circumstances.
1869 0 : if (gwr%nkbz > 4**3) w_k = w_g + tol2 * merge(+1, -5, np_k < 5)
1870 :
1871 : est%speedup = speedup(gwr%nkbz, nint(np_k), w_k) * speedup(gwr%g_nfft, nint(np_g), w_g) * &
1872 0 : speedup(gwr%ntau, nint(np_t), w_t) * speedup(gwr%nsppol, nint(np_s), w_s)
1873 0 : est%efficiency = est%speedup / np_tot
1874 :
1875 : contains
1876 :
1877 0 : real(dp) pure function speedup(size, np, weight)
1878 : ! Expected speedup for a `size` problem and `np` processes
1879 : integer,intent(in) :: size, np
1880 : real(dp),intent(in) :: weight
1881 0 : if (np == 1) then
1882 : speedup = one
1883 : else
1884 0 : speedup = (weight*size) / (one* ((size / np) + merge(0, 1, mod(size, np) == 0)))
1885 : end if
1886 0 : end function speedup
1887 :
1888 : end function estimate
1889 : !!***
1890 :
1891 : !----------------------------------------------------------------------
1892 :
1893 : !!****f* m_gwr/est_print
1894 : !! NAME
1895 : !! est_print
1896 : !!
1897 : !! FUNCTION
1898 : !! Print memory estimate.
1899 : !!
1900 : !! SOURCE
1901 :
1902 0 : subroutine est_print(est, units)
1903 :
1904 : !Arguments ------------------------------------
1905 : class(est_t), intent(in) :: est
1906 : integer,intent(in) :: units(:)
1907 :
1908 : !Local variables-------------------------------
1909 : character(len=4),parameter :: fmt = "f8.1"
1910 : ! *************************************************************************
1911 :
1912 0 : call wrtout(units, "- Resident memory in Mb for G(g,g',+/-tau) and chi(g,g',tau):")
1913 0 : call wrtout(units, sjoin("- G_k(g,g,tau): ", ftoa(est%mem_green_gg, fmt=fmt)))
1914 0 : call wrtout(units, sjoin("- Chi_q(g,g,tau): ", ftoa(est%mem_chi_gg, fmt=fmt)))
1915 0 : call wrtout(units, sjoin("- u_k(g,b): ", ftoa(est%mem_ugb, fmt=fmt)))
1916 0 : call wrtout(units, "- Temporary memory allocated inside the tau loops:")
1917 0 : call wrtout(units, sjoin("- G_k(r,g): ", ftoa(est%mem_green_rg, fmt=fmt)))
1918 0 : call wrtout(units, sjoin("- chi_q(r,g): ", ftoa(est%mem_chi_rg, fmt=fmt)))
1919 :
1920 0 : end subroutine est_print
1921 : !!***
1922 :
1923 : !----------------------------------------------------------------------
1924 :
1925 : !!****f* m_gwr/gwr_malloc_free_mats
1926 : !! NAME
1927 : !! gwr_malloc_free_mats
1928 : !!
1929 : !! FUNCTION
1930 : !! Allocate/Free PBLAS matrices according to `what` for the set of k/q-points selected by `mask_ibz`.
1931 : !!
1932 : !! INPUTS
1933 : !! mask_ibz
1934 : !! what
1935 : !! action
1936 : !!
1937 : !! SOURCE
1938 :
1939 0 : subroutine gwr_malloc_free_mats(gwr, mask_ibz, what, action)
1940 :
1941 : !Arguments ------------------------------------
1942 : class(gwr_t), target, intent(inout) :: gwr
1943 : integer,intent(in) :: mask_ibz(:)
1944 : character(len=*),intent(in) :: what, action
1945 :
1946 : !Local variables-------------------------------
1947 : integer :: my_is, my_it, ipm, npw, col_bsize, itau, spin, ik_ibz, iq_ibz, iab
1948 : !integer :: ii, num_pm, ipm_list__(2)
1949 : type(__slkmat_t), pointer :: mat
1950 : character(len=500) :: msg !, gpu_action
1951 : ! *************************************************************************
1952 :
1953 0 : ABI_CHECK(string_in(action, "malloc, free"), sjoin("Invalid action:", action))
1954 :
1955 : !gpu_action = "None"; if (gwr%dtset%gpu_option == ABI_GPU_OPENMP) gpu_action = "alloc"
1956 :
1957 : !num_pm = 2; ipm_list__ = [1, 2]
1958 : !if (present(ipm_list)) then
1959 : ! num_pm = size(ipm_list)
1960 : ! ABI_CHECK_IRANGE(num_pm, 1, 2, "num_pm not in [1, 2]")
1961 : ! ipm_list__(1:num_pm) = ipm_list(:)
1962 : !end if
1963 :
1964 0 : do my_is=1,gwr%my_nspins
1965 0 : spin = gwr%my_spins(my_is)
1966 0 : do my_it=1,gwr%my_ntau
1967 0 : itau = gwr%my_itaus(my_it)
1968 : ! NB: all the PBLAS matrices are MPI distributed over g' in blocks if action == "malloc"
1969 :
1970 0 : select case (what)
1971 : case ("green")
1972 : ! ========================
1973 : ! Allocate/free G_k(g,g', +-itau)
1974 : ! ========================
1975 0 : ABI_CHECK_IEQ(size(mask_ibz), gwr%nkibz, "wrong mask size")
1976 :
1977 0 : do ik_ibz=1,gwr%nkibz
1978 0 : if (mask_ibz(ik_ibz) == 0) cycle
1979 0 : npw = gwr%green_desc_kibz(ik_ibz)%npw
1980 0 : ABI_CHECK(block_dist_1d(npw, gwr%g_comm%nproc, col_bsize, msg), msg)
1981 0 : do iab=1,gwr%nsig_ab
1982 0 : associate (gt => gwr%gt_kibz(:, ik_ibz, itau, spin, iab))
1983 0 : do ipm=1,2
1984 0 : if (action == "malloc") call gt(ipm)%init(npw, npw, gwr%g_slkproc, istwfk1, size_blocs=[-1, col_bsize]) !, gpu_action=gpu_action)
1985 0 : if (action == "free") call gt(ipm)%free()
1986 : end do
1987 : end associate
1988 : end do
1989 : end do
1990 :
1991 : case ("tchi", "wc")
1992 : ! ===========================
1993 : ! Allocate/free tchi_q(g,g', +itau)
1994 : ! ===========================
1995 0 : ABI_CHECK_IEQ(size(mask_ibz), gwr%nqibz, "wrong mask size")
1996 :
1997 0 : do iq_ibz=1,gwr%nqibz
1998 0 : if (mask_ibz(iq_ibz) == 0) cycle
1999 0 : npw = gwr%tchi_desc_qibz(iq_ibz)%npw
2000 0 : ABI_CHECK(block_dist_1d(npw, gwr%g_comm%nproc, col_bsize, msg), msg)
2001 0 : if (what == "tchi") mat => gwr%tchi_qibz(iq_ibz, itau, spin)
2002 0 : if (what == "wc") mat => gwr%wc_qibz(iq_ibz, itau, spin)
2003 0 : if (action == "malloc") call mat%init(npw, npw, gwr%g_slkproc, 1, size_blocs=[-1, col_bsize]) !, gpu_action=gpu_action)
2004 0 : if (action == "free") call mat%free()
2005 : end do
2006 :
2007 : case ("sigma")
2008 : ! ================================
2009 : ! Allocate/free sigmac_kibz(g,g', +- itau)
2010 : ! ================================
2011 0 : ABI_CHECK_IEQ(size(mask_ibz), gwr%nkibz, "wrong mask size")
2012 0 : do ik_ibz=1,gwr%nkibz
2013 0 : if (mask_ibz(ik_ibz) == 0) cycle
2014 0 : npw = gwr%tchi_desc_qibz(iq_ibz)%npw
2015 0 : ABI_CHECK(block_dist_1d(npw, gwr%g_comm%nproc, col_bsize, msg), msg)
2016 0 : do iab=1,gwr%nsig_ab
2017 0 : associate (sigc => gwr%sigc_kibz(:, ik_ibz, itau, spin, iab))
2018 0 : do ipm=1,2
2019 0 : if (action == "malloc") call sigc(ipm)%init(npw, npw, gwr%g_slkproc, 1, size_blocs=[-1, col_bsize]) !, gpu_action=gpu_action)
2020 0 : if (action == "free") call sigc(ipm)%free()
2021 : end do
2022 : end associate
2023 : end do
2024 : end do
2025 :
2026 : case default
2027 0 : ABI_ERROR(sjoin("Invalid what:", what))
2028 : end select
2029 :
2030 : end do ! my_it
2031 : end do ! my_is
2032 :
2033 0 : call wrtout(std_out, "")
2034 0 : call gwr%print_mem([std_out])
2035 :
2036 0 : end subroutine gwr_malloc_free_mats
2037 : !!***
2038 :
2039 : !----------------------------------------------------------------------
2040 :
2041 : !!****f* m_gwr/gwr_free
2042 : !! NAME
2043 : !! gwr_free
2044 : !!
2045 : !! FUNCTION
2046 : !! Free dynamic memory in gwr object.
2047 : !!
2048 : !! SOURCE
2049 :
2050 0 : subroutine gwr_free(gwr)
2051 :
2052 : !Arguments ------------------------------------
2053 : class(gwr_t), intent(inout) :: gwr
2054 : ! *************************************************************************
2055 :
2056 0 : ABI_SFREE(gwr%ks_vbik)
2057 0 : ABI_SFREE(gwr%kbz)
2058 0 : ABI_SFREE(gwr%kbz2ibz)
2059 0 : ABI_SFREE(gwr%kbz2ibz_symrel)
2060 0 : ABI_SFREE(gwr%qbz2ibz)
2061 0 : ABI_SFREE(gwr%my_kbz_inds)
2062 0 : ABI_SFREE(gwr%my_kibz_inds)
2063 0 : ABI_SFREE(gwr%my_qbz_inds)
2064 0 : ABI_SFREE(gwr%my_qibz_inds)
2065 0 : ABI_SFREE(gwr%qbz)
2066 0 : ABI_SFREE(gwr%qibz)
2067 0 : ABI_SFREE(gwr%wtq)
2068 0 : ABI_SFREE(gwr%chi0_head_myw)
2069 0 : ABI_SFREE(gwr%chi0_uwing_myw)
2070 0 : ABI_SFREE(gwr%chi0_lwing_myw)
2071 0 : ABI_SFREE(gwr%my_spins)
2072 0 : ABI_SFREE(gwr%my_itaus)
2073 0 : ABI_SFREE(gwr%tau_master)
2074 0 : ABI_SFREE(gwr%np_kibz)
2075 0 : ABI_SFREE(gwr%itreat_ikibz)
2076 0 : ABI_SFREE(gwr%np_qibz)
2077 0 : ABI_SFREE(gwr%itreat_iqibz)
2078 0 : ABI_SFREE_NOCOUNT(gwr%tau_mesh)
2079 0 : ABI_SFREE_NOCOUNT(gwr%tau_wgs)
2080 0 : ABI_SFREE_NOCOUNT(gwr%iw_mesh)
2081 0 : ABI_SFREE_NOCOUNT(gwr%iw_wgs)
2082 0 : ABI_SFREE_NOCOUNT(gwr%cosft_tw)
2083 0 : ABI_SFREE_NOCOUNT(gwr%cosft_wt)
2084 0 : ABI_SFREE_NOCOUNT(gwr%sinft_wt)
2085 0 : ABI_SFREE(gwr%kcalc)
2086 0 : ABI_SFREE(gwr%bstart_ks)
2087 0 : ABI_SFREE(gwr%bstop_ks)
2088 0 : ABI_SFREE(gwr%nbcalc_ks)
2089 0 : ABI_SFREE(gwr%kcalc2ibz)
2090 0 : ABI_SFREE(gwr%sigx_mat)
2091 0 : ABI_SFREE(gwr%sigc_iw_mat)
2092 0 : ABI_SFREE(gwr%chinpw_qibz)
2093 :
2094 0 : call gwr%ks_gaps%free()
2095 0 : call gwr%qp_ebands%free()
2096 0 : call gwr%qp_ebands_prev%free()
2097 0 : call gwr%kcalc_wfd%free()
2098 0 : call gwr%wfk_hdr%free()
2099 :
2100 : ! Free descriptors
2101 0 : if (allocated(gwr%green_desc_kibz)) then
2102 0 : call desc_array_free(gwr%green_desc_kibz)
2103 0 : ABI_FREE(gwr%green_desc_kibz)
2104 : end if
2105 0 : if (allocated(gwr%tchi_desc_qibz)) then
2106 0 : call desc_array_free(gwr%tchi_desc_qibz)
2107 0 : ABI_FREE(gwr%tchi_desc_qibz)
2108 : end if
2109 :
2110 : ! Free PBLAS matrices
2111 0 : if (allocated(gwr%gt_kibz)) then
2112 0 : call slk_array_free(gwr%gt_kibz)
2113 0 : ABI_FREE(gwr%gt_kibz)
2114 : end if
2115 0 : if (allocated(gwr%tchi_qibz)) then
2116 0 : call slk_array_free(gwr%tchi_qibz)
2117 0 : ABI_FREE(gwr%tchi_qibz)
2118 : end if
2119 0 : if (allocated(gwr%wc_qibz)) then
2120 0 : call slk_array_free(gwr%wc_qibz)
2121 0 : ABI_FREE(gwr%wc_qibz)
2122 : end if
2123 0 : if (allocated(gwr%sigc_kibz)) then
2124 0 : call slk_array_free(gwr%sigc_kibz)
2125 0 : ABI_FREE(gwr%sigc_kibz)
2126 : end if
2127 : ! Release the scalapack pressor.
2128 0 : call gwr%g_slkproc%free()
2129 :
2130 0 : if (allocated(gwr%ugb)) then
2131 0 : call slk_array_free(gwr%ugb)
2132 0 : ABI_FREE(gwr%ugb)
2133 : end if
2134 : !if (allocated(gwr%nato_ugb)) then
2135 : ! call slk_array_free(gwr%nato_ugb)
2136 : ! ABI_FREE(gwr%nato_ugb)
2137 : !end if
2138 0 : call gwr%gtau_slkproc%free()
2139 :
2140 : ! datatypes.
2141 0 : call gwr%ks_me%free()
2142 0 : call gwr%vcgen_eps%free()
2143 0 : if (gwr%has_vcgen_sigma) call gwr%vcgen_sigma%free()
2144 :
2145 0 : if (allocated(gwr%degtab)) then
2146 0 : call degtab_array_free(gwr%degtab)
2147 0 : ABI_FREE(gwr%degtab)
2148 : end if
2149 :
2150 : ! Free MPI communicators
2151 0 : call gwr%spin_comm%free(); call gwr%g_comm%free(); call gwr%tau_comm%free()
2152 0 : call gwr%kpt_comm%free(); call gwr%gtau_comm%free(); call gwr%kg_comm%free()
2153 0 : call gwr%kgt_comm%free(); call gwr%kts_comm%free(); call gwr%comm%free()
2154 :
2155 0 : end subroutine gwr_free
2156 : !!***
2157 :
2158 : ! Free array of desc_t objects.
2159 0 : subroutine desc_array1_free(desc_array1)
2160 : type(desc_t),intent(inout) :: desc_array1(:)
2161 : integer :: ii
2162 :
2163 0 : do ii=1,size(desc_array1, dim=1)
2164 0 : call desc_array1(ii)%free()
2165 : end do
2166 0 : end subroutine desc_array1_free
2167 :
2168 : !----------------------------------------------------------------------
2169 :
2170 : !!****f* m_gwr/gwr_load_kcalc_wfd
2171 : !! NAME
2172 : !! gwr_load_kcalc_wfd
2173 : !!
2174 : !! FUNCTION
2175 : !! Load the KS states to compute Sigma_nk from the WFK file
2176 : !!
2177 : !! INPUTS
2178 : !! wfk_path=Name of the WFK file.
2179 : !!
2180 : !! OUTPUT
2181 : !! tmp_kstab
2182 : !!
2183 : !! SOURCE
2184 :
2185 0 : subroutine gwr_load_kcalc_wfd(gwr, wfk_path, tmp_kstab)
2186 :
2187 : !Arguments ------------------------------------
2188 : class(gwr_t),intent(inout) :: gwr
2189 : character(len=*),intent(in) :: wfk_path
2190 : integer,allocatable,intent(out) :: tmp_kstab(:,:,:)
2191 :
2192 : !Local variables-------------------------------
2193 : !scalars
2194 : integer :: mband, nkibz, nsppol, spin, ik_ibz, ikcalc
2195 : real(dp) :: cpu, wall, gflops
2196 : !character(len=5000) :: msg
2197 : type(ebands_t) :: ks_ebands
2198 0 : type(hdr_type) :: wfk_hdr
2199 : !arrays
2200 0 : integer,allocatable :: nband(:,:), wfd_istwfk(:)
2201 0 : logical,allocatable :: bks_mask(:,:,:), keep_ur(:,:,:)
2202 : ! *************************************************************************
2203 :
2204 0 : call cwtime(cpu, wall, gflops, "start")
2205 :
2206 : associate (wfd => gwr%kcalc_wfd, dtset => gwr%dtset)
2207 :
2208 0 : ks_ebands = wfk_read_ebands(wfk_path, gwr%comm%value, out_hdr=wfk_hdr)
2209 0 : call wfk_hdr%vs_dtset(dtset)
2210 :
2211 : ! TODO: Add more consistency checks e.g. nkibz,...
2212 : !cryst = wfk_hdr%get_crystal()
2213 : !call cryst%print(header="crystal structure from WFK file")
2214 :
2215 0 : nkibz = ks_ebands%nkpt; nsppol = ks_ebands%nsppol
2216 :
2217 : ! Don't take mband from ks_ebands but compute it from gwr%bstop_ks
2218 0 : mband = maxval(gwr%bstop_ks) !; mband = ks_ebands%mband
2219 :
2220 : ! Initialize the wave function descriptor.
2221 : ! Only wavefunctions for the symmetrical imagine of the k wavevectors
2222 : ! treated by this MPI rank are stored.
2223 0 : ABI_MALLOC(nband, (nkibz, nsppol))
2224 0 : ABI_MALLOC(bks_mask, (mband, nkibz, nsppol))
2225 0 : ABI_MALLOC(keep_ur, (mband, nkibz, nsppol))
2226 0 : nband = mband; bks_mask = .False.; keep_ur = .False.
2227 :
2228 0 : ABI_ICALLOC(tmp_kstab, (2, nkibz, nsppol))
2229 :
2230 0 : do spin=1,gwr%nsppol
2231 0 : do ikcalc=1,gwr%nkcalc ! TODO: Should be spin dependent!
2232 0 : ik_ibz = gwr%kcalc2ibz(ikcalc, 1)
2233 0 : associate (b1 => gwr%bstart_ks(ikcalc, spin), b2 => gwr%bstop_ks(ikcalc, spin))
2234 0 : tmp_kstab(:, ik_ibz, spin) = [b1, b2]
2235 0 : bks_mask(b1:b2, ik_ibz, spin) = .True.
2236 : end associate
2237 : end do
2238 : end do
2239 :
2240 : ! Impose istwfk = 1 for all k-points.
2241 : ! wfd_read_wfk will handle a possible conversion if the WFK contains istwfk /= 1.
2242 0 : ABI_MALLOC(wfd_istwfk, (nkibz))
2243 0 : wfd_istwfk = 1
2244 :
2245 : call wfd%init(gwr%cryst, gwr%pawtab, gwr%psps, keep_ur, mband, nband, nkibz, dtset%nsppol, bks_mask, &
2246 : dtset%nspden, dtset%nspinor, dtset%ecutwfn, dtset%ecutsm, dtset%dilatmx, wfd_istwfk, ks_ebands%kptns, gwr%g_ngfft, &
2247 0 : dtset%nloalg, dtset%prtvol, dtset%pawprtvol, gwr%comm%value)
2248 :
2249 0 : call wfd%print([std_out], header="Wavefunctions for GWR calculation")
2250 :
2251 0 : ABI_FREE(nband)
2252 0 : ABI_FREE(keep_ur)
2253 0 : ABI_FREE(wfd_istwfk)
2254 0 : ABI_FREE(bks_mask)
2255 :
2256 0 : call ks_ebands%free(); call wfk_hdr%free()
2257 :
2258 : ! Read KS wavefunctions.
2259 0 : call wfd%read_wfk(wfk_path, iomode_from_fname(wfk_path))
2260 : end associate
2261 :
2262 0 : call cwtime_report(" gwr_load_kcalc_from_wfk:", cpu, wall, gflops)
2263 0 : call pstat_proc%print(_PSTAT_ARGS_)
2264 :
2265 0 : end subroutine gwr_load_kcalc_wfd
2266 : !!***
2267 :
2268 : !----------------------------------------------------------------------
2269 :
2270 : !!****f* m_gwr/gwr_read_ugb_from_wfk
2271 : !! NAME
2272 : !! gwr_read_ugb_from_wfk
2273 : !!
2274 : !! FUNCTION
2275 : !! Read wavefunctions from the WFK file `wfk_path` and store them in gwr%ugb (MPI distributed).
2276 : !!
2277 : !! SOURCE
2278 :
2279 0 : subroutine gwr_read_ugb_from_wfk(gwr, wfk_path)
2280 :
2281 : !Arguments ------------------------------------
2282 : class(gwr_t),target,intent(inout) :: gwr
2283 : character(len=*),intent(in) :: wfk_path
2284 :
2285 : !Local variables-------------------------------
2286 : !scalars
2287 : integer,parameter :: formeig0 = 0, master = 0
2288 : integer :: mband, min_nband, nkibz, nsppol, my_is, my_iki, spin, ik_ibz, ierr, bcast_comm, color
2289 : integer :: npw_k, mpw_disk, istwf_k, il_b, ib, band, iloc, cg_spad, gw_spad
2290 : integer :: nbsum, npwsp, npw_k_disk, npwsp_disk, bstart, bstop, band_step, nb, nmiss, ig, igw, spinor, icg
2291 : logical :: print_time
2292 : real(dp) :: cpu, wall, gflops, cpu_green, wall_green, gflops_green
2293 : complex(gwp) :: cdum
2294 : character(len=5000) :: msg
2295 : logical :: have_band, need_block_ks, io_in_kcomm, cut_ug
2296 : type(ebands_t) :: wfk_ebands
2297 0 : type(wfk_t) :: wfk
2298 : type(dataset_type),pointer :: dtset
2299 : type(xcomm_t), pointer :: io_comm
2300 : !arrays
2301 : integer :: units(2)
2302 0 : integer,allocatable :: kg_k_disk(:,:), gf2wfd(:)
2303 : !logical,allocatable :: bmask(:)
2304 : real(dp) :: kk_ibz(3), tsec(2)
2305 0 : real(dp),target,allocatable :: cg_work(:,:,:)
2306 0 : real(dp),contiguous, pointer :: cg_k(:,:)
2307 : ! *************************************************************************
2308 :
2309 0 : units = [std_out, ab_out]
2310 0 : call cwtime(cpu, wall, gflops, "start")
2311 0 : call timab(1921, 1, tsec)
2312 :
2313 0 : dtset => gwr%dtset
2314 0 : wfk_ebands = wfk_read_ebands(wfk_path, gwr%comm%value, out_hdr=gwr%wfk_hdr)
2315 0 : call gwr%wfk_hdr%vs_dtset(dtset)
2316 :
2317 : ! TODO: Add more consistency checks e.g. nkibz,...
2318 : !cryst = gwr%wfk_hdr%get_crystal()
2319 : !call cryst%print(header="crystal structure from WFK file")
2320 :
2321 : ! TODO: Could read the wavefunctions twice and use ecutwfc for sigma_c and ecut for sigma_x.
2322 0 : nkibz = wfk_ebands%nkpt; nsppol = wfk_ebands%nsppol; mband = wfk_ebands%mband; min_nband = minval(wfk_ebands%nband)
2323 :
2324 0 : nbsum = dtset%nband(1)
2325 0 : if (nbsum > min_nband) then
2326 0 : ABI_ERROR(sjoin("WFK file contains", itoa(min_nband), "states while you're asking for:", itoa(nbsum)))
2327 0 : nbsum = min_nband
2328 : end if
2329 0 : call wfk_ebands%free()
2330 :
2331 0 : cut_ug = (abs(gwr%dtset%ecut - gwr%dtset%ecutwfn) > tol3)
2332 0 : if (cut_ug) then
2333 0 : call wrtout(units, sjoin(" Cutting u(g) as ecutwfn:", ftoa(gwr%dtset%ecutwfn), " < ecut: ", ftoa(gwr%dtset%ecut)))
2334 : end if
2335 :
2336 : ! ==============================================
2337 : ! Build Green's functions in g-space for given k
2338 : ! ==============================================
2339 :
2340 : ! for tau > 0:
2341 : !
2342 : ! G_k(r,r',itau) = i \sum_b^{occ} psi_b(r) \psi_b^*(r') exp(e_b tau)
2343 : !
2344 : ! for tau < 0:
2345 : !
2346 : ! G_k(r,r',itau) = -i \sum_b^{empty} psi_b(r) \psi_b^*(r') exp(e_b tau)
2347 : !
2348 : ! NB: G_k is constructed for k in the IBZ, then we rotate the k-point to obtain G_k in the BZ.
2349 : !
2350 : ! TODO:
2351 : ! 1) Make sure that gvec in gwr and wfd agree with each other.
2352 : ! 2) May implement trick used in gwst to add empty states approximated with LC of PWs.
2353 :
2354 : ! Select occupied or empty G.
2355 : ! if (eig_nk < -tol6) then
2356 : ! !ipm = 1
2357 : ! !gt_cfact = j_dpc * exp(gwr%tau_mesh(itau) * eig_nk)
2358 : ! ! Vasp convention
2359 : ! ipm = 2
2360 : ! gt_cfact = exp(gwr%tau_mesh(itau) * eig_nk)
2361 : ! else if (eig_nk > tol6) then
2362 : ! !ipm = 2
2363 : ! !gt_cfact = -j_dpc * exp(-gwr%tau_mesh(itau) * eig_nk)
2364 : ! ! Vasp convention
2365 : ! ipm = 1
2366 : ! gt_cfact = -exp(-gwr%tau_mesh(itau) * eig_nk)
2367 : ! else
2368 : ! ABI_WARNING("Metallic system of semiconductor with Fermi level inside bands!!!!")
2369 : ! end if
2370 :
2371 0 : call wrtout(std_out, sjoin(" Reading KS states with nbsum:", itoa(nbsum), "..."), do_flush=.True.)
2372 :
2373 : ! Init set of (npwsp, nbsum) PBLAS matrix distributed within the g_comm communicator.
2374 : ! and distribute it over bands so that each proc reads a subset of bands in read_band_block
2375 : ! Note size_blocs below that corresponds to a round-robin distribution along the band axis.
2376 :
2377 0 : ABI_MALLOC(gwr%ugb, (gwr%nkibz, gwr%nsppol))
2378 0 : gwr%ugb_nband = nbsum
2379 :
2380 0 : do my_is=1,gwr%my_nspins
2381 0 : spin = gwr%my_spins(my_is)
2382 0 : do my_iki=1,gwr%my_nkibz
2383 0 : ik_ibz = gwr%my_kibz_inds(my_iki)
2384 0 : npw_k = gwr%green_desc_kibz(ik_ibz)%npw; npwsp = npw_k * gwr%nspinor
2385 0 : call gwr%ugb(ik_ibz, spin)%init(npwsp, gwr%ugb_nband, gwr%g_slkproc, istwfk1, size_blocs=[-1, 1])
2386 : end do
2387 : end do
2388 0 : call gwr%print_mem([std_out])
2389 0 : if (gwr%comm%me == 0) call pstat_proc%print(_PSTAT_ARGS_)
2390 :
2391 0 : mpw_disk = maxval(gwr%wfk_hdr%npwarr)
2392 0 : ABI_MALLOC(kg_k_disk, (3, mpw_disk))
2393 :
2394 : ! Master reads and broadcasts. Much faster on lumi
2395 0 : call wrtout(std_out, " Using IO version based on master reads and brodcasts ...")
2396 0 : io_comm => gwr%comm; io_in_kcomm = .False.
2397 0 : io_comm => gwr%kpt_comm; io_in_kcomm = .True.
2398 :
2399 0 : if (io_comm%me == master) then
2400 0 : call wfk%open_read(wfk_path, formeig0, iomode_from_fname(wfk_path), get_unit(), xmpi_comm_self)
2401 : end if
2402 :
2403 : ! TODO This to maximize the size of cg_work and decrease number of IO operations.
2404 : !min_mem_mb = pstat_proc%pstat_min_mem_mb_per_proc(gwr%comm)
2405 :
2406 0 : do spin=1,gwr%nsppol
2407 0 : if (io_in_kcomm .and. .not. any(gwr%my_spins == spin)) cycle
2408 :
2409 0 : do ik_ibz=1,gwr%nkibz
2410 0 : print_time = gwr%comm%me == 0 .and. (ik_ibz < LOG_MODK .or. mod(ik_ibz, LOG_MODK) == 0)
2411 0 : if (print_time) call cwtime(cpu_green, wall_green, gflops_green, "start")
2412 0 : kk_ibz = gwr%kibz(:, ik_ibz)
2413 0 : npw_k = gwr%green_desc_kibz(ik_ibz)%npw
2414 0 : npw_k_disk = gwr%wfk_hdr%npwarr(ik_ibz); istwf_k = gwr%wfk_hdr%istwfk(ik_ibz); npwsp_disk = npw_k_disk * gwr%nspinor
2415 :
2416 0 : ABI_CHECK_IEQ(istwf_k, 1, "istwfk_k should be 1")
2417 : ! See m_wfd for calls to convert to istwfk 1
2418 : !change_gsphere = istwfk_disk /= wfd%istwfk(ik_ibz)
2419 :
2420 : ! Create communicator with master and all procs requiring this (k,s) block (color == 1)
2421 0 : need_block_ks = any(gwr%my_spins == spin) .and. any(gwr%my_kibz_inds == ik_ibz)
2422 0 : color = merge(1, 0, (need_block_ks .or. io_comm%me == master))
2423 0 : call xmpi_comm_split(io_comm%value, color, io_comm%me, bcast_comm, ierr)
2424 :
2425 : ! TODO: Optimize this part
2426 : ! Find band_step that gives good compromise between memory and efficiency.
2427 : !band_step = memb_limited_step(1, nbsum, 2*npwsp_disk, xmpi_bsize_dp, min_mem_mb * 0.8_dp)
2428 0 : band_step = 200
2429 :
2430 0 : do bstart=1, nbsum, band_step
2431 0 : bstop = min(bstart + band_step - 1, nbsum); nb = bstop - bstart + 1
2432 :
2433 0 : ABI_MALLOC(cg_work, (2, npwsp_disk, nb)) ! This array is always in double precision.
2434 0 : if (io_comm%me == master) then
2435 0 : call c_f_pointer(c_loc(cg_work), cg_k, shape=[2, npwsp_disk * nb])
2436 0 : call wfk%read_band_block([bstart, bstop], ik_ibz, spin, xmpio_single, kg_k=kg_k_disk, cg_k=cg_k)
2437 : end if
2438 :
2439 0 : if (color == 1) then
2440 0 : call xmpi_bcast(kg_k_disk, master, bcast_comm, ierr)
2441 0 : call xmpi_bcast(cg_work, master, bcast_comm, ierr)
2442 : endif
2443 :
2444 : ! Copy my portion of cg_work to buffer_cplx (here we have dp --> sp conversion).
2445 0 : if (need_block_ks) then
2446 : associate (ugb => gwr%ugb(ik_ibz, spin), desc_k => gwr%green_desc_kibz(ik_ibz))
2447 :
2448 : ! Table with the correspondence btw the k-centered sphere of the WFK file
2449 : ! and the one used in wfd (possibly smaller due to ecutwfn).
2450 0 : if (cut_ug .and. bstart == 1) then
2451 0 : ABI_MALLOC(gf2wfd, (npw_k_disk))
2452 0 : call kg_map(npw_k, desc_k%gvec, npw_k_disk, kg_k_disk, gf2wfd, nmiss)
2453 : end if
2454 :
2455 0 : do band=bstart, bstop
2456 0 : ib = band - bstart + 1
2457 0 : call ugb%glob2loc(1, band, iloc, il_b, have_band); if (.not. have_band) cycle
2458 :
2459 0 : if (.not. cut_ug) then
2460 0 : if (band == bstart) then
2461 0 : ABI_CHECK(all(kg_k_disk(:,1:npw_k_disk) == desc_k%gvec), "kg_k_disk != desc_k%gvec")
2462 : end if
2463 0 : ugb%buffer_cplx(:, il_b) = cmplx(cg_work(1,:,ib), cg_work(2,:,ib), kind=gwp)
2464 :
2465 : else
2466 : !ugb%buffer_cplx(:, il_b) = zero
2467 0 : do spinor=1,gwr%nspinor
2468 0 : cg_spad = (spinor-1) * npw_k_disk
2469 0 : gw_spad = (spinor-1) * npw_k
2470 0 : do ig=1,npw_k_disk
2471 0 : icg = ig + cg_spad
2472 0 : igw = gf2wfd(ig) + gw_spad
2473 0 : if (gf2wfd(ig) /= 0) then
2474 0 : ugb%buffer_cplx(igw, il_b) = cmplx(cg_work(1,icg,ib), cg_work(2,icg,ib), kind=gwp)
2475 : end if
2476 : end do
2477 : end do ! spinor
2478 :
2479 : ! Re-normalize wavefunctions..
2480 0 : cdum = xdotc(npw_k*gwr%nspinor, ugb%buffer_cplx(:,il_b), 1, ugb%buffer_cplx(:,il_b), 1)
2481 0 : if (istwf_k > 1) then
2482 0 : cdum = two * DBLE(cdum)
2483 : associate (ug1 => ugb%buffer_cplx(1,il_b))
2484 0 : if (istwf_k == 2) cdum = cdum - conjg(ug1) * ug1
2485 : end associate
2486 : end if
2487 0 : cdum = one / sqrt(cdum)
2488 0 : call xscal(npw_k*gwr%nspinor, cdum, ugb%buffer_cplx(:,il_b), 1)
2489 : !print *, "new norm:", xdotc(npw_k*gwr%nspinor, ugb%buffer_cplx(:,il_b), 1, ugb%buffer_cplx(:,il_b), 1)
2490 : end if
2491 :
2492 : end do ! band
2493 : end associate
2494 : end if
2495 :
2496 0 : ABI_FREE(cg_work)
2497 : end do ! bstart
2498 :
2499 0 : ABI_SFREE(gf2wfd)
2500 0 : call xmpi_comm_free(bcast_comm)
2501 :
2502 0 : if (print_time) then
2503 0 : write(msg,'(4x,2(a,i0),a)')" Read ugb_k: ik_ibz [", ik_ibz, "/", gwr%nkibz, "]"
2504 0 : call cwtime_report(msg, cpu_green, wall_green, gflops_green); if (ik_ibz == LOG_MODK) call wrtout(std_out, " ...")
2505 : end if
2506 : end do ! ik_ibz
2507 : end do ! spin
2508 0 : if (io_comm%me == master) call wfk%close()
2509 :
2510 0 : ABI_FREE(kg_k_disk)
2511 0 : call gwr%print_mem([std_out])
2512 :
2513 0 : call cwtime_report(" gwr_read_ugb_from_wfk:", cpu, wall, gflops)
2514 0 : call timab(1921, 2, tsec)
2515 :
2516 0 : end subroutine gwr_read_ugb_from_wfk
2517 : !!***
2518 :
2519 : !----------------------------------------------------------------------
2520 :
2521 : !!****f* m_gwr/gwr_build_green
2522 : !! NAME
2523 : !! gwr_build_green
2524 : !!
2525 : !! FUNCTION
2526 : !! Build Green's functions in imaginary time from the gwr%ugb matrices stored in memory.
2527 : !! Store only G_k for the IBZ k-points treated by this MPI proc.
2528 : !!
2529 : !! INPUTS
2530 : !! free_ugb: True if the gwr%ugb wavefunctions should be deallocated before returning.
2531 : !!
2532 : !! SOURCE
2533 :
2534 0 : subroutine gwr_build_green(gwr, free_ugb)
2535 :
2536 : !Arguments ------------------------------------
2537 : class(gwr_t),target,intent(inout) :: gwr
2538 : logical,intent(in) :: free_ugb
2539 :
2540 : !Local variables-------------------------------
2541 : !scalars
2542 : integer :: my_is, my_iki, spin, ik_ibz, band, itau, ipm, il_b, npw, isgn, my_it, nbsum !, ig_glob, ig_loc, jg_loc, nb_occ
2543 : integer :: ii, icomp
2544 : real(dp), parameter :: eratio = 0.95_dp
2545 : real(dp) :: eig_nk, cpu, wall, gflops, cpu_k, wall_k, gflops_k !, f_nk
2546 : logical :: print_time, compute_svd
2547 : character(len=500) :: msg
2548 : real(dp) :: gt_rfact, s2_sum, s2_sum_all
2549 0 : type(__slkmat_t), target :: work_gb(gwr%nspinor), green, u_mat, vt_mat
2550 0 : real(gwp),allocatable :: s_vals(:)
2551 : !arrays
2552 0 : integer :: mask_kibz(gwr%nkibz), units(2) !, ija(2), ijb(2)
2553 : !integer :: occ_idx(gwr%ks_ebands%nkpt, gwr%ks_ebands%nsppol)
2554 : real(dp) :: tsec(2) , kk_ibz(3) !, kg(3)
2555 0 : real(dp),contiguous, pointer :: qp_eig(:,:,:), qp_occ(:,:,:)
2556 : integer :: iab, iiab, jiab, ispinor !,i, j
2557 : integer, parameter :: spinor_idxs(2, 4) = RESHAPE([1, 1, 2, 2, 1, 2, 2, 1], [2, 4])
2558 : ! *************************************************************************
2559 :
2560 0 : call cwtime(cpu, wall, gflops, "start")
2561 0 : call timab(1922, 1, tsec)
2562 0 : units = [std_out, ab_out]
2563 0 : nbsum = gwr%dtset%nband(1)
2564 :
2565 : ! Use KS or QP energies depending on the iteration state.
2566 0 : if (gwr%scf_iteration == 1) then
2567 : call wrtout(units, " Building Green's functions from KS orbitals and KS energies...", &
2568 0 : pre_newlines=2, newlines=1, do_flush=.True.)
2569 0 : qp_eig => gwr%ks_ebands%eig; qp_occ => gwr%ks_ebands%occ
2570 0 : msg = sjoin("Fermi energy is not set to zero! fermie:", ftoa(gwr%ks_ebands%fermie))
2571 0 : ABI_CHECK(abs(gwr%ks_ebands%fermie) < tol12, msg)
2572 :
2573 : !occ_idx = gwr%ks_ebands%get_occupied()
2574 :
2575 : ! Allocate my Green's functions in IBZ if this is the first iteration.
2576 0 : mask_kibz = 0; mask_kibz(gwr%my_kibz_inds(:)) = 1
2577 0 : call gwr%malloc_free_mats(mask_kibz, "green", "malloc")
2578 :
2579 : else
2580 : call wrtout(units, " Building Green's functions from KS orbitals and QP energies...", &
2581 0 : pre_newlines=2, newlines=1, do_flush=.True.)
2582 0 : qp_eig => gwr%qp_ebands%eig; qp_occ => gwr%qp_ebands%occ
2583 0 : msg = sjoin("Fermi energy is not set to zero! fermie:", ftoa(gwr%qp_ebands%fermie))
2584 0 : ABI_CHECK(abs(gwr%qp_ebands%fermie) < tol12, msg)
2585 :
2586 : !occ_idx = gwr%qp_ebands%get_occupied()
2587 : end if
2588 :
2589 0 : ABI_CHECK(allocated(gwr%ugb), "gwr%ugb array should be allocated!")
2590 0 : compute_svd = .False.
2591 : !compute_svd = .True.
2592 :
2593 0 : do my_is=1,gwr%my_nspins
2594 0 : spin = gwr%my_spins(my_is)
2595 : ! Loop over my k-points in the IBZ
2596 0 : do my_iki=1,gwr%my_nkibz
2597 0 : print_time = gwr%comm%me == 0 .and. (my_iki < LOG_MODK .or. mod(my_iki, LOG_MODK) == 0)
2598 0 : if (print_time) call cwtime(cpu_k, wall_k, gflops_k, "start")
2599 0 : ik_ibz = gwr%my_kibz_inds(my_iki)
2600 0 : kk_ibz = gwr%kibz(:, ik_ibz)
2601 0 : associate (ugb_ks => gwr%ugb(ik_ibz, spin), desc_k => gwr%green_desc_kibz(ik_ibz))
2602 0 : npw = desc_k%npw
2603 : ! Init output of pzgemm in g-communicator
2604 0 : call green%init(npw, npw, gwr%g_slkproc, istwfk1) ! size_blocs=[-1, col_bsize])
2605 :
2606 : ! Loop over my_ntau as pzgemm is MPI-parallelized inside g_comm.
2607 0 : do my_it=1,gwr%my_ntau
2608 0 : itau = gwr%my_itaus(my_it)
2609 0 : do ipm=1,2
2610 0 : do ispinor = 1, gwr%nspinor
2611 0 : call ugb_ks%cut(npw, ugb_ks%size_global(2), work_gb(ispinor), ija=[(ispinor - 1)*npw + 1, 1])
2612 :
2613 : !work_gb(my_is)%buffer_cplx = gwr %ugb(ik_ibz, spin)%buffer_cplx
2614 :
2615 : !call ugb_ks%change_size_blocs(work_gb, size_blocs=, processor=)
2616 : !call work_gb%copy(green, empty=.True.)
2617 :
2618 : ! Loop over my_ntau as pzgemm is MPI-parallelized inside g_comm.
2619 : ! do my_it=1,gwr%my_ntau
2620 : ! itau = gwr%my_itaus(my_it)
2621 : ! do ipm=1,2
2622 : ! Multiply my columns by exponentials in imaginary time.
2623 : ! work_gb%buffer_cplx = ugb_ks%buffer_cplx
2624 :
2625 : !!!$OMP PARALLEL DO PRIVATE(band, f_nk, eig_nk, gt_rfact)
2626 : !$OMP PARALLEL DO PRIVATE(band, eig_nk, gt_rfact)
2627 0 : do il_b = 1, work_gb(ispinor)%size_local(2)
2628 0 : band = work_gb(ispinor)%loc2gcol(il_b)
2629 : !f_nk = qp_occ(band, ik_ibz, spin)
2630 0 : eig_nk = qp_eig(band, ik_ibz, spin)
2631 0 : gt_rfact = zero
2632 0 : if (ipm == 2) then
2633 0 : if (eig_nk < -tol6) gt_rfact = exp(gwr%tau_mesh(itau) * eig_nk)
2634 : else
2635 0 : if (eig_nk > tol6) gt_rfact = exp(-gwr%tau_mesh(itau) * eig_nk)
2636 : end if
2637 :
2638 : !work_gb%buffer_cplx(:,il_b) = work_gb%buffer_cplx(:,il_b) * sqrt(gt_rfact)
2639 0 : call xscal(npw, real(sqrt(gt_rfact), kind=gwp), work_gb(ispinor)%buffer_cplx(:, il_b), 1)
2640 : end do ! il_b
2641 : end do !ispinor
2642 : ! end do ! ipm
2643 : ! end do ! itau
2644 :
2645 : ! Now build G(g,g',ipm) with PZGEMM.
2646 0 : isgn = merge(1, -1, ipm == 2)
2647 0 : do iab = 1, gwr%nsig_ab
2648 0 : iiab = spinor_idxs(1, iab)
2649 0 : jiab = spinor_idxs(2, iab)
2650 :
2651 : ! TODO: optimize this part
2652 : ! This wont' work for metals
2653 : !nb_occ = occ_idx(ik_ibz, spin)
2654 : ! nb_occ = -1
2655 : !if (ipm == 1) then
2656 : ! ija = [1, nb_occ]; ijb = ija
2657 : !else
2658 : ! ija = [nb_occ+1, gwr%ugb_nband]; ijb = ija
2659 : !end if
2660 0 : call slk_pgemm("N", "C", work_gb(iiab), isgn*cone_gw, work_gb(jiab), czero_gw, green)
2661 :
2662 : ! SVD. NB: green matrix in destroyed in output.
2663 : if (compute_svd) then
2664 : call green%svd("N", "N", u_mat, s_vals, vt_mat)
2665 : s2_sum_all = sum(s_vals**2)
2666 : icomp = -1
2667 : do ii=1,size(s_vals)
2668 : s2_sum = sum(s_vals(1:ii)**2)
2669 : if (icomp == -1 .and. s2_sum / s2_sum_all > eratio) icomp = ii
2670 : !write(std_out, *)ii, s_vals(ii), 100 * s2_sum / s2_sum_all
2671 : end do
2672 : write(std_out, "(a,i0,2a,3(a,1x,i0))") &
2673 : "SVD: For ik_ibz: ", ik_ibz, ", kpt: ", trim(ktoa(kk_ibz)), ", itau: ", itau, ", ipm: ", ipm, ", spin: ", spin
2674 : write(std_out, "(a,i0,2(a,f5.2),a,i0)") &
2675 : "SVD: Need ", icomp, " vectors with frac: ", (100.0_dp * icomp) / size(s_vals), &
2676 : "% to reach eratio: ", eratio, ", G matrix size: ", size(s_vals)
2677 : ABI_FREE(s_vals)
2678 : end if
2679 :
2680 : ! Redistribute data.
2681 0 : call gwr%gt_kibz(ipm, ik_ibz, itau, spin, iab)%take_from(green)
2682 : end do ! iab
2683 0 : call slk_array_free(work_gb)
2684 :
2685 : end do ! ipm
2686 : end do ! my_it
2687 :
2688 0 : call green%free()
2689 : ! Free wavefunctions if asked for.
2690 0 : if (free_ugb) call ugb_ks%free()
2691 :
2692 0 : if (print_time) then
2693 0 : write(msg,'(4x,3(a,i0),a)')"G_ikbz [", my_iki, "/", gwr%my_nkibz, "] (tot: ", gwr%nkibz, ")"
2694 0 : call cwtime_report(msg, cpu_k, wall_k, gflops_k); if (my_iki == LOG_MODK) call wrtout(std_out, " ...")
2695 : end if
2696 : end associate
2697 : end do ! my_iki
2698 : end do ! my_is
2699 :
2700 0 : if (gwr%dtset%prtvol > 0) call gwr%print_trace(units, "gt_kibz")
2701 0 : call gwr%print_mem([std_out])
2702 :
2703 0 : call cwtime_report(" gwr_build_green:", cpu, wall, gflops)
2704 0 : call timab(1922, 2, tsec)
2705 :
2706 : !if (compute_svd) stop "compute_svd"
2707 :
2708 0 : end subroutine gwr_build_green
2709 : !!***
2710 :
2711 : !----------------------------------------------------------------------
2712 :
2713 : !!****f* m_gwr/gwr_gk_to_scbox
2714 : !! NAME
2715 : !! gwr_gk_to_scbox
2716 : !!
2717 : !! FUNCTION
2718 : !! Insert G_k(g',r) in the FFT box of the supercell: k+g' index.
2719 : !!
2720 : !! INPUTS
2721 : !! select_my_kbz: Mask used to select a subset of gwr%my_nkbz k-points.
2722 : !!
2723 : !! OUTPUT
2724 : !!
2725 : !! SOURCE
2726 :
2727 0 : subroutine gwr_gk_to_scbox(gwr, sc_ngfft, select_my_kbz, desc_mykbz, green_scgvec, my_ir, ndat, gt_gpr, gt_scbox, gt_scbox_win)
2728 :
2729 : !Arguments ------------------------------------
2730 : class(gwr_t),target,intent(in) :: gwr
2731 : integer,intent(in) :: sc_ngfft(18)
2732 : logical,intent(in) :: select_my_kbz(gwr%my_nkbz)
2733 : integer,intent(out) :: green_scgvec(3, gwr%green_mpw)
2734 : type(desc_t),intent(inout) :: desc_mykbz(gwr%my_nkbz)
2735 : type(__slkmat_t),intent(in) :: gt_gpr(2, gwr%my_nkbz)
2736 : integer,intent(in) :: my_ir, ndat
2737 : complex(gwp), intent(out) :: gt_scbox(product(sc_ngfft(4:6)), gwr%sc_batch_size, 2)
2738 : integer,optional,intent(inout) :: gt_scbox_win
2739 :
2740 : !Local variables-------------------------------
2741 0 : integer :: my_ikf, ik_bz, ipm, gg(3), idat, iepoch, ii, idat_list(gwr%kpt_comm%nproc), ierr ! ig,
2742 : !real(dp) :: tsec(2) !, cpu, wall, gflops
2743 : ! *************************************************************************
2744 :
2745 : !call cwtime(cpu, wall, gflops, "start")
2746 : !call timab(1929, 1, tsec)
2747 :
2748 : ! Take the union of (k,g') for k in the BZ.
2749 : ! Note gwr%ngkpt instead of gwr%ngqpt.
2750 0 : if (.not. present(gt_scbox_win)) then
2751 : ! Zero output array.
2752 0 : gt_scbox = czero_gw
2753 :
2754 0 : do my_ikf=1,gwr%my_nkbz
2755 : if (.not. select_my_kbz(my_ikf)) continue
2756 0 : ik_bz = gwr%my_kbz_inds(my_ikf); gg = nint(gwr%kbz(:,ik_bz) * gwr%ngkpt)
2757 0 : do ipm=1,2
2758 : call desc_mykbz(my_ikf)%to_scbox(gwr%kbz(:, ik_bz), gwr%ngkpt, sc_ngfft, ndat, &
2759 0 : gt_gpr(ipm, my_ikf)%buffer_cplx(1,my_ir), gt_scbox(:,:,ipm))
2760 : end do
2761 : end do ! my_ikf
2762 :
2763 : else
2764 : ! Each MPI proc operates on a different idat vector at each epoch
2765 0 : idat_list = cshift([(ii, ii=1,gwr%kpt_comm%nproc)], shift=-gwr%kpt_comm%me)
2766 :
2767 0 : do iepoch=1,gwr%kpt_comm%nproc
2768 0 : call xmpi_win_fence(XMPI_MODE_NOPRECEDE, gt_scbox_win, ierr) ! Start the RMA epoch
2769 0 : idat = idat_list(iepoch)
2770 0 : if (idat > ndat) goto 10
2771 0 : if (iepoch == 1) then
2772 : ! Zero output array.
2773 0 : do ipm=1,2
2774 0 : gt_scbox(:,idat,ipm) = czero_gw
2775 : end do
2776 : end if
2777 :
2778 0 : do my_ikf=1,gwr%my_nkbz
2779 : if (.not. select_my_kbz(my_ikf)) continue
2780 0 : ik_bz = gwr%my_kbz_inds(my_ikf); gg = nint(gwr%kbz(:, ik_bz) * gwr%ngkpt)
2781 0 : do ipm=1,2
2782 : call desc_mykbz(my_ikf)%to_scbox(gwr%kbz(:, ik_bz), gwr%ngkpt, sc_ngfft, ndat1, &
2783 0 : gt_gpr(ipm, my_ikf)%buffer_cplx(1,my_ir+idat-1), gt_scbox(:,idat,ipm))
2784 : end do
2785 : end do ! my_ikf
2786 : 10 continue
2787 : !call xmpi_barrier(gwr%kpt_comm%value)
2788 : !IF (.not. MPI_ASYNC_PROTECTS_NONBLOCKING) CALL MPI_F_SYNC_REG(gt_scbox)
2789 0 : call xmpi_win_fence(XMPI_MODE_NOSUCCEED, gt_scbox_win, ierr) ! End the RMA epoch
2790 : end do ! iepoch
2791 : end if
2792 :
2793 : !call cwtime_report(" gwr_gk_to_scbox:", cpu, wall, gflops)
2794 : !call timab(1929, 2, tsec)
2795 :
2796 0 : end subroutine gwr_gk_to_scbox
2797 : !!***
2798 :
2799 : !----------------------------------------------------------------------
2800 :
2801 : !!****f* m_gwr/gwr_wcq_to_scbox
2802 : !! NAME
2803 : !! gwr_wcq_to_scbox
2804 : !!
2805 : !! FUNCTION
2806 : !! Insert W_q(g',r) in the FFT box of the supercell: q+g' index.
2807 : !!
2808 : !! INPUTS
2809 : !! select_my_qbz: Mask used to select a subset of gwr%my_qkbz q-points.
2810 : !!
2811 : !! OUTPUT
2812 : !!
2813 : !! SOURCE
2814 :
2815 0 : subroutine gwr_wcq_to_scbox(gwr, sc_ngfft, select_my_qbz, desc_myqbz, wc_scgvec, my_ir, ndat, &
2816 0 : wc_gpr, wct_scbox, wct_scbox_win)
2817 :
2818 : !Arguments ------------------------------------
2819 : class(gwr_t),target,intent(in) :: gwr
2820 : integer,intent(in) :: sc_ngfft(18)
2821 : logical,intent(in) :: select_my_qbz(gwr%my_nqbz)
2822 : integer,intent(out) :: wc_scgvec(3, gwr%tchi_mpw)
2823 : type(desc_t),intent(inout) :: desc_myqbz(gwr%my_nqbz)
2824 : type(__slkmat_t),intent(in) :: wc_gpr(gwr%my_nqbz)
2825 : integer,intent(in) :: my_ir, ndat
2826 : complex(gwp),intent(out) :: wct_scbox(product(sc_ngfft(4:6)), gwr%sc_batch_size)
2827 : !complex(gwp),intent(out) :: wct_scbox(:,:)
2828 : integer,optional,intent(inout) :: wct_scbox_win
2829 :
2830 : !Local variables-------------------------------
2831 0 : integer :: my_iqf, iq_bz, idat, iepoch, ii, idat_list(gwr%kpt_comm%nproc), ierr ! gg(3), ig,
2832 : !real(dp) :: tsec(2) !, cpu, wall, gflops
2833 : ! *************************************************************************
2834 :
2835 : !call timab(1930, 1, tsec)
2836 :
2837 : ! Take the union of (q,g') for q in the BZ. Note gwr%ngqpt instead of gwr%ngkpt.
2838 :
2839 0 : if (.not. present(wct_scbox_win)) then
2840 0 : wct_scbox = czero_gw
2841 0 : do my_iqf=1,gwr%my_nqbz
2842 : if (.not. select_my_qbz(my_iqf)) continue
2843 0 : iq_bz = gwr%my_qbz_inds(my_iqf)
2844 :
2845 : call desc_myqbz(my_iqf)%to_scbox(gwr%qbz(:,iq_bz), gwr%ngqpt, sc_ngfft, ndat, &
2846 0 : wc_gpr(my_iqf)%buffer_cplx(1,my_ir), wct_scbox)
2847 : end do ! my_iqf
2848 :
2849 : else
2850 : ! Each MPI proc operates on a different idat vector at each epoch
2851 0 : idat_list = cshift([(ii, ii=1,gwr%kpt_comm%nproc)], shift=-gwr%kpt_comm%me)
2852 :
2853 0 : do iepoch=1,gwr%kpt_comm%nproc
2854 0 : call xmpi_win_fence(XMPI_MODE_NOPRECEDE, wct_scbox_win, ierr) ! Start the RMA epoch
2855 0 : idat = idat_list(iepoch)
2856 0 : if (idat > ndat) goto 10
2857 0 : if (iepoch == 1) wct_scbox(:,idat) = czero_gw
2858 :
2859 0 : do my_iqf=1,gwr%my_nkbz
2860 : if (.not. select_my_qbz(my_iqf)) continue
2861 0 : iq_bz = gwr%my_qbz_inds(my_iqf)
2862 : call desc_myqbz(my_iqf)%to_scbox(gwr%qbz(:,iq_bz), gwr%ngqpt, sc_ngfft, ndat1, &
2863 0 : wc_gpr(my_iqf)%buffer_cplx(1,my_ir+idat-1), wct_scbox(:,idat))
2864 : end do ! my_iqf
2865 : 10 continue
2866 : !call xmpi_barrier(gwr%kpt_comm%value)
2867 : !IF (.not. MPI_ASYNC_PROTECTS_NONBLOCKING) CALL MPI_F_SYNC_REG(wct_scbox)
2868 0 : call xmpi_win_fence(XMPI_MODE_NOSUCCEED, wct_scbox_win, ierr) ! End the RMA epoch
2869 : end do ! iepoch
2870 : end if
2871 :
2872 : !call timab(1930, 2, tsec)
2873 :
2874 0 : end subroutine gwr_wcq_to_scbox
2875 : !!***
2876 :
2877 : !----------------------------------------------------------------------
2878 :
2879 : !!****f* m_gwr/gwr_rotate_gpm
2880 : !! NAME
2881 : !! gwr_rotate_gpm
2882 : !!
2883 : !! FUNCTION
2884 : !! Reconstruct the Green's functions in the BZ from the IBZ.
2885 : !!
2886 : !! INPUTS
2887 : !! ik_bz = Index of the k-point in the BZ
2888 : !! itau = tau index (global index)
2889 : !! spin = spin index (global index)
2890 : !! [ipm_list]=Optional list of ipm indices to be considered, e.g. ipm_list=[2] to compute the -tau component.
2891 : !!
2892 : !! OUTPUT
2893 : !! desc_kbz = Descriptor in the BZ
2894 : !! gt_pm(2) = Gk(+/-tau)
2895 : !!
2896 : !! NOTES
2897 : !!
2898 : !! * Remember the symmetry properties of \tilde\espilon^{-1}
2899 : !!
2900 : !! If q_bz = S q_ibz + G0:
2901 : !!
2902 : !! $\epsilon^{-1}_{SG1-G0, SG2-G0}(q_bz) = e^{+iS(G2-G1).\tau} \epsilon^{-1}_{G1, G2)}(q)
2903 : !!
2904 : !! If time-reversal symmetry can be used then:
2905 : !!
2906 : !! $\epsilon^{-1}_{G1,G2}(-q_bz) = e^{+i(G1-G2).\tau} \epsilon^{-1}_{-S^{-1}(G1+Go), -S^{-1}(G2+G0)}^*(q)
2907 : !!
2908 : !! In the present implementation we are not considering a possible umklapp vector G0 in the
2909 : !! expression Sq = q+G0. Treating this case would require some changes in the G-sphere
2910 : !! since we have to consider G - G0. The code however stops in sigma if a nonzero G0 is required
2911 : !! to reconstruct the BZ.
2912 : !!
2913 : !! SOURCE
2914 :
2915 0 : subroutine gwr_rotate_gpm(gwr, ik_bz, itau, spin, desc_kbz, gt_pm, ipm_list)
2916 :
2917 : !Arguments ------------------------------------
2918 : class(gwr_t),intent(in) :: gwr
2919 : integer,intent(in) :: ik_bz, spin, itau
2920 : type(desc_t),intent(out) :: desc_kbz
2921 : type(__slkmat_t),intent(out) :: gt_pm(2, gwr%nsig_ab)
2922 : integer,optional,intent(in) :: ipm_list(:)
2923 :
2924 : !Local variables-------------------------------
2925 : !scalars
2926 : integer :: ig1, ig2, il_g1, il_g2, ipm, ik_ibz, isym_k, trev_k, g0_k(3), tsign_k, ii, num_pm, ipm_list__(2)
2927 : integer :: iab, iiab, jiab
2928 : logical :: isirr_k
2929 : !arrays
2930 : integer :: g1(3), g2(3)
2931 : real(dp) :: tnon(3), spinrot_k(4) !, cpu, wall, gflops
2932 : complex(dp) :: ph2, ph1, spinrot_cmat1(2,2), spinrot_cmat2(2,2), tmp_mat(2,2)
2933 : integer, parameter :: spinor_idxs(2, 4) = RESHAPE([1, 1, 2, 2, 1, 2, 2, 1], [2, 4])
2934 : ! *************************************************************************
2935 :
2936 : !call cwtime(cpu, wall, gflops, "start")
2937 0 : num_pm = 2; ipm_list__ = [1, 2]
2938 0 : if (present(ipm_list)) then
2939 0 : num_pm = size(ipm_list)
2940 0 : ABI_CHECK_IRANGE(num_pm, 1, 2, "num_pm not in [1, 2]")
2941 0 : ipm_list__(1:num_pm) = ipm_list(:)
2942 : end if
2943 :
2944 0 : ik_ibz = gwr%kbz2ibz(1, ik_bz); isym_k = gwr%kbz2ibz(2, ik_bz)
2945 0 : trev_k = gwr%kbz2ibz(6, ik_bz); g0_k = gwr%kbz2ibz(3:5, ik_bz)
2946 0 : isirr_k = (isym_k == 1 .and. trev_k == 0 .and. all(g0_k == 0))
2947 0 : tsign_k = merge(1, -1, trev_k == 0)
2948 : !ABI_CHECK(all(g0_k == 0), sjoin("For kbz:", ktoa(gwr%kbz(:, ik_bz)), "g0_k:", ltoa(g0_k), " != 0"))
2949 :
2950 : ! Copy descriptor from IBZ
2951 : associate (desc_kibz => gwr%green_desc_kibz(ik_ibz))
2952 0 : call desc_kibz%copy(desc_kbz)
2953 :
2954 0 : if (isirr_k) then
2955 : ! Copy the PBLAS matrices with the two Green's functions and we are done.
2956 0 : do ii=1,num_pm
2957 0 : ipm = ipm_list__(ii)
2958 0 : do iab=1,gwr%nsig_ab
2959 0 : call gwr%gt_kibz(ipm, ik_ibz, itau, spin, iab)%copy(gt_pm(ipm, iab))
2960 : end do
2961 : end do
2962 : goto 10
2963 : end if
2964 :
2965 : ! From:
2966 : !
2967 : ! u_{Sk}(Sg) = e^{-i(Sk+Sg).tnon} u_k(g)
2968 : !
2969 : ! and
2970 : !
2971 : ! u_{k+g0}(g-g0) = u_k(g)
2972 : !
2973 : ! one obtains:
2974 : !
2975 : ! G_{Sk+g0}(Sg-g0,Sg'-g0) = e^{-i tnon.S(g-g')} G_k{g,g'}
2976 : !
2977 : ! For time-reversal, we have u_{-k}(g) = u_{k}{-g}^*
2978 : !
2979 : ! G_{-k}(-g,-g') = [G_k(g,g')]*
2980 :
2981 : !ABI_WARNING_IF(trev_k == 0, "green: trev_k /= 0 should be tested")
2982 :
2983 : ! Rotate gvec, recompute gbound and rotate vc_sqrt_eps
2984 : ! TODO: 1) Handle TR and routine to rotate tchi/W including vc_sqrt_eps
2985 : ! 2) Make sure that the FFT box is large enough to accommodate umklapps
2986 :
2987 0 : desc_kbz%ig0 = -1
2988 : !$OMP PARALLEL DO
2989 0 : do ig1=1,desc_kbz%npw
2990 0 : desc_kbz%gvec(:,ig1) = tsign_k * matmul(gwr%cryst%symrec(:,:,isym_k), desc_kibz%gvec(:,ig1)) - g0_k
2991 0 : if (all(desc_kbz%gvec(:,ig1) == 0)) desc_kbz%ig0 = ig1
2992 : end do
2993 0 : desc_kbz%kin_sorted = .False.
2994 0 : ABI_CHECK(desc_kbz%ig0 /= -1, "Cannot find g=0 after rotation!")
2995 :
2996 0 : call sphereboundary(desc_kbz%gbound, desc_kbz%istwfk, desc_kbz%gvec, gwr%g_mgfft, desc_kbz%npw)
2997 :
2998 : ! Get G_k with k in the BZ.
2999 0 : tnon = gwr%cryst%tnons(:, isym_k)
3000 0 : do ii=1,num_pm
3001 0 : ipm = ipm_list__(ii)
3002 0 : do iab=1,gwr%nsig_ab
3003 0 : call gwr%gt_kibz(ipm, ik_ibz, itau, spin, iab)%copy(gt_pm(ipm, iab))
3004 : end do
3005 : ! associate (gk_i => gwr%gt_kibz(ipm, ik_ibz, itau, spin, :), gk_f => gt_pm(ipm, :))
3006 : !!$OMP PARALLEL DO PRIVATE(ig1, g2, ph2, ig1, g2, ph1)
3007 0 : do il_g2=1, gt_pm(ipm, 1)%size_local(2)
3008 0 : ig2 = mod(gt_pm(ipm, 1)%loc2gcol(il_g2) - 1, desc_kbz%npw) + 1
3009 0 : g2 = desc_kbz%gvec(:,ig2)
3010 0 : ph2 = exp(+j_dpc * two_pi * dot_product(g2, tnon))
3011 0 : do il_g1=1, gt_pm(ipm, 1)%size_local(1)
3012 0 : ig1 = mod(gt_pm(ipm, 1)%loc2grow(il_g1) - 1, desc_kbz%npw) + 1
3013 0 : g1 = desc_kbz%gvec(:,ig1)
3014 0 : ph1 = exp(-j_dpc * two_pi * dot_product(g1, tnon))
3015 0 : if (gwr%nspinor == 1) then
3016 0 : gt_pm(ipm, 1)%buffer_cplx(il_g1, il_g2) = gwr%gt_kibz(ipm, ik_ibz, itau, spin, 1)%buffer_cplx(il_g1, il_g2) * ph1 * ph2
3017 : else
3018 0 : spinrot_k = gwr%cryst%spinrot(:, isym_k)
3019 :
3020 0 : spinrot_cmat1(1,1) = spinrot_k(1) - j_dpc*spinrot_k(4)
3021 0 : spinrot_cmat1(1,2) =-spinrot_k(3) - j_dpc*spinrot_k(2)
3022 0 : spinrot_cmat1(2,1) = spinrot_k(3) - j_dpc*spinrot_k(2)
3023 0 : spinrot_cmat1(2,2) = spinrot_k(1) + j_dpc*spinrot_k(4)
3024 :
3025 0 : spinrot_cmat2(1,1) = spinrot_k(1) + j_dpc*spinrot_k(4)
3026 0 : spinrot_cmat2(1,2) = spinrot_k(3) + j_dpc*spinrot_k(2)
3027 0 : spinrot_cmat2(2,1) =-spinrot_k(3) + j_dpc*spinrot_k(2)
3028 0 : spinrot_cmat2(2,2) = spinrot_k(1) - j_dpc*spinrot_k(4)
3029 :
3030 0 : do iab=1,gwr%nsig_ab
3031 0 : iiab = spinor_idxs(1, iab); jiab = spinor_idxs(2, iab)
3032 0 : tmp_mat(iiab, jiab) = gwr%gt_kibz(ipm, ik_ibz, itau, spin, iab)%buffer_cplx(il_g1, il_g2)
3033 : end do
3034 0 : tmp_mat = matmul(spinrot_cmat1, matmul(tmp_mat, spinrot_cmat2)) * ph1 * ph2
3035 0 : do iab=1,gwr%nsig_ab
3036 0 : iiab = spinor_idxs(1, iab); jiab = spinor_idxs(2, iab)
3037 0 : gt_pm(ipm, iab)%buffer_cplx(il_g1, il_g2) = tmp_mat(iiab, jiab)
3038 : end do
3039 : end if
3040 0 : if (trev_k == 1) then
3041 0 : if (gwr%nspinor == 1) then
3042 0 : gt_pm(ipm, 1)%buffer_cplx(il_g1, il_g2) = conjg(gt_pm(ipm, 1)%buffer_cplx(il_g1, il_g2))
3043 : else
3044 0 : gt_pm(ipm, 1)%buffer_cplx(il_g1, il_g2) = conjg(tmp_mat(2, 2))
3045 0 : gt_pm(ipm, 2)%buffer_cplx(il_g1, il_g2) = conjg(tmp_mat(1, 1))
3046 0 : gt_pm(ipm, 3)%buffer_cplx(il_g1, il_g2) = - conjg(tmp_mat(2, 1))
3047 0 : gt_pm(ipm, 4)%buffer_cplx(il_g1, il_g2) = - conjg(tmp_mat(1, 2))
3048 : end if
3049 : end if
3050 : end do
3051 : end do
3052 : ! end associate
3053 : end do ! ii
3054 : end associate
3055 :
3056 : 10 continue
3057 : !call cwtime_report(" gwr_rotate_gpm:", cpu, wall, gflops)
3058 :
3059 0 : end subroutine gwr_rotate_gpm
3060 : !!***
3061 :
3062 : !----------------------------------------------------------------------
3063 :
3064 : !!****f* m_gwr/gwr_get_myk_green_gpr
3065 : !! NAME
3066 : !! gwr_get_myk_green_gpr
3067 : !!
3068 : !! FUNCTION
3069 : !! Use FFTs to compute G_k(g,g') --> G_k(g',r) for each k in the BZ treated by this MPI proc for given spin and tau.
3070 : !!
3071 : !! 1) FFT Transform the first index and multiply by e^{ik.r}:
3072 : !!
3073 : !! G_k(g,g') --> G_k(r,g') = e^{ik.r} \sum_g e^{ig.r} G_k(g,g')
3074 : !!
3075 : !! NB: This is a local operation.
3076 : !!
3077 : !! 2) MPI transpose the matrix to go from (r,g') to (g',r) distribution.
3078 : !!
3079 : !! INPUTS
3080 : !! select_my_kbz: Mask used to select a subset of gwr%my_nkbz k-points.
3081 : !!
3082 : !! OUTPUT
3083 : !!
3084 : !! SOURCE
3085 :
3086 0 : subroutine gwr_get_myk_green_gpr(gwr, itau, spin, select_my_kbz, desc_mykbz, gt_gpr)
3087 :
3088 : !Arguments ------------------------------------
3089 : class(gwr_t),intent(in) :: gwr
3090 : integer,intent(in) :: itau, spin
3091 : logical,intent(in) :: select_my_kbz(gwr%my_nkbz)
3092 : type(desc_t),intent(out) :: desc_mykbz(gwr%my_nkbz)
3093 : type(__slkmat_t),intent(inout) :: gt_gpr(2, gwr%my_nkbz, gwr%nsig_ab)
3094 :
3095 : !Local variables-------------------------------
3096 : !scalars
3097 : integer :: my_ikf, ik_bz, ig2, ipm, npw, col_bsize, ndat, gpu_option, gpu_mode, iab
3098 : logical :: k_is_gamma
3099 : real(dp) :: kk_bz(3), cpu, wall, gflops, mem_mb
3100 0 : complex(gwp),allocatable :: ceikr(:)
3101 : character(len=500) :: msg, gpu_action
3102 0 : type(__slkmat_t) :: rgp, gt_pm(2, gwr%nsig_ab)
3103 0 : type(uplan_t) :: uplan_k
3104 : ! *************************************************************************
3105 :
3106 0 : call cwtime(cpu, wall, gflops, "start")
3107 0 : gpu_option = gwr%dtset%gpu_option
3108 0 : gpu_action = "None"; if (gpu_option == ABI_GPU_OPENMP) gpu_action = "alloc"
3109 :
3110 0 : mem_mb = two * gwr%my_nkbz * two * gwp * gwr%g_nfft * gwr%green_mpw * b2Mb / gwr%g_slkproc%grid%nprocs
3111 0 : call wrtout(std_out, sjoin(" Estimated local memory for Green's functions: ", ftoa(mem_mb, fmt="f8.1"), ' [Mb] <<< MEM'))
3112 :
3113 0 : ABI_MALLOC(ceikr, (gwr%g_nfft))
3114 : #ifdef HAVE_OPENMP_OFFLOAD
3115 : !$OMP TARGET ENTER DATA MAP(alloc:ceikr) IF (gpu_option == ABI_GPU_OPENMP)
3116 : #endif
3117 :
3118 0 : do my_ikf=1,gwr%my_nkbz
3119 : if (.not. select_my_kbz(my_ikf)) continue
3120 0 : ik_bz = gwr%my_kbz_inds(my_ikf)
3121 0 : kk_bz = gwr%kbz(:, ik_bz)
3122 0 : k_is_gamma = normv(kk_bz, gwr%cryst%gmet, "G") < GW_TOLQ0
3123 0 : if (.not. k_is_gamma) then
3124 0 : call calc_ceikr(kk_bz, gwr%g_ngfft, gwr%g_nfft, 1, ceikr)
3125 : #ifdef HAVE_OPENMP_OFFLOAD
3126 : !$omp target update to(ceikr) if (gpu_option == ABI_GPU_OPENMP)
3127 : #endif
3128 : end if
3129 :
3130 : ! Get G_kbz(+/- itau) in the BZ.
3131 0 : call gwr%rotate_gpm(ik_bz, itau, spin, desc_mykbz(my_ikf), gt_pm)
3132 :
3133 0 : associate (desc_k => desc_mykbz(my_ikf))
3134 : call uplan_k%init(desc_k%npw, 1, gwr%uc_batch_size, gwr%g_ngfft, desc_k%istwfk, &
3135 0 : desc_k%gvec, gwp, gpu_option)
3136 :
3137 0 : do ipm=1,2
3138 0 : do iab=1,gwr%nsig_ab
3139 : ! Allocate rgp PBLAS matrix to store G_kbz(r,g')
3140 : ! Here we're gonna have a lot of memory allocated due to loop over the full BZ!.
3141 0 : associate (g_gp => gt_pm(ipm, iab))
3142 0 : npw = desc_k%npw
3143 0 : ABI_CHECK(block_dist_1d(npw, gwr%g_comm%nproc, col_bsize, msg), msg)
3144 0 : call rgp%init(gwr%g_nfft, npw, gwr%g_slkproc, desc_k%istwfk, size_blocs=[-1, col_bsize]) !, gpu_action=gpu_action)
3145 :
3146 : ! Perform FFT G_k(g,g') -> G_k(r,g') and store results in rgp.
3147 0 : gpu_mode = 1
3148 0 : do ig2=1, g_gp%size_local(2), gwr%uc_batch_size
3149 0 : ndat = blocked_loop(ig2, g_gp%size_local(2), gwr%uc_batch_size)
3150 0 : if (k_is_gamma) then
3151 0 : call uplan_k%execute_gr(ndat, g_gp%buffer_cplx(:, ig2), rgp%buffer_cplx(:, ig2), gpu_mode=gpu_mode)
3152 : else
3153 0 : call uplan_k%execute_gr(ndat, g_gp%buffer_cplx(:, ig2), rgp%buffer_cplx(:, ig2), phase_r=ceikr, gpu_mode=gpu_mode)
3154 : end if
3155 : end do ! ig2
3156 :
3157 : ! MPI transpose: G_k(r,g') -> G_k(g',r)
3158 0 : call rgp%ptrans("N", gt_gpr(ipm, my_ikf, iab), free=.True.)
3159 : end associate
3160 : end do ! iab
3161 : end do ! ipm
3162 :
3163 0 : call uplan_k%free(); call slk_array_free(gt_pm)
3164 : end associate
3165 : end do ! my_ikf
3166 :
3167 0 : mem_mb = sum(slk_array_locmem_mb(gt_gpr))
3168 0 : call wrtout(std_out, sjoin(" Local memory for G_kbz(g',r,itau): ", ftoa(mem_mb, fmt="f8.1"), "[Mb] <<< MEM"))
3169 :
3170 : #ifdef HAVE_OPENMP_OFFLOAD
3171 : !$OMP TARGET EXIT DATA MAP(delete: ceikr) if (gpu_option == ABI_GPU_OPENMP)
3172 : #endif
3173 0 : ABI_FREE(ceikr)
3174 :
3175 0 : call cwtime_report(" gwr_get_myk_green_gpr:", cpu, wall, gflops)
3176 :
3177 0 : end subroutine gwr_get_myk_green_gpr
3178 : !!***
3179 :
3180 : !----------------------------------------------------------------------
3181 :
3182 : !!****f* m_gwr/gwr_get_gkbz_rpr_pm
3183 : !! NAME
3184 : !! gwr_get_gkbz_rpr_pm
3185 : !!
3186 : !! FUNCTION
3187 : !! Compute G_k(r',r) from G_k(g,g') for k in the BZ and given spin and tau.
3188 : !! Note that the output matrix `gk_rpr_pm` is transposed i.e. (r',r) instead of (r,r').
3189 : !!
3190 : !! INPUTS
3191 : !!
3192 : !! OUTPUT
3193 : !!
3194 : !! SOURCE
3195 :
3196 0 : subroutine gwr_get_gkbz_rpr_pm(gwr, ik_bz, itau, spin, gk_rpr_pm, &
3197 0 : g0, ipm_list) ! optional
3198 :
3199 : !Arguments ------------------------------------
3200 : class(gwr_t),intent(in) :: gwr
3201 : integer,intent(in) :: ik_bz, itau, spin
3202 : type(__slkmat_t),intent(inout) :: gk_rpr_pm(2, gwr%nsig_ab)
3203 : integer,optional,intent(in) :: g0(3), ipm_list(:)
3204 :
3205 : !Local variables-------------------------------
3206 : !scalars
3207 : integer :: ig2, ipm, npw, col_bsize, ir1, ndat, ii, num_pm, ipm_list__(2), gpu_option, gpu_mode, iab
3208 : logical :: have_g0
3209 : !real(dp) :: cpu, wall, gflops
3210 0 : type(__slkmat_t) :: rgp, gt_pm(2, gwr%nsig_ab), gpr
3211 0 : type(desc_t) :: desc_kbz
3212 0 : type(uplan_t) :: uplan_k
3213 0 : complex(gwp),allocatable :: ceig0r(:), conjg_ceig0r(:)
3214 : character(len=500) :: msg, gpu_action
3215 : ! *************************************************************************
3216 :
3217 : !call cwtime(cpu, wall, gflops, "start")
3218 : ABI_NVTX_START_RANGE(NVTX_GWR_GKBZ_RPR_PM)
3219 :
3220 0 : gpu_option = gwr%dtset%gpu_option
3221 :
3222 0 : num_pm = 2; ipm_list__ = [1, 2]
3223 0 : if (present(ipm_list)) then
3224 0 : num_pm = size(ipm_list)
3225 0 : ABI_CHECK_IRANGE(num_pm, 1, 2, "num_pm not in [1, 2]")
3226 0 : ipm_list__(1:num_pm) = ipm_list
3227 : end if
3228 :
3229 0 : have_g0 = .False.
3230 0 : if (present(g0)) then
3231 : ! NB: Non-zero g0, requires the application of the phase.
3232 0 : if (any(g0 /= 0)) then
3233 0 : have_g0 = .True.
3234 0 : ABI_MALLOC(ceig0r, (gwr%g_nfft))
3235 0 : call calc_ceigr(-g0, gwr%g_nfft, 1, gwr%g_ngfft, ceig0r)
3236 0 : ABI_MALLOC(conjg_ceig0r, (gwr%g_nfft))
3237 0 : conjg_ceig0r = conjg(ceig0r)
3238 : #ifdef HAVE_OPENMP_OFFLOAD
3239 : !$OMP TARGET ENTER DATA MAP(alloc:ceig0r, conjg_ceig0r) IF (gpu_option == ABI_GPU_OPENMP)
3240 : !$omp target update to(ceig0r, conjg_ceig0r) if (gpu_option == ABI_GPU_OPENMP)
3241 : #endif
3242 : end if
3243 : end if
3244 :
3245 : ! Get G_k(g,g', +/- itau) in the BZ.
3246 0 : call gwr%rotate_gpm(ik_bz, itau, spin, desc_kbz, gt_pm, ipm_list=ipm_list__(1:num_pm))
3247 :
3248 : call uplan_k%init(desc_kbz%npw, 1, gwr%uc_batch_size, gwr%g_ngfft, desc_kbz%istwfk, &
3249 0 : desc_kbz%gvec, gwp, gpu_option)
3250 :
3251 0 : gpu_action = "None"; if (gpu_option == ABI_GPU_OPENMP) gpu_action = "alloc"
3252 :
3253 : ! For each tau in imp_list__
3254 0 : do ii=1,num_pm
3255 0 : ipm = ipm_list__(ii)
3256 : ! Allocate temporary rgp PBLAS matrix to store G(r,g')
3257 0 : npw = desc_kbz%npw
3258 0 : ABI_CHECK(block_dist_1d(npw, gwr%g_comm%nproc, col_bsize, msg), msg)
3259 0 : do iab=1,gwr%nsig_ab
3260 0 : call rgp%init(gwr%g_nfft, npw, gwr%g_slkproc, desc_kbz%istwfk, size_blocs=[-1, col_bsize]) !, gpu_action=gpu_action)
3261 : associate (g_gp => gt_pm(ipm, iab))
3262 0 : gpu_mode = 1
3263 0 : do ig2=1, g_gp%size_local(2), gwr%uc_batch_size
3264 : ! G_k(g,g') -> G_k(r,g') and store results in rgp.
3265 0 : ndat = blocked_loop(ig2, g_gp%size_local(2), gwr%uc_batch_size)
3266 0 : if (have_g0) then
3267 0 : call uplan_k%execute_gr(ndat, g_gp%buffer_cplx(:,ig2), rgp%buffer_cplx(:,ig2), phase_r=ceig0r, gpu_mode=gpu_mode)
3268 : else
3269 0 : call uplan_k%execute_gr(ndat, g_gp%buffer_cplx(:,ig2), rgp%buffer_cplx(:,ig2), gpu_mode=gpu_mode)
3270 : end if
3271 : end do ! ig2
3272 : end associate
3273 :
3274 : ! MPI transpose: G_k(r,g') -> G_k(g',r) and transform g' index.
3275 0 : call rgp%ptrans("N", gpr, free=.True.)
3276 :
3277 : gpu_mode = 1
3278 0 : do ir1=1, gpr%size_local(2), gwr%uc_batch_size
3279 : ! G_k(g',r) -> G_k(r',r) and store results in rgp.
3280 0 : ndat = blocked_loop(ir1, gpr%size_local(2), gwr%uc_batch_size)
3281 0 : if (have_g0) then
3282 : call uplan_k%execute_gr(ndat, gpr%buffer_cplx(:,ir1), gk_rpr_pm(ipm, iab)%buffer_cplx(:,ir1), &
3283 0 : isign=-1, iscale=0, phase_r=conjg_ceig0r, gpu_mode=gpu_mode)
3284 : else
3285 : call uplan_k%execute_gr(ndat, gpr%buffer_cplx(:,ir1), gk_rpr_pm(ipm, iab)%buffer_cplx(:,ir1), &
3286 0 : isign=-1, iscale=0, gpu_mode=gpu_mode)
3287 : end if
3288 : end do ! ir1
3289 0 : call gpr%free()
3290 : end do
3291 : end do ! ii
3292 :
3293 0 : call slk_array_free(gt_pm); call desc_kbz%free(); call uplan_k%free()
3294 :
3295 0 : if (have_g0) then
3296 : #ifdef HAVE_OPENMP_OFFLOAD
3297 : !$OMP TARGET EXIT DATA MAP(delete: ceig0r, conjg_ceig0r) if (gpu_option == ABI_GPU_OPENMP)
3298 : #endif
3299 0 : ABI_FREE(ceig0r)
3300 0 : ABI_FREE(conjg_ceig0r)
3301 : end if
3302 :
3303 : ! FIXME: Transfer data from CPU to GPU.
3304 0 : if (gpu_option == ABI_GPU_OPENMP) then
3305 0 : do ii=1,num_pm
3306 0 : ipm = ipm_list__(ii)
3307 0 : do iab=1,gwr%nsig_ab
3308 0 : call gk_rpr_pm(ipm, iab)%gpu_map("update_to")
3309 : end do
3310 : end do
3311 : end if
3312 :
3313 : ABI_NVTX_END_RANGE()
3314 : !call cwtime_report(" gwr_get_gkbz_rpr_pm:", cpu, wall, gflops)
3315 :
3316 0 : end subroutine gwr_get_gkbz_rpr_pm
3317 : !!***
3318 :
3319 : !----------------------------------------------------------------------
3320 :
3321 : !! !!****f* m_gwr/gwr_ggp_to_rpr
3322 : !! !! NAME
3323 : !! !! gwr_ggp_to_rpr
3324 : !! !!
3325 : !! !! FUNCTION
3326 : !! !! Helper function to FFT transform a two-point function: F_{g,g'} --> F_{r',r}
3327 : !! !!
3328 : !! !! INPUTS
3329 : !! !!
3330 : !! !! OUTPUT
3331 : !! !!
3332 : !! !! SOURCE
3333 : !!
3334 : !! !subroutine gwr_ggp_to_rpr(gwr, desc, g_gp, rp_r)
3335 : !! !
3336 : !! !!Arguments ------------------------------------
3337 : !! ! class(gwr_t),intent(in) :: gwr
3338 : !! ! type(desc_t),intent(in) :: desc
3339 : !! ! type(__slkmat_t),intent(in) :: g_gp
3340 : !! ! type(__slkmat_t),intent(inout) :: rp_r
3341 : !! !
3342 : !! !!Local variables-------------------------------
3343 : !! ! integer :: ig2, npw, nrsp, col_bsize, ir1, ndat
3344 : !! ! type(__slkmat_t) :: rgp, gpr
3345 : !! ! character(len=500) :: msg
3346 : !! ! type(uplan_t) :: uplan_k
3347 : !! !! *************************************************************************
3348 : !! !
3349 : !! ! ABI_ERROR("Not Implemented Error")
3350 : !! !
3351 : !! ! ! Allocate intermediate rgp PBLAS matrix to store F(r,g')
3352 : !! ! npw = desc%npw
3353 : !! ! nrsp = gwr%g_nfft * gwr%nspinor
3354 : !! ! ABI_CHECK(block_dist_1d(npw, gwr%g_comm%nproc, col_bsize, msg), msg)
3355 : !! ! call rgp%init(nrsp, npw, gwr%g_slkproc, desc%istwfk, size_blocs=[-1, col_bsize])
3356 : !! !
3357 : !! ! call uplan_k%init(desc%npw, gwr%nspinor, gwr%uc_batch_size, gwr%g_ngfft, desc%istwfk, &
3358 : !! ! desc%gvec, gwp, gwr%dtset%gpu_option)
3359 : !! !
3360 : !! ! ! F(g,g') --> F(r,g') and store results in rgp.
3361 : !! ! do ig2=1, g_gp%size_local(2), gwr%uc_batch_size
3362 : !! ! ndat = blocked_loop(ig2, g_gp%size_local(2), gwr%uc_batch_size)
3363 : !! ! call uplan_k%execute_gr(ndat, g_gp%buffer_cplx(:,ig2), rgp%buffer_cplx(:,ig2))
3364 : !! ! end do
3365 : !! !
3366 : !! ! ! F(r,g') --> F(g',r)
3367 : !! ! call rgp%ptrans("N", gpr, free=.True.)
3368 : !! !
3369 : !! ! ! F(g',r) --> F(r',r) and store results in rp_r.
3370 : !! ! do ir1=1, gpr%size_local(2), gwr%uc_batch_size
3371 : !! ! ndat = blocked_loop(ir1, gpr%size_local(2), gwr%uc_batch_size)
3372 : !! ! call uplan_k%execute_gr(ndat, gpr%buffer_cplx(:,ir1), rp_r%buffer_cplx(:,ir1), isign=-1, iscale=0)
3373 : !! ! end do
3374 : !! !
3375 : !! ! call uplan_k%free()
3376 : !! ! call gpr%free()
3377 : !! !
3378 : !! !end subroutine gwr_ggp_to_rpr
3379 : !! !!!***
3380 :
3381 : !----------------------------------------------------------------------
3382 :
3383 : !!****f* m_gwr/gwr_rpr_to_ggp
3384 : !! NAME
3385 : !! gwr_rpr_to_ggp
3386 : !!
3387 : !! FUNCTION
3388 : !! Helper function to FFT a two-point function: F_{r',r} --> F_{g,g'}
3389 : !! Note that rp_r is destroyed in output.
3390 : !!
3391 : !! INPUTS
3392 : !!
3393 : !! OUTPUT
3394 : !!
3395 : !! SOURCE
3396 :
3397 0 : subroutine gwr_rpr_to_ggp(gwr, desc, rp_r, rfact, g_gp)
3398 :
3399 : !Arguments ------------------------------------
3400 : class(gwr_t),intent(in) :: gwr
3401 : type(desc_t),intent(in) :: desc
3402 : real(dp),intent(in) :: rfact
3403 : class(__slkmat_t),intent(inout) :: rp_r, g_gp
3404 :
3405 : !Local variables-------------------------------
3406 : integer :: ig2, npw, nr, col_bsize, ir2, ndat, isign, gpu_option, gpu_mode
3407 0 : type(__slkmat_t) :: r_gp, gp_r
3408 : character(len=500) :: msg, gpu_action
3409 0 : type(uplan_t) :: uplan_k
3410 : ! *************************************************************************
3411 :
3412 : ABI_NVTX_START_RANGE(NVTX_GWR_RPR_TO_GGP)
3413 :
3414 : ! Allocate intermediate gp_r PBLAS matrix to store F(g',r)
3415 0 : npw = desc%npw; nr = gwr%g_nfft
3416 0 : ABI_CHECK(block_dist_1d(nr, gwr%g_comm%nproc, col_bsize, msg), msg)
3417 :
3418 0 : gpu_option = gwr%dtset%gpu_option
3419 0 : gpu_action = "None"; if (gpu_option == ABI_GPU_OPENMP) gpu_action = "alloc"
3420 0 : call gp_r%init(npw, nr, gwr%g_slkproc, desc%istwfk, size_blocs=[-1, col_bsize])
3421 :
3422 : call uplan_k%init(desc%npw, 1, gwr%uc_batch_size, gwr%g_ngfft, desc%istwfk, desc%gvec, gwp, &
3423 0 : 0)
3424 : !gwr%dtset%gpu_option) ! FIXME GPU option
3425 :
3426 0 : isign = +1 ! This should be ok
3427 : !isign = -1
3428 :
3429 0 : if (gwr%dtset%gpu_option == ABI_GPU_OPENMP) call rp_r%gpu_map("update_from") ! FIXME
3430 :
3431 : ! F(r',r) --> F(g',r) and store results in gp_r.
3432 0 : gpu_mode = 1
3433 0 : do ir2=1, rp_r%size_local(2), gwr%uc_batch_size
3434 0 : ndat = blocked_loop(ir2, rp_r%size_local(2), gwr%uc_batch_size)
3435 : call uplan_k%execute_rg(ndat, rp_r%buffer_cplx(:,ir2), gp_r%buffer_cplx(:,ir2), &
3436 0 : isign=isign, iscale=0, gpu_mode=gpu_mode)
3437 : end do
3438 :
3439 : ! F(g',r) --> F(r,g')
3440 : !call gp_r%ptrans("N", r_gp, free=.True.)
3441 : ! FIXME: I don't know why but C is needed here.
3442 0 : call gp_r%ptrans("C", r_gp, free=.True.)
3443 :
3444 : ! F(r,g') --> F(g,g') and store results in g_gp.
3445 : gpu_mode = 1
3446 0 : do ig2=1, g_gp%size_local(2), gwr%uc_batch_size
3447 0 : ndat = blocked_loop(ig2, g_gp%size_local(2), gwr%uc_batch_size)
3448 : call uplan_k%execute_rg(ndat, r_gp%buffer_cplx(:,ig2), g_gp%buffer_cplx(:,ig2), &
3449 0 : isign=-isign, iscale=0, gpu_mode=gpu_mode)
3450 : end do
3451 :
3452 : ! Scale output.
3453 0 : g_gp%buffer_cplx = g_gp%buffer_cplx * rfact
3454 :
3455 0 : if (gwr%dtset%gpu_option == ABI_GPU_OPENMP) call g_gp%gpu_map("update_to") ! FIXME
3456 :
3457 0 : call uplan_k%free(); call r_gp%free()
3458 : ABI_NVTX_END_RANGE()
3459 :
3460 0 : end subroutine gwr_rpr_to_ggp
3461 : !!***
3462 :
3463 : !----------------------------------------------------------------------
3464 :
3465 : !!****f* m_gwr/gwr_rotate_wc
3466 : !! NAME
3467 : !! gwr_rotate_wc
3468 : !!
3469 : !! FUNCTION
3470 : !! Reconstruct Wc(q,g,g') in the BZ from the IBZ.
3471 : !!
3472 : !! INPUTS
3473 : !!
3474 : !! OUTPUT
3475 : !!
3476 : !! SOURCE
3477 :
3478 0 : subroutine gwr_rotate_wc(gwr, iq_bz, itau, spin, desc_qbz, wc_qbz)
3479 :
3480 : !Arguments ------------------------------------
3481 : class(gwr_t),intent(inout) :: gwr
3482 : integer,intent(in) :: iq_bz, itau, spin
3483 : type(desc_t),intent(out) :: desc_qbz
3484 : type(__slkmat_t),intent(inout) :: wc_qbz
3485 :
3486 : !Local variables-------------------------------
3487 : !scalars
3488 : integer :: ig1, ig2, il_g1, il_g2, iq_ibz, isym_q, trev_q, tsign_q
3489 : logical :: isirr_q, q_is_gamma
3490 : !arrays
3491 : integer :: g1(3), g2(3), g0_q(3)
3492 : real(dp) :: tnon(3), qq_bz(3)
3493 : complex(dp) :: ph2, ph1
3494 : ! *************************************************************************
3495 :
3496 : ABI_NVTX_START_RANGE(NVTX_GWR_ROTATE_WC)
3497 0 : ABI_CHECK(gwr%wc_space == "itau", sjoin("wc_space:", gwr%wc_space, " != itau"))
3498 :
3499 0 : qq_bz = gwr%qbz(:, iq_bz)
3500 0 : q_is_gamma = normv(qq_bz, gwr%cryst%gmet, "G") < GW_TOLQ0
3501 :
3502 0 : iq_ibz = gwr%qbz2ibz(1, iq_bz); isym_q = gwr%qbz2ibz(2, iq_bz)
3503 0 : trev_q = gwr%qbz2ibz(6, iq_bz); g0_q = gwr%qbz2ibz(3:5, iq_bz)
3504 0 : isirr_q = (isym_q == 1 .and. trev_q == 0 .and. all(g0_q == 0))
3505 0 : tsign_q = merge(1, -1, trev_q == 0)
3506 : ! TODO: Understand why legacy GW does not need umklapp
3507 : !ABI_CHECK(all(g0_q == 0), sjoin("For qbz:", ktoa(gwr%qbz(:, iq_bz)), "g0_q:", ltoa(g0_q), " != 0"))
3508 :
3509 : ! Copy descriptor from IBZ
3510 : associate (desc_qibz => gwr%tchi_desc_qibz(iq_ibz))
3511 0 : call desc_qibz%copy(desc_qbz)
3512 :
3513 0 : if (isirr_q) then
3514 : ! Copy the PBLAS matrix in wc_qbz and we are done.
3515 0 : call gwr%wc_qibz(iq_ibz, itau, spin)%copy(wc_qbz); goto 10
3516 : end if
3517 :
3518 : !ABI_WARNING_IF(trev_q == 0, "trev_q should be tested")
3519 : ! rotate gvec, recompute gbound and rotate vc_sqrt_eps.
3520 : ! TODO: 1) Handle TR and routine to rotate tchi/W including vc_sqrt_eps
3521 : ! 2) Make sure that FFT box is large enough to accomodate umklapps
3522 0 : desc_qbz%ig0 = -1
3523 0 : do ig1=1,desc_qbz%npw
3524 0 : desc_qbz%gvec(:,ig1) = tsign_q * matmul(gwr%cryst%symrec(:,:,isym_q), desc_qibz%gvec(:,ig1)) - g0_q
3525 0 : if (all(desc_qbz%gvec(:,ig1) == 0)) desc_qbz%ig0 = ig1
3526 : end do
3527 0 : desc_qbz%kin_sorted = .False.
3528 0 : ABI_CHECK(desc_qbz%ig0 /= -1, "Cannot find g = 0 after g-vector rotation!")
3529 :
3530 0 : call sphereboundary(desc_qbz%gbound, desc_qbz%istwfk, desc_qbz%gvec, gwr%g_mgfft, desc_qbz%npw)
3531 :
3532 : ! Compute sqrt(vc(q,G))
3533 : ! TODO: rotate vc_sqrt_eps
3534 : ! vc(Sq, Sg) = vc(q, g)
3535 : ! vc(-q, -g) = vc(q, g)
3536 0 : call desc_qbz%get_vc_sqrt(qq_bz, q_is_gamma, gwr, "sigma", gwr%gtau_comm%value)
3537 :
3538 : ! Get Wc_q with q in the BZ.
3539 0 : tnon = gwr%cryst%tnons(:, isym_q)
3540 0 : associate (wq_i => gwr%wc_qibz(iq_ibz, itau, spin), wq_f => wc_qbz)
3541 0 : call wq_i%copy(wc_qbz)
3542 :
3543 : !!!$OMP PARALLEL DO PRIVATE(ig2, g2, ph2, ig1, g2, ph1)
3544 0 : do il_g2=1, wq_f%size_local(2)
3545 0 : ig2 = mod(wq_f%loc2gcol(il_g2) - 1, desc_qbz%npw) + 1
3546 0 : g2 = desc_qbz%gvec(:,ig2)
3547 0 : ph2 = exp(+j_dpc * two_pi * dot_product(g2, tnon))
3548 0 : do il_g1=1, wq_f%size_local(1)
3549 0 : ig1 = mod(wq_f%loc2grow(il_g1) - 1, desc_qbz%npw) + 1
3550 0 : g1 = desc_qbz%gvec(:,ig1)
3551 0 : ph1 = exp(-j_dpc * two_pi * dot_product(g1, tnon))
3552 0 : wq_f%buffer_cplx(il_g1, il_g2) = wq_i%buffer_cplx(il_g1, il_g2) * ph1 * ph2
3553 0 : if (trev_q == 1) wq_f%buffer_cplx(il_g1, il_g2) = conjg(wq_f%buffer_cplx(il_g1, il_g2))
3554 : end do
3555 : end do
3556 : end associate
3557 : end associate
3558 :
3559 : 10 continue
3560 : ABI_NVTX_END_RANGE()
3561 :
3562 0 : end subroutine gwr_rotate_wc
3563 : !!***
3564 :
3565 : !----------------------------------------------------------------------
3566 :
3567 : !!****f* m_gwr/gwr_get_myq_wc_gpr
3568 : !! NAME
3569 : !! gwr_get_myq_wc_gpr
3570 : !!
3571 : !! FUNCTION
3572 : !! Use FFTs to compute: Wc_q(g,g') --> Wc_q(g',r)
3573 : !! for each q in the BZ treated by this MPI proc for given `spin` and `itau` index:
3574 : !!
3575 : !! 1) FFT Transform the first index: Wc(g,g',it) --> Wc(r,g',it) (local operation)
3576 : !! 2) MPI transposition: Wc(r,g',it) --> Wc(g',r,it)
3577 : !!
3578 : !! INPUTS
3579 : !! select_my_qbz: Mask used to select a subset of gwr%my_qkbz q-points.
3580 : !!
3581 : !! OUTPUT
3582 : !!
3583 : !! SOURCE
3584 :
3585 0 : subroutine gwr_get_myq_wc_gpr(gwr, itau, spin, select_my_qbz, desc_myqbz, wc_gpr)
3586 :
3587 : !Arguments ------------------------------------
3588 : class(gwr_t),intent(inout) :: gwr
3589 : integer,intent(in) :: itau, spin
3590 : logical,intent(in) :: select_my_qbz(gwr%my_nqbz)
3591 : type(desc_t),target,intent(out) :: desc_myqbz(gwr%my_nqbz)
3592 : type(__slkmat_t),intent(inout) :: wc_gpr(gwr%my_nqbz)
3593 :
3594 : !Local variables-------------------------------
3595 : !scalars
3596 : integer :: my_iqf, iq_bz, ig2, npw, col_bsize, ndat, gpu_option, gpu_mode
3597 : real(dp) :: cpu, wall, gflops, mem_mb, qq_bz(3)
3598 : logical :: q_is_gamma
3599 : character(len=500) :: msg, gpu_action
3600 0 : type(__slkmat_t) :: rgp, wc_qbz
3601 0 : type(uplan_t) :: uplan_q
3602 0 : complex(gwp),allocatable :: ceiqr(:)
3603 : ! *************************************************************************
3604 :
3605 0 : call cwtime(cpu, wall, gflops, "start")
3606 : ABI_NVTX_START_RANGE(NVTX_GWR_MYQ_WW_GPR)
3607 :
3608 0 : gpu_option = gwr%dtset%gpu_option
3609 :
3610 0 : ABI_MALLOC(ceiqr, (gwr%g_nfft))
3611 : #ifdef HAVE_OPENMP_OFFLOAD
3612 : !$OMP TARGET ENTER DATA MAP(alloc:ceiqr) IF (gpu_option == ABI_GPU_OPENMP)
3613 : #endif
3614 :
3615 0 : gpu_action = "None"; if (gpu_option == ABI_GPU_OPENMP) gpu_action = "alloc"
3616 :
3617 0 : do my_iqf=1,gwr%my_nqbz
3618 : if (.not. select_my_qbz(my_iqf)) continue
3619 0 : iq_bz = gwr%my_qbz_inds(my_iqf); qq_bz = gwr%qbz(:, iq_bz)
3620 0 : q_is_gamma = normv(qq_bz, gwr%cryst%gmet, "G") < GW_TOLQ0
3621 0 : if (.not. q_is_gamma) then
3622 0 : call calc_ceikr(qq_bz, gwr%g_ngfft, gwr%g_nfft, 1, ceiqr)
3623 : #ifdef HAVE_OPENMP_OFFLOAD
3624 : !$omp target update to(ceiqr) if (gpu_option == ABI_GPU_OPENMP)
3625 : #endif
3626 : end if
3627 :
3628 : ! Get Wc_q in the BZ.
3629 0 : call gwr%rotate_wc(iq_bz, itau, spin, desc_myqbz(my_iqf), wc_qbz)
3630 : associate (desc_q => desc_myqbz(my_iqf))
3631 :
3632 : ! Allocate rgp PBLAS matrix to store Wc_q(r, g')
3633 0 : npw = desc_q%npw
3634 0 : ABI_CHECK(block_dist_1d(npw, gwr%g_comm%nproc, col_bsize, msg), msg)
3635 0 : call rgp%init(gwr%g_nfft, npw, gwr%g_slkproc, desc_q%istwfk, size_blocs=[-1, col_bsize])
3636 :
3637 : call uplan_q%init(desc_q%npw, 1, gwr%uc_batch_size, gwr%g_ngfft, desc_q%istwfk, &
3638 0 : desc_q%gvec, gwp, gpu_option)
3639 :
3640 : ! FFT and store results in rgp
3641 0 : gpu_mode = 1
3642 0 : do ig2=1,wc_qbz%size_local(2), gwr%uc_batch_size
3643 0 : ndat = blocked_loop(ig2, wc_qbz%size_local(2), gwr%uc_batch_size)
3644 :
3645 0 : if (q_is_gamma) then
3646 0 : call uplan_q%execute_gr(ndat, wc_qbz%buffer_cplx(:, ig2), rgp%buffer_cplx(:, ig2), gpu_mode=gpu_mode)
3647 : else
3648 0 : call uplan_q%execute_gr(ndat, wc_qbz%buffer_cplx(:, ig2), rgp%buffer_cplx(:, ig2), phase_r=ceiqr, gpu_mode=gpu_mode)
3649 : end if
3650 : end do ! ig2
3651 :
3652 0 : call uplan_q%free()
3653 :
3654 : ! MPI transposition: Wc(r,g') -> Wc(g',r)
3655 0 : call rgp%ptrans("N", wc_gpr(my_iqf), free=.True.)
3656 : end associate
3657 0 : call wc_qbz%free()
3658 :
3659 : !if (gpu_option == ABI_GPU_OPENMP) call wc_gpr(my_iqf)%gpu_map("update_to")
3660 : end do ! my_iqf
3661 :
3662 : #ifdef HAVE_OPENMP_OFFLOAD
3663 : !$OMP TARGET EXIT DATA MAP(delete: ceiqr) if (gpu_option == ABI_GPU_OPENMP)
3664 : #endif
3665 0 : ABI_FREE(ceiqr)
3666 :
3667 0 : mem_mb = sum(slk_array_locmem_mb(wc_gpr))
3668 0 : call wrtout(std_out, sjoin(" Local memory for Wc(g',r):", ftoa(mem_mb, fmt="f8.1"), "[Mb] <<< MEM"))
3669 0 : call cwtime_report(" gwr_get_myq_wc_gpr:", cpu, wall, gflops)
3670 :
3671 : ABI_NVTX_END_RANGE()
3672 :
3673 0 : end subroutine gwr_get_myq_wc_gpr
3674 : !!***
3675 :
3676 : !----------------------------------------------------------------------
3677 :
3678 : !!****f* m_gwr/gwr_get_wc_rpr_qbz
3679 : !! NAME
3680 : !! gwr_get_wc_rpr_qbz
3681 : !!
3682 : !! FUNCTION
3683 : !! Compute Wc_q(r',r') for q in the BZ
3684 : !!
3685 : !! INPUTS
3686 : !!
3687 : !! OUTPUT
3688 : !!
3689 : !! SOURCE
3690 :
3691 0 : subroutine gwr_get_wc_rpr_qbz(gwr, g0_q, iq_bz, itau, spin, wc_rpr)
3692 :
3693 : !Arguments ------------------------------------
3694 : class(gwr_t),intent(inout) :: gwr
3695 : integer,intent(in) :: g0_q(3)
3696 : integer,intent(in) :: iq_bz, itau, spin
3697 : type(__slkmat_t),intent(inout) :: wc_rpr
3698 :
3699 : !Local variables-------------------------------
3700 : !scalars
3701 : integer :: ig2, npw, nr, col_bsize, ir1, ndat, gpu_option, gpu_mode
3702 : character(len=500) :: msg, gpu_action
3703 0 : type(desc_t) :: desc_qbz
3704 0 : type(__slkmat_t) :: wc_ggp, rgp, gpr
3705 0 : type(uplan_t) :: uplan_k
3706 0 : complex(gwp),allocatable :: ceig0r(:), conjg_ceig0r(:)
3707 : ! *************************************************************************
3708 :
3709 : ABI_NVTX_START_RANGE(NVTX_GWR_WC_RPR_QBZ)
3710 :
3711 0 : gpu_option = gwr%dtset%gpu_option
3712 0 : gpu_action = "None"; if (gpu_option == ABI_GPU_OPENMP) gpu_action = "alloc"
3713 :
3714 : ! NB: Non-zero g0, requires the application of the phase.
3715 0 : if (any(g0_q /= 0)) then
3716 0 : ABI_MALLOC(ceig0r, (gwr%g_nfft))
3717 0 : ABI_MALLOC(conjg_ceig0r, (gwr%g_nfft))
3718 0 : call calc_ceigr(-g0_q, gwr%g_nfft, 1, gwr%g_ngfft, ceig0r)
3719 0 : conjg_ceig0r = conjg(ceig0r)
3720 : #ifdef HAVE_OPENMP_OFFLOAD
3721 : !$OMP TARGET ENTER DATA MAP(alloc:ceig0r, conjg_ceig0r) IF (gpu_option == ABI_GPU_OPENMP)
3722 : !$omp target update to(ceig0r, conjg_ceig0r) if (gpu_option == ABI_GPU_OPENMP)
3723 : #endif
3724 : end if
3725 :
3726 : ! Get W_q(g,g') in the BZ.
3727 0 : call gwr%rotate_wc(iq_bz, itau, spin, desc_qbz, wc_ggp)
3728 :
3729 : ! Allocate rgp PBLAS matrix to store Wc(r,g')
3730 0 : nr = gwr%g_nfft
3731 0 : npw = desc_qbz%npw
3732 0 : ABI_CHECK(block_dist_1d(npw, gwr%g_comm%nproc, col_bsize, msg), msg)
3733 0 : call rgp%init(nr, npw, gwr%g_slkproc, desc_qbz%istwfk, size_blocs=[-1, col_bsize]) ! , gpu_action=gpu_action)
3734 :
3735 : call uplan_k%init(desc_qbz%npw, 1, gwr%uc_batch_size, gwr%g_ngfft, desc_qbz%istwfk, &
3736 0 : desc_qbz%gvec, gwp, gpu_option)
3737 :
3738 : ! FFT Wc(g,g') -> Wc(r,g') and store results in rgp
3739 0 : gpu_mode = 1
3740 0 : do ig2=1,wc_ggp%size_local(2), gwr%uc_batch_size
3741 0 : ndat = blocked_loop(ig2, wc_ggp%size_local(2), gwr%uc_batch_size)
3742 :
3743 0 : if (any(g0_q /= 0)) then
3744 : call uplan_k%execute_gr(ndat, wc_ggp%buffer_cplx(:,ig2), rgp%buffer_cplx(:,ig2), &
3745 0 : phase_r=ceig0r, gpu_mode=gpu_mode)
3746 : else
3747 : call uplan_k%execute_gr(ndat, wc_ggp%buffer_cplx(:,ig2), rgp%buffer_cplx(:,ig2), &
3748 0 : gpu_mode=gpu_mode)
3749 : end if
3750 : end do ! ig2
3751 :
3752 : ! MPI transpose: Wc(r,g') -> Wc(g',r)
3753 0 : call rgp%ptrans("N", gpr, free=.True.)
3754 :
3755 : ! Wc_q(g',r) -> Wc_q(r',r) and store results in wc_rgp.
3756 : gpu_mode = 1
3757 0 : do ir1=1,gpr%size_local(2), gwr%uc_batch_size
3758 0 : ndat = blocked_loop(ir1, gpr%size_local(2), gwr%uc_batch_size)
3759 0 : if (any(g0_q /= 0)) then
3760 : call uplan_k%execute_gr(ndat, gpr%buffer_cplx(:, ir1), wc_rpr%buffer_cplx(:, ir1), &
3761 0 : isign=-1, iscale=0, phase_r=conjg_ceig0r, gpu_mode=gpu_mode)
3762 : else
3763 : call uplan_k%execute_gr(ndat, gpr%buffer_cplx(:, ir1), wc_rpr%buffer_cplx(:, ir1), &
3764 0 : isign=-1, iscale=0, gpu_mode=gpu_mode)
3765 : end if
3766 : end do ! ir1
3767 :
3768 0 : call uplan_k%free(); call gpr%free(); call desc_qbz%free(); call wc_ggp%free()
3769 :
3770 0 : if (any(g0_q /= 0)) then
3771 : #ifdef HAVE_OPENMP_OFFLOAD
3772 : !$OMP TARGET EXIT DATA MAP(delete: ceig0r, conjg_ceig0r) if (gpu_option == ABI_GPU_OPENMP)
3773 : #endif
3774 0 : ABI_SFREE(ceig0r)
3775 0 : ABI_SFREE(conjg_ceig0r)
3776 : end if
3777 :
3778 0 : if (gpu_option == ABI_GPU_OPENMP) call wc_rpr%gpu_map("update_to")
3779 : ABI_NVTX_END_RANGE()
3780 :
3781 0 : end subroutine gwr_get_wc_rpr_qbz
3782 : !!***
3783 :
3784 : !----------------------------------------------------------------------
3785 :
3786 : !!****f* m_gwr/gwr_cos_transform
3787 : !! NAME
3788 : !! gwr_cos_transform
3789 : !!
3790 : !! FUNCTION
3791 : !! Perform cosine transform.
3792 : !!
3793 : !! INPUTS
3794 : !! what: "tchi" or "wc"
3795 : !! mode: "iw2t" for omega to tau or "it2w" for tau to omega.
3796 : !! [sum_spins]: True to sum the two spin-channgels when what == "tchi". Default: False.
3797 : !!
3798 : !! SOURCE
3799 :
3800 0 : subroutine gwr_cos_transform(gwr, what, mode, sum_spins)
3801 :
3802 : !Arguments ------------------------------------
3803 : class(gwr_t),target,intent(inout) :: gwr
3804 : character(len=*),intent(in) :: what, mode
3805 : logical,optional,intent(in) :: sum_spins
3806 :
3807 : !Local variables-------------------------------
3808 : !scalars
3809 : integer, parameter :: TAU_SPACE = 0, W_SPACE = 1
3810 : integer :: my_iqi, my_is, ig1, ig2, my_it, ierr, iq_ibz, itau, spin, it0, iw, cnt
3811 : integer :: ndat, idat, loc1_size, loc2_size, batch_size, from_space, units(2)
3812 : real(dp) :: cpu, wall, gflops !, min_abs_err, max_abs_err
3813 : complex(dp) :: cval
3814 : logical :: sum_spins_, do_chi_fit
3815 : !arrays
3816 0 : integer :: mask_qibz(gwr%nqibz)
3817 0 : real(dp), contiguous, pointer :: weights_ptr(:,:)
3818 0 : real(dp),allocatable :: beta_r(:,:)
3819 0 : complex(dp) :: wgt_globmy(gwr%ntau, gwr%my_ntau) ! Complex instead of real to be able to call ZGEMM.
3820 0 : complex(dp),allocatable :: cwork_myit(:,:,:), glob_cwork(:,:,:), alpha_c(:,:)
3821 0 : type(__slkmat_t), pointer :: mats(:)
3822 : ! *************************************************************************
3823 :
3824 0 : units = [std_out, ab_out]
3825 :
3826 : ABI_NVTX_START_RANGE(NVTX_GWR_COS_TRANSFORM)
3827 0 : call cwtime(cpu, wall, gflops, "start")
3828 :
3829 0 : sum_spins_ = .False.; if (present(sum_spins)) sum_spins_ = sum_spins
3830 :
3831 0 : call wrtout(std_out, sjoin(" Performing cosine transform. what:", what, ", mode:", mode))
3832 0 : mask_qibz = 0; mask_qibz(gwr%my_qibz_inds(:)) = 1
3833 :
3834 : ! Target weights depending on mode.
3835 0 : select case(mode)
3836 : case ("iw2t")
3837 : ! From omega to tau
3838 0 : from_space = W_SPACE
3839 0 : if (what == "tchi") then
3840 0 : ABI_CHECK(gwr%tchi_space == "iomega", sjoin("mode:", mode, "with what:", what, "and tchi_space:", gwr%tchi_space))
3841 0 : gwr%tchi_space = "itau"
3842 : end if
3843 0 : if (what == "wc") then
3844 0 : ABI_CHECK(gwr%wc_space == "iomega", sjoin("mode:", mode, "with what:", what, "and wc_space:", gwr%wc_space))
3845 0 : gwr%wc_space = "itau"
3846 : end if
3847 0 : weights_ptr => gwr%cosft_tw
3848 :
3849 : case ("it2w")
3850 : ! From tau to omega
3851 0 : from_space = TAU_SPACE
3852 0 : if (what == "tchi") then
3853 0 : ABI_CHECK(gwr%tchi_space == "itau", sjoin("mode:", mode, " with what:", what, "and tchi_space:", gwr%tchi_space))
3854 0 : gwr%tchi_space = "iomega"
3855 : end if
3856 0 : if (what == "wc") then
3857 0 : ABI_CHECK(gwr%wc_space == "itau", sjoin("mode:", mode, " with what:", what, "and wc_space:", gwr%wc_space))
3858 0 : gwr%wc_space = "iomega"
3859 : end if
3860 0 : weights_ptr => gwr%cosft_wt
3861 :
3862 : case default
3863 0 : ABI_ERROR(sjoin("Wrong mode:", mode))
3864 : end select
3865 :
3866 : ! Extract my weights from global array.
3867 0 : do my_it=1,gwr%my_ntau
3868 0 : itau = gwr%my_itaus(my_it)
3869 0 : do iw=1,gwr%ntau
3870 0 : wgt_globmy(iw, my_it) = weights_ptr(iw, itau)
3871 : end do
3872 : end do
3873 :
3874 0 : do_chi_fit = (iand(gwr%dtset%gwr_fit, CHI_FIT) /= 0)
3875 0 : if (do_chi_fit) then
3876 0 : call wrtout(units, " Activating fit of matrix elements in tau/iw space")
3877 : end if
3878 :
3879 : ! Perform inhomogeneous FT in parallel.
3880 0 : do my_is=1,gwr%my_nspins
3881 0 : spin = gwr%my_spins(my_is)
3882 0 : do my_iqi=1,gwr%my_nqibz
3883 0 : iq_ibz = gwr%my_qibz_inds(my_iqi)
3884 0 : associate (desc_q => gwr%tchi_desc_qibz(iq_ibz))
3885 :
3886 0 : mats => null()
3887 0 : if (what == "tchi") mats => gwr%tchi_qibz(iq_ibz, :, spin)
3888 0 : if (what =="wc") mats => gwr%wc_qibz(iq_ibz, :, spin)
3889 0 : ABI_CHECK(associated(mats), sjoin("Invalid value for what:", what))
3890 :
3891 : ! Use the first itau index to get the size of the local buffer.
3892 : ! Block over ig2 to reduce the number of MPI calls and take advantage of ZGEMM.
3893 0 : it0 = gwr%my_itaus(1)
3894 0 : loc1_size = mats(it0)%size_local(1)
3895 0 : loc2_size = mats(it0)%size_local(2)
3896 :
3897 : ! batch_size in terms of columns
3898 : ! TODO: Determine batch_size automatically to avoid going OOM
3899 0 : batch_size = 48
3900 : !batch_size = loc2_size
3901 :
3902 0 : ABI_MALLOC(cwork_myit, (gwr%my_ntau, loc1_size, batch_size))
3903 0 : ABI_MALLOC(glob_cwork, (gwr%ntau, loc1_size, batch_size))
3904 :
3905 0 : if (do_chi_fit) then
3906 : ! Allocate coefficients for the fit.
3907 0 : ABI_MALLOC(beta_r, (loc1_size, batch_size))
3908 0 : ABI_MALLOC(alpha_c, (loc1_size, batch_size))
3909 : end if
3910 :
3911 0 : do ig2=1,mats(it0)%size_local(2), batch_size
3912 0 : ndat = blocked_loop(ig2, mats(it0)%size_local(2), batch_size)
3913 :
3914 : ! TODO
3915 : ! When fit mode is activated, collect all tau/omega points for this set of (g1, g2) inside tau_comm
3916 : ! Each MPI rank performs the fit locally using the first point and all the points treated by the rank.
3917 : ! compute loss functions of all the fits and find the one leading to the minimum loss.
3918 0 : if (do_chi_fit) then
3919 0 : glob_cwork = zero
3920 0 : do idat=1,ndat
3921 0 : do my_it=1,gwr%my_ntau
3922 0 : itau = gwr%my_itaus(my_it)
3923 0 : do ig1=1,mats(it0)%size_local(1)
3924 0 : glob_cwork(itau, ig1, idat) = mats(itau)%buffer_cplx(ig1, ig2+idat-1)
3925 : end do
3926 : end do
3927 : end do
3928 0 : call xmpi_sum(glob_cwork, gwr%tau_comm%value, ierr)
3929 :
3930 : ! Start the fit
3931 0 : cnt = 0; beta_r = zero; alpha_c = zero
3932 0 : do idat=1,ndat
3933 0 : do ig1=1,mats(it0)%size_local(1)
3934 0 : cnt = cnt + 1; if (gwr%tau_comm%skip(cnt)) cycle ! MPI parallelism inside tau_comm
3935 0 : if (from_space == TAU_SPACE) then
3936 : call fit_tau_exp(gwr%ntau, gwr%tau_mesh, gwr%tau_wgs, glob_cwork(:,ig1,idat), &
3937 0 : alpha_c(ig1,idat), beta_r(ig1,idat), ierr)
3938 0 : else if (from_space == W_SPACE) then
3939 : call fit_iomega(gwr%ntau, gwr%iw_mesh, gwr%iw_wgs, glob_cwork(:,ig1,idat), &
3940 0 : alpha_c(ig1,idat), beta_r(ig1,idat), ierr)
3941 : else
3942 0 : ABI_ERROR(sjoin("Invalid from_space:", itoa(from_space)))
3943 : end if
3944 : !if (from_space == W_SPACE) print *, "my_it, alpha, beta", alpha_c(ig1,idat), beta_r(ig1,idat)
3945 : end do ! ig1
3946 : end do ! idat
3947 0 : call xmpi_sum(alpha_c, gwr%tau_comm%value, ierr)
3948 0 : call xmpi_sum(beta_r, gwr%tau_comm%value, ierr)
3949 : end if ! do_chi_fit
3950 :
3951 : ! Extract (g1, g2) matrix elements as a function of tau/omega
3952 : !!$OMP PARALLEL DO PRIVATE(itau, cval) COLLAPSE(2)
3953 0 : do idat=1,ndat
3954 0 : do my_it=1,gwr%my_ntau
3955 0 : itau = gwr%my_itaus(my_it)
3956 0 : cval = zero
3957 0 : do ig1=1,mats(it0)%size_local(1)
3958 0 : if (do_chi_fit) then
3959 : ! Evaluate the fit and remove it from the signal.
3960 0 : if (from_space == TAU_SPACE) then
3961 0 : cval = fit_tau_exp_eval("func", gwr%tau_mesh(itau), alpha_c(ig1,idat), beta_r(ig1,idat))
3962 0 : else if (from_space == W_SPACE) then
3963 0 : cval = fit_iomega_eval("func", gwr%iw_mesh(itau), alpha_c(ig1,idat), beta_r(ig1,idat))
3964 : end if
3965 : if (from_space == W_SPACE .and. any(my_it == [1, gwr%my_ntau])) then
3966 : !if (from_space == TAU_SPACE .and. any(my_it == [1, gwr%my_ntau])) then
3967 : !print * "beta_r, alpha:", beta_r(ig1,idat), alpha_c(ig1,idat)
3968 : !write(*, "(a,i3,1x, *(es12.5,2x))") "my_it abs_diff_1", my_it, abs(cval - mats(itau)%buffer_cplx(ig1, ig2+idat-1)), &
3969 : ! cval, mats(itau)%buffer_cplx(ig1, ig2+idat-1)
3970 : end if
3971 : end if
3972 0 : cwork_myit(my_it, ig1, idat) = mats(itau)%buffer_cplx(ig1, ig2+idat-1) - cval
3973 : end do
3974 : end do
3975 : end do
3976 :
3977 : ! Compute contribution to itau matrix,
3978 : call ZGEMM("N", "N", gwr%ntau, loc1_size*ndat, gwr%my_ntau, cone, &
3979 0 : wgt_globmy, gwr%ntau, cwork_myit, gwr%my_ntau, czero, glob_cwork, gwr%ntau)
3980 :
3981 0 : call xmpi_sum(glob_cwork, gwr%tau_comm%value, ierr)
3982 :
3983 : ! Update my local (g1, g2) entry to have it in imaginary-frequency.
3984 : !!$OMP PARALLEL DO PRIVATE(itau, cval) COLLAPSE(2)
3985 0 : do idat=1,ndat
3986 0 : do my_it=1,gwr%my_ntau
3987 0 : itau = gwr%my_itaus(my_it)
3988 0 : cval = zero
3989 0 : do ig1=1,mats(it0)%size_local(1)
3990 :
3991 0 : if (do_chi_fit) then
3992 : ! Add Fourier transform of the fitted model.
3993 0 : if (from_space == TAU_SPACE) then
3994 0 : cval = fit_tau_exp_eval("ft", gwr%iw_mesh(itau), alpha_c(ig1,idat), beta_r(ig1,idat))
3995 0 : else if (from_space == W_SPACE) then
3996 0 : cval = fit_iomega_eval("ft", gwr%tau_mesh(itau), alpha_c(ig1,idat), beta_r(ig1,idat))
3997 : end if
3998 : !if (from_space == W_SPACE .and. my_it == 1) then
3999 : !if (from_space == TAU_SPACE .and. my_it == 1) then
4000 : ! !print *, "beta_r, alpha:", beta_r(ig1,idat), alpha_c(ig1,idat)
4001 : ! print *, "my_it, abs_diff_2", my_it, abs(cval - mats(itau)%buffer_cplx(ig1, ig2+idat-1)), &
4002 : ! cval - mats(itau)%buffer_cplx(ig1, ig2+idat-1)
4003 : !end if
4004 : end if
4005 : !if (from_space == TAU_SPACE) then
4006 : !if (from_space == W_SPACE) then
4007 : !write(200, *)"mats:", mats(itau)%buffer_cplx(ig1, ig2+idat-1)
4008 : !write(300, *)"cval", cval
4009 : !end if
4010 :
4011 0 : mats(itau)%buffer_cplx(ig1, ig2+idat-1) = glob_cwork(itau, ig1, idat) + cval
4012 : end do ! ig1
4013 : end do ! my_it
4014 : end do ! idat
4015 :
4016 : end do ! ig2
4017 :
4018 0 : ABI_FREE(cwork_myit)
4019 0 : ABI_FREE(glob_cwork)
4020 0 : ABI_SFREE(alpha_c)
4021 0 : ABI_SFREE(beta_r)
4022 : end associate
4023 : end do ! my_iqi
4024 : end do ! my_is
4025 : !stop
4026 :
4027 0 : if (sum_spins_) then ! gwr%nsppol == 2 .and.
4028 : ! Sum over spin channels.
4029 0 : do my_iqi=1,gwr%my_nqibz
4030 0 : iq_ibz = gwr%my_qibz_inds(my_iqi)
4031 0 : do my_is=1,gwr%my_nspins
4032 0 : spin = gwr%my_spins(my_is)
4033 0 : mats => null()
4034 0 : if (what == "tchi") mats => gwr%tchi_qibz(iq_ibz,:,spin)
4035 : !if (what =="wc") mats => gwr%wc_qibz(iq_ibz, :, spin)
4036 0 : ABI_CHECK(associated(mats), sjoin("Invalid value for what:", what))
4037 :
4038 0 : do my_it=1,gwr%my_ntau
4039 0 : itau = gwr%my_itaus(my_it)
4040 :
4041 0 : if (gwr%nsppol == 1 .and. gwr%nspinor == 1) then
4042 0 : mats(itau)%buffer_cplx = two * mats(itau)%buffer_cplx
4043 :
4044 0 : else if (gwr%nsppol == 2) then
4045 0 : if (gwr%spin_comm%nproc > 1) then
4046 : ! Spins are distributed thus we have to sum them.
4047 0 : call xmpi_sum(mats(itau)%buffer_cplx, gwr%spin_comm%value, ierr)
4048 : else
4049 : ! Spins are not distributed. This should happen only in sequential.
4050 0 : if (spin == 1) then
4051 0 : mats(itau)%buffer_cplx = mats(itau)%buffer_cplx + gwr%tchi_qibz(iq_ibz,itau,spin+1)%buffer_cplx
4052 0 : gwr%tchi_qibz(iq_ibz,itau,spin+1)%buffer_cplx = mats(itau)%buffer_cplx
4053 : end if
4054 : end if
4055 : end if
4056 :
4057 : end do ! my_it
4058 : end do ! my_is
4059 : end do ! my_iqi
4060 : end if
4061 :
4062 : ABI_NVTX_END_RANGE()
4063 0 : call cwtime_report(" gwr_cos_transform:", cpu, wall, gflops)
4064 :
4065 0 : end subroutine gwr_cos_transform
4066 : !!***
4067 :
4068 : !!****f* m_gwr/fit_tau_exp
4069 : !! NAME
4070 : !!
4071 : !! FUNCTION
4072 : !! Fit values in imaginary time using A exp^{-b t} with A complex and b real and > 0.
4073 : !! The fit passes through the first tau point, the second point is selected by
4074 : !! minimizing the "distance" between the fit and the ab-initio results cvals.
4075 : !!
4076 : !! b = -\frac{\ln(y_n / y_0)}{\tau_n - \tau_0},
4077 : !! A = y_0 e^{b \tau_0}
4078 : !!
4079 : !! SOURCE
4080 :
4081 0 : subroutine fit_tau_exp(ntau, tau_mesh, tau_wgs, cvals, alpha_c, beta_r, ierr)
4082 :
4083 : !Arguments ------------------------------------
4084 : integer,intent(in) :: ntau
4085 : real(dp),intent(in) :: tau_mesh(ntau), tau_wgs(ntau)
4086 : complex(dp),intent(in) :: cvals(ntau)
4087 : complex(dp),intent(out) :: alpha_c
4088 : real(dp),intent(out) :: beta_r
4089 : integer,intent(out) :: ierr
4090 :
4091 : !Local variables-------------------------------
4092 : integer :: ii
4093 : real(dp) :: loss, min_loss, my_beta_r
4094 0 : complex(dp) :: cfit(ntau), zz, my_alpha_c
4095 : ! *************************************************************************
4096 :
4097 0 : min_loss = huge(one); alpha_c = zero; beta_r = zero
4098 0 : do ii=2,ntau
4099 : ! Find my_beta_r. Note that we take the real part of the log to avoid oscillatory behaviour in the exp.
4100 0 : zz = -log(cvals(ii) / cvals(1)) / (tau_mesh(ii) - tau_mesh(1))
4101 0 : my_beta_r = real(zz)
4102 0 : my_alpha_c = cvals(1) * exp(+my_beta_r * tau_mesh(1))
4103 : ! Compute loss function.
4104 0 : cfit(:) = my_alpha_c * exp(-my_beta_r * tau_mesh)
4105 0 : loss = sum(tau_wgs * abs(cvals - cfit)**2)
4106 0 : if (loss < min_loss) then
4107 0 : min_loss = loss; alpha_c = my_alpha_c; beta_r = my_beta_r
4108 : end if
4109 : end do
4110 :
4111 : ! If something goes wrong, disable the fit.
4112 0 : ierr = 0
4113 0 : if (beta_r <= tol12) then
4114 0 : alpha_c = zero; beta_r = tol6; ierr = 1
4115 : end if
4116 :
4117 0 : end subroutine fit_tau_exp
4118 : !!***
4119 :
4120 : !!****f* m_gwr/fit_tau_exp_eval
4121 : !! NAME
4122 : !!
4123 : !! FUNCTION
4124 : !! Exalute tau fit or it's Fourier transform.
4125 : !!
4126 : !! SOURCE
4127 :
4128 0 : pure complex(dp) function fit_tau_exp_eval(what, xx, alpha_c, beta_r) result(cval)
4129 :
4130 : !Arguments ------------------------------------
4131 : character(len=*),intent(in) :: what
4132 : real(dp),intent(in) :: xx, beta_r
4133 : complex(dp),intent(in) :: alpha_c
4134 : ! *************************************************************************
4135 :
4136 0 : select case (what)
4137 : case ("func")
4138 0 : cval = alpha_c * exp(-beta_r * xx)
4139 : case ("ft")
4140 : ! \mathcal{F}\{A e^{-b |t|} \}(\omega) = \frac{2A b}{b^2 + \omega^2}
4141 : !cval = (two * alpha_c * beta_r) / (beta_r**2 + xx**2)
4142 : ! Cosine-transform.
4143 0 : cval = (alpha_c * two * beta_r) / (beta_r**2 + xx**2)
4144 : case default
4145 0 : cval = huge(one)
4146 : end select
4147 :
4148 0 : end function fit_tau_exp_eval
4149 : !!***
4150 :
4151 : !!****f* m_gwr/fit_iomega
4152 : !! NAME
4153 : !!
4154 : !! FUNCTION
4155 : !! To fit the function
4156 : !!
4157 : !! f(\omega) = \frac{A}{b^2 + \omega^2}
4158 : !!
4159 : !! to pass through two given points (\omega_1, y_1) and (\omega_2, y_2), follow these steps.
4160 : !!
4161 : !! A = \frac{y_1 y_2 (\omega_2^2 - \omega_1^2)}{y_1 - y_2}.
4162 : !! b^2 = \frac{y_2 \omega_2^2 - y_1 \omega_1^2}{y_1 - y_2},
4163 : !!
4164 : !! SOURCE
4165 :
4166 0 : subroutine fit_iomega(ntau, iw_mesh, iw_wgs, cvals, alpha_c, beta_r, ierr)
4167 :
4168 : !Arguments ------------------------------------
4169 : integer,intent(in) :: ntau
4170 : real(dp),intent(in) :: iw_mesh(ntau), iw_wgs(ntau)
4171 : complex(dp),intent(in) :: cvals(ntau)
4172 : complex(dp),intent(out) :: alpha_c
4173 : real(dp),intent(out) :: beta_r
4174 : integer,intent(out) :: ierr
4175 :
4176 : !Local variables-------------------------------
4177 : integer :: ii
4178 : real(dp) :: loss, min_loss, w0, wn, b2 ! my_beta_r,
4179 0 : complex(dp) :: my_alpha_c, cfit(ntau), f0, fn ! zz, b2_cplx,
4180 : ! *************************************************************************
4181 :
4182 0 : min_loss = huge(one); w0 = iw_mesh(1); f0 = cvals(1); alpha_c = czero; beta_r = zero
4183 :
4184 0 : do ii=2,ntau
4185 : ! Find alpha_c and beta_r
4186 0 : wn = iw_mesh(ii); fn = cvals(ii)
4187 : !b2_cplx = (f0*w0**2 - fn*wn**2) / (fn - f0)
4188 : !b2 = real(b2)
4189 0 : b2 = (real(f0) * w0**2 - real(fn) * wn**2) / (real(fn) - real(f0))
4190 : !print *, "b2:", b2
4191 :
4192 0 : if (b2 <= tol12) then
4193 : b2 = tol12; my_alpha_c = zero
4194 : else
4195 : !my_alpha_c = f0*fn * (wn**2 - w0**2) / (f0 - fn)
4196 : !print *, "b2:", b2
4197 : !my_alpha_c = f0 *((fn*wn**2 - f0*w0**2)/(f0 - fn) + w0**2)
4198 0 : my_alpha_c = f0 * (b2 + w0**2)
4199 : end if
4200 :
4201 : ! Compute loss function.
4202 0 : cfit(:) = my_alpha_c / (b2 + iw_mesh**2)
4203 0 : loss = sum(iw_wgs * abs(cvals - cfit)**2)
4204 0 : if (loss < min_loss) then
4205 0 : min_loss = loss; alpha_c = my_alpha_c; beta_r = sqrt(b2)
4206 : end if
4207 : end do
4208 :
4209 : ! DEBUG: disable the fit
4210 : !beta_r = zero; alpha_c = zero
4211 :
4212 0 : ierr = 0; if (b2 <= tol12) ierr = 1
4213 :
4214 : !if (alpha_c /= zero) then
4215 : ! print *, "beta_r, alpha_c", beta_r, alpha_c, min_loss
4216 : !end if
4217 :
4218 : ! If something goes wrong, disable the fit.
4219 : !beta_r = zero; alpha_c = zero
4220 : !if ((my_beta_r) > zero) then
4221 : ! beta_r = my_beta_r
4222 : ! alpha_c = my_alpha_c
4223 : !end if
4224 :
4225 0 : end subroutine fit_iomega
4226 : !!***
4227 :
4228 : !!****f* m_gwr/fit_iomega_eval
4229 : !! NAME
4230 : !!
4231 : !! FUNCTION
4232 : !!
4233 : !! SOURCE
4234 :
4235 0 : pure complex(dp) function fit_iomega_eval(what, xx, alpha_c, beta_r) result(cval)
4236 :
4237 : !Arguments ------------------------------------
4238 : character(len=*),intent(in) :: what
4239 : real(dp),intent(in) :: xx, beta_r
4240 : complex(dp),intent(in) :: alpha_c
4241 : ! *************************************************************************
4242 :
4243 0 : select case (what)
4244 : case ("func")
4245 0 : cval = alpha_c / (beta_r**2 + xx**2)
4246 : case ("ft")
4247 0 : cval = zero
4248 0 : if (alpha_c /= zero) then
4249 : !cval = alpha_c * exp(-beta_r * abs(xx))
4250 : ! TODO: check sign in prefactor
4251 : !cval = (alpha_c / (two * beta_r)) * exp(-beta_r * abs(xx))
4252 : !cval = - (alpha_c / (two * beta_r)) * exp(-beta_r * abs(xx))
4253 : ! Cosine-transform
4254 0 : cval = (alpha_c / (two * beta_r)) * exp(-beta_r * abs(xx))
4255 : end if
4256 :
4257 : case default
4258 0 : cval = huge(one)
4259 : end select
4260 :
4261 0 : end function fit_iomega_eval
4262 : !!***
4263 :
4264 : !----------------------------------------------------------------------
4265 :
4266 : !!****f* m_gwr/desc_init
4267 : !! NAME
4268 : !! desc_init
4269 : !!
4270 : !! FUNCTION
4271 : !! Initialize the descriptor.
4272 : !!
4273 : !! INPUTS
4274 : !!
4275 : !! OUTPUT
4276 : !!
4277 : !! SOURCE
4278 :
4279 0 : subroutine desc_init(desc, kk, istwfk, ecut, gwr, kin_sorted, rot)
4280 :
4281 : !Arguments ------------------------------------
4282 : class(desc_t),intent(inout) :: desc
4283 : real(dp),intent(in) :: kk(3)
4284 : integer,intent(in) :: istwfk
4285 : real(dp),intent(in) :: ecut
4286 : class(gwr_t),intent(in) :: gwr
4287 : logical,optional,intent(in) :: kin_sorted, rot
4288 :
4289 : !Local variables-------------------------------
4290 : integer :: ig, ig1, ig2, itim, isym, istep_forward, istep_backward, grot(3)
4291 : ! character(len=256) :: msg
4292 : logical :: found, rot__
4293 0 : real(dp),allocatable :: gnorm(:)
4294 0 : integer,allocatable :: igvec(:)
4295 : ! *************************************************************************
4296 :
4297 0 : desc%kin_sorted = .False.; if (present(kin_sorted)) desc%kin_sorted = kin_sorted
4298 0 : rot__ = .False.; if (present(rot)) rot__ = rot
4299 0 : desc%istwfk = istwfk
4300 0 : call get_kg(kk, desc%istwfk, ecut, gwr%cryst%gmet, desc%npw, desc%gvec, kin_sorted=desc%kin_sorted)
4301 :
4302 0 : ABI_MALLOC(desc%gbound, (2 * gwr%g_mgfft + 8, 2))
4303 0 : call sphereboundary(desc%gbound, desc%istwfk, desc%gvec, gwr%g_mgfft, desc%npw)
4304 :
4305 : ! Find the index of g = 0.
4306 0 : desc%ig0 = -1
4307 0 : do ig=1,desc%npw
4308 0 : if (all(desc%gvec(:,ig) == 0)) then
4309 0 : desc%ig0 = ig; exit
4310 : end if
4311 : end do
4312 :
4313 0 : if (rot__) then
4314 0 : ABI_ICALLOC(desc%rottb, (desc%npw, gwr%cryst%timrev, gwr%cryst%nsym))
4315 0 : ABI_ICALLOC(desc%rottbm1, (desc%npw, gwr%cryst%timrev, gwr%cryst%nsym))
4316 0 : ABI_CALLOC(desc%phmGt, (desc%npw, gwr%cryst%nsym))
4317 0 : ABI_CALLOC(desc%phmSGt, (desc%npw, gwr%cryst%nsym))
4318 : ! Fast sort for norm(desc%gvec) and store indices in igvec.
4319 0 : ABI_MALLOC(gnorm, (desc%npw))
4320 0 : ABI_MALLOC(igvec, (desc%npw))
4321 :
4322 0 : do ig=1,desc%npw
4323 0 : igvec(ig) = ig
4324 0 : gnorm(ig) = normv(desc%gvec(:,ig), gwr%cryst%gmet, "G") ** 2
4325 : end do
4326 :
4327 0 : call sort_dp(desc%npw, gnorm, igvec, tol14)
4328 :
4329 0 : ABI_FREE(gnorm)
4330 :
4331 0 : do ig1=1,desc%npw
4332 0 : do itim=1,gwr%cryst%timrev
4333 0 : do isym=1,gwr%cryst%nsym
4334 0 : grot=(3-2*itim)*MATMUL(gwr%cryst%symrec(:,:,isym),desc%gvec(:,ig1))
4335 0 : found=.FALSE.
4336 : ! * Loop on the shell of ig1 to speed up the search.
4337 : istep_forward = ig1; istep_backward = ig1
4338 0 : do while (istep_forward <= desc%npw .or. istep_backward >= 1)
4339 0 : if (istep_forward <= desc%npw) then
4340 0 : ig2 = igvec(istep_forward)
4341 0 : if (ALL(ABS(grot(:)-desc%gvec(:,ig2))==0)) then
4342 0 : found=.TRUE.
4343 0 : desc%rottb(ig1,itim,isym)=ig2
4344 0 : desc%rottbm1(ig2,itim,isym)=ig1
4345 0 : desc%phmGt(ig1,isym) = exp(-j_dpc*two_pi*DOT_PRODUCT(desc%gvec(:,ig1), gwr%cryst%tnons(:,isym)))
4346 0 : desc%phmSGt(ig1,isym) = exp(-j_dpc*two_pi*DOT_PRODUCT(grot(:), gwr%cryst%tnons(:,isym)))
4347 0 : exit
4348 : end if
4349 : end if
4350 0 : if (istep_backward >= 1) then
4351 0 : ig2 = igvec(istep_backward)
4352 0 : if (ALL(ABS(grot(:)-desc%gvec(:,ig2))==0)) then
4353 0 : found=.TRUE.
4354 0 : desc%rottb(ig1,itim,isym)=ig2
4355 0 : desc%rottbm1(ig2,itim,isym)=ig1
4356 0 : desc%phmGt(ig1,isym) = exp(-j_dpc*two_pi*DOT_PRODUCT(desc%gvec(:,ig1), gwr%cryst%tnons(:,isym)))
4357 0 : desc%phmSGt(ig1,isym) = exp(-j_dpc*two_pi*DOT_PRODUCT(grot(:), gwr%cryst%tnons(:,isym)))
4358 0 : exit
4359 : end if
4360 : end if
4361 0 : istep_forward = istep_forward + 1
4362 0 : istep_backward = istep_backward - 1
4363 : end do
4364 : ! if (.not.found) then
4365 : ! write(msg,'(3a,i5,a,i5,1x,2(3i10,a),a,i3,a,i3)')&
4366 : ! 'G-shell not closed',ch10,&
4367 : ! ' Initial G vector ',ig1,'/',desc%npw,desc%gvec(:,ig1),' Rotated G vector ',grot(:),ch10,&
4368 : ! ' Through sym ',isym,' and itim ',itim
4369 : ! ABI_ERROR(msg)
4370 : ! end if
4371 : end do ! itim
4372 : end do ! isym
4373 : end do ! ig1
4374 :
4375 0 : ABI_FREE(igvec)
4376 :
4377 : end if ! rot__
4378 :
4379 0 : end subroutine desc_init
4380 : !!***
4381 :
4382 : !----------------------------------------------------------------------
4383 :
4384 : !!****f* m_gwr/desc_get_vc_sqrt
4385 : !! NAME
4386 : !! desc_get_vc_sqrt
4387 : !!
4388 : !! FUNCTION
4389 : !! Compute square root of the Coulomb interaction vc(q,g).
4390 : !!
4391 : !! SOURCE
4392 :
4393 0 : subroutine desc_get_vc_sqrt(desc, qpt, q_is_gamma, gwr, mode, comm)
4394 :
4395 : !Arguments ------------------------------------
4396 : class(desc_t),intent(inout) :: desc
4397 : real(dp),intent(in) :: qpt(3)
4398 : logical, intent(in) :: q_is_gamma
4399 : class(gwr_t),intent(in) :: gwr
4400 : character(len=*),intent(in) :: mode
4401 : integer,intent(in) :: comm
4402 : ! *************************************************************************
4403 :
4404 : ABI_UNUSED([q_is_gamma])
4405 :
4406 0 : if (mode == "epsilon" .or. .not. gwr%has_vcgen_sigma) then
4407 0 : if (allocated(desc%vc_sqrt_eps)) return
4408 0 : ABI_MALLOC(desc%vc_sqrt_eps, (desc%npw))
4409 0 : call gwr%vcgen_eps%get_vc_sqrt(qpt, desc%npw, desc%gvec, gwr%q0, gwr%cryst, desc%vc_sqrt_eps, comm)
4410 :
4411 0 : else if (mode == "sigma") then
4412 0 : if (allocated(desc%vc_sqrt_sigma)) return
4413 0 : ABI_MALLOC(desc%vc_sqrt_sigma, (desc%npw))
4414 0 : call gwr%vcgen_sigma%get_vc_sqrt(qpt, desc%npw, desc%gvec, gwr%q0, gwr%cryst, desc%vc_sqrt_sigma, comm)
4415 :
4416 : else
4417 0 : ABI_ERROR(sjoin("Invalid mode:", mode))
4418 : end if
4419 :
4420 : end subroutine desc_get_vc_sqrt
4421 : !!***
4422 :
4423 : !----------------------------------------------------------------------
4424 :
4425 : !!****f* m_gwr/desc_copy
4426 : !! NAME
4427 : !! desc_copy
4428 : !!
4429 : !! FUNCTION
4430 : !! Copy object
4431 : !! NB: cannot use obj1 = obj2 syntax because ABINIT memory-leak detector
4432 : !! won't see the allocation automatically performed by the compiler.
4433 : !!
4434 : !! SOURCE
4435 :
4436 0 : subroutine desc_copy(in_desc, new_desc)
4437 :
4438 : !Arguments ------------------------------------
4439 : class(desc_t),intent(in) :: in_desc
4440 : class(desc_t),intent(out) :: new_desc
4441 : ! *************************************************************************
4442 :
4443 0 : call new_desc%free()
4444 :
4445 0 : new_desc%istwfk = in_desc%istwfk
4446 0 : new_desc%npw = in_desc%npw
4447 0 : new_desc%ig0 = in_desc%ig0
4448 0 : new_desc%kin_sorted = in_desc%kin_sorted
4449 :
4450 0 : call alloc_copy(in_desc%gvec, new_desc%gvec)
4451 0 : call alloc_copy(in_desc%gbound, new_desc%gbound)
4452 0 : if (allocated(in_desc%vc_sqrt_eps)) call alloc_copy(in_desc%vc_sqrt_eps, new_desc%vc_sqrt_eps)
4453 0 : if (allocated(in_desc%vc_sqrt_sigma)) call alloc_copy(in_desc%vc_sqrt_sigma, new_desc%vc_sqrt_sigma)
4454 :
4455 0 : if (allocated(in_desc%g2box)) then
4456 0 : call alloc_copy(in_desc%g2box, new_desc%g2box)
4457 0 : new_desc%cached_sc_ngfft = in_desc%cached_sc_ngfft
4458 : end if
4459 :
4460 0 : end subroutine desc_copy
4461 : !!***
4462 :
4463 : !----------------------------------------------------------------------
4464 :
4465 : !!****f* m_gwr/desc_to_scbox
4466 : !! NAME
4467 : !! desc_to_scbox
4468 : !!
4469 : !! FUNCTION
4470 : !! Insert cg_k array defined on the k-centered g-sphere with npw vectors inside the FFT box.
4471 : !! The main difference wrt to sphere is that cfft is not initialized to zero. See notes below.
4472 : !!
4473 : !! INPUTS
4474 : !! sc_ngfft:
4475 : !! n1,n2,n3=physical dimension of the FFT box
4476 : !! n4,n5,n6=memory dimension of cfft
4477 : !! npw=number of G vectors in basis at this k point
4478 : !! ndat=number of items to process
4479 : !! cg(npw*ndat)= contains values for npw G vectors in basis sphere
4480 : !!
4481 : !! OUTPUT
4482 : !! cfft(n4,n5,n6*ndat) = array on FFT box filled with cg data
4483 : !! Note that cfft is intent(inout) so that we can add contributions from different k-points.
4484 : !!
4485 : !! SOURCE
4486 :
4487 0 : subroutine desc_to_scbox(desc, kk, ngkpt, sc_ngfft, ndat, cg, cfft)
4488 :
4489 : !Arguments ------------------------------------
4490 : !scalars
4491 : class(desc_t),intent(inout) :: desc
4492 : real(dp),intent(in) :: kk(3)
4493 : integer,intent(in) :: ngkpt(3)
4494 : integer,intent(in) :: sc_ngfft(6), ndat
4495 : !arrays
4496 : complex(gwp),intent(in) :: cg(desc%npw, ndat)
4497 : complex(gwp),intent(inout) :: cfft(sc_ngfft(4)*sc_ngfft(5)*sc_ngfft(6),ndat)
4498 :
4499 : !Local variables-------------------------------
4500 : integer :: n1, n2, n3, n4, n5, n6, i1, i2, i3, idat, ipw, kg(3), gg(3), ifft, npw
4501 : logical :: compute_mapping
4502 : !real(dp) :: tsec(2)
4503 : ! *************************************************************************
4504 :
4505 : ! TODO: Add op_type
4506 : !call timab(1931, 1, tsec)
4507 :
4508 0 : npw = desc%npw
4509 0 : n1 = sc_ngfft(1); n2 = sc_ngfft(2); n3 = sc_ngfft(3)
4510 0 : n4 = sc_ngfft(4); n5 = sc_ngfft(5); n6 = sc_ngfft(6)
4511 0 : gg = nint(kk * ngkpt)
4512 :
4513 0 : compute_mapping = .not. allocated(desc%g2box) .or. any(desc%cached_sc_ngfft /= sc_ngfft(1:6))
4514 :
4515 : ! FIXME This is not thread safe
4516 : if (compute_mapping) then
4517 0 : ABI_REMALLOC(desc%g2box, (npw))
4518 0 : desc%cached_sc_ngfft = sc_ngfft(1:6)
4519 0 : do ipw=1,npw
4520 0 : kg = gg + ngkpt * desc%gvec(:,ipw) ! k+g
4521 0 : i1 = modulo(kg(1), n1)
4522 0 : i2 = modulo(kg(2), n2)
4523 0 : i3 = modulo(kg(3), n3)
4524 0 : desc%g2box(ipw) = 1 + i1 + n4*(i2+i3*n5)
4525 : end do
4526 : end if
4527 :
4528 : !do ipw=1,npw
4529 : ! if (any(desc%gvec(:,ipw) > sc_ngfft(1:3)/2) .or. any(desc%gvec(:,ipw) < -(sc_ngfft(1:3)-1)/2) ) then
4530 : ! ABI_ERROR(sjoin(" The G-vector: ",ltoa(desc%gvec(:, ipw))," falls outside the FFT box. Increase boxcutmin (?)"))
4531 : ! end if
4532 : !end do
4533 :
4534 : ! Insert cg into cfft
4535 : !$OMP PARALLEL DO PRIVATE(ifft) IF (ndat > 1)
4536 0 : do idat=1,ndat
4537 0 : do ipw=1,npw
4538 0 : ifft = desc%g2box(ipw)
4539 0 : cfft(ifft,idat) = cg(ipw,idat)
4540 : end do
4541 : end do
4542 :
4543 : !call timab(1931, 2, tsec)
4544 :
4545 0 : end subroutine desc_to_scbox
4546 : !!***
4547 :
4548 : !----------------------------------------------------------------------
4549 :
4550 : !!****f* m_gwr/desc_free
4551 : !! NAME
4552 : !! desc_free
4553 : !!
4554 : !! FUNCTION
4555 : !! Free memory
4556 : !!
4557 : !! SOURCE
4558 :
4559 0 : subroutine desc_free(desc)
4560 :
4561 : !Arguments ------------------------------------
4562 : class(desc_t),intent(inout) :: desc
4563 : ! *************************************************************************
4564 :
4565 0 : ABI_SFREE(desc%gvec)
4566 0 : ABI_SFREE(desc%gbound)
4567 0 : ABI_SFREE(desc%vc_sqrt_eps)
4568 0 : ABI_SFREE(desc%vc_sqrt_sigma)
4569 0 : ABI_SFREE(desc%g2box)
4570 0 : ABI_SFREE(desc%rottb)
4571 0 : ABI_SFREE(desc%rottbm1)
4572 0 : ABI_SFREE(desc%phmGt)
4573 0 : ABI_SFREE(desc%phmSGt)
4574 0 : desc%cached_sc_ngfft = -1
4575 :
4576 0 : end subroutine desc_free
4577 : !!***
4578 :
4579 : !----------------------------------------------------------------------
4580 :
4581 : !!****f* m_gwr/gwr_print
4582 : !! NAME
4583 : !! gwr_print
4584 : !!
4585 : !! FUNCTION
4586 : !! Print info on the gwr object.
4587 : !!
4588 : !! INPUTS
4589 : !!
4590 : !! SOURCE
4591 :
4592 0 : subroutine gwr_print(gwr, units, header)
4593 :
4594 : !Arguments ------------------------------------
4595 : class(gwr_t),intent(in) :: gwr
4596 : integer,intent(in) :: units(:)
4597 : character(len=*),optional,intent(in) :: header
4598 :
4599 : !Local variables-------------------------------
4600 : integer :: ii
4601 : character(len=500) :: msg
4602 : type(yamldoc_t) :: ydoc
4603 : ! *********************************************************************
4604 :
4605 0 : msg = ' ==== Info on the gwr_t object ==== '; if (present(header)) msg=' ==== '//trim(adjustl(header))//' ==== '
4606 0 : call wrtout(units, msg)
4607 :
4608 0 : ydoc = yamldoc_open('GWR_params') !, width=11, real_fmt='(3f8.3)')
4609 0 : call ydoc%add_string("gwr_task", gwr%dtset%gwr_task)
4610 0 : call ydoc%add_int("nband", gwr%dtset%nband(1))
4611 0 : call ydoc%add_int("ntau", gwr%ntau)
4612 0 : call ydoc%add_int1d("ngkpt", gwr%ngkpt)
4613 0 : call ydoc%add_int1d("ngqpt", gwr%ngqpt)
4614 0 : msg = "supercell"; if (.not. gwr%use_supercell_for_tchi) msg = "BZ-convolutions"
4615 0 : call ydoc%add_string("chi_algo", msg)
4616 0 : msg = "supercell"; if (.not. gwr%use_supercell_for_sigma) msg = "BZ-convolutions"
4617 0 : call ydoc%add_string("sigma_algo", msg)
4618 0 : call ydoc%add_int("nkibz", gwr%nkibz)
4619 0 : call ydoc%add_int("nqibz", gwr%nqibz)
4620 0 : call ydoc%add_int("inclvkb", gwr%dtset%inclvkb)
4621 0 : call ydoc%add_real1d("q0", gwr%q0) ! "for long-wavelenght limit"))
4622 0 : call ydoc%add_int("gw_icutcoul", gwr%dtset%gw_icutcoul)
4623 0 : call ydoc%add_int("green_mpw", gwr%green_mpw)
4624 0 : call ydoc%add_int("tchi_mpw", gwr%tchi_mpw)
4625 0 : call ydoc%add_int1d("g_ngfft", gwr%g_ngfft(1:6))
4626 0 : call ydoc%add_real("gwr_boxcutmin", gwr%dtset%gwr_boxcutmin)
4627 0 : call ydoc%add_int1d("P gwr_np_kgts", gwr%dtset%gwr_np_kgts)
4628 0 : call ydoc%add_int1d("P np_kibz", gwr%np_kibz)
4629 0 : call ydoc%add_int1d("P np_qibz", gwr%np_qibz)
4630 : ! Print Max error due to the inhomogeneous FT.
4631 0 : call ydoc%add_real("min_transition_energy_eV", gwr%te_min * Ha_eV)
4632 0 : call ydoc%add_real("max_transition_energy_eV", gwr%te_max * Ha_eV)
4633 0 : call ydoc%add_real("eratio", gwr%te_max / gwr%te_min)
4634 0 : call ydoc%add_real("ft_max_err_t2w_cos", gwr%ft_max_error(1))
4635 0 : call ydoc%add_real("ft_max_err_w2t_cos", gwr%ft_max_error(2))
4636 0 : call ydoc%add_real("ft_max_err_t2w_sin", gwr%ft_max_error(3))
4637 0 : call ydoc%add_real("cosft_duality_error", gwr%cosft_duality_error)
4638 : ! Print imaginary time/frequency mesh with weights.
4639 0 : call ydoc%open_tabular("Minimax imaginary tau/omega mesh in a.u.", comment="tau, weight(tau), omega, weight(omega)")
4640 0 : do ii=1,gwr%ntau
4641 0 : write(msg, "(i0, 4(es12.5,2x))")ii, gwr%tau_mesh(ii), gwr%tau_wgs(ii), gwr%iw_mesh(ii), gwr%iw_wgs(ii)
4642 0 : call ydoc%add_tabular_line(msg)
4643 : end do
4644 :
4645 0 : call ydoc%write_units_and_free(units)
4646 :
4647 0 : end subroutine gwr_print
4648 : !!***
4649 :
4650 : !!****f* m_gwr/gwr_print_mem
4651 : !! NAME
4652 : !! gwr_print_mem
4653 : !!
4654 : !! FUNCTION
4655 : !! Print memory allocated for matrices.
4656 : !!
4657 : !! SOURCE
4658 :
4659 0 : subroutine gwr_print_mem(gwr, units)
4660 :
4661 : !Arguments ------------------------------------
4662 : class(gwr_t),intent(in) :: gwr
4663 : integer,intent(in) :: units(:)
4664 :
4665 : !Local variables-------------------------------
4666 : !scalars
4667 : real(dp) :: mem_mb
4668 : !character(len=500) :: msg
4669 : ! *********************************************************************
4670 :
4671 0 : if (allocated(gwr%gt_kibz)) then
4672 0 : mem_mb = sum(slk_array_locmem_mb(gwr%gt_kibz))
4673 0 : if (mem_mb > zero) then
4674 0 : call wrtout(units, sjoin("- Local memory for G(g,g',kibz,itau): ", ftoa(mem_mb, fmt="f8.1"), ' [Mb] <<< MEM'))
4675 : end if
4676 : end if
4677 0 : if (allocated(gwr%tchi_qibz)) then
4678 0 : mem_mb = sum(slk_array_locmem_mb(gwr%tchi_qibz))
4679 0 : if (mem_mb > zero) then
4680 0 : call wrtout(units, sjoin("- Local memory for Chi(g,g',qibz,itau): ", ftoa(mem_mb, fmt="f8.1"), ' [Mb] <<< MEM'))
4681 : end if
4682 : end if
4683 0 : if (allocated(gwr%wc_qibz)) then
4684 0 : mem_mb = sum(slk_array_locmem_mb(gwr%wc_qibz))
4685 0 : if (mem_mb > zero) then
4686 0 : call wrtout(units, sjoin("- Local memory for Wc(g,g,qibz,itau): ", ftoa(mem_mb, fmt="f8.1"), ' [Mb] <<< MEM'))
4687 : end if
4688 : end if
4689 0 : if (allocated(gwr%sigc_kibz)) then
4690 0 : mem_mb = sum(slk_array_locmem_mb(gwr%sigc_kibz))
4691 0 : if (mem_mb > zero) then
4692 0 : call wrtout(units, sjoin("- Local memory for Sigma_c(g,g',kibz,itau): ", ftoa(mem_mb, fmt="f8.1"), ' [Mb] <<< MEM'))
4693 : end if
4694 : end if
4695 0 : if (allocated(gwr%ugb)) then
4696 0 : mem_mb = sum(slk_array_locmem_mb(gwr%ugb))
4697 0 : if (mem_mb > zero) then
4698 0 : call wrtout(units, sjoin('- Local memory for u_gb wavefunctions: ', ftoa(mem_mb, fmt="f8.1"), ' [Mb] <<< MEM'))
4699 : end if
4700 : end if
4701 0 : call wrtout(units, " ")
4702 :
4703 0 : end subroutine gwr_print_mem
4704 : !!***
4705 :
4706 : !----------------------------------------------------------------------
4707 :
4708 : !!****f* m_gwr/gwr_build_tchi
4709 : !! NAME
4710 : !! gwr_build_tchi
4711 : !!
4712 : !! FUNCTION
4713 : !! High-level routine to compute the irreducible polarizability.
4714 : !!
4715 : !! SOURCE
4716 :
4717 0 : subroutine gwr_build_tchi(gwr)
4718 :
4719 : !Arguments ------------------------------------
4720 : class(gwr_t),target,intent(inout) :: gwr
4721 :
4722 : !Local variables-------------------------------
4723 : !scalars
4724 : integer :: my_is, my_it, my_ikf, ig, my_ir, my_nr, nr, npw, ncol_glob, col_bsize, my_iqi, gt_scbox_win, gpu_option, iab
4725 : integer :: idat, ndat, max_ndat, sc_nfft, sc_nfftsp, spin, ik_bz, iq_ibz, ikq_ibz, ikq_bz, ierr, ipm, itau, ig2, ifft !, ii
4726 : integer :: use_umklp, gpu_mode ! ik_ibz, isym_k, trev_k, tsign_k, ! g0_k(3),
4727 : !integer :: my_ikf_start, my_ikf_stop !, nkf_batch_size, nkf_now, op_type
4728 : integer :: itim, isym
4729 : integer(kind=XMPI_ADDRESS_KIND) :: buf_count
4730 : real(dp) :: cpu_tau, wall_tau, gflops_tau, cpu_all, wall_all, gflops_all, cpu_ir, wall_ir, gflops_ir
4731 : real(dp) :: cpu_ikf, wall_ikf, gflops_ikf
4732 : real(dp) :: tchi_rfact, mem_mb, local_max, max_abs_imag_chit
4733 : real(gwp) :: wtqp, wtqm
4734 : complex(gwp) :: head_q
4735 : complex(dp) :: chq(3), wng(3)
4736 : logical :: q_is_gamma, use_shmem_for_k, use_mpi_for_k, print_time, keep_tchim !, doit ! isirr_k,
4737 : character(len=5000) :: msg
4738 : character(len=50) :: gpu_action
4739 : type(desc_t),pointer :: desc_q ! desc_k,
4740 0 : type(__slkmat_t) :: chi_rgp
4741 : type(c_ptr) :: void_ptr
4742 : !arrays
4743 0 : integer :: sc_ngfft(18), gg(3), g0_kq(3), mask_qibz(gwr%nqibz), need_kibz(gwr%nkibz), got_kibz(gwr%nkibz), units(2)
4744 0 : integer,allocatable :: green_scgvec(:,:), chi_scgvec(:,:)
4745 0 : logical :: select_my_kbz(gwr%my_nkbz)
4746 : real(dp) :: kk_bz(3), kpq_bz(3), qq_ibz(3), tsec(2)
4747 0 : complex(gwp) ABI_ASYNC, contiguous, pointer :: gt_scbox(:,:,:)
4748 0 : complex(gwp),allocatable :: low_wing_q(:), up_wing_q(:), cemiqr(:)
4749 : !complex(gwp),contiguous, pointer :: buf_cplx(:,:)
4750 0 : type(__slkmat_t) :: gkq_rpr_pm(2, gwr%nsig_ab), gk_rpr_pm(2, gwr%nsig_ab), work2, work1, chiq_ggp
4751 0 : type(__slkmat_t),target,allocatable :: gt_gpr(:,:,:), chiq_gpr(:), chiq_rpr(:)
4752 0 : type(desc_t),target,allocatable :: desc_mykbz(:)
4753 0 : type(littlegroup_t),allocatable :: ltg_qibz(:)
4754 : type(fftbox_plan3_t) :: green_plan
4755 0 : type(uplan_t) :: uplan_q
4756 : ! *************************************************************************
4757 :
4758 0 : call cwtime(cpu_all, wall_all, gflops_all, "start")
4759 0 : call timab(1923, 1, tsec)
4760 :
4761 0 : units = [std_out, ab_out]
4762 0 : gpu_option = gwr%dtset%gpu_option
4763 :
4764 0 : ABI_CHECK(gwr%tchi_space == "none", sjoin("tchi_space: ", gwr%tchi_space, " != none"))
4765 0 : gwr%tchi_space = "itau"
4766 :
4767 : ! Allocate tchi_q(g,g') matrices
4768 0 : mask_qibz = 0; mask_qibz(gwr%my_qibz_inds(:)) = 1
4769 0 : call gwr%print_mem([std_out])
4770 :
4771 0 : call gwr%malloc_free_mats(mask_qibz, "tchi", "malloc")
4772 0 : max_abs_imag_chit = zero
4773 :
4774 : ! Setup FFT mesh in the supercell.
4775 0 : sc_ngfft = gwr%g_ngfft
4776 0 : sc_ngfft(1:3) = gwr%ngkpt * gwr%g_ngfft(1:3); sc_ngfft(4:6) = sc_ngfft(1:3)
4777 0 : sc_nfft = product(sc_ngfft(1:3)); sc_nfftsp = sc_nfft !* gwr%nspinor
4778 :
4779 0 : if (gwr%use_supercell_for_tchi) then
4780 : ! ============================
4781 : ! Chi algorithm with supercell
4782 : ! ============================
4783 0 : call print_chi_header()
4784 :
4785 : ! Be careful when using the FFT plan with ndat as ndat can change inside the loop if we start to block.
4786 : ! Perhaps the safest approach would be to generate the plan on the fly.
4787 0 : max_ndat = gwr%sc_batch_size
4788 0 : use_mpi_for_k = gwr%sc_batch_size == gwr%kpt_comm%nproc .and. gwr%kpt_comm%nproc > 1
4789 : !use_mpi_for_k = .False.
4790 :
4791 0 : use_shmem_for_k = gwr%sc_batch_size == gwr%kpt_comm%nproc .and. gwr%kpt_comm%nproc > 1
4792 0 : use_shmem_for_k = use_shmem_for_k .and. gwr%kpt_comm%can_use_shmem()
4793 0 : if (gwr%dtset%userie == 234) use_shmem_for_k = .False.
4794 : #ifndef HAVE_MPI_ALLOCATE_SHARED_CPTR
4795 : use_shmem_for_k = .False.
4796 : #endif
4797 :
4798 0 : if (use_shmem_for_k) then
4799 0 : buf_count = 2 * (sc_nfftsp * max_ndat * 2)
4800 0 : call gwr%kpt_comm%allocate_shared_master(buf_count, gwp, xmpi_info_null, void_ptr, gt_scbox_win)
4801 0 : call c_f_pointer(void_ptr, gt_scbox, shape=[sc_nfftsp, max_ndat, 2])
4802 : end if
4803 :
4804 0 : call wrtout(std_out, sjoin(" use_mpi_for_k:", yesno(use_mpi_for_k)))
4805 0 : call wrtout(std_out, sjoin(" use_shmem_for_k:", yesno(use_shmem_for_k)))
4806 0 : mem_mb = (sc_nfftsp * max_ndat * 2 * gwp) * b2Mb
4807 0 : call wrtout(std_out, sjoin(" Memory for gt_scbox array:", ftoa(mem_mb, fmt="f8.1"), ' [Mb] <<< MEM'))
4808 :
4809 0 : if (.not. use_shmem_for_k) then
4810 0 : ABI_MALLOC(gt_scbox, (sc_nfftsp, max_ndat, 2))
4811 : #ifdef HAVE_OPENMP_OFFLOAD
4812 : !$OMP TARGET ENTER DATA MAP(alloc:gt_scbox(1:sc_nfftsp,1:max_ndat,1:2)) IF (gpu_option == ABI_GPU_OPENMP)
4813 : #endif
4814 : end if
4815 :
4816 : ! Build plan for dense FFTs.
4817 0 : call green_plan%from_ngfft(sc_ngfft, max_ndat*2, gpu_option)
4818 :
4819 : ! The g-vectors in the supercell for G and tchi.
4820 0 : ABI_MALLOC(green_scgvec, (3, gwr%green_mpw))
4821 0 : ABI_MALLOC(chi_scgvec, (3, gwr%tchi_mpw))
4822 0 : ABI_MALLOC(gt_gpr, (2, gwr%my_nkbz, gwr%nsig_ab))
4823 0 : ABI_MALLOC(chiq_gpr, (gwr%my_nqibz))
4824 0 : ABI_MALLOC(desc_mykbz, (gwr%my_nkbz))
4825 :
4826 0 : ABI_MALLOC(cemiqr, (gwr%g_nfft)) ! The phase e^{-iq.r} in the unit cell.
4827 : #ifdef HAVE_OPENMP_OFFLOAD
4828 : !$OMP TARGET ENTER DATA MAP(alloc:cemiqr) IF (gpu_option == ABI_GPU_OPENMP)
4829 : #endif
4830 :
4831 0 : if (gwr%comm%me == 0) call pstat_proc%print(_PSTAT_ARGS_)
4832 0 : call wrtout(std_out, " Allocating PBLAS arrays for tchi_q(g',r) for all q in the IBZ treated by this MPI rank.")
4833 0 : call wrtout(std_out, " Here we're gonna have a big allocation peak...")
4834 : ! TODO: To reduce memory one could use a diagonal approximation for chi at large G so that we can use a smaller ecuteps.
4835 :
4836 0 : do my_iqi=1,gwr%my_nqibz
4837 0 : iq_ibz = gwr%my_qibz_inds(my_iqi)
4838 0 : npw = gwr%tchi_desc_qibz(iq_ibz)%npw
4839 0 : ncol_glob = gwr%g_nfft
4840 0 : ABI_CHECK(block_dist_1d(ncol_glob, gwr%g_comm%nproc, col_bsize, msg), msg)
4841 0 : call chiq_gpr(my_iqi)%init(npw, gwr%g_nfft, gwr%g_slkproc, 1, size_blocs=[-1, col_bsize])
4842 0 : if (gwr%comm%me == 0 .and. mod(my_iqi, 2) == 0) call pstat_proc%print(_PSTAT_ARGS_)
4843 : end do
4844 :
4845 0 : mem_mb = sum(slk_array_locmem_mb(chiq_gpr))
4846 0 : call wrtout(std_out, sjoin(" Local memory for Chi_q(g',r) matrices: ", ftoa(mem_mb, fmt="f8.1"), ' [Mb] <<< MEM'))
4847 0 : if (gwr%comm%me == 0) call pstat_proc%print(_PSTAT_ARGS_)
4848 :
4849 0 : select_my_kbz = .True.
4850 : !nkf_batch_size = gwr%my_nkbz
4851 :
4852 : ! Loop over my spins and my taus.
4853 0 : do my_is=1,gwr%my_nspins
4854 0 : spin = gwr%my_spins(my_is)
4855 0 : do my_it=1,gwr%my_ntau
4856 0 : call cwtime(cpu_tau, wall_tau, gflops_tau, "start")
4857 0 : itau = gwr%my_itaus(my_it)
4858 :
4859 : ! TODO: To reduce memory one could allocate and then accumulate chi only for a subset of k-points in the BZ
4860 : ! inside an extra loop over k-groups. This increase the number of FFTs by ngroups but memory decreases
4861 : ! get_myk_green_gpr should receive a mask and box2gsph should accumulate for ik_group > 1.
4862 : ! First of all, I need to undestand if get_myk_green_gpr is responsible for the OOM (very likely)
4863 :
4864 : ! This trick cannot be used for chi as we have GG but it might be implemented for GW
4865 : ! where Sigma = G1_k W + G2_k W + G3_k W ...
4866 :
4867 : !do my_ikf_start=1, gwr%my_nkbz, nkf_batch_size
4868 : ! nkf_now = blocked_loop(my_ikf_start, gwr%my_nkbz, nkf_batch_size)
4869 : ! my_ikf_stop = min(my_ikf_start + nkf_now, gwr%my_nkbz)
4870 : ! !select_my_kbz = .False.; select_my_kbz(my_ifk_start:my_ifk_stop) = .True.
4871 : ! !op_type = OP_COPY; if (my_ifk_start /= 0) op_type = OP_SUM
4872 : !end do ! my_ifk_start
4873 :
4874 : ! G_k(g,g') --> G_k(g',r) e^{ik.r} for each k in the BZ treated by me.
4875 0 : call gwr%get_myk_green_gpr(itau, spin, select_my_kbz, desc_mykbz, gt_gpr)
4876 0 : if (my_it == 1 .and. gwr%comm%me == 0) call pstat_proc%print(_PSTAT_ARGS_)
4877 :
4878 : ! Loop over r in the unit cell that is now MPI-distributed inside g_comm.
4879 : ! This is a bottleneck but perhaps one can take advantage of localization.
4880 : ! Also, one can save all the FFTs in a matrix G(mnfft * ndat, my_nkbz) multiply by the e^{-ikr} phase
4881 : ! and then use zgemm to compute Out(r,L) = [e^{-ikr}G_k(r)] e^{-ikL} with precomputed e^{-iLk} phases.
4882 0 : my_nr = gt_gpr(1,1,1)%size_local(2)
4883 0 : do my_ir=1, my_nr, gwr%sc_batch_size
4884 0 : ndat = blocked_loop(my_ir, my_nr, gwr%sc_batch_size)
4885 0 : print_time = (gwr%comm%me == 0 .and. (my_ir <= 6 * gwr%sc_batch_size .or. mod(my_ir, LOG_MODR) == 0))
4886 0 : if (print_time) call cwtime(cpu_ir, wall_ir, gflops_ir, "start")
4887 0 : do iab=1, gwr%nsig_ab
4888 :
4889 : ! TODO: GPU version
4890 0 : if (.not. use_shmem_for_k) then
4891 :
4892 : ! Insert G_k(g',r) in G'-space in the supercell FFT box (ndat vectors starting at my_ir).
4893 0 : call gwr%gk_to_scbox(sc_ngfft, select_my_kbz, desc_mykbz, green_scgvec, my_ir, ndat, gt_gpr(:,:,iab), gt_scbox)
4894 : #ifdef HAVE_OPENMP_OFFLOAD
4895 : !$omp target update to(gt_scbox(1:sc_nfftsp,1:max_ndat,1:2)) if (gpu_option == ABI_GPU_OPENMP)
4896 : #endif
4897 :
4898 0 : if (.not. use_mpi_for_k) then
4899 : ! G(G',r) --> G(R',r) = sum_{k,g'} e^{-i(k+g').R'} G_k(g',r)
4900 0 : if (gwr%kpt_comm%nproc > 1) call xmpi_sum(gt_scbox, gwr%kpt_comm%value, ierr)
4901 0 : call green_plan%execute(gt_scbox(:,1,1), -1, max_ndat*2, iscale=0)
4902 :
4903 : ! Compute tchi(R',r) for this r and store it in (:,:,1). Note that results are real so one might use r2c FFT.
4904 : ! Then back to tchi(G'=q+g',r) immediately with isign + 1.
4905 : !gt_scbox(:,:,1) = gt_scbox(:,:,1) * conjg(gt_scbox(:,:,2))
4906 : #ifdef HAVE_OPENMP_OFFLOAD
4907 : !$OMP TARGET TEAMS DISTRIBUTE PARALLEL DO COLLAPSE(2) MAP(to:gt_scbox(1:sc_nfftsp,1:max_ndat,1:2)) IF (gpu_option == ABI_GPU_OPENMP)
4908 : #endif
4909 0 : do idat=1,max_ndat
4910 0 : do ifft=1,sc_nfftsp
4911 0 : gt_scbox(ifft,idat,1) = gt_scbox(ifft,idat,1) * conjg(gt_scbox(ifft,idat,2))
4912 : end do
4913 : end do
4914 : !max_abs_imag_chit = max(max_abs_imag_chit, maxval(abs(aimag(gt_scbox(:,:,1)))))
4915 :
4916 0 : call green_plan%execute(gt_scbox(:,1,1), +1, max_ndat*2)
4917 : #ifdef HAVE_OPENMP_OFFLOAD
4918 : !$omp target update from(gt_scbox(1:sc_nfftsp,1:max_ndat,1:2)) if (gpu_option == ABI_GPU_OPENMP)
4919 : #endif
4920 :
4921 : else
4922 : ! Reduce one G_k(tau) on the idat-1 proc and perform ndat FFTs in parallel.
4923 : ! Finally, broadcast from the (idat-1) proc inside gwr%kpt_comm.
4924 0 : do ipm=1,2
4925 0 : do idat=1,ndat
4926 0 : call xmpi_sum_master(gt_scbox(:,idat,ipm), idat-1, gwr%kpt_comm%value, ierr)
4927 : end do
4928 : end do
4929 0 : idat = gwr%kpt_comm%me + 1
4930 0 : do ipm=1,2
4931 0 : call green_plan%execute(gt_scbox(:,idat,ipm), -1, ndat=1, iscale=0)
4932 : end do
4933 0 : gt_scbox(:,idat,1) = gt_scbox(:,idat,1) * conjg(gt_scbox(:,idat,2))
4934 0 : call green_plan%execute(gt_scbox(:,idat,1), +1, ndat=1)
4935 0 : do idat=1,ndat
4936 0 : call xmpi_bcast(gt_scbox(:,idat,1), idat-1, gwr%kpt_comm%value, ierr)
4937 : end do
4938 : end if
4939 :
4940 : else
4941 : ! use_shmem_for_k --> MPI shared window version. Only gt_scbox is shared.
4942 :
4943 : call gwr%gk_to_scbox(sc_ngfft, select_my_kbz, desc_mykbz, green_scgvec, my_ir, ndat, gt_gpr(:,:,iab), gt_scbox, &
4944 0 : gt_scbox_win=gt_scbox_win)
4945 :
4946 : ! Now each MPI proc operates on different idat entries.
4947 : !IF (.not. MPI_ASYNC_PROTECTS_NONBLOCKING) CALL MPI_F_SYNC_REG(gt_scbox)
4948 0 : call xmpi_win_fence(XMPI_MODE_NOPRECEDE, gt_scbox_win, ierr) ! Start the RMA epoch
4949 0 : idat = gwr%kpt_comm%me + 1
4950 0 : if (idat <= ndat) then
4951 0 : do ipm=1,2
4952 0 : call green_plan%execute(gt_scbox(:,idat,ipm), -1, ndat=1, iscale=0)
4953 : end do
4954 0 : gt_scbox(:,idat,1) = gt_scbox(:,idat,1) * conjg(gt_scbox(:,idat,2))
4955 0 : call green_plan%execute(gt_scbox(:,idat,1), +1, ndat=1)
4956 : end if
4957 : !IF (.not. MPI_ASYNC_PROTECTS_NONBLOCKING) CALL MPI_F_SYNC_REG(gt_scbox)
4958 : !call xmpi_barrier(gwr%kpt_comm%value)
4959 0 : call xmpi_win_fence(XMPI_MODE_NOSUCCEED, gt_scbox_win, ierr) ! End the RMA epoch
4960 : end if
4961 :
4962 : ! Now extract tchi_q(g',r) on the ecuteps (q+g)-sphere from the FFT box in the supercell
4963 : ! and save data in chiq_gpr PBLAS matrix. Only my q-points in the IBZ are considered.
4964 : ! Alternatively, one can avoid the above FFT, use zero-padded to go from the supercell
4965 : ! to the ecuteps g-sphere inside the my_iqi loop. This approach should play well with k-point parallelism.
4966 0 : do my_iqi=1,gwr%my_nqibz
4967 0 : iq_ibz = gwr%my_qibz_inds(my_iqi); qq_ibz = gwr%qibz(:, iq_ibz); desc_q => gwr%tchi_desc_qibz(iq_ibz)
4968 0 : gg = nint(qq_ibz * gwr%ngqpt)
4969 0 : do ig=1,desc_q%npw
4970 0 : chi_scgvec(:,ig) = gg + gwr%ngqpt(:) * desc_q%gvec(:,ig) ! q+g
4971 : end do
4972 : call box2gsph(merge(OP_COPY, OP_ACC, iab == 1),&
4973 : sc_ngfft, desc_q%npw, ndat, chi_scgvec, &
4974 0 : gt_scbox(:,1,1), chiq_gpr(my_iqi)%buffer_cplx(:,my_ir))
4975 : ! TODO:
4976 : !call desc_q%box2gsph(qq_ibz, gwr%ngqpt, sc_ngfft, gwr%nspinor * ndat, &
4977 : ! gt_scbox(:,1,1), chiq_gpr(my_iqi)%buffer_cplx(:,my_ir))
4978 : end do ! my_iqi
4979 : end do ! iab
4980 :
4981 0 : if (print_time) then
4982 0 : write(msg,'(4x,3(a,i0),a)')"Chi my_ir [", my_ir, "/", my_nr, "] (tot: ", gwr%g_nfft, ")"
4983 0 : call cwtime_report(msg, cpu_ir, wall_ir, gflops_ir)
4984 : end if
4985 : end do ! my_ir (end cpu intensive loop)
4986 :
4987 : ! Free descriptors and PBLAS matrices in kBZ.
4988 0 : call desc_array_free(desc_mykbz); call slk_array_free(gt_gpr)
4989 :
4990 : ! Now we have tchi_q(g',r).
4991 : ! For each IBZ q-point treated by this MPI proc, do:
4992 : !
4993 : ! 1) MPI transpose to have tchi_q(r,g')
4994 : ! 2) FFT along the first dimension to get tchi_q(g,g') and store it in gwr%tchi_qibz
4995 : !
4996 0 : tchi_rfact = one / gwr%g_nfft / gwr%cryst%ucvol / (gwr%nkbz * gwr%nqbz)
4997 :
4998 0 : do my_iqi=1,gwr%my_nqibz
4999 0 : iq_ibz = gwr%my_qibz_inds(my_iqi)
5000 0 : q_is_gamma = normv(gwr%qibz(:,iq_ibz), gwr%cryst%gmet, "G") < GW_TOLQ0
5001 0 : desc_q => gwr%tchi_desc_qibz(iq_ibz)
5002 :
5003 : ! Note the minus sign in q.
5004 0 : call calc_ceikr(-gwr%qibz(:,iq_ibz), gwr%g_ngfft, gwr%g_nfft, 1, cemiqr)
5005 0 : cemiqr = cemiqr * tchi_rfact
5006 : #ifdef HAVE_OPENMP_OFFLOAD
5007 : !$omp target update to(cemiqr) if (gpu_option == ABI_GPU_OPENMP)
5008 : #endif
5009 :
5010 : ! MPI-transposition: tchi_q(g',r) => tchi_q(r,g')
5011 0 : call chiq_gpr(my_iqi)%ptrans("N", chi_rgp)
5012 :
5013 : ! FFT tchi_q(r,g') --> tchi_q(g,g'). Results stored in gwr%tchi_qibz.
5014 : call uplan_q%init(desc_q%npw, 1, gwr%uc_batch_size, gwr%g_ngfft, istwfk1, &
5015 0 : desc_q%gvec, gwp, gpu_option)
5016 :
5017 0 : gpu_mode = 1
5018 0 : do ig2=1, chi_rgp%size_local(2), gwr%uc_batch_size
5019 0 : ndat = blocked_loop(ig2, chi_rgp%size_local(2), gwr%uc_batch_size)
5020 :
5021 : call uplan_q%execute_rg(ndat, chi_rgp%buffer_cplx(:, ig2), &
5022 0 : gwr%tchi_qibz(iq_ibz, itau, spin)%buffer_cplx(:, ig2), phase_r=cemiqr, gpu_mode=gpu_mode)
5023 : end do ! ig2
5024 :
5025 0 : call uplan_q%free()
5026 0 : call chi_rgp%free()
5027 :
5028 0 : call gwr%tchi_qibz(iq_ibz, itau, spin)%set_imag_diago_to_zero(local_max)
5029 : end do ! my_iqi
5030 :
5031 0 : write(msg,'(3(a,i0),a)')" My itau [", my_it, "/", gwr%my_ntau, "] (tot: ", gwr%ntau, ")"
5032 0 : call cwtime_report(msg, cpu_tau, wall_tau, gflops_tau, end_str=ch10)
5033 : end do ! my_it
5034 : end do ! my_is
5035 :
5036 0 : if (use_shmem_for_k) then
5037 0 : call xmpi_win_free(gt_scbox_win, ierr)
5038 : else
5039 : #ifdef HAVE_OPENMP_OFFLOAD
5040 : !$OMP TARGET EXIT DATA MAP(delete: gt_scbox(1:sc_nfftsp,1:max_ndat,1:2)) if (gpu_option == ABI_GPU_OPENMP)
5041 : #endif
5042 0 : ABI_FREE(gt_scbox)
5043 : end if
5044 :
5045 0 : ABI_FREE(green_scgvec)
5046 0 : ABI_FREE(chi_scgvec)
5047 0 : ABI_FREE(gt_gpr)
5048 0 : ABI_FREE(desc_mykbz)
5049 0 : call slk_array_free(chiq_gpr)
5050 0 : ABI_FREE(chiq_gpr)
5051 0 : call green_plan%free()
5052 :
5053 : #ifdef HAVE_OPENMP_OFFLOAD
5054 : !$OMP TARGET EXIT DATA MAP(delete:cemiqr) IF (gpu_option == ABI_GPU_OPENMP)
5055 : #endif
5056 0 : ABI_FREE(cemiqr)
5057 :
5058 : else ! not gwr%use_supercell_for_tchi
5059 : ! ===================================================================
5060 : ! Mixed-space algorithm in the unit cell with convolutions in k-space
5061 : ! ===================================================================
5062 0 : call print_chi_header()
5063 :
5064 0 : call wrtout(std_out, " Allocating memory for G_k(r',r) and chi_q(r',r)...")
5065 0 : call wrtout(std_out, " Here we're gonna have a big allocation peak...")
5066 0 : if (gwr%comm%me == 0) call pstat_proc%print(_PSTAT_ARGS_)
5067 :
5068 : ! Need all nqibz matrices in chi_q here as the iq_ibz loop is the innermost one unlike in the legacy GW code.
5069 0 : nr = gwr%g_nfft
5070 0 : col_bsize = nr / gwr%g_comm%nproc; if (mod(nr, gwr%g_comm%nproc) /= 0) col_bsize = col_bsize + 1
5071 0 : tchi_rfact = one / gwr%cryst%ucvol
5072 :
5073 0 : gpu_action = "None";
5074 0 : if (gpu_option == ABI_GPU_OPENMP) then
5075 0 : gpu_action = "alloc"; call wrtout(std_out, " Allocating Chi_q(r,r', +tau) on the GPU...")
5076 : end if
5077 :
5078 0 : ABI_MALLOC(chiq_rpr, (gwr%nqibz))
5079 0 : do iq_ibz=1,gwr%nqibz
5080 0 : call chiq_rpr(iq_ibz)%init(nr, nr, gwr%g_slkproc, 1, size_blocs=[-1, col_bsize], gpu_action=gpu_action)
5081 : end do
5082 :
5083 0 : call pstat_proc%print(_PSTAT_ARGS_)
5084 :
5085 : ! Allocate G_k(r',r, +/- tau) and G_kq(r',r, +/- tau)
5086 : ! TODO: Can save memory here as we don't need +/- tau for each k+q.
5087 0 : do ipm=1,2
5088 0 : do iab=1,gwr%nsig_ab
5089 0 : call gk_rpr_pm(ipm, iab)%init(nr, nr, gwr%g_slkproc, 1, size_blocs=[-1, col_bsize]) !, gpu_action=gpu_action)
5090 0 : call gkq_rpr_pm(ipm, iab)%init(nr, nr, gwr%g_slkproc, 1, size_blocs=[-1, col_bsize]) !, gpu_action=gpu_action)
5091 : end do
5092 : end do
5093 :
5094 0 : mem_mb = sum(slk_array_locmem_mb(chiq_rpr)) + sum(slk_array_locmem_mb(gk_rpr_pm)) + sum(slk_array_locmem_mb(gkq_rpr_pm))
5095 0 : call wrtout(std_out, sjoin(" Local memory for Chi_q(r',r) (gt_gpr): ", ftoa(mem_mb, fmt="f8.1"), ' [Mb] <<< MEM'))
5096 0 : call pstat_proc%print(_PSTAT_ARGS_)
5097 :
5098 : ! The little group is needed when symchi == 1 (default)
5099 : ! If use_umklp == 1 then symmetries requiring an umklapp to preserve qibz are included as well.
5100 : ! TODO: Note that TR is not yet supported so timrev is set to 1 even if TR has been used to generate the GS IBZ.
5101 0 : ABI_MALLOC(ltg_qibz, (gwr%nqibz))
5102 0 : use_umklp = 0
5103 : !gw_timrev = kpts_timrev_from_kptopt(gwr%ks_ebands%kptopt) + 1
5104 0 : do iq_ibz=1,gwr%nqibz
5105 : call ltg_qibz(iq_ibz)%init(gwr%qibz(:,iq_ibz), gwr%nkbz, gwr%kbz, gwr%cryst, use_umklp, &
5106 0 : npwe=gwr%tchi_desc_qibz(iq_ibz)%npw, gvec=gwr%tchi_desc_qibz(iq_ibz)%gvec)
5107 : !call ltg_qibz(iq_ibz)%init(gwr%qibz(:,iq_ibz), gwr%nkbz, gwr%kbz, gwr%cryst, use_umklp, npwe=0, timrev=1)
5108 0 : if (gwr%comm%me == 0) call ltg_qibz(iq_ibz)%print([std_out], prtvol=gwr%dtset%prtvol)
5109 : end do
5110 :
5111 : ! Compute mask with the k+q points in the IBZ required by this MPI proc.
5112 0 : need_kibz = 0
5113 0 : do my_ikf=1,gwr%my_nkbz
5114 0 : ik_bz = gwr%my_kbz_inds(my_ikf); kk_bz = gwr%kbz(:, ik_bz)
5115 0 : do iq_ibz=1,gwr%nqibz
5116 0 : qq_ibz = gwr%qibz(:, iq_ibz); kpq_bz = kk_bz + qq_ibz
5117 0 : call findqg0(ikq_bz, g0_kq, kpq_bz, gwr%nkbz, gwr%kbz, gwr%mG0)
5118 : ! TODO: here I may need to take into account the umklapp
5119 : !ABI_CHECK(all(g0_kq == 0), sjoin("g0_kq != 0, kk_bz", ktoa(kpq_bz), "qq_ibz:", ktoa(qq_ibz)))
5120 0 : ikq_ibz = gwr%kbz2ibz(1, ikq_bz)
5121 0 : need_kibz(ikq_ibz) = 1
5122 : end do
5123 : end do
5124 :
5125 : ! Begin loop over spin and tau points.
5126 0 : do my_is=1,gwr%my_nspins
5127 0 : spin = gwr%my_spins(my_is)
5128 0 : do my_it=1,gwr%my_ntau
5129 0 : call cwtime(cpu_tau, wall_tau, gflops_tau, "start")
5130 0 : itau = gwr%my_itaus(my_it)
5131 :
5132 : ! Redistribute G_k(g,g') with k in the IBZ so that each MPI proc
5133 : ! can reconstruct G_{k+q} in the BZ inside the MPI-distributed loops.
5134 : ! TODO: support for ipm_list else we have a memory leak.
5135 0 : call gwr%redistrib_gt_kibz(itau, spin, need_kibz, got_kibz, "communicate") !ipm_list=
5136 0 : if (my_it == 1 .and. gwr%comm%me == 0) call pstat_proc%print(_PSTAT_ARGS_)
5137 :
5138 : ! Sum over my k-points in the BZ.
5139 0 : if (gpu_option == ABI_GPU_OPENMP) then
5140 0 : call slk_array_gpu_set_zero(chiq_rpr)
5141 : else
5142 0 : call slk_array_set_zero(chiq_rpr)
5143 : end if
5144 :
5145 0 : do my_ikf=1,gwr%my_nkbz
5146 0 : print_time = gwr%comm%me == 0 .and. (my_ikf <= LOG_MODK .or. mod(my_ikf, LOG_MODK) == 0)
5147 0 : if (print_time) call cwtime(cpu_ikf, wall_ikf, gflops_ikf, "start")
5148 0 : ik_bz = gwr%my_kbz_inds(my_ikf); kk_bz = gwr%kbz(:, ik_bz)
5149 :
5150 : ! Use symmetries to get G_kbz(g,g') from the IBZ, then G_kbz(g,g') -> G_kbz(r',r).
5151 : ! TODO: here I may need to take into account the umklapp
5152 0 : call gwr%get_gkbz_rpr_pm(ik_bz, itau, spin, gk_rpr_pm, ipm_list=[1]) ! g0=??
5153 :
5154 : ! Accumulate contribution to chi_q(r',r) with q in the IBZ.
5155 0 : do iq_ibz=1,gwr%nqibz
5156 0 : if (gwr%dtset%symchi /= 0 .and. ltg_qibz(iq_ibz)%ibzq(ik_bz) == 0) cycle
5157 0 : qq_ibz = gwr%qibz(:,iq_ibz); kpq_bz = kk_bz + qq_ibz
5158 :
5159 0 : call findqg0(ikq_bz, g0_kq, kpq_bz, gwr%nkbz, gwr%kbz, gwr%mG0)
5160 : ! TODO: here I may need to take into account the umklapp if k+q is outside the BZ.
5161 : !ABI_CHECK(all(g0_kq == 0), sjoin("g0_kq != 0, kk_bz", ktoa(kpq_bz), "qq_ibz:", ktoa(qq_ibz)))
5162 :
5163 : ! Use symmetries to get G_kqbz(g,g') from the IBZ, then G_kqbz(g,g') -> G_kqbz(r',r).
5164 : ! Note that only G_kq(-itau) is needed.
5165 0 : call gwr%get_gkbz_rpr_pm(ikq_bz, itau, spin, gkq_rpr_pm, g0=g0_kq, ipm_list=[2])
5166 :
5167 : ! The weight depends on q_ibz and the symmetries of the little group of qq_ibz.
5168 0 : wtqp = one / gwr%nkbz; wtqm = zero
5169 0 : if (gwr%dtset%symchi /= 0) then
5170 0 : wtqp = (one * sum(ltg_qibz(iq_ibz)%wtksym(1,:,ik_bz))) / gwr%nkbz
5171 0 : wtqm = (one * sum(ltg_qibz(iq_ibz)%wtksym(2,:,ik_bz))) / gwr%nkbz
5172 : !ABI_CHECK(wtqm == zero, sjoin("TR is not yet implemented:, wqtm:", ftoa(wtqm)))
5173 : end if
5174 :
5175 : ! Accumulate.
5176 :
5177 : !chiq_rpr(iq_ibz)%buffer_cplx = chiq_rpr(iq_ibz)%buffer_cplx + &
5178 : ! wtqp * gk_rpr_pm(1)%buffer_cplx * conjg(gkq_rpr_pm(2)%buffer_cplx) ! RECHECK EQ. This one works but requires ptrans with C
5179 : ! !wtqp * gkq_rpr_pm(1)%buffer_cplx * conjg(gk_rpr_pm(2)%buffer_cplx) ! This should be OK
5180 0 : do iab=1,gwr%nsig_ab
5181 : call cplx_mat_plus_bc(chiq_rpr(iq_ibz)%bufsize, chiq_rpr(iq_ibz)%buffer_cplx(:,1), &
5182 0 : wtqp+wtqm, "C", gkq_rpr_pm(2, iab)%buffer_cplx(:,1), gk_rpr_pm(1, iab)%buffer_cplx(:,1), gpu_option)
5183 : end do ! iab
5184 :
5185 : end do ! iq_ibz
5186 :
5187 0 : if (print_time) then
5188 0 : write(msg,'(4x,3(a,i0),a)')"Chi my_ikf [", my_ikf, "/", gwr%my_nkbz, "] (tot: ", gwr%nkbz, ")"
5189 0 : call cwtime_report(msg, cpu_ikf, wall_ikf, gflops_ikf)
5190 : end if
5191 : end do ! my_ikf
5192 :
5193 : ! Deallocate got_kibz Green's functions.
5194 0 : call gwr%redistrib_gt_kibz(itau, spin, need_kibz, got_kibz, "free")
5195 :
5196 : ! From chi_q(r',r) to chi_q(g,g') for each q in the IBZ.
5197 0 : do iq_ibz=1,gwr%nqibz
5198 0 : call xmpi_sum(chiq_rpr(iq_ibz)%buffer_cplx, gwr%kpt_comm%value, ierr)
5199 : end do
5200 :
5201 0 : tchi_rfact = one / gwr%cryst%ucvol
5202 0 : do iq_ibz=1,gwr%nqibz
5203 0 : if (.not. any(iq_ibz == gwr%my_qibz_inds)) cycle
5204 0 : call gwr%tchi_qibz(iq_ibz, itau, spin)%copy(chiq_ggp, empty=.True.)
5205 0 : call gwr%rpr_to_ggp(gwr%tchi_desc_qibz(iq_ibz), chiq_rpr(iq_ibz), tchi_rfact, chiq_ggp)
5206 0 : call chiq_ggp%copy(work1, empty=.True.)
5207 :
5208 : ! Here we symmetrize chi0 to get the integral in the BZ.
5209 : ! This section is needed only if symchi /= 0.
5210 : ! TODO: Timrev should be tested. At present is disabled.
5211 : associate(desc => gwr%tchi_desc_qibz(iq_ibz), ltg => ltg_qibz(iq_ibz))
5212 0 : call gwr%rpr_to_ggp(gwr%tchi_desc_qibz(iq_ibz), chiq_rpr(iq_ibz), tchi_rfact, chiq_ggp)
5213 0 : do itim=1, ltg%timrev
5214 0 : do isym=1, ltg%nsym_sg
5215 0 : if (ltg%preserve(itim,isym) /= 1) cycle
5216 : associate(sglist => desc%rottbm1(ltg%igmG0(1:desc%npw, itim, isym), itim, isym), &
5217 0 : phase => desc%phmGt(:, isym))
5218 0 : call slk_array_set_zero(work1)
5219 : ! (g,g') --> (Sg, g')
5220 0 : do ig2=1,work1%size_local(2)
5221 0 : if (itim == 1) then
5222 0 : work1%buffer_cplx(:,ig2) = chiq_ggp%buffer_cplx(sglist, ig2) * phase
5223 : else
5224 0 : work1%buffer_cplx(:,ig2) = GWPC_CONJG(chiq_ggp%buffer_cplx(sglist, ig2)) * phase
5225 : end if
5226 : end do
5227 : ! (Sg, g') --> (g', Sg)
5228 0 : call work1%ptrans("C", work2, free=.False.)
5229 : ! (g', Sg) --> (Sg', Sg)
5230 0 : do ig2=1,work2%size_local(2)
5231 0 : work2%buffer_cplx(:,ig2) = work2%buffer_cplx(sglist, ig2) * phase
5232 : end do
5233 : ! (Sg', Sg) --> (Sg, Sg')
5234 0 : call work2%ptrans("C", work1, free=.True.)
5235 0 : gwr%tchi_qibz(iq_ibz, itau, spin)%buffer_cplx(:,:) = gwr%tchi_qibz(iq_ibz, itau, spin)%buffer_cplx(:,:)+work1%buffer_cplx(:,:)
5236 : end associate
5237 : end do ! isym
5238 : end do ! itim
5239 :
5240 0 : call work1%free()
5241 : gwr%tchi_qibz(iq_ibz, itau, spin)%buffer_cplx(:,:) = gwr%tchi_qibz(iq_ibz, itau, spin)%buffer_cplx(:,:) &
5242 0 : & / ltg%nsym_ltg
5243 :
5244 : end associate
5245 0 : call chiq_ggp%free()
5246 : end do ! iq_ibz
5247 :
5248 0 : write(msg,'(3(a,i0),a)')" My itau [", my_it, "/", gwr%my_ntau, "] (tot: ", gwr%ntau, ")"
5249 0 : call cwtime_report(msg, cpu_tau, wall_tau, gflops_tau)
5250 : end do ! my_it
5251 : end do ! spin
5252 :
5253 : ! Free memory
5254 0 : call slk_array_free(gk_rpr_pm); call slk_array_free(gkq_rpr_pm); call slk_array_free(chiq_rpr)
5255 0 : ABI_FREE(chiq_rpr)
5256 :
5257 0 : do iq_ibz=1,gwr%nqibz
5258 0 : call ltg_qibz(iq_ibz)%free()
5259 : end do
5260 0 : ABI_FREE(ltg_qibz)
5261 0 : call wrtout(std_out, " Mixed space algorithm for chi completed.")
5262 :
5263 : end if ! super cell or mixed space algorithm.
5264 : !call wrtout(std_out, sjoin(" max_abs_imag_chit", ftoa(max_abs_imag_chit)))
5265 :
5266 0 : if (gwr%comm%me == 0) call pstat_proc%print(_PSTAT_ARGS_)
5267 :
5268 : ! Print trace of chi_q(i tau) matrices for testing purposes.
5269 0 : if (gwr%dtset%prtvol > 0) call gwr%print_trace(units, "tchi_qibz")
5270 :
5271 : ! Write tchi(i tau). NB: this option is not documented in the docs.
5272 0 : keep_tchim = .False.
5273 0 : if (gwr%dtset%prtsuscep == -1) then
5274 0 : call gwr%ncwrite_tchi_wc("tchi", "tau", keep_tchim, trim(gwr%dtfil%filnam_ds(4))//'_TCHIM.nc')
5275 0 : keep_tchim = .True.
5276 : end if
5277 :
5278 : ! Transform irreducible tchi from imaginary tau to imaginary omega.
5279 : ! Also, sum over spins to get total tchi if collinear spin.
5280 0 : call gwr%cos_transform("tchi", "it2w", sum_spins=.True.)
5281 :
5282 0 : if (gwr%kpt_comm%me == 0) then
5283 : ! ===================================================
5284 : ! ==== Construct head and wings from the tensor =====
5285 : ! ===================================================
5286 : associate (desc_q0 => gwr%tchi_desc_qibz(1), mat_ts => gwr%tchi_qibz(1,:,:))
5287 0 : ABI_CHECK_IEQ(desc_q0%ig0, 1, "ig0 should be 1")
5288 0 : ABI_MALLOC(up_wing_q, (desc_q0%npw))
5289 0 : ABI_MALLOC(low_wing_q, (desc_q0%npw))
5290 :
5291 0 : do my_is=1,gwr%my_nspins
5292 0 : spin = gwr%my_spins(my_is)
5293 0 : do my_it=1,gwr%my_ntau
5294 0 : itau = gwr%my_itaus(my_it)
5295 :
5296 0 : do ig=2,desc_q0%npw
5297 0 : wng = gwr%chi0_uwing_myw(:,ig, my_it)
5298 0 : up_wing_q(ig) = vdotw(gwr%q0, wng, gwr%cryst%gmet, "G")
5299 0 : wng = gwr%chi0_lwing_myw(:,ig,my_it)
5300 0 : low_wing_q(ig) = vdotw(gwr%q0, wng, gwr%cryst%gmet, "G")
5301 : end do
5302 0 : chq = matmul(gwr%chi0_head_myw(:,:,my_it), gwr%q0)
5303 0 : head_q = vdotw(gwr%q0, chq, gwr%cryst%gmet, "G")
5304 :
5305 0 : call mat_ts(itau, spin)%set_head_and_wings(head_q, low_wing_q, up_wing_q)
5306 : end do ! my_it
5307 : end do ! my_is
5308 : end associate
5309 0 : ABI_FREE(up_wing_q)
5310 0 : ABI_FREE(low_wing_q)
5311 : end if
5312 :
5313 : ! Print trace of chi_q(i omega) matrices for testing purposes.
5314 0 : if (gwr%dtset%prtvol > 0) call gwr%print_trace(units, "tchi_qibz")
5315 :
5316 : ! Write file with chi0(i omega).
5317 0 : if (abs(gwr%dtset%prtsuscep) == 1) then
5318 0 : call gwr%ncwrite_tchi_wc("tchi", "omega", keep_tchim, trim(gwr%dtfil%filnam_ds(4))//'_TCHIM.nc')
5319 : end if
5320 :
5321 0 : call cwtime_report(" gwr_build_tchi:", cpu_all, wall_all, gflops_all)
5322 0 : call timab(1923, 2, tsec)
5323 :
5324 : contains
5325 :
5326 0 : subroutine print_chi_header()
5327 0 : if (gwr%comm%me /= 0) return
5328 0 : if (gwr%use_supercell_for_tchi) then
5329 0 : call wrtout(std_out, " Building chi0(r,R, itau) in the supercell with FFTs ", pre_newlines=2)
5330 : else
5331 0 : call wrtout(std_out, " Building chi_q(r,r', itau) with convolutions in k-space:", pre_newlines=2)
5332 : end if
5333 0 : call wrtout(std_out, sjoin(" gwr_np_kgts:", ltoa(gwr%dtset%gwr_np_kgts)))
5334 0 : call wrtout(std_out, sjoin(" ngkpt:", ltoa(gwr%ngkpt), ", ngqpt:", ltoa(gwr%ngqpt)))
5335 0 : call wrtout(std_out, sjoin(" gwr_boxcutmin:", ftoa(gwr%dtset%gwr_boxcutmin)))
5336 0 : call wrtout(std_out, sjoin(" sc_ngfft:", ltoa(sc_ngfft(1:8))))
5337 0 : call wrtout(std_out, sjoin(" my_ntau:", itoa(gwr%my_ntau), ", ntau:", itoa(gwr%ntau)))
5338 0 : call wrtout(std_out, sjoin(" my_nkbz:", itoa(gwr%my_nkbz), ", nkbz:", itoa(gwr%nkbz)))
5339 0 : call wrtout(std_out, sjoin(" my_nkibz:", itoa(gwr%my_nkibz), ", nkibz:", itoa(gwr%nkibz)))
5340 0 : call wrtout(std_out, sjoin("- FFT uc_batch_size:", itoa(gwr%uc_batch_size)))
5341 0 : call wrtout(std_out, sjoin("- FFT sc_batch_size:", itoa(gwr%sc_batch_size)), do_flush=.True.)
5342 : end subroutine print_chi_header
5343 :
5344 : end subroutine gwr_build_tchi
5345 : !!***
5346 :
5347 : !----------------------------------------------------------------------
5348 :
5349 : !!****f* m_gwr/gwr_redistrib_gt_kibz
5350 : !! NAME
5351 : !! gwr_redistrib_gt_kibz
5352 : !!
5353 : !! FUNCTION
5354 : !! Redistribute/deallocate G_k
5355 : !!
5356 : !! If action == "communicate":
5357 : !! Redistribute G_k for fixed (itau, spin) according to `need_kibz` table.
5358 : !! Also, set got_kibz to 1 for each IBZ k-point that has been received.
5359 : !!
5360 : !! If action == "free":
5361 : !! Use input `got_kibz` array to deallocate matrices received in a previous call.
5362 : !!
5363 : !! INPUTS
5364 : !!
5365 : !! OUTPUT
5366 : !!
5367 : !! SOURCE
5368 :
5369 0 : subroutine gwr_redistrib_gt_kibz(gwr, itau, spin, need_kibz, got_kibz, action)
5370 :
5371 : !Arguments ------------------------------------
5372 : class(gwr_t),target,intent(inout) :: gwr
5373 : integer,intent(in) :: itau, spin, need_kibz(gwr%nkibz)
5374 : integer,intent(inout) :: got_kibz(gwr%nkibz)
5375 : character(len=*),intent(in) :: action
5376 : !integer,optional,intent(in) :: ipm_list(:)
5377 :
5378 : !Local variables-------------------------------
5379 0 : integer :: ik_ibz, ipm, ierr, do_mpi_kibz(gwr%nkibz), sender_kibz(gwr%nkibz)
5380 : integer :: bcast_comm, sender_in_bcast_comm, color, iab
5381 : logical :: im_sender
5382 : !integer :: num_pm, ipm_list__(2)
5383 : real(dp) :: kk_ibz(3), cpu, wall, gflops
5384 0 : complex(gwp),contiguous, pointer :: ck_ptr(:,:)
5385 : ! *************************************************************************
5386 :
5387 0 : call cwtime(cpu, wall, gflops, "start")
5388 :
5389 : !num_pm = 2; ipm_list__ = [1, 2]
5390 : !if (present(ipm_list)) then
5391 : ! num_pm = size(ipm_list)
5392 : ! ABI_CHECK_IRANGE(num_pm, 1, 2, "num_pm not in [1, 2]")
5393 : ! ipm_list__(1:num_pm) = ipm_list(:)
5394 : !end if
5395 :
5396 : select case (action)
5397 : case ("communicate")
5398 0 : do_mpi_kibz = need_kibz
5399 0 : do ik_ibz=1,gwr%nkibz
5400 0 : if (allocated(gwr%green_desc_kibz(ik_ibz)%gvec)) do_mpi_kibz(ik_ibz) = 0
5401 : end do
5402 0 : call xmpi_sum(do_mpi_kibz, gwr%kpt_comm%value, ierr)
5403 : !do_mpi_kibz = 1
5404 :
5405 : ! All procs enter the loop. Sender_kibz stores the rank of the sender in gwr%kpt_comm
5406 0 : got_kibz = 0; sender_kibz(:) = huge(1)
5407 0 : do ik_ibz=1,gwr%nkibz
5408 0 : if (do_mpi_kibz(ik_ibz) == 0) cycle
5409 0 : kk_ibz = gwr%kibz(:, ik_ibz)
5410 0 : if (allocated(gwr%green_desc_kibz(ik_ibz)%gvec)) sender_kibz(ik_ibz) = gwr%kpt_comm%me
5411 0 : if (need_kibz(ik_ibz) /= 0 .and. .not. allocated(gwr%green_desc_kibz(ik_ibz)%gvec)) then
5412 : ! NB: Use same args as those used to init the descriptors in gwr_init
5413 : ! so that the ordering of gvec is consistent across MPI procs.
5414 0 : got_kibz(ik_ibz) = 1
5415 0 : call gwr%green_desc_kibz(ik_ibz)%init(kk_ibz, istwfk1, gwr%dtset%ecutwfn, gwr)
5416 : end if
5417 : end do
5418 :
5419 : ! Define the sender for each kibz in do_mpi_kibz.
5420 0 : call xmpi_min_ip(sender_kibz, gwr%kpt_comm%value, ierr)
5421 :
5422 : ! Allocate memory
5423 0 : call gwr%malloc_free_mats(got_kibz, "green", "malloc")
5424 :
5425 : ! MPI communication
5426 0 : do ik_ibz=1,gwr%nkibz
5427 0 : if (do_mpi_kibz(ik_ibz) == 0) cycle
5428 :
5429 : ! Create subcommunicators with color and bcast only inside subcomm.
5430 0 : im_sender = gwr%kpt_comm%me == sender_kibz(ik_ibz)
5431 0 : color = merge(1, 0, im_sender .or. need_kibz(ik_ibz) /= 0)
5432 0 : call xmpi_comm_split(gwr%kpt_comm%value, color, gwr%kpt_comm%me, bcast_comm, ierr)
5433 :
5434 0 : if (color == 1) then
5435 0 : sender_in_bcast_comm = xmpi_comm_translate_rank(gwr%kpt_comm%value, sender_kibz(ik_ibz), bcast_comm)
5436 0 : do ipm=1,2
5437 0 : do iab=1,gwr%nsig_ab
5438 0 : ck_ptr => gwr%gt_kibz(ipm, ik_ibz, itau, spin, iab)%buffer_cplx
5439 0 : call xmpi_bcast(ck_ptr, sender_in_bcast_comm, bcast_comm, ierr)
5440 : end do
5441 : end do
5442 : end if
5443 0 : call xmpi_comm_free(bcast_comm)
5444 : end do
5445 :
5446 : case ("free")
5447 : ! Use got_kibz to free previously allocated memory.
5448 0 : do ik_ibz=1,gwr%nkibz
5449 0 : if (got_kibz(ik_ibz) == 1) call gwr%green_desc_kibz(ik_ibz)%free()
5450 : end do
5451 0 : call gwr%malloc_free_mats(got_kibz, "green", "free")
5452 :
5453 : case default
5454 0 : ABI_ERROR(sjoin("Invalid action:", action))
5455 : end select
5456 :
5457 0 : if (action == "communicate") call cwtime_report(" gwr_redistrib_gt_kibz:", cpu, wall, gflops)
5458 :
5459 0 : end subroutine gwr_redistrib_gt_kibz
5460 : !!***
5461 :
5462 : !!****f* m_gwr/gwr_redistrib_mats_qibz
5463 : !! NAME
5464 : !! gwr_redistrib_mats_qibz
5465 : !!
5466 : !! FUNCTION
5467 : !! If action == "communicate":
5468 : !! Redistribute chi_q (wc_q) for fixed (itau, spin) according to `need_qibz` table.
5469 : !! Also, set `got_qibz` to 1 for each IBZ q-point that has been received.
5470 : !! If action == "free":
5471 : !! Use `got_qibz` to deallocate matrices received in a previous call with "communicate".
5472 : !!
5473 : !! INPUTS
5474 : !!
5475 : !! OUTPUT
5476 : !!
5477 : !! SOURCE
5478 :
5479 0 : subroutine gwr_redistrib_mats_qibz(gwr, what, itau, spin, need_qibz, got_qibz, action)
5480 :
5481 : !Arguments ------------------------------------
5482 : class(gwr_t),target,intent(inout) :: gwr
5483 : character(len=*),intent(in) :: what
5484 : integer,intent(in) :: itau, spin, need_qibz(gwr%nqibz)
5485 : integer,intent(inout) :: got_qibz(gwr%nqibz)
5486 : character(len=*),intent(in) :: action
5487 :
5488 : !Local variables-------------------------------
5489 0 : integer :: iq_ibz, ierr, bcast_comm, color, do_mpi_qibz(gwr%nqibz), sender_qibz(gwr%nqibz), sender_in_bcast_comm
5490 : logical :: im_sender
5491 : logical, parameter :: timeit = .False.
5492 : real(dp) :: qq_ibz(3), cpu, wall, gflops
5493 0 : complex(gwp),contiguous, pointer :: cq_ptr(:,:)
5494 : ! *************************************************************************
5495 :
5496 0 : ABI_CHECK(what == "tchi" .or. what == "wc", sjoin("Invalid what:", what))
5497 : if (timeit) call cwtime(cpu, wall, gflops, "start")
5498 :
5499 : select case (action)
5500 : case ("communicate")
5501 0 : do_mpi_qibz = need_qibz
5502 0 : do iq_ibz=1,gwr%nqibz
5503 0 : select case (what)
5504 : case ("tchi")
5505 0 : if (allocated(gwr%tchi_qibz(iq_ibz, itau, spin)%buffer_cplx)) do_mpi_qibz(iq_ibz) = 0
5506 : case ("wc")
5507 0 : if (allocated(gwr%wc_qibz(iq_ibz, itau, spin)%buffer_cplx)) do_mpi_qibz(iq_ibz) = 0
5508 : case default
5509 0 : ABI_ERROR(sjoin("Invalid what:", what))
5510 : end select
5511 : end do
5512 :
5513 0 : call xmpi_sum(do_mpi_qibz, gwr%kpt_comm%value, ierr)
5514 : !do_mpi_qibz = 1
5515 :
5516 : ! All procs enter the loop. Sender_qibz stores the rank of the sender in gwr%kpt_comm
5517 0 : got_qibz = 0; sender_qibz(:) = huge(1)
5518 0 : do iq_ibz=1,gwr%nqibz
5519 0 : if (do_mpi_qibz(iq_ibz) == 0) cycle
5520 0 : qq_ibz = gwr%qibz(:, iq_ibz)
5521 0 : if (allocated(gwr%tchi_desc_qibz(iq_ibz)%gvec)) sender_qibz(iq_ibz) = gwr%kpt_comm%me
5522 0 : if (need_qibz(iq_ibz) /= 0 .and. .not. allocated(gwr%tchi_desc_qibz(iq_ibz)%gvec)) then
5523 : ! NB: Use same args as those used to init the descriptors in gwr_init
5524 : ! so that gvec ordering is consistent across MPI procs.
5525 0 : got_qibz(iq_ibz) = 1
5526 0 : call gwr%tchi_desc_qibz(iq_ibz)%init(qq_ibz, istwfk1, gwr%dtset%ecuteps, gwr, kin_sorted=.True.)
5527 : end if
5528 : end do
5529 :
5530 : ! Define the sender for each qibz in do_mpi_qibz
5531 0 : call xmpi_min_ip(sender_qibz, gwr%kpt_comm%value, ierr)
5532 :
5533 : ! Allocate memory
5534 0 : call gwr%malloc_free_mats(got_qibz, what, "malloc")
5535 :
5536 : ! MPI communication
5537 0 : do iq_ibz=1,gwr%nqibz
5538 0 : if (do_mpi_qibz(iq_ibz) == 0) cycle
5539 :
5540 : ! Create subcommunicators with color and bcast only inside subcomm.
5541 0 : im_sender = gwr%kpt_comm%me == sender_qibz(iq_ibz)
5542 0 : color = merge(1, 0, im_sender .or. need_qibz(iq_ibz) /= 0)
5543 0 : call xmpi_comm_split(gwr%kpt_comm%value, color, gwr%kpt_comm%me, bcast_comm, ierr)
5544 :
5545 0 : if (color == 1) then
5546 0 : if (what == "tchi") cq_ptr => gwr%tchi_qibz(iq_ibz, itau, spin)%buffer_cplx
5547 0 : if (what == "wc") cq_ptr => gwr%wc_qibz(iq_ibz, itau, spin)%buffer_cplx
5548 0 : sender_in_bcast_comm = xmpi_comm_translate_rank(gwr%kpt_comm%value, sender_qibz(iq_ibz), bcast_comm)
5549 0 : call xmpi_bcast(cq_ptr, sender_in_bcast_comm, bcast_comm, ierr)
5550 : end if
5551 0 : call xmpi_comm_free(bcast_comm)
5552 : end do ! iq_ibz
5553 :
5554 : case ("free")
5555 : ! Use got_qibz table to free previously allocated memory
5556 0 : do iq_ibz=1,gwr%nqibz
5557 0 : if (got_qibz(iq_ibz) /= 0) call gwr%tchi_desc_qibz(iq_ibz)%free()
5558 : end do
5559 0 : call gwr%malloc_free_mats(got_qibz, what, "free")
5560 :
5561 : case default
5562 0 : ABI_ERROR(sjoin("Invalid action:", action))
5563 : end select
5564 :
5565 : if (timeit) call cwtime_report(" gwr_redistrib_mats_qibz:", cpu, wall, gflops)
5566 :
5567 0 : end subroutine gwr_redistrib_mats_qibz
5568 : !!***
5569 :
5570 : !----------------------------------------------------------------------
5571 :
5572 : !!****f* m_gwr/gwr_print_trace
5573 : !! NAME
5574 : !! gwr_print_trace
5575 : !!
5576 : !! FUNCTION
5577 : !! Print traces of PBLAS matrices to units.
5578 : !! NB: This is a global routine that should be called by all procs inside gwr%comm.
5579 : !!
5580 : !! INPUTS
5581 : !!
5582 : !! OUTPUT
5583 : !!
5584 : !! SOURCE
5585 :
5586 0 : subroutine gwr_print_trace(gwr, units, what)
5587 :
5588 : !Arguments ------------------------------------
5589 : class(gwr_t),target,intent(inout) :: gwr
5590 : integer,intent(in) :: units(:)
5591 : character(len=*),intent(in) :: what
5592 :
5593 : !Local variables-------------------------------
5594 : integer,parameter :: master = 0
5595 : integer :: my_is, spin, my_it, itau, iq_ibz, ierr, my_iqi, my_iki, ik_ibz, ipm, iab
5596 : character(len=5000) :: comment
5597 0 : complex(dp),allocatable :: ctrace3(:,:,:), ctrace5(:,:,:,:,:) !, ctrace4(:,:,:,:)
5598 0 : type(__slkmat_t),contiguous, pointer :: mats(:,:,:)
5599 : ! *************************************************************************
5600 :
5601 : ! NB: The same q/k point in the IBZ might be available on different procs in kpt_comm
5602 : ! hence we have to rescale the trace before summing the results in gwr%comm.
5603 0 : comment = "Invalid space!"
5604 :
5605 0 : select case (what)
5606 : case ("tchi_qibz", "wc_qibz")
5607 : ! Trace of tchi or Wc
5608 0 : ABI_CALLOC(ctrace3, (gwr%nqibz, gwr%ntau, gwr%nsppol))
5609 :
5610 0 : if (what == "tchi_qibz") then
5611 0 : mats => gwr%tchi_qibz
5612 0 : if (gwr%tchi_space == "iomega") comment = " (iq_ibz, iomega) table"
5613 0 : if (gwr%tchi_space == "itau") comment = " (iq_ibz, itau) table"
5614 0 : else if (what == "wc_qibz") then
5615 0 : mats => gwr%wc_qibz
5616 0 : if (gwr%wc_space == "iomega") comment = " (iq_ibz, iomega) table"
5617 0 : if (gwr%wc_space == "itau") comment = " (iq_ibz, itau) table"
5618 : end if
5619 :
5620 0 : do my_is=1,gwr%my_nspins
5621 0 : spin = gwr%my_spins(my_is)
5622 0 : do my_it=1,gwr%my_ntau
5623 0 : itau = gwr%my_itaus(my_it)
5624 0 : do my_iqi=1,gwr%my_nqibz
5625 0 : iq_ibz = gwr%my_qibz_inds(my_iqi)
5626 0 : ctrace3(iq_ibz, itau, spin) = mats(iq_ibz, itau, spin)%get_trace() / gwr%np_qibz(iq_ibz)
5627 : end do
5628 : end do
5629 : end do
5630 :
5631 0 : call xmpi_sum_master(ctrace3, 0, gwr%kts_comm%value, ierr)
5632 :
5633 0 : if (gwr%comm%me == master) then
5634 0 : do spin=1,gwr%nsppol
5635 0 : call wrtout(units, sjoin(" Trace of:", what, "for spin:", itoa(spin), "for testing purposes:"))
5636 0 : call wrtout(units, comment, pre_newlines=2)
5637 0 : call print_arr(units, ctrace3(:,:,spin))
5638 : end do
5639 : end if
5640 0 : ABI_FREE(ctrace3)
5641 :
5642 : case ("gt_kibz")
5643 : ! Trace of Green's functions.
5644 0 : ABI_CALLOC(ctrace5, (gwr%nkibz, gwr%ntau, 2, gwr%nsppol, gwr%nsig_ab))
5645 :
5646 0 : do my_is=1,gwr%my_nspins
5647 0 : spin = gwr%my_spins(my_is)
5648 0 : do my_it=1,gwr%my_ntau
5649 0 : itau = gwr%my_itaus(my_it)
5650 0 : do my_iki=1,gwr%my_nkibz
5651 0 : ik_ibz = gwr%my_kibz_inds(my_iki)
5652 0 : do ipm=1,2
5653 0 : do iab=1,gwr%nsig_ab
5654 0 : ctrace5(ik_ibz, itau, ipm, spin, iab) = gwr%gt_kibz(ipm, ik_ibz, itau, spin, iab)%get_trace() / gwr%np_kibz(ik_ibz)
5655 : end do
5656 : end do
5657 : end do
5658 : end do
5659 : end do
5660 0 : comment = " (ik_ibz, itau) table"
5661 :
5662 0 : call xmpi_sum_master(ctrace5, master, gwr%kts_comm%value, ierr)
5663 :
5664 0 : if (gwr%comm%me == master) then
5665 0 : do spin=1,gwr%nsppol
5666 0 : do ipm=1,2
5667 0 : do iab=1,gwr%nsig_ab
5668 0 : if (gwr%nspinor == 2) then
5669 0 : call wrtout(units, sjoin(" Trace of:", what, "for ipm:", itoa(ipm), ", spin:", itoa(spin), ", iab:", itoa(iab), "for testing purposes:"))
5670 : else
5671 0 : call wrtout(units, sjoin(" Trace of:", what, "for ipm:", itoa(ipm), ", spin:", itoa(spin), "for testing purposes:"))
5672 : end if
5673 0 : call wrtout(units, comment, newlines=1)
5674 0 : call print_arr(units, ctrace5(:,:, ipm, spin, iab))
5675 : end do
5676 : end do
5677 : end do
5678 : end if
5679 0 : ABI_FREE(ctrace5)
5680 :
5681 : case default
5682 0 : ABI_ERROR(sjoin("Invalid value of what:", what))
5683 : end select
5684 :
5685 0 : end subroutine gwr_print_trace
5686 : !!***
5687 :
5688 : !----------------------------------------------------------------------
5689 :
5690 : !!****f* m_gwr/gwr_build_wc
5691 : !! NAME
5692 : !! gwr_build_wc
5693 : !!
5694 : !! FUNCTION
5695 : !! Compute Wc(i tau,g,g') from tchi(i omega,g,g')
5696 : !!
5697 : !! INPUTS
5698 : !!
5699 : !! OUTPUT
5700 : !!
5701 : !! SOURCE
5702 :
5703 0 : subroutine gwr_build_wc(gwr)
5704 :
5705 : !Arguments ------------------------------------
5706 : class(gwr_t),target,intent(inout) :: gwr
5707 :
5708 : !Local variables-------------------------------
5709 : !scalars
5710 : integer,parameter :: master = 0
5711 : integer :: my_iqi, my_it, my_is, iq_ibz, spin, itau, iw, ierr, npwe
5712 : integer :: il_g1, il_g2, ig1, ig2, iglob1, iglob2, ig0
5713 : real(dp) :: cpu_all, wall_all, gflops_all, cpu_q, wall_q, gflops_q, i_sz !, cpu_tmp, wall_tmp, gflops_tmp
5714 : logical :: q_is_gamma, free_tchi, print_time, keep_wcimw
5715 : character(len=5000) :: msg
5716 : complex(dp) :: vcs_g1, vcs_g2
5717 0 : type(__slkmat_t) :: em1
5718 : type(yamldoc_t) :: ydoc
5719 : !arrays
5720 : integer :: units(2)
5721 : real(dp) :: qq_ibz(3), tsec(2)
5722 0 : complex(dp) :: em1_wq(gwr%ntau, gwr%nqibz), eps_wq(gwr%ntau, gwr%nqibz)
5723 : ! *************************************************************************
5724 :
5725 : ABI_NVTX_START_RANGE(NVTX_GWR_BUILD_WC)
5726 0 : units = [std_out, ab_out]
5727 :
5728 0 : call cwtime(cpu_all, wall_all, gflops_all, "start")
5729 0 : call timab(1924, 1, tsec)
5730 0 : call wrtout(units, " Building correlated screening Wc(i omega) ...", pre_newlines=2)
5731 :
5732 0 : call gwr%vcgen_eps%print(units, " Info on Coulomb term used in epsilon and W", gwr%dtset%prtvol)
5733 :
5734 0 : ABI_CHECK(gwr%tchi_space == "iomega", sjoin("tchi_space: ", gwr%tchi_space, " != iomega"))
5735 :
5736 0 : if (allocated(gwr%wc_qibz)) then
5737 0 : call slk_array_free(gwr%wc_qibz)
5738 0 : ABI_FREE(gwr%wc_qibz)
5739 0 : gwr%wc_space = "none"
5740 : end if
5741 :
5742 0 : ABI_CHECK(gwr%wc_space == "none", sjoin("wc_space: ", gwr%wc_space, " != none"))
5743 0 : gwr%wc_space = "iomega"
5744 :
5745 : ! =======================================
5746 : ! Allocate PBLAS arrays for wc_qibz(g,g')
5747 : ! =======================================
5748 : ! Note that we have already summed tchi over spin.
5749 : ! Also, G=0 corresponds to iglob = 1 as only q-points in the IBZ are treated here.
5750 : ! This is not true for the other q-points in the full BZ as we may have a non-zero umklapp g0_q.
5751 0 : ABI_MALLOC(gwr%wc_qibz, (gwr%nqibz, gwr%ntau, gwr%nsppol))
5752 :
5753 0 : free_tchi = .True.; if (free_tchi) gwr%tchi_space = "none"
5754 0 : em1_wq = zero; eps_wq = zero
5755 :
5756 : ! If possible, use 2d rectangular grid of processors for diagonalization.
5757 : !call slkproc_4diag%init(gwr%g_comm%value)
5758 :
5759 0 : do my_iqi=1,gwr%my_nqibz
5760 0 : print_time = gwr%comm%me == 0 .and. (my_iqi <= LOG_MODK .or. mod(my_iqi, LOG_MODK) == 0)
5761 0 : if (print_time) call cwtime(cpu_q, wall_q, gflops_q, "start")
5762 0 : iq_ibz = gwr%my_qibz_inds(my_iqi); qq_ibz = gwr%qibz(:, iq_ibz)
5763 0 : q_is_gamma = normv(qq_ibz, gwr%cryst%gmet, "G") < GW_TOLQ0
5764 :
5765 : associate (desc_q => gwr%tchi_desc_qibz(iq_ibz))
5766 0 : ig0 = desc_q%ig0
5767 0 : npwe = desc_q%npw
5768 :
5769 : ! The spin loop is needed so that procs in different pools can operate
5770 : ! on their own matrix that has been already summed over (collinear) spins.
5771 0 : do my_is=1,gwr%my_nspins
5772 0 : spin = gwr%my_spins(my_is)
5773 0 : do my_it=1,gwr%my_ntau
5774 0 : itau = gwr%my_itaus(my_it)
5775 :
5776 : ! Build symmetrized RPA epsilon: 1 - Vc^{1/2} chi0 Vc^{1/2}
5777 : ! Note vc_sqrt_eps here.
5778 0 : associate (wc => gwr%wc_qibz(iq_ibz, itau, spin))
5779 0 : call gwr%tchi_qibz(iq_ibz, itau, spin)%copy(wc)
5780 0 : if (free_tchi) call gwr%tchi_qibz(iq_ibz, itau, spin)%free()
5781 :
5782 0 : do il_g2=1,wc%size_local(2)
5783 0 : iglob2 = wc%loc2gcol(il_g2)
5784 0 : ig2 = mod(iglob2 - 1, desc_q%npw) + 1
5785 0 : vcs_g2 = desc_q%vc_sqrt_eps(ig2)
5786 0 : do il_g1=1,wc%size_local(1)
5787 0 : iglob1 = wc%loc2grow(il_g1)
5788 0 : ig1 = mod(iglob1 - 1, desc_q%npw) + 1
5789 0 : vcs_g1 = desc_q%vc_sqrt_eps(ig1)
5790 0 : wc%buffer_cplx(il_g1, il_g2) = -wc%buffer_cplx(il_g1, il_g2) * vcs_g1 * vcs_g2
5791 0 : if (iglob1 == iglob2) then
5792 0 : wc%buffer_cplx(il_g1, il_g2) = one + wc%buffer_cplx(il_g1, il_g2)
5793 0 : if (iglob1 == ig0 .and. iglob2 == ig0) then
5794 : ! Store epsilon_{iw, iq_ibz}(0, 0). Rescale by np_qibz because we will MPI reduce this array.
5795 0 : eps_wq(itau, iq_ibz) = wc%buffer_cplx(il_g1, il_g2) / gwr%np_qibz(iq_ibz)
5796 : end if
5797 : end if
5798 : end do ! il_g1
5799 : end do ! il_g2
5800 :
5801 : ! Invert symmetrized epsilon.
5802 : ! NB: PZGETRF requires square block cyclic decomposition along the two axes
5803 : ! hence we have to redistribute the data before calling invert and then
5804 : ! go back to colum-distribution, that is: wc --> em1 --> wc
5805 :
5806 0 : call wc%change_size_blocs(em1) ! processor=slkproc_4diag
5807 : ! Use hpd_invert as eps along imag axis is always hermitian.
5808 : !call em1%invert()
5809 0 : call em1%hpd_invert("U")
5810 0 : call wc%take_from(em1, free=.True.) ! processor=wc%processor)
5811 :
5812 : !call wrtout(std_out, sjoin(" e-1 at q:", ktoa(qq_ibz), "i omega:", ftoa(gwr%iw_mesh(itau) * Ha_eV), "eV"))
5813 : !call print_arr(units, wc%buffer_cplx)
5814 :
5815 : ! Build Wc(q, iw) = e^{-1}_q(g,g',iw) - delta_{gg'} v_q(g,g') by removing bare vc.
5816 0 : do il_g2=1,wc%size_local(2)
5817 0 : iglob2 = wc%loc2gcol(il_g2)
5818 0 : ig2 = mod(iglob2 - 1, desc_q%npw) + 1
5819 0 : vcs_g2 = desc_q%vc_sqrt_eps(ig2)
5820 0 : if (gwr%has_vcgen_sigma) vcs_g2 = desc_q%vc_sqrt_sigma(ig2)
5821 0 : do il_g1=1,wc%size_local(1)
5822 0 : iglob1 = wc%loc2grow(il_g1)
5823 0 : ig1 = mod(iglob1 - 1, desc_q%npw) + 1
5824 0 : vcs_g1 = desc_q%vc_sqrt_eps(ig1)
5825 0 : if (gwr%has_vcgen_sigma) vcs_g1 = desc_q%vc_sqrt_sigma(ig1)
5826 :
5827 0 : if (iglob1 == ig0 .and. iglob2 == ig0) then
5828 : ! Store epsilon^{-1}_{iw, iq_ibz}(0, 0). Rescale by np_qibz because we will MPI reduce this array.
5829 0 : em1_wq(itau, iq_ibz) = wc%buffer_cplx(il_g1, il_g2) / gwr%np_qibz(iq_ibz)
5830 : end if
5831 :
5832 : ! Subtract exchange part.
5833 0 : if (iglob1 == iglob2) wc%buffer_cplx(il_g1, il_g2) = wc%buffer_cplx(il_g1, il_g2) - one
5834 :
5835 : ! Handle divergence in Wc for q --> 0
5836 : ! Here we always use vcgen_eps
5837 0 : i_sz = gwr%vcgen_eps%i_sz
5838 0 : if (gwr%has_vcgen_sigma) i_sz = gwr%vcgen_sigma%i_sz
5839 :
5840 0 : if (q_is_gamma .and. (iglob1 == ig0 .or. iglob2 == ig0)) then
5841 0 : if (iglob1 == ig0 .and. iglob2 == ig0) then
5842 0 : vcs_g1 = sqrt(i_sz); vcs_g2 = sqrt(i_sz)
5843 0 : else if (iglob1 == ig0) then
5844 0 : vcs_g1 = sqrt(i_sz)
5845 0 : else if (iglob2 == ig0) then
5846 0 : vcs_g2 = sqrt(i_sz)
5847 : end if
5848 : end if
5849 :
5850 0 : wc%buffer_cplx(il_g1, il_g2) = wc%buffer_cplx(il_g1, il_g2) * vcs_g1 * vcs_g2 / gwr%cryst%ucvol
5851 : end do ! il_g1
5852 : end do ! il_g2
5853 : end associate
5854 :
5855 : end do ! my_it
5856 : end do ! my_is
5857 : end associate
5858 :
5859 0 : if (print_time) then
5860 0 : write(msg,'(4x,2(a,i0),a)')"My iq_ibz [", my_iqi, "/", gwr%my_nqibz, "]"
5861 0 : call cwtime_report(msg, cpu_q, wall_q, gflops_q)
5862 : end if
5863 : end do ! my_iqi
5864 :
5865 : !call slkproc_4diag%free()
5866 :
5867 0 : call xmpi_sum_master(em1_wq, master, gwr%kgt_comm%value, ierr)
5868 0 : call xmpi_sum_master(eps_wq, master, gwr%kgt_comm%value, ierr)
5869 :
5870 0 : if (gwr%comm%me == master) then
5871 : ! Print results to ab_out for testing purposes.
5872 0 : ydoc = yamldoc_open('EMACRO_WITHOUT_LOCAL_FIELDS') !, width=11, real_fmt='(3f8.3)')
5873 0 : call ydoc%open_tabular("epsilon_{iw, q -> Gamma}(0,0)") ! comment="(iomega, iq_ibz)")
5874 0 : do iw=1,gwr%ntau
5875 0 : write(msg, "(3(es16.8,2x))") gwr%iw_mesh(iw), real(eps_wq(iw, 1)), aimag(eps_wq(iw, 1))
5876 0 : call ydoc%add_tabular_line(msg)
5877 : end do
5878 0 : call ydoc%write_units_and_free(units)
5879 :
5880 0 : ydoc = yamldoc_open('EMACRO_WITH_LOCAL_FIELDS') !, width=11, real_fmt='(3f8.3)')
5881 0 : call ydoc%open_tabular("epsilon_{iw, q -> Gamma}(0,0)") !, comment="(iomega, iq_ibz)")
5882 0 : do iw=1,gwr%ntau
5883 0 : write(msg, "(3(es16.8,2x))") gwr%iw_mesh(iw), real(em1_wq(iw, 1)), aimag(em1_wq(iw, 1))
5884 0 : call ydoc%add_tabular_line(msg)
5885 : end do
5886 0 : call ydoc%write_units_and_free(units)
5887 : end if
5888 :
5889 : ! Print trace of wc_q(iomega) matrices for testing purposes.
5890 0 : if (gwr%dtset%prtvol > 0) call gwr%print_trace(units, "wc_qibz")
5891 :
5892 : ! Write file with Wc(i omega)
5893 0 : keep_wcimw = .False.
5894 0 : if (gwr%dtset%prtsuscep == -1) then
5895 0 : call gwr%ncwrite_tchi_wc("wc", "omega", keep_wcimw, trim(gwr%dtfil%filnam_ds(4))//'_WCIM.nc')
5896 0 : keep_wcimw = .True.
5897 : end if
5898 :
5899 : ! Cosine transform from iomega to itau to get Wc(i tau)
5900 0 : call gwr%cos_transform("wc", "iw2t")
5901 :
5902 : ! Print trace of wc_q(itau) matrices for testing purposes.
5903 : ! if (gwr%dtset%prtvol > 0) call gwr%print_trace(units, "wc_qibz")
5904 :
5905 : ! Write file with Wc(i tau)
5906 0 : if (abs(gwr%dtset%prtsuscep) == 1) then
5907 0 : call gwr%ncwrite_tchi_wc("wc", "tau", keep_wcimw, trim(gwr%dtfil%filnam_ds(4))//'_WCIM.nc')
5908 : end if
5909 :
5910 : ! Print trace of wc_q(iomega) matrices for testing purposes.
5911 : !if (gwr%dtset%prtvol > 0) call gwr%print_trace(units, "wc_qibz")
5912 :
5913 0 : call cwtime_report(" gwr_build_wc:", cpu_all, wall_all, gflops_all)
5914 0 : call timab(1924, 2, tsec)
5915 : ABI_NVTX_END_RANGE()
5916 :
5917 0 : end subroutine gwr_build_wc
5918 : !!***
5919 :
5920 : !----------------------------------------------------------------------
5921 :
5922 : !!****f* m_gwr/gwr_build_sigmac
5923 : !! NAME
5924 : !! gwr_build_sigmac
5925 : !!
5926 : !! FUNCTION
5927 : !! Build Sigma_c(i tau) and compute matrix elements in the KS basis set.
5928 : !!
5929 : !! INPUTS
5930 : !!
5931 : !! OUTPUT
5932 : !!
5933 : !! SOURCE
5934 :
5935 0 : subroutine gwr_build_sigmac(gwr)
5936 :
5937 : !Arguments ------------------------------------
5938 : class(gwr_t),target,intent(inout) :: gwr
5939 :
5940 : !Local variables-------------------------------
5941 : !scalars
5942 : integer,parameter :: master = 0
5943 : integer :: my_is, my_it, spin, ikcalc_ibz, ik_ibz, sc_nfft, my_ir, my_nr, iw, idat, max_ndat, ndat, ii, jj, irow, iab, iiab, jiab, itim
5944 : integer :: iq_ibz, iq_bz, itau, ierr, ibc, ib1, ib2, bmin, bmax, band, band1, ifft, gpu_option
5945 : integer :: band2, band2_start, band2_stop, nbc
5946 : integer :: my_ikf, ipm, ik_bz, ikcalc, uc_ir, ir, ncid, col_bsize, nr, sc_nfftsp, iter_ncid
5947 : integer :: isym_k, trev_k, g0_k(3), tsign_k !, b1gw, b2gw, ! my_iqi, sc_ir, ig, my_iqf
5948 : integer :: gt_request, wct_request
5949 : integer :: band_val, ibv, unt_it, unt_iw, unt_rw ! ncerr,
5950 : integer(kind=XMPI_ADDRESS_KIND) :: buf_count
5951 : integer :: gt_scbox_win, wct_scbox_win, use_umklp, ideg, nstates, nb1, nb2, nspinor
5952 : integer(c_size_t) :: bufsize
5953 : !integer :: my_ikf_start, my_ikf_stop, nkf_batch_size, nkf_now, op_type
5954 : real(dp) :: e0, ks_gap, qp_gap, qp_pade_gap, sigx, vxc_val, vu, v_meanf, eshift, sigma_fact
5955 : real(dp) :: cpu_tau, wall_tau, gflops_tau, cpu_all, wall_all, gflops_all !, cpu, wall, gflops
5956 : real(dp) :: mem_mb, cpu_ir, wall_ir, gflops_ir, cpu_ikf, wall_ikf, gflops_ikf
5957 : real(dp) :: max_abs_imag_wct, max_abs_re_wct, sck_ucvol, scq_ucvol, beta_r
5958 : real(gwp) :: wtqm, wtqp
5959 : complex(dp) :: zz, zsc, sigc_e0__, dsigc_de0, z_e0, sig_xc, hhartree_bk, qp_ene, qp_ene_prev, alpha_c, sigc_zsc
5960 : logical :: k_is_gamma, use_shmem_for_k, use_mpi_for_k, isirr_k, do_sigma_fit
5961 : logical :: compute_this_kbz, print_time, sigc_is_herm, band_inversion ! define,
5962 : character(len=500) :: msg, gpu_action
5963 0 : type(gaps_t) :: new_gaps
5964 : type(yamldoc_t) :: ydoc
5965 : type(c_ptr) :: void_ptr
5966 0 : type(sigma_pade_t) :: spade
5967 : !arrays
5968 0 : integer :: sc_ngfft(18), need_qibz(gwr%nqibz), got_qibz(gwr%nqibz), units(2), dat_units(3), g0_q(3) ! gg(3),
5969 0 : integer,allocatable :: green_scgvec(:,:), wc_scgvec(:,:)
5970 0 : logical :: select_my_kbz(gwr%my_nkbz), select_my_qbz(gwr%my_nqbz)
5971 : real(dp) :: kk_bz(3), kcalc_bz(3), qq_bz(3), tsec(2) !, qq_ibz(3)
5972 0 : real(dp),allocatable :: betas_r(:,:,:), zcut_pm(:,:,:)
5973 : complex(gwp) :: cpsi_r, sigc_pm(2)
5974 0 : complex(dp) :: odd_t(gwr%ntau), even_t(gwr%ntau), avg_2ntau(2,gwr%ntau), cvals(gwr%ntau)
5975 0 : complex(dp),target,allocatable :: sigc_it_mat(:,:,:,:,:,:), alphas_c(:,:,:)
5976 0 : complex(gwp),allocatable :: loc_cwork(:)
5977 0 : complex(gwp) ABI_ASYNC, contiguous, pointer :: gt_scbox(:,:,:), wct_scbox(:,:)
5978 0 : complex(gwp),allocatable :: uc_psir_bk(:,:,:), scph1d_kcalc(:,:,:), uc_ceikr(:), ur(:), ucpsi_r(:)
5979 0 : type(__slkmat_t) :: gt_gpr(2, gwr%my_nkbz, gwr%nsig_ab), gk_rpr_pm(2, gwr%nsig_ab), wc_rpr, wc_gpr(gwr%my_nqbz)
5980 0 : type(__slkmat_t), target :: sigc_rpr(2,2,gwr%nkcalc, gwr%nsig_ab)
5981 0 : type(desc_t), target :: desc_mykbz(gwr%my_nkbz), desc_myqbz(gwr%my_nqbz)
5982 : type(fftbox_plan3_t) :: green_plan, wt_plan
5983 0 : type(littlegroup_t) :: ltg_kcalc(gwr%nkcalc)
5984 : integer, parameter :: spinor_idxs(2, 4) = RESHAPE([1, 1, 2, 2, 1, 2, 2, 1], [2, 4])
5985 0 : integer,allocatable :: iperm(:)
5986 0 : real(dp),allocatable :: sorted_qpe(:)
5987 0 : real(dp) :: e0_kcalc(gwr%b1gw:gwr%b2gw, gwr%nkcalc, gwr%nsppol), rw_mesh(gwr%nwr)
5988 0 : real(dp) :: spfunc_diag(gwr%nwr, gwr%b1gw:gwr%b2gw, gwr%nkcalc, gwr%nsppol)
5989 0 : integer :: pade_solver_ierr(gwr%b1gw:gwr%b2gw, gwr%nkcalc, gwr%nsppol)
5990 0 : real(dp) :: ks_gaps(gwr%nkcalc, gwr%nsppol), qpz_gaps(gwr%nkcalc, gwr%nsppol), qp_pade_gaps(gwr%nkcalc, gwr%nsppol)
5991 0 : complex(dp) :: ze0_kcalc(gwr%b1gw:gwr%b2gw, gwr%nkcalc, gwr%nsppol)
5992 0 : complex(dp) :: sigc_e0(gwr%b1gw:gwr%b2gw, gwr%nkcalc, gwr%nsppol)
5993 0 : complex(dp) :: qpz_ene(gwr%b1gw:gwr%b2gw, gwr%nkcalc, gwr%nsppol), imag_zmesh(gwr%ntau)
5994 0 : complex(dp) :: qp_pade(gwr%b1gw:gwr%b2gw, gwr%nkcalc, gwr%nsppol)
5995 0 : complex(dp) :: sigxc_rw_diag(gwr%nwr, gwr%b1gw:gwr%b2gw, gwr%nkcalc, gwr%nsppol)
5996 : !complex(gwp),contiguous, pointer :: buf_cplx(:,:)
5997 0 : type(sigijtab_t),allocatable :: Sigxij_tab(:,:), Sigcij_tab(:,:)
5998 : ! *************************************************************************
5999 :
6000 0 : call cwtime(cpu_all, wall_all, gflops_all, "start")
6001 0 : call timab(1925, 1, tsec)
6002 :
6003 0 : nspinor = gwr%nspinor
6004 0 : units = [std_out, ab_out]
6005 0 : gpu_option = gwr%dtset%gpu_option
6006 0 : if (gwr%sig_diago) then
6007 0 : call wrtout(units, " Computing diagonal matrix elements of Sigma_c", pre_newlines=1)
6008 : else
6009 0 : call wrtout(units, " Computing diagonal + off-diagonal matrix elements of Sigma_c", pre_newlines=1)
6010 : end if
6011 :
6012 0 : if (gwr%has_vcgen_sigma) then
6013 0 : call gwr%vcgen_sigma%print(units, " Info on Coulomb term used in Sigma_c", gwr%dtset%prtvol)
6014 : else
6015 0 : call gwr%vcgen_eps%print(units, " Info on Coulomb term used in Sigma_c", gwr%dtset%prtvol)
6016 : end if
6017 :
6018 0 : ABI_CHECK(gwr%wc_space == "itau", sjoin("wc_space: ", gwr%wc_space, " != itau"))
6019 :
6020 : !mask_kibz = 0; mask_kibz(gwr%my_kibz_inds(:)) = 1
6021 : !call gwr%malloc_free_mats(mask_kibz, "sigma" "malloc")
6022 :
6023 : !if (gwr%scf_iteration == 1) then
6024 : !else
6025 : !end if
6026 :
6027 : ! Set FFT mesh in the supercell.
6028 : ! Be careful when using the FFT plan as ndat can change inside the loop if we start to block.
6029 : ! Perhaps the safest approach would be to generate the plan on the fly.
6030 :
6031 0 : sc_ngfft = gwr%g_ngfft
6032 0 : sc_ngfft(1:3) = gwr%ngkpt * gwr%g_ngfft(1:3)
6033 0 : sc_ngfft(4:6) = sc_ngfft(1:3)
6034 0 : sc_nfft = product(sc_ngfft(1:3)); sc_nfftsp = sc_nfft !* gwr%nspinor
6035 : !sc_mgfft = maxval(sc_ngfft(1:3))
6036 0 : sck_ucvol = gwr%cryst%ucvol * product(gwr%ngkpt)
6037 0 : scq_ucvol = gwr%cryst%ucvol * product(gwr%ngqpt)
6038 :
6039 : ! Set FFT mesh used to compute u(r) in the unit cell.
6040 0 : call gwr%kcalc_wfd%change_ngfft(gwr%cryst, gwr%psps, gwr%g_ngfft)
6041 :
6042 : ! Table for \Sigmac_ij matrix elements.
6043 0 : sigc_is_herm = .False.
6044 : call sigtk_sigma_tables(gwr%nkcalc, gwr%nkibz, gwr%nsppol, gwr%bstart_ks, gwr%bstop_ks, gwr%kcalc2ibz(:,1), &
6045 0 : gwr%sig_diago, sigc_is_herm, sigxij_tab, sigcij_tab)
6046 :
6047 0 : call sigijtab_free(Sigxij_tab)
6048 0 : ABI_FREE(Sigxij_tab)
6049 :
6050 : ! Allocate matrix elements Sigmac_(itau) in the KS basis set.
6051 0 : ii = gwr%b1gw; jj = gwr%b2gw
6052 0 : if (gwr%sig_diago) then
6053 0 : ii = 1; jj = 1
6054 : end if
6055 0 : ABI_CALLOC(sigc_it_mat, (2, gwr%ntau, gwr%b1gw:gwr%b2gw, ii:jj, gwr%nkcalc, gwr%nsppol))
6056 0 : ABI_RECALLOC(gwr%sigc_iw_mat, (gwr%ntau, gwr%b1gw:gwr%b2gw, ii:jj, gwr%nkcalc, gwr%nsppol))
6057 :
6058 0 : do_sigma_fit = (iand(gwr%dtset%gwr_fit, SIGMA_FIT) /= 0)
6059 0 : ABI_CALLOC(alphas_c, (2, gwr%b1gw:gwr%b2gw, ii:jj))
6060 0 : ABI_CALLOC(betas_r, (2, gwr%b1gw:gwr%b2gw, ii:jj))
6061 0 : ABI_CALLOC(zcut_pm, (2, gwr%b1gw:gwr%b2gw, ii:jj))
6062 0 : zcut_pm = gwr%dtset%zcut
6063 :
6064 0 : if (do_sigma_fit) then
6065 0 : call wrtout(units, " Activating fit of sigma matrix elements in tau space")
6066 : end if
6067 :
6068 0 : max_abs_imag_wct = zero; max_abs_re_wct = zero
6069 0 : call gwr%print_mem([std_out])
6070 :
6071 0 : if (gwr%use_supercell_for_sigma) then
6072 :
6073 : ! NOTE:
6074 : ! There are two possibilities here:
6075 : !
6076 : ! 1) Compute the matrix elements of Sigma_c in the KS basis set by integrating over the real-space supercell.
6077 : !
6078 : ! 2) Compute and store Sigma_c^k(g,g',iomega) and then compute the matrix elements in g-space.
6079 : !
6080 : ! The first option requires less memory provided we are interested in a small set of KS states.
6081 : ! The second option is interesting if we need to compute several matrix elements, including off-diagonal terms.
6082 0 : call print_sigma_header()
6083 :
6084 0 : max_ndat = gwr%sc_batch_size
6085 : use_mpi_for_k = gwr%sc_batch_size > 1 .and. gwr%sc_batch_size == gwr%kpt_comm%nproc
6086 0 : use_mpi_for_k = .False.
6087 :
6088 0 : use_shmem_for_k = gwr%sc_batch_size == gwr%kpt_comm%nproc .and. gwr%kpt_comm%nproc > 1
6089 0 : use_shmem_for_k = use_shmem_for_k .and. gwr%kpt_comm%can_use_shmem()
6090 : #ifndef HAVE_MPI_ALLOCATE_SHARED_CPTR
6091 : use_shmem_for_k = .False.
6092 : #endif
6093 :
6094 0 : if (use_shmem_for_k) then
6095 0 : buf_count = 2 * (sc_nfftsp * max_ndat * 2)
6096 0 : call gwr%kpt_comm%allocate_shared_master(buf_count, gwp, xmpi_info_null, void_ptr, gt_scbox_win)
6097 0 : call c_f_pointer(void_ptr, gt_scbox, shape=[sc_nfftsp, max_ndat, 2])
6098 0 : buf_count = 2 * (sc_nfftsp * max_ndat)
6099 0 : call gwr%kpt_comm%allocate_shared_master(buf_count, gwp, xmpi_info_null, void_ptr, wct_scbox_win)
6100 0 : call c_f_pointer(void_ptr, wct_scbox, shape=[sc_nfftsp, max_ndat])
6101 : end if
6102 :
6103 0 : call wrtout(std_out, sjoin(" use_mpi_for_k:", yesno(use_mpi_for_k)))
6104 0 : call wrtout(std_out, sjoin(" use_shmem_for_k:", yesno(use_shmem_for_k)))
6105 0 : mem_mb = 3 * (sc_nfftsp * max_ndat * gwp) * b2Mb
6106 0 : call wrtout(std_out, sjoin(" Memory for gt_scbox/wct_scbox arrays:", ftoa(mem_mb, fmt="f8.1"), ' [Mb] <<< MEM'))
6107 :
6108 0 : if (.not. use_shmem_for_k) then
6109 0 : ABI_CALLOC(gt_scbox, (sc_nfft, max_ndat, 2))
6110 0 : ABI_CALLOC(wct_scbox, (sc_nfft, max_ndat))
6111 : #ifdef HAVE_OPENMP_OFFLOAD
6112 : !$OMP TARGET ENTER DATA MAP(to:gt_scbox(1:sc_nfft,1:max_ndat,1:2), wct_scbox(1:sc_nfft,1:max_ndat)) IF (gpu_option == ABI_GPU_OPENMP)
6113 : #endif
6114 : end if
6115 :
6116 : ! Build plans for dense FFTs.
6117 0 : call green_plan%from_ngfft(sc_ngfft, max_ndat*2, gpu_option)
6118 0 : call wt_plan%from_ngfft(sc_ngfft, max_ndat, gpu_option)
6119 :
6120 0 : sigma_fact = one / (sck_ucvol * scq_ucvol)
6121 :
6122 : ! The g-vectors in the supercell for G and tchi.
6123 0 : ABI_MALLOC(green_scgvec, (3, gwr%green_mpw))
6124 0 : ABI_MALLOC(wc_scgvec, (3, gwr%tchi_mpw))
6125 :
6126 0 : select_my_kbz = .True.; select_my_qbz = .True.
6127 :
6128 0 : do my_is=1,gwr%my_nspins
6129 0 : spin = gwr%my_spins(my_is)
6130 :
6131 : ! Load wavefunctions for GW corrections in the unit cell.
6132 : ! TODO: MPI distribute or use MPI shared memory
6133 0 : bmin = minval(gwr%bstart_ks(:, spin)); bmax = maxval(gwr%bstop_ks(:, spin))
6134 0 : ABI_MALLOC_OR_DIE(uc_psir_bk, (gwr%g_nfft * gwr%nspinor, bmin:bmax, gwr%nkcalc), ierr)
6135 0 : ABI_MALLOC(ur, (gwr%g_nfft * gwr%nspinor))
6136 0 : ABI_MALLOC(uc_ceikr, (gwr%g_nfft * gwr%nspinor))
6137 0 : ABI_MALLOC(ucpsi_r, (gwr%g_nfft))
6138 :
6139 0 : do ikcalc=1,gwr%nkcalc
6140 0 : kcalc_bz = gwr%kcalc(:, ikcalc); ikcalc_ibz = gwr%kcalc2ibz(ikcalc, 1) ! NB: Assuming wfs in the IBZ.
6141 : ! Compute e^{ik.r} phases in the unit cell.
6142 0 : call calc_ceikr(kcalc_bz, gwr%g_ngfft, gwr%g_nfft, gwr%nspinor, uc_ceikr)
6143 :
6144 0 : do band=gwr%bstart_ks(ikcalc, spin), gwr%bstop_ks(ikcalc, spin)
6145 0 : call gwr%kcalc_wfd%get_ur(band, ikcalc_ibz, spin, ur)
6146 0 : uc_psir_bk(:, band, ikcalc) = ur * uc_ceikr
6147 : end do
6148 : end do ! ikcalc
6149 :
6150 0 : ABI_FREE(ur)
6151 0 : ABI_FREE(uc_ceikr)
6152 :
6153 : ! Pre-compute one-dimensional factors to get 3d e^{ik.L}
6154 0 : call get_1d_sc_phases(gwr%ngkpt, gwr%nkcalc, gwr%kcalc, scph1d_kcalc)
6155 :
6156 : ! Construct Sigma(itau) in the supercell.
6157 0 : do my_it=1,gwr%my_ntau
6158 0 : call cwtime(cpu_tau, wall_tau, gflops_tau, "start")
6159 0 : itau = gwr%my_itaus(my_it)
6160 :
6161 : ! G_k(g,g') --> G_k(g',r) e^{ik.r} for each k in the BZ treated by me.
6162 0 : call gwr%get_myk_green_gpr(itau, spin, select_my_kbz, desc_mykbz, gt_gpr)
6163 0 : if (my_it == 1 .and. gwr%comm%me == 0) call pstat_proc%print(_PSTAT_ARGS_)
6164 :
6165 : ! Wc_q(g,g') --> Wc_q(g',r) e^{iq.r} for each q in the BZ treated by me.
6166 0 : call gwr%get_myq_wc_gpr(itau, spin, select_my_qbz, desc_myqbz, wc_gpr)
6167 0 : if (my_it == 1 .and. gwr%comm%me == 0) call pstat_proc%print(_PSTAT_ARGS_)
6168 :
6169 0 : my_nr = gt_gpr(1,1,1)%size_local(2)
6170 0 : ABI_CHECK(my_nr == wc_gpr(1)%size_local(2), "my_nr != wc_gpr(1)%size_local(2)")
6171 :
6172 : ! Loop over r in the unit cell that is now MPI-distributed inside g_comm.
6173 0 : do my_ir=1, my_nr, gwr%sc_batch_size
6174 0 : print_time = (gwr%comm%me == 0 .and. (my_ir <= 3 * gwr%sc_batch_size .or. mod(my_ir, LOG_MODR) == 0))
6175 0 : if (print_time) call cwtime(cpu_ir, wall_ir, gflops_ir, "start")
6176 0 : ndat = blocked_loop(my_ir, my_nr, gwr%sc_batch_size)
6177 0 : uc_ir = gt_gpr(1,1,1)%loc2gcol(my_ir) ! FIXME: This won't work if nspinor 2
6178 :
6179 0 : if (.not. use_shmem_for_k) then
6180 : ! Insert Wc_q(g',r) in G'-space in the supercell FFT box (ndat vectors starting at my_ir)
6181 0 : call gwr%wcq_to_scbox(sc_ngfft, select_my_qbz, desc_myqbz, wc_scgvec, my_ir, ndat, wc_gpr, wct_scbox)
6182 : #ifdef HAVE_OPENMP_OFFLOAD
6183 : !$omp target update to(wct_scbox(1:sc_nfft,1:max_ndat)) if (gpu_option == ABI_GPU_OPENMP)
6184 : #endif
6185 0 : if (gwr%kpt_comm%nproc > 1) call xmpi_isum_ip(wct_scbox, gwr%kpt_comm%value, wct_request, ierr)
6186 :
6187 : ! Wc(G',r) --> Wc(R',r)
6188 0 : if (gwr%kpt_comm%nproc > 1) call xmpi_wait(wct_request, ierr)
6189 0 : call wt_plan%execute(wct_scbox(:,1), -1, max_ndat, iscale=0)
6190 : else
6191 : call gwr%wcq_to_scbox(sc_ngfft, select_my_qbz, desc_myqbz, wc_scgvec, my_ir, ndat, wc_gpr, wct_scbox, &
6192 0 : wct_scbox_win=wct_scbox_win)
6193 : end if
6194 :
6195 : ! TODO: Should block using nproc in kpt_comm, scatter data and perform multiple FFTs in parallel.
6196 0 : do iab=1,gwr%nsig_ab
6197 0 : iiab = spinor_idxs(1, iab); jiab = spinor_idxs(2, iab)
6198 0 : if (.not. use_shmem_for_k) then
6199 :
6200 : ! Insert G_k(g',r) in G'-space in the supercell FFT box (ndat vectors starting at my_ir).
6201 0 : call gwr%gk_to_scbox(sc_ngfft, select_my_kbz, desc_mykbz, green_scgvec, my_ir, ndat, gt_gpr(:,:,iab), gt_scbox)
6202 : #ifdef HAVE_OPENMP_OFFLOAD
6203 : !$omp target update to(gt_scbox(1:sc_nfft,1:max_ndat,1:2)) if (gpu_option == ABI_GPU_OPENMP)
6204 : #endif
6205 0 : if (gwr%kpt_comm%nproc > 1) call xmpi_isum_ip(gt_scbox, gwr%kpt_comm%value, gt_request, ierr)
6206 :
6207 : ! G(G',r) --> G(R',r)
6208 0 : if (gwr%kpt_comm%nproc > 1) call xmpi_wait(gt_request, ierr)
6209 0 : call green_plan%execute(gt_scbox(:,1,1), -1, max_ndat*2, iscale=0)
6210 :
6211 : ! Use gt_scbox to store GW (R',r, +/- i tau) for this set of ndat r-point
6212 : !gt_scbox(:,:,1) = gt_scbox(:,:,1) * wct_scbox(:,:) * sigma_fact
6213 : !gt_scbox(:,:,2) = gt_scbox(:,:,2) * wct_scbox(:,:) * sigma_fact
6214 : #ifdef HAVE_OPENMP_OFFLOAD
6215 : !$OMP TARGET TEAMS DISTRIBUTE PARALLEL DO COLLAPSE(3) MAP(to:gt_scbox(1:sc_nfft,1:max_ndat,1:2), wct_scbox(1:sc_nfft,1:max_ndat)) if (gpu_option == ABI_GPU_OPENMP)
6216 : #endif
6217 0 : do ipm=1,2
6218 0 : do idat=1,max_ndat
6219 0 : do ifft=1,sc_nfft
6220 0 : gt_scbox(ifft,idat,ipm) = gt_scbox(ifft,idat,ipm) * wct_scbox(ifft,idat) * sigma_fact
6221 : end do
6222 : end do
6223 : end do
6224 : #ifdef HAVE_OPENMP_OFFLOAD
6225 : !$omp target update from(gt_scbox(1:sc_nfft,1:max_ndat,1:2)) if (gpu_option == ABI_GPU_OPENMP)
6226 : #endif
6227 : !print *, "Maxval abs imag G:", maxval(abs(aimag(gt_scbox)))
6228 :
6229 : else
6230 : ! use_shmem_for_k --> MPI shared window version. Only gt_scbox are wct_scbox are shared.
6231 : call gwr%gk_to_scbox(sc_ngfft, select_my_kbz, desc_mykbz, green_scgvec, my_ir, ndat, gt_gpr(:,:,iab), gt_scbox, &
6232 0 : gt_scbox_win=gt_scbox_win)
6233 :
6234 : ! Now each MPI proc operates on different idat entries.
6235 0 : call xmpi_win_fence(XMPI_MODE_NOSUCCEED, gt_scbox_win, ierr) ! Start the RMA epoch
6236 0 : idat = gwr%kpt_comm%me + 1
6237 0 : if (idat <= ndat) then
6238 0 : call wt_plan%execute(wct_scbox(:,idat), -1, ndat=1, iscale=0)
6239 0 : do ipm=1,2
6240 0 : call green_plan%execute(gt_scbox(:,idat,ipm), -1, ndat=1, iscale=0)
6241 0 : gt_scbox(:,idat,ipm) = gt_scbox(:,idat,ipm) * wct_scbox(:,idat) * sigma_fact
6242 : end do
6243 : end if
6244 : !IF (.not. MPI_ASYNC_PROTECTS_NONBLOCKING) CALL MPI_F_SYNC_REG(gt_scbox)
6245 : !call xmpi_barrier(gwr%kpt_comm%value)
6246 0 : call xmpi_win_fence(XMPI_MODE_NOPRECEDE, gt_scbox_win, ierr) ! End the RMA epoch
6247 : end if
6248 :
6249 : ! Integrate Sigma matrix elements in the R-supercell for ndat r-points and accumulate.
6250 : ! possibly including off-diagonal terms.
6251 0 : do ikcalc=1,gwr%nkcalc
6252 0 : if (gwr%kpt_comm%skip(ikcalc)) cycle ! FIXME: Temporary hack till I find a better MPI algo for k-points.
6253 0 : k_is_gamma = normv(gwr%kcalc(:,ikcalc), gwr%cryst%gmet, "G") < GW_TOLQ0
6254 :
6255 0 : do band2=gwr%bstart_ks(ikcalc, spin), gwr%bstop_ks(ikcalc, spin)
6256 0 : do irow=1,Sigcij_tab(ikcalc, spin)%col(band2)%size1
6257 0 : band1 = Sigcij_tab(ikcalc, spin)%col(band2)%bidx(irow)
6258 0 : do idat=1,ndat
6259 : !if (use_shmem_for_k .and. idat /= gwr%kpt_comm + 1) cycle
6260 0 : ir = uc_ir + idat - 1
6261 0 : cpsi_r = conjg(uc_psir_bk((iiab-1)*gwr%g_nfft + ir, band1, ikcalc))
6262 0 : ucpsi_r = uc_psir_bk((jiab-1)*gwr%g_nfft+1:jiab*gwr%g_nfft, band2, ikcalc)
6263 0 : do ipm=1,2
6264 : call sc_sum(gwr%ngkpt, gwr%g_ngfft, scph1d_kcalc(:,:,ikcalc), k_is_gamma, &
6265 0 : cpsi_r, gt_scbox(:,idat,ipm), ucpsi_r, sigc_pm(ipm))
6266 : end do
6267 0 : if (gwr%sig_diago) then
6268 0 : sigc_it_mat(:, itau,band1,1,ikcalc,spin) = sigc_it_mat(:,itau,band1,1,ikcalc,spin) + sigc_pm(:)
6269 : else
6270 0 : sigc_it_mat(:,itau,band1,band2,ikcalc,spin) = sigc_it_mat(:,itau,band1,band2,ikcalc,spin) + sigc_pm(:)
6271 : end if
6272 : end do ! idat
6273 : end do
6274 : end do ! band2
6275 : end do ! ikcalc
6276 : end do ! iab
6277 :
6278 : !if (use_shmem_for_k) call xmpi_sum
6279 :
6280 0 : if (print_time) then
6281 0 : write(msg,'(4x,3(a,i0),a)')"Sigma_c my_ir [", my_ir, "/", my_nr, "] (tot: ", gwr%g_nfft, ")"
6282 0 : call cwtime_report(msg, cpu_ir, wall_ir, gflops_ir)
6283 : end if
6284 : end do ! my_ir
6285 :
6286 : ! Free descriptors and PBLAS matrices in kBZ and qBZ.
6287 0 : call desc_array_free(desc_mykbz); call desc_array_free(desc_myqbz)
6288 0 : call slk_array_free(gt_gpr); call slk_array_free(wc_gpr)
6289 :
6290 0 : write(msg,'(1x,3(a,i0),a)')"Sigma_c my_itau [", my_it, "/", gwr%my_ntau, "] (tot: ", gwr%ntau, ")"
6291 0 : call cwtime_report(msg, cpu_tau, wall_tau, gflops_tau, end_str=ch10)
6292 : end do ! my_it
6293 :
6294 0 : ABI_FREE(scph1d_kcalc)
6295 0 : ABI_FREE(ucpsi_r)
6296 0 : ABI_FREE(uc_psir_bk)
6297 : end do ! my_is
6298 :
6299 0 : sigc_it_mat = -sigc_it_mat * (gwr%cryst%ucvol / gwr%g_nfft) ** 2
6300 :
6301 : !call wrtout(std_out, sjoin(" Maxval abs re W:", ftoa(max_abs_re_wct)))
6302 : !call wrtout(std_out, sjoin(" Maxval abs imag W:", ftoa(max_abs_imag_wct)))
6303 0 : if (.not. use_shmem_for_k) then
6304 : #ifdef HAVE_OPENMP_OFFLOAD
6305 : !$OMP TARGET EXIT DATA MAP(delete: gt_scbox(1:sc_nfft,1:max_ndat,1:2), wct_scbox(1:sc_nfft,1:max_ndat)) if (gpu_option == ABI_GPU_OPENMP)
6306 : #endif
6307 0 : ABI_FREE(gt_scbox)
6308 0 : ABI_FREE(wct_scbox)
6309 : else
6310 0 : call xmpi_win_free(gt_scbox_win, ierr)
6311 0 : call xmpi_win_free(wct_scbox_win, ierr)
6312 : end if
6313 :
6314 0 : call green_plan%free(); call wt_plan%free()
6315 :
6316 0 : ABI_FREE(green_scgvec)
6317 0 : ABI_FREE(wc_scgvec)
6318 :
6319 : else
6320 : ! ===================================================================
6321 : ! Mixed-space algorithm in the unit cell with convolutions in k-space
6322 : ! ===================================================================
6323 0 : call print_sigma_header()
6324 :
6325 : ! Define tables to account for symmetries:
6326 : ! - when looping over the BZ, we only need to include the union of IBZ_x for x in kcalc.
6327 : ! - when accumulating the self-energy, we have to use weights that depend on x.
6328 :
6329 : ! The little group is needed when symsigma == 1
6330 : ! If use_umklp == 1 then symmetries requiring an umklapp to preserve k_gw are included as well.
6331 : ! Note that TR is not yet supported so timrev is set to 1 even if TR has been used to generate the GS IBZ.
6332 0 : use_umklp = 1
6333 : !gw_timrev = kpts_timrev_from_kptopt(gwr%ks_ebands%kptopt) + 1
6334 0 : do ikcalc=1,gwr%nkcalc
6335 0 : call ltg_kcalc(ikcalc)%init(gwr%kcalc(:,ikcalc), gwr%nkbz, gwr%kbz, gwr%cryst, use_umklp, npwe=0)
6336 0 : if (gwr%comm%me == 0 .and. gwr%dtset%symsigma /= 0) then
6337 0 : call ltg_kcalc(ikcalc)%print([std_out], prtvol=gwr%dtset%prtvol)
6338 : end if
6339 : end do
6340 :
6341 0 : call wrtout(std_out, " Allocating PBLAS matrices to store Wc_q(r',r,tau), and Sigma_kcalc(r',r,+/-tau) in the unit cell.")
6342 0 : nr = gwr%g_nfft
6343 0 : col_bsize = nr / gwr%g_comm%nproc; if (mod(nr, gwr%g_comm%nproc) /= 0) col_bsize = col_bsize + 1
6344 :
6345 0 : call wc_rpr%init(nr, nr, gwr%g_slkproc, 1, size_blocs=[-1, col_bsize])
6346 :
6347 0 : gpu_action = "None"
6348 0 : if (gpu_option == ABI_GPU_OPENMP) then
6349 0 : gpu_action = "alloc"; call wrtout(std_out, " Allocating Sigma_k(r,r', +/-tau) on the GPU...")
6350 : end if
6351 :
6352 0 : do ipm=1,2
6353 0 : do iab=1,gwr%nsig_ab
6354 0 : call gk_rpr_pm(ipm, iab)%init(nr, nr, gwr%g_slkproc, 1, size_blocs=[-1, col_bsize])
6355 0 : do ikcalc=1,gwr%nkcalc
6356 0 : do itim=1,2
6357 0 : call sigc_rpr(itim,ipm,ikcalc, iab)%init(nr, nr, gwr%g_slkproc, 1, size_blocs=[-1, col_bsize], gpu_action=gpu_action)
6358 : end do
6359 : end do
6360 : end do
6361 : end do
6362 :
6363 0 : mem_mb = slk_array_locmem_mb(wc_rpr) + sum(slk_array_locmem_mb(gk_rpr_pm)) + sum(slk_array_locmem_mb(sigc_rpr))
6364 0 : call wrtout(std_out, sjoin(" Local memory for PBLAS (r,r') matrices: ", ftoa(mem_mb, fmt="f8.1"), ' [Mb] <<< MEM'))
6365 0 : if (gwr%comm%me == 0) call pstat_proc%print(_PSTAT_ARGS_)
6366 :
6367 0 : ii = sigc_rpr(1,1,1,1)%size_local(2)
6368 0 : ABI_MALLOC(loc_cwork, (ii))
6369 :
6370 0 : do my_is=1,gwr%my_nspins
6371 0 : spin = gwr%my_spins(my_is)
6372 :
6373 : ! Load wavefunctions for GW corrections in the real-space unit cell.
6374 : ! TODO: MPI distribute or use MPI shared memory
6375 0 : bmin = minval(gwr%bstart_ks(:, spin)); bmax = maxval(gwr%bstop_ks(:, spin))
6376 0 : ABI_MALLOC_OR_DIE(uc_psir_bk, (nr * gwr%nspinor, bmin:bmax, gwr%nkcalc), ierr)
6377 : #ifdef HAVE_OPENMP_OFFLOAD
6378 : !$OMP TARGET ENTER DATA MAP(alloc:uc_psir_bk) IF (gpu_option == ABI_GPU_OPENMP)
6379 : #endif
6380 :
6381 : !! !$OMP PARALLEL DO COLLAPSE(2) PRIVATE(ikcalc_ibz)
6382 0 : do ikcalc=1,gwr%nkcalc
6383 0 : do band=gwr%bstart_ks(ikcalc, spin), gwr%bstop_ks(ikcalc, spin)
6384 0 : ikcalc_ibz = gwr%kcalc2ibz(ikcalc, 1) ! NB: Assuming wfs in IBZ
6385 0 : call gwr%kcalc_wfd%get_ur(band, ikcalc_ibz, spin, uc_psir_bk(:, band, ikcalc))
6386 : end do
6387 : end do
6388 : #ifdef HAVE_OPENMP_OFFLOAD
6389 : !$omp target update to(uc_psir_bk) if (gpu_option == ABI_GPU_OPENMP)
6390 : #endif
6391 :
6392 0 : need_qibz = 0
6393 0 : do my_ikf=1,gwr%my_nkbz
6394 0 : ik_bz = gwr%my_kbz_inds(my_ikf); kk_bz = gwr%kbz(:, ik_bz)
6395 0 : do ikcalc=1,gwr%nkcalc
6396 0 : qq_bz = gwr%kcalc(:,ikcalc) - kk_bz !; qq_bz = -qq_bz
6397 : ! TODO: here I may need to take into account the umklapp
6398 0 : call findqg0(iq_bz, g0_q, qq_bz, gwr%nqbz, gwr%qbz, gwr%mG0)
6399 : !ABI_CHECK(all(g0_q == 0), sjoin("g0_q != 0, kcalc", ktoa(gwr%kcalc(:,ikcalc)), "kk_bz:", ktoa(kk_bz)))
6400 0 : iq_ibz = gwr%qbz2ibz(1, iq_bz)
6401 0 : need_qibz(iq_ibz) = 1
6402 : end do
6403 : end do
6404 :
6405 : ! Construct Sigma(itau) using convolutions in k-space and real-space representation in the unit cell.
6406 0 : do my_it=1,gwr%my_ntau
6407 0 : call cwtime(cpu_tau, wall_tau, gflops_tau, "start")
6408 0 : itau = gwr%my_itaus(my_it)
6409 :
6410 : ! Redistribute W_q(g,g') in the IBZ so that each MPI proc can reconstruct Wc_q in the BZ inside the loops
6411 0 : call gwr%redistrib_mats_qibz("wc", itau, spin, need_qibz, got_qibz, "communicate")
6412 0 : if (my_it == 1 .and. gwr%comm%me == 0) call pstat_proc%print(_PSTAT_ARGS_)
6413 :
6414 0 : if (gpu_option == ABI_GPU_OPENMP) then
6415 0 : call slk_array_gpu_set_zero(sigc_rpr)
6416 : end if
6417 : !else
6418 0 : call slk_array_set_zero(sigc_rpr)
6419 : !end if
6420 :
6421 : ! Sum over my k-points in the BZ.
6422 0 : do my_ikf=1,gwr%my_nkbz
6423 0 : print_time = (gwr%comm%me == 0 .and. (my_ikf <= LOG_MODK .or. mod(my_ikf, LOG_MODK) == 0))
6424 0 : if (print_time) call cwtime(cpu_ikf, wall_ikf, gflops_ikf, "start")
6425 0 : ik_bz = gwr%my_kbz_inds(my_ikf); kk_bz = gwr%kbz(:,ik_bz)
6426 :
6427 0 : ik_ibz = gwr%kbz2ibz(1, ik_bz); isym_k = gwr%kbz2ibz(2, ik_bz)
6428 0 : trev_k = gwr%kbz2ibz(6, ik_bz); g0_k = gwr%kbz2ibz(3:5, ik_bz)
6429 : isirr_k = (isym_k == 1 .and. trev_k == 0 .and. all(g0_k == 0))
6430 : tsign_k = merge(1, -1, trev_k == 0)
6431 : !if (.not. isirr_k) cycle
6432 :
6433 : ! Skip this BZ k-point if it is not in the IBZ(ikcalc) of some ikcalc.
6434 0 : compute_this_kbz = .True.
6435 0 : if (gwr%dtset%symsigma /= 0) then
6436 0 : compute_this_kbz = .False.
6437 0 : do ikcalc=1,gwr%nkcalc
6438 0 : if (ltg_kcalc(ikcalc)%ibzq(ik_bz) == 1) then
6439 : compute_this_kbz = .True.; exit
6440 : end if
6441 : end do
6442 : end if
6443 0 : if (.not. compute_this_kbz) cycle ! my_ikf loop
6444 :
6445 : ! Use symmetries to get G_kbz from the IBZ then G_k(g,g') --> G_k(r',r)
6446 0 : call gwr%get_gkbz_rpr_pm(ik_bz, itau, spin, gk_rpr_pm)
6447 :
6448 0 : do ikcalc=1,gwr%nkcalc
6449 0 : if (gwr%dtset%symsigma /= 0 .and. ltg_kcalc(ikcalc)%ibzq(ik_bz) == 0) cycle ! FIXME: iq_bz or ikq?
6450 0 : qq_bz = gwr%kcalc(:, ikcalc) - kk_bz !; qq_bz = -qq_bz
6451 : ! TODO: here I may need to take into account the umklapp
6452 0 : call findqg0(iq_bz, g0_q, qq_bz, gwr%nqbz, gwr%qbz, gwr%mG0)
6453 : !ABI_CHECK(all(g0_q == 0), sjoin("g0_q != 0", ktoa(gwr%kcalc(:,ikcalc)), "kk_bz", ktoa(kk_bz)))
6454 : !iq_ibz = gwr%qbz2ibz(1, iq_bz)
6455 0 : call gwr%get_wc_rpr_qbz(g0_q, iq_bz, itau, spin, wc_rpr)
6456 :
6457 : ! The integration weight depends on ikcalc.
6458 0 : wtqp = one / gwr%nkbz; wtqm = zero
6459 0 : if (gwr%dtset%symsigma /= 0) then
6460 : ! If symsigma, sum only q"s in IBZ_k, then symmetrize the matrix elements.
6461 : ! In this case elements are weighted according to wtqp and wtqm. wtqm is for time-reversal.
6462 : associate (ltg_k => ltg_kcalc(ikcalc))
6463 0 : wtqp = (one * sum(ltg_k%wtksym(1,:,ik_bz))) / gwr%nkbz ! FIXME: iq_bz or ik_bz?
6464 0 : wtqm = (one * sum(ltg_k%wtksym(2,:,ik_bz))) / gwr%nkbz
6465 : end associate
6466 : end if
6467 :
6468 0 : do ipm=1,2
6469 : !sigc_rpr(1,ipm,ikcalc)%buffer_cplx = sigc_rpr(1,ipm,ikcalc)%buffer_cplx + &
6470 : ! wtqp * gk_rpr_pm(ipm)%buffer_cplx * wc_rpr%buffer_cplx
6471 0 : do iab=1,gwr%nsig_ab
6472 0 : bufsize = sigc_rpr(1,ipm,ikcalc,iab)%bufsize
6473 : call cplx_mat_plus_bc(bufsize, sigc_rpr(1,ipm,ikcalc,iab)%buffer_cplx(:,1), &
6474 : wtqp, "N", gk_rpr_pm(ipm,iab)%buffer_cplx(:,1), wc_rpr%buffer_cplx(:,1), &
6475 0 : gpu_option)
6476 :
6477 : call cplx_mat_plus_bc(bufsize, sigc_rpr(2,ipm,ikcalc,iab)%buffer_cplx(:,1), &
6478 : wtqm, "N", gk_rpr_pm(ipm,iab)%buffer_cplx(:,1), wc_rpr%buffer_cplx(:,1), &
6479 0 : gpu_option)
6480 :
6481 : !sigc_rpr(1, ipm, ikcalc)%buffer_cplx = sigc_rpr(1, ipm, ikcalc)%buffer_cplx + &
6482 : ! (wtqp + wtqm) * real(gk_rpr_pm(ipm)%buffer_cplx * wc_rpr%buffer_cplx, kind=gwp) &
6483 : ! + (wtqp - wtqm) * j_gw * aimag(gk_rpr_pm(ipm)%buffer_cplx * wc_rpr%buffer_cplx)
6484 : end do ! iab
6485 : end do ! ipm
6486 :
6487 : end do ! ikcalc
6488 :
6489 0 : if (print_time) then
6490 0 : write(msg,'(4x,3(a,i0),a)')"Sigma_c my_ikf [", my_ikf, "/", gwr%my_nkbz, "] (tot: ", gwr%nkbz, ")"
6491 0 : call cwtime_report(msg, cpu_ikf, wall_ikf, gflops_ikf)
6492 : end if
6493 : end do ! my_ikf
6494 :
6495 : ! Deallocate extra Wc matrices defined by got_qibz.
6496 0 : call gwr%redistrib_mats_qibz("wc", itau, spin, need_qibz, got_qibz, "free")
6497 :
6498 : ! Integrate self-energy matrix elements in the unit cell.
6499 : ! Remember that Sigma is stored as (r',r) and that the second dimension is MPI-distributed.
6500 : ! In case of k or g distribution, sigc_pm is a partial 6d integral that will be ALL_REDUCED in gwr%comm afterwards.
6501 : ! TODO: Off-diagonal terms although this is not the most efficient algorithm
6502 0 : do ikcalc=1,gwr%nkcalc
6503 0 : do iab=1,gwr%nsig_ab
6504 0 : iiab = spinor_idxs(1, iab); jiab = spinor_idxs(2, iab)
6505 0 : if (gpu_option == ABI_GPU_OPENMP) then
6506 0 : do ipm=1,2
6507 0 : do itim=1,2
6508 0 : call sigc_rpr(itim,ipm,ikcalc,iab)%gpu_map("update_from")
6509 : end do
6510 : end do
6511 : end if
6512 0 : do band=gwr%bstart_ks(ikcalc, spin), gwr%bstop_ks(ikcalc, spin)
6513 : call sig_braket_ur(sigc_rpr(:,:,ikcalc,iab), gwr%g_nfft, &
6514 : uc_psir_bk((jiab-1)*gwr%g_nfft+1:jiab*gwr%g_nfft, band, ikcalc), &
6515 : uc_psir_bk((iiab-1)*gwr%g_nfft+1:iiab*gwr%g_nfft, band, ikcalc), &
6516 0 : sigc_pm, loc_cwork)
6517 0 : if (gwr%sig_diago) sigc_it_mat(:, itau, band, 1, ikcalc, spin) = sigc_it_mat(:, itau, band, 1, ikcalc, spin) + sigc_pm(:)
6518 : end do ! band
6519 : end do ! iab
6520 : end do ! ikcalc
6521 :
6522 0 : write(msg,'(3(a,i0),a)')" Sigma_c my_itau [", my_it, "/", gwr%my_ntau, "] (tot: ", gwr%ntau, ")"
6523 0 : call cwtime_report(msg, cpu_tau, wall_tau, gflops_tau)
6524 : end do ! my_it
6525 :
6526 : #ifdef HAVE_OPENMP_OFFLOAD
6527 : !$OMP TARGET EXIT DATA MAP(delete:uc_psir_bk) IF (gpu_option == ABI_GPU_OPENMP)
6528 : #endif
6529 0 : ABI_FREE(uc_psir_bk)
6530 : end do ! my_is
6531 :
6532 0 : sigc_it_mat = -sigc_it_mat * (one/gwr%g_nfft) ** 2
6533 :
6534 0 : ABI_FREE(loc_cwork)
6535 0 : call wc_rpr%free(); call slk_array_free(sigc_rpr); call slk_array_free(gk_rpr_pm)
6536 0 : do ikcalc=1,gwr%nkcalc
6537 0 : call ltg_kcalc(ikcalc)%free()
6538 : end do
6539 0 : call wrtout(std_out, " Mixed space algorithm for sigma completed")
6540 : end if
6541 :
6542 0 : if (gwr%comm%me == 0) call pstat_proc%print(_PSTAT_ARGS_)
6543 :
6544 0 : call sigijtab_free(Sigcij_tab)
6545 0 : ABI_FREE(Sigcij_tab)
6546 :
6547 : ! Collect results and average
6548 0 : call xmpi_sum(sigc_it_mat, gwr%comm%value, ierr)
6549 :
6550 : ! Average over degenerate states.
6551 : ! if (gwr%dtset%symsigma == +1 .and. .not. gwr%use_supercell_for_sigma) then
6552 0 : if (gwr%dtset%symsigma == +1) then
6553 0 : call wrtout(std_out, " Symsigma 1 --> Averaging Sig_c matrix elements within degenerate subspaces.")
6554 0 : ABI_CHECK(gwr%sig_diago, "symsigma = 1 requires diagonal Sigma_c")
6555 0 : do spin=1,gwr%nsppol
6556 0 : do ikcalc=1,gwr%nkcalc
6557 0 : do ideg=1,size(gwr%degtab(ikcalc, spin)%bids)
6558 0 : associate (bids => gwr%degtab(ikcalc, spin)%bids(ideg)%vals)
6559 0 : nstates = size(bids)
6560 0 : avg_2ntau = sum(sigc_it_mat(:,:,bids(:), 1,ikcalc, spin), dim=3) / nstates
6561 0 : do ii=1,nstates
6562 0 : sigc_it_mat(:,:,bids(ii), 1,ikcalc, spin) = avg_2ntau
6563 : end do
6564 : end associate
6565 : end do ! ideg
6566 : end do
6567 : end do
6568 : end if ! symsigma == +1
6569 :
6570 : ! Store matrix elements of Sigma_c(it), separate even and odd part
6571 : ! then use sine/cosine transform to get Sigma_c(i omega).
6572 : ! Finally, perform analytic continuation with Pade' to go to the real-frequency axis
6573 : ! for computing QP corrections and spectral functions. All procs execute this part as it's very cheap.
6574 :
6575 0 : imag_zmesh(:) = j_dpc * gwr%iw_mesh
6576 :
6577 : ! Save previous QP bands in qp_ebands_prev (needed for self-consistency)
6578 : ! In the loop below, we also update gwr%qp_ebands%eig with the QP results and recompute occ/fermie.
6579 0 : gwr%qp_ebands_prev%eig = gwr%qp_ebands%eig
6580 0 : gwr%qp_ebands_prev%occ = gwr%qp_ebands%occ
6581 :
6582 0 : e0_kcalc = zero; spfunc_diag = zero; pade_solver_ierr = 0; ze0_kcalc = zero; sigc_e0 = zero
6583 0 : qpz_ene = zero; qp_pade = zero; sigxc_rw_diag = zero
6584 0 : ks_gaps = -one; qpz_gaps = -one ; qp_pade_gaps = -one
6585 :
6586 0 : do spin=1,gwr%nsppol
6587 0 : do ikcalc=1,gwr%nkcalc
6588 0 : ik_ibz = gwr%kcalc2ibz(ikcalc, 1)
6589 0 : do band=gwr%bstart_ks(ikcalc, spin), gwr%bstop_ks(ikcalc, spin)
6590 0 : ibc = band - gwr%bstart_ks(ikcalc, spin) + 1
6591 0 : nb1 = gwr%bstop_ks(ikcalc, spin) - gwr%bstart_ks(ikcalc, spin) + 1
6592 :
6593 : ! FT Sigma(itau) --> Sigma(iw)
6594 0 : band2_start = 1; band2_stop = 1
6595 0 : if (.not. gwr%sig_diago) then
6596 0 : band2_start = gwr%bstart_ks(ikcalc, spin); band2_stop = gwr%bstop_ks(ikcalc, spin)
6597 : end if
6598 :
6599 0 : do band2=band2_start, band2_stop
6600 0 : associate (cvals_pmt => sigc_it_mat(:, :, band, band2, ikcalc, spin))
6601 0 : ib2 = band2 - band2_start + 1
6602 0 : nb2 = band2_stop - band2_start + 1
6603 :
6604 0 : if (do_sigma_fit) then
6605 0 : cvals = cvals_pmt(1,:)
6606 0 : call fit_tau_exp(gwr%ntau, gwr%tau_mesh, gwr%tau_wgs, cvals, alpha_c, beta_r, ierr)
6607 0 : alphas_c(1,band, band2) = alpha_c; betas_r(1,band,band2) = beta_r
6608 0 : zcut_pm(1, band, band2) = gwr%dtset%zcut
6609 : ! Remove the fit from the ab-initio data.
6610 0 : cvals_pmt(1,:) = cvals_pmt(1,:) - alpha_c * exp(-beta_r * gwr%tau_mesh)
6611 0 : if (gwr%comm%value == master) then
6612 0 : write(100, "(a,2(i0,1x))")"# +tau fit for band, band2: ", band, band2
6613 0 : write(100, *)"# alpha_c, beta_r: ", alpha_c, beta_r
6614 0 : do ii=1,gwr%ntau
6615 0 : zz = alpha_c * exp(-beta_r * gwr%tau_mesh(ii)); write(100, *) c2r(cvals_pmt(1,ii)), c2r(zz), abs(cvals_pmt(1,ii) - zz)
6616 : end do
6617 : end if
6618 : ! TODO: Recheck this part, in particular the order of -tau
6619 0 : cvals = cvals_pmt(2,:)
6620 0 : call fit_tau_exp(gwr%ntau, gwr%tau_mesh, gwr%tau_wgs, cvals, alpha_c, beta_r, ierr)
6621 0 : alphas_c(2, band, band2) = alpha_c; betas_r(2, band, band2) = beta_r
6622 0 : zcut_pm(2, band, band2) = gwr%dtset%zcut
6623 : ! Remove the fit from the ab-initio data.
6624 0 : cvals_pmt(2,:) = cvals_pmt(2,:) - alpha_c * exp(-beta_r * gwr%tau_mesh)
6625 0 : if (gwr%comm%value == master) then
6626 0 : write(101, "(a,2(i0,1x))")"# -tau fit for band, band2: ", band, band2
6627 0 : write(101, *)"# alpha_c, beta_r: ", alpha_c, beta_r
6628 0 : do ii=1,gwr%ntau
6629 0 : zz = alpha_c * exp(-beta_r * gwr%tau_mesh(ii)); write(101, *) c2r(cvals_pmt(2,ii)), c2r(zz), abs(cvals_pmt(2,ii) - zz)
6630 : end do
6631 : end if
6632 : end if ! do_sigma_fit
6633 :
6634 : ! f(t) = E(t) + O(t) = (f(t) + f(-t)) / 2 + (f(t) - f(-t)) / 2
6635 0 : even_t = (cvals_pmt(1,:) + cvals_pmt(2,:)) / two; odd_t = (cvals_pmt(1,:) - cvals_pmt(2,:)) / two
6636 0 : gwr%sigc_iw_mat(:, band, band2, ikcalc, spin) = matmul(gwr%cosft_wt, even_t) + j_dpc * matmul(gwr%sinft_wt, odd_t)
6637 : end associate
6638 : end do ! band2
6639 :
6640 : ! NB: e0 is always set to the KS energy even in case of self-consistency.
6641 0 : e0 = gwr%ks_ebands%eig(band, ik_ibz, spin)
6642 0 : if ( gwr%sig_diago) sigx = gwr%sigx_mat(band, 1, ikcalc, spin)
6643 0 : if (.not. gwr%sig_diago) sigx = gwr%sigx_mat(band, band, ikcalc, spin)
6644 :
6645 : ! Note vxc[n_val] instead of vxc[n_val + n_nlcc] with the model core charge.
6646 0 : if (gwr%nspinor == 2) then
6647 0 : vxc_val = SUM(gwr%ks_me%vxcval(band, band, ik_ibz, :))
6648 : else
6649 0 : vxc_val = gwr%ks_me%vxcval(band, band, ik_ibz, spin)
6650 : end if
6651 0 : vu = zero; if (gwr%dtset%usepawu /= 0) vu = gwr%ks_me%vu(band, band, ik_ibz, spin)
6652 0 : v_meanf = vxc_val + vu
6653 :
6654 0 : band2 = merge(1, band, gwr%sig_diago)
6655 :
6656 : call spade%init(gwr%ntau, imag_zmesh, gwr%sigc_iw_mat(:, band, band2, ikcalc, spin), &
6657 0 : alphas_c(:, band, band2), betas_r(:, band, band2), zcut_pm(:, band, band2))
6658 0 : spade%do_sigma_fit = do_sigma_fit
6659 :
6660 : ! Solve the QP equation with Newton-Rapson starting from e0.
6661 0 : zz = cmplx(e0, zero)
6662 0 : call spade%qp_solve(e0, v_meanf, sigx, zz, zsc, sigc_zsc, msg, ierr)
6663 0 : qp_pade(band, ikcalc, spin) = zsc
6664 0 : pade_solver_ierr(band, ikcalc, spin) = ierr
6665 0 : ABI_WARNING_IF(ierr /= 0, msg)
6666 :
6667 0 : call spade%eval(zz, sigc_e0__, dvdz=dsigc_de0)
6668 :
6669 : ! Z = (1 - dSigma / domega(E0))^{-1}
6670 0 : z_e0 = one / (one - dsigc_de0)
6671 :
6672 : ! Compute linearized QP solution and store results
6673 0 : qp_ene = e0 + z_e0 * (sigc_e0__ + sigx - v_meanf)
6674 0 : qpz_ene(band, ikcalc, spin) = qp_ene
6675 0 : e0_kcalc(band, ikcalc, spin) = e0
6676 0 : sigc_e0(band, ikcalc, spin) = sigc_e0__
6677 0 : ze0_kcalc(band, ikcalc, spin) = z_e0
6678 :
6679 : ! IMPORTANT: Here we update qp_ebands%eig with the new ones obtained with the linearized QP equation.
6680 0 : gwr%qp_ebands%eig(band, ik_ibz, spin) = real(qp_ene)
6681 :
6682 : ! Compute Spectral function using linear mesh **centered** around KS e0.
6683 0 : rw_mesh = arth(e0 - gwr%wr_step * (gwr%nwr / 2), gwr%wr_step, gwr%nwr)
6684 0 : hhartree_bk = gwr%ks_ebands%eig(band, ik_ibz, spin) - v_meanf
6685 0 : do iw=1,gwr%nwr
6686 0 : zz = rw_mesh(iw)
6687 0 : call spade%eval(zz, sigc_e0__)
6688 0 : sig_xc = sigx + sigc_e0__
6689 0 : sigxc_rw_diag(iw, band, ikcalc, spin) = sig_xc
6690 :
6691 : spfunc_diag(iw, band, ikcalc, spin) = one / pi * abs(aimag(sigc_e0__)) &
6692 0 : / ( (real(rw_mesh(iw) - hhartree_bk - sig_xc)) ** 2 + (aimag(sigc_e0__)) ** 2) ! / Ha_eV
6693 :
6694 : !Sr%hhartree = hdft - KS_me%vxcval
6695 : !spfunc_diag(iw, band, ikcalc, spin) = &
6696 : ! one / pi * abs(aimag(sigc_e0__)) &
6697 : ! /( (real(rw_mesh(iw) - Sr%hhartree(ib, ib, ik_ibz, spin) - sigx_xc)) ** 2 &
6698 : ! +(aimag(sigc_e0__)) ** 2) / Ha_eV
6699 : end do ! iw
6700 0 : call spade%free()
6701 :
6702 : end do ! band
6703 : end do ! ikcalc
6704 : end do ! spin
6705 :
6706 0 : ABI_SFREE(alphas_c)
6707 0 : ABI_SFREE(betas_r)
6708 0 : ABI_SFREE(zcut_pm)
6709 :
6710 0 : if (gwr%nkcalc == gwr%nkibz) then
6711 : ! Shift the bands that are not explicitly included in the SCF calculation.
6712 : ! using the correction evaluated at bstop_ks/bstart_ks to accelerate self-consistent calculations.
6713 0 : do spin=1,gwr%nsppol
6714 0 : do ikcalc=1,gwr%nkcalc
6715 0 : ik_ibz = gwr%kcalc2ibz(ikcalc, 1)
6716 0 : band = gwr%bstop_ks(ikcalc, spin)
6717 0 : if (band + 1 <= size(gwr%qp_ebands%eig, dim=1)) then
6718 0 : eshift = gwr%qp_ebands%eig(band, ik_ibz, spin) - gwr%qp_ebands_prev%eig(band, ik_ibz, spin)
6719 0 : call wrtout(std_out, sjoin(" Correcting bands >= ", itoa(band+1), " with eshift:", ftoa(eshift * Ha_meV), "(meV)"))
6720 0 : gwr%qp_ebands%eig(band + 1:, ik_ibz, spin) = gwr%qp_ebands%eig(band + 1:, ik_ibz, spin) + eshift
6721 : end if
6722 0 : band = gwr%bstart_ks(ikcalc, spin)
6723 0 : if (band > 1) then ! unlikely
6724 0 : eshift = gwr%qp_ebands%eig(band, ik_ibz, spin) - gwr%qp_ebands_prev%eig(band, ik_ibz, spin)
6725 0 : call wrtout(std_out, sjoin(" Correcting bands < ", itoa(band), " with eshift:", ftoa(eshift * Ha_meV), "(meV)"))
6726 0 : gwr%qp_ebands%eig(:band - 1, ik_ibz, spin) = gwr%qp_ebands%eig(:band - 1, ik_ibz, spin) + eshift
6727 : end if
6728 : end do
6729 : end do
6730 :
6731 : ! Recompute occupancies and set fermie to zero.
6732 : ! FIXME: Possible problem here if the QP energies are not ordered!
6733 0 : call gwr%qp_ebands%update_occ(gwr%dtset%spinmagntarget, prtvol=gwr%dtset%prtvol, fermie_to_zero=.True.)
6734 : end if
6735 :
6736 0 : if (gwr%comm%me == 0) then
6737 : ! Master writes results to ab_out, std_out and GWR.nc
6738 0 : if (any(pade_solver_ierr /= 0)) then
6739 : ! Write warning if QP solver failed.
6740 0 : ierr = count(pade_solver_ierr /= 0)
6741 0 : call wrtout([ab_out, std_out], sjoin(" WARNING: QP solver failed for:", itoa(ierr), "states"))
6742 : end if
6743 :
6744 0 : call write_notations([std_out, ab_out])
6745 0 : do spin=1,gwr%nsppol
6746 0 : do ikcalc=1,gwr%nkcalc
6747 0 : ik_ibz = gwr%kcalc2ibz(ikcalc, 1)
6748 :
6749 0 : ydoc = yamldoc_open('GWR_SelfEnergy_ee', width=11, real_fmt='(3f8.3)')
6750 0 : call ydoc%add_real1d('kpoint', gwr%kcalc(:, ikcalc))
6751 0 : call ydoc%add_int('spin', spin, int_fmt="(i1)")
6752 0 : call ydoc%add_int('gwr_scf_iteration', gwr%scf_iteration)
6753 0 : call ydoc%add_string('gwr_task', gwr%dtset%gwr_task)
6754 :
6755 : ! Compute gaps assuming KS band indices.
6756 0 : band_val = gwr%ks_vbik(ik_ibz, spin)
6757 0 : nbc = gwr%bstop_ks(ikcalc, spin) - gwr%bstart_ks(ikcalc, spin) + 1
6758 0 : ib1 = gwr%bstart_ks(ikcalc, spin); ib2 = gwr%bstop_ks(ikcalc, spin)
6759 :
6760 0 : if (band_val >= gwr%bstart_ks(ikcalc, spin) .and. band_val + 1 <= gwr%bstop_ks(ikcalc, spin)) then
6761 0 : ibv = band_val - gwr%bstart_ks(ikcalc, spin) + 1
6762 0 : ks_gap = gwr%ks_ebands%eig(band_val+1, ik_ibz, spin) - gwr%ks_ebands%eig(band_val, ik_ibz, spin)
6763 :
6764 : ! This to detect a possible band inversion and compute qp_gaps accordingly.
6765 0 : band_inversion = .False.
6766 0 : call sort_rvals(nbc, real(qpz_ene(ib1:, ikcalc, spin)), iperm, sorted_qpe, tol=tol6)
6767 :
6768 0 : if (iperm(ibv) /= ibv .or. iperm(ibv + 1) /= ibv + 1) then
6769 0 : band_inversion = .True.
6770 0 : call ydoc%add_int('QP_VBM_band', iperm(ibv) + gwr%bstart_ks(ikcalc, spin) - 1)
6771 0 : call ydoc%add_int('QP_CBM_band', iperm(ibv+1) + gwr%bstart_ks(ikcalc, spin) - 1)
6772 0 : qp_gap = sorted_qpe(ibv+1) - sorted_qpe(ibv)
6773 0 : qp_pade_gap = qp_pade(band_val+1, ikcalc, spin) - qp_pade(band_val, ikcalc, spin)
6774 : else
6775 0 : call ydoc%add_int('QP_VBM_band', ibv + gwr%bstart_ks(ikcalc, spin) - 1)
6776 0 : call ydoc%add_int('QP_CBM_band', ibv+1 + gwr%bstart_ks(ikcalc, spin) - 1)
6777 0 : qp_gap = gwr%qp_ebands%eig(band_val+1, ik_ibz, spin) - gwr%qp_ebands%eig(band_val, ik_ibz, spin)
6778 0 : qp_pade_gap = qp_pade(band_val+1, ikcalc, spin) - qp_pade(band_val, ikcalc, spin)
6779 : end if
6780 0 : ABI_FREE(iperm)
6781 0 : ABI_FREE(sorted_qpe)
6782 :
6783 0 : call ydoc%add_real('KS_gap', ks_gap * Ha_eV)
6784 0 : call ydoc%add_real('QP_gap', qp_gap * Ha_eV)
6785 0 : call ydoc%add_real('Delta_QP_KS', (qp_gap - ks_gap) * Ha_eV)
6786 0 : ks_gaps(ikcalc, spin)= ks_gap
6787 0 : qpz_gaps(ikcalc, spin) = qp_gap
6788 0 : qp_pade_gaps(ikcalc, spin) = qp_pade_gap
6789 : end if
6790 :
6791 0 : call ydoc%open_tabular('data') !, tag='SigmaeeData')
6792 0 : write(msg, "(a5, *(a9))") "Band", "E0", "<VxcDFT>", "SigX", "SigC(E0)", "Z", "E-E0", "E-Eprev", "E", "Occ(E)"
6793 0 : call ydoc%add_tabular_line(msg)
6794 :
6795 0 : do band=gwr%bstart_ks(ikcalc, spin), gwr%bstop_ks(ikcalc, spin)
6796 0 : ibc = band - gwr%bstart_ks(ikcalc, spin) + 1
6797 0 : e0 = gwr%ks_ebands%eig(band, ik_ibz, spin)
6798 0 : qp_ene = gwr%qp_ebands%eig(band, ik_ibz, spin)
6799 0 : qp_ene_prev = gwr%qp_ebands_prev%eig(band, ik_ibz, spin)
6800 0 : if ( gwr%sig_diago) sigx = gwr%sigx_mat(band, 1, ikcalc, spin)
6801 0 : if (.not. gwr%sig_diago) sigx = gwr%sigx_mat(band, band, ikcalc, spin)
6802 0 : if (gwr%nspinor == 2) then
6803 0 : vxc_val = SUM(gwr%ks_me%vxcval(band, band, ik_ibz, :))
6804 : else
6805 0 : vxc_val = gwr%ks_me%vxcval(band, band, ik_ibz, spin)
6806 : end if
6807 :
6808 : write(msg,'(i5, *(f9.3))') &
6809 0 : band, & ! Band
6810 0 : e0 * Ha_eV, & ! E0
6811 0 : real(vxc_val)*Ha_eV, & ! <VxcDFT>
6812 0 : real(sigx) * Ha_eV, & ! SigX
6813 0 : real(sigc_e0(band, ikcalc, spin)) * Ha_eV, & ! SigC(E0)
6814 0 : real(ze0_kcalc(band, ikcalc, spin)), & ! Z
6815 0 : (real(qp_ene - e0)) * Ha_eV, & ! E-E0
6816 0 : real(qp_ene - qp_ene_prev) * Ha_eV, & ! E-Eprev
6817 0 : real(qp_ene) * Ha_eV, & ! E
6818 0 : gwr%qp_ebands%occ(band, ik_ibz, spin) ! Occ(E)
6819 0 : call ydoc%add_tabular_line(msg)
6820 : end do
6821 :
6822 0 : call ydoc%write_units_and_free([std_out, ab_out])
6823 : end do ! ikcalc
6824 : end do ! spin
6825 :
6826 : ! Print KS and QP gaps
6827 0 : call gwr%ks_gaps%print(units, header="Kohn-Sham gaps and band edges from IBZ mesh")
6828 :
6829 0 : new_gaps = gwr%qp_ebands%get_gaps(ierr)
6830 0 : write(msg,"(a,i0,a)")" QP gaps and band edges taking into account Sigma_nk corrections for ",gwr%nkcalc," k-points"
6831 0 : call new_gaps%print(units, header=msg)
6832 0 : if (ierr /= 0) then
6833 0 : ABI_WARNING("Cannot compute QP fundamental and direct gap (likely metal)")
6834 : end if
6835 0 : call new_gaps%free()
6836 :
6837 : ! Write results to text files.
6838 0 : if (open_file(strcat(gwr%dtfil%filnam_ds(4), '_SIGC_IT'), msg, newunit=unt_it, action="write") /= 0) then
6839 0 : ABI_ERROR(msg)
6840 : end if
6841 0 : write(unt_it, "(a)")"# Diagonal elements of Sigma_c(i tau, +/-) in atomic units"
6842 0 : write(unt_it, "(a)")"# tau Re/Im Sigma_c(+itau) Re/Im Sigma_c(-itau)"
6843 :
6844 0 : if (open_file(strcat(gwr%dtfil%filnam_ds(4), '_SIGXC_IW'), msg, newunit=unt_iw, action="write") /= 0) then
6845 0 : ABI_ERROR(msg)
6846 : end if
6847 0 : write(unt_iw, "(a)")"# Diagonal elements of Sigma_xc(i omega) in eV units"
6848 0 : write(unt_iw, "(a)")"# omega Re/Im Sigma_c(i omega)"
6849 :
6850 0 : if (open_file(strcat(gwr%dtfil%filnam_ds(4), '_SIGXC_RW'), msg, newunit=unt_rw, action="write") /= 0) then
6851 0 : ABI_ERROR(msg)
6852 : end if
6853 0 : write(unt_rw, "(a)")"# Diagonal elements of Sigma_xc(omega) in eV units and spectral function A(omega)"
6854 0 : write(unt_rw, "(a)")"# omega Re/Im Sigma_xc(omega), A(omega)"
6855 :
6856 0 : dat_units = [unt_it, unt_iw, unt_rw]
6857 0 : call write_units(dat_units, "# Fermi energy set to zero. Energies in eV")
6858 0 : call write_units(dat_units, sjoin("# nkcalc:", itoa(gwr%nkcalc), ", nsppol:", itoa(gwr%nsppol)))
6859 :
6860 : ! TODO: Improve file format. Add compatibility with gnuplot format for datasets?
6861 0 : do spin=1,gwr%nsppol
6862 0 : do ikcalc=1,gwr%nkcalc
6863 0 : ik_ibz = gwr%kcalc2ibz(ikcalc, 1)
6864 0 : call write_units(dat_units, sjoin("# kpt:", ktoa(gwr%kcalc(:, ikcalc)), "spin:", itoa(spin)))
6865 0 : do band=gwr%bstart_ks(ikcalc, spin), gwr%bstop_ks(ikcalc, spin)
6866 0 : ibc = band - gwr%bstart_ks(ikcalc, spin) + 1
6867 0 : e0 = gwr%ks_ebands%eig(band, ik_ibz, spin)
6868 0 : band2 = merge(1, band, gwr%sig_diago)
6869 0 : sigx = gwr%sigx_mat(band, band2, ikcalc, spin)
6870 :
6871 0 : call write_units(dat_units, sjoin("# band:", itoa(band), ", spin:", itoa(spin)))
6872 0 : call write_units(dat_units, sjoin("# sigx_ev:", ftoa(sigx * Ha_eV)))
6873 :
6874 0 : do itau=1,gwr%ntau
6875 : ! FIXME itau is not ordered
6876 : write(unt_it, "(*(es16.8))") &
6877 0 : gwr%tau_mesh(itau), &
6878 0 : c2r(sigc_it_mat(1, itau, band, band2, ikcalc, spin)), &
6879 0 : c2r(sigc_it_mat(2, itau, band, band2, ikcalc, spin))
6880 : write(unt_iw, "(*(es16.8))") &
6881 0 : gwr%iw_mesh(itau) * Ha_eV, &
6882 0 : (c2r(gwr%sigc_iw_mat(itau, band, band2, ikcalc, spin) + sigx)) * Ha_eV
6883 : end do
6884 :
6885 : ! Write Sigma_xc(omega) and A(omega)
6886 0 : rw_mesh = arth(e0 - gwr%wr_step * (gwr%nwr / 2), gwr%wr_step, gwr%nwr) * Ha_eV
6887 0 : do iw=1,gwr%nwr
6888 : write(unt_rw, "(*(es16.8))") &
6889 0 : rw_mesh(iw), &
6890 0 : c2r(sigxc_rw_diag(iw, band, ikcalc, spin)) * Ha_eV, &
6891 0 : spfunc_diag(iw, band, ikcalc, spin) / Ha_eV
6892 : end do
6893 : end do
6894 : end do
6895 : end do
6896 :
6897 0 : close(unt_it); close(unt_iw); close(unt_rw)
6898 :
6899 : ! ======================
6900 : ! Add results to GWR.nc
6901 : ! ======================
6902 0 : if (gwr%gwrnc_write) then
6903 0 : NCF_CHECK(nctk_open_modify(ncid, gwr%gwrnc_path, xmpi_comm_self))
6904 :
6905 : ! Define arrays with results.
6906 : ! TODO: Add matrix elements of vxc, have to trasfer data from vxcval to nkcalc packing
6907 0 : call ncwrite_sigmac(ncid)
6908 :
6909 : if (.true.) then
6910 0 : NCF_CHECK(nf90_def_grp(ncid, strcat("iter", itoa(gwr%scf_iteration)), iter_ncid))
6911 0 : call ncwrite_sigmac(iter_ncid)
6912 : end if
6913 :
6914 0 : NCF_CHECK(nf90_put_var(ncid, vid("scf_iteration"), gwr%scf_iteration))
6915 0 : NCF_CHECK(nf90_put_var(ncid, vid("gwr_completed"), 1))
6916 0 : NCF_CHECK(nf90_close(ncid))
6917 : end if
6918 : end if ! master
6919 :
6920 0 : ABI_FREE(sigc_it_mat)
6921 : !ABI_FREE(sigc_iw_mat)
6922 :
6923 0 : call cwtime_report(" gwr_build_sigmac:", cpu_all, wall_all, gflops_all)
6924 0 : call timab(1925, 2, tsec)
6925 :
6926 : contains
6927 0 : integer function vid(vname)
6928 : character(len=*),intent(in) :: vname
6929 0 : vid = nctk_idname(ncid, vname)
6930 : end function vid
6931 :
6932 0 : subroutine print_sigma_header()
6933 :
6934 0 : if (gwr%comm%me /= 0) return
6935 0 : if (gwr%use_supercell_for_sigma) then
6936 0 : call wrtout(std_out, sjoin(" Building Sigma_c in the supercell with FFT mesh:", ltoa(sc_ngfft(1:3))), pre_newlines=2)
6937 : else
6938 0 : call wrtout([std_out,ab_out], " Building Sigma_c with convolutions in k-space:", pre_newlines=2)
6939 : end if
6940 0 : call wrtout(std_out, sjoin(" gwr_np_kgts:", ltoa(gwr%dtset%gwr_np_kgts)))
6941 0 : call wrtout(std_out, sjoin(" ngkpt:", ltoa(gwr%ngkpt), " ngqpt:", ltoa(gwr%ngqpt)))
6942 0 : call wrtout(std_out, sjoin(" gwr_boxcutmin:", ftoa(gwr%dtset%gwr_boxcutmin)))
6943 0 : call wrtout(std_out, sjoin(" my_ntau:", itoa(gwr%my_ntau), "ntau:", itoa(gwr%ntau)))
6944 0 : call wrtout(std_out, sjoin(" my_nkbz:", itoa(gwr%my_nkbz), "nkibz:", itoa(gwr%nkibz)))
6945 0 : call wrtout(std_out, sjoin("- FFT uc_batch_size:", itoa(gwr%uc_batch_size)))
6946 0 : call wrtout(std_out, sjoin("- FFT sc_batch_size:", itoa(gwr%sc_batch_size)), do_flush=.True.)
6947 :
6948 : end subroutine print_sigma_header
6949 :
6950 0 : subroutine ncwrite_sigmac(myncid)
6951 : integer,intent(in) :: myncid
6952 : !logical,intent(in), optional :: mydefine
6953 : integer :: myncerr
6954 :
6955 : ! Write Sigma_c to GWR.nc
6956 0 : NCF_CHECK(nctk_set_datamode(myncid))
6957 : ! if (.not. present(mydefine) .or. mydefine) then
6958 : if (.true.) then
6959 : myncerr = nctk_def_arrays(myncid, [ &
6960 : nctkarr_t("e0_kcalc", "dp", "smat_bsize1, nkcalc, nsppol"), &
6961 : nctkarr_t("ze0_kcalc", "dp", "two, smat_bsize1, nkcalc, nsppol"), &
6962 : !nctkarr_t("vxc_kcalc", "dp", "two, smat_bsize1, nkcalc, nsppol"), &
6963 : nctkarr_t("qpz_ene", "dp", "two, smat_bsize1, nkcalc, nsppol"), &
6964 : nctkarr_t("qp_pade", "dp", "two, smat_bsize1, nkcalc, nsppol"), &
6965 : nctkarr_t("pade_solver_ierr", "int", "smat_bsize1, nkcalc, nsppol"), &
6966 : nctkarr_t("ks_gaps", "dp", "nkcalc, nsppol"), &
6967 : nctkarr_t("qpz_gaps", "dp", "nkcalc, nsppol"), &
6968 : nctkarr_t("qp_pade_gaps", "dp", "nkcalc, nsppol"), &
6969 : nctkarr_t("sigx_mat", "dp", "two, smat_bsize1, smat_bsize2, nkcalc, nsppol"), &
6970 : nctkarr_t("sigc_it_mat", "dp", "two, two, ntau, smat_bsize1, smat_bsize2, nkcalc, nsppol"), &
6971 : nctkarr_t("sigc_iw_mat", "dp", "two, ntau, smat_bsize1, smat_bsize2, nkcalc, nsppol"), &
6972 : nctkarr_t("sigxc_rw_diag", "dp", "two, nwr, smat_bsize1, nkcalc, nsppol"), &
6973 : nctkarr_t("spfunc_diag", "dp", "nwr, smat_bsize1, nkcalc, nsppol") &
6974 0 : ])
6975 0 : NCF_CHECK(myncerr)
6976 : end if
6977 : ! Write data.
6978 0 : NCF_CHECK(nctk_set_datamode(myncid))
6979 0 : NCF_CHECK(nf90_put_var(myncid, nctk_idname(myncid, "e0_kcalc"), e0_kcalc))
6980 0 : NCF_CHECK(nf90_put_var(myncid, nctk_idname(myncid, "ze0_kcalc"), c2r(ze0_kcalc)))
6981 0 : NCF_CHECK(nf90_put_var(myncid, nctk_idname(myncid, "sigx_mat"), c2r(gwr%sigx_mat(:,:,:,1:gwr%nsppol))))
6982 0 : NCF_CHECK(nf90_put_var(myncid, nctk_idname(myncid, "qpz_ene"), c2r(qpz_ene)))
6983 0 : NCF_CHECK(nf90_put_var(myncid, nctk_idname(myncid, "qp_pade"), c2r(qp_pade)))
6984 0 : NCF_CHECK(nf90_put_var(myncid, nctk_idname(myncid, "pade_solver_ierr"), pade_solver_ierr))
6985 0 : NCF_CHECK(nf90_put_var(myncid, nctk_idname(myncid, "ks_gaps"), ks_gaps))
6986 0 : NCF_CHECK(nf90_put_var(myncid, nctk_idname(myncid, "qpz_gaps"), qpz_gaps))
6987 0 : NCF_CHECK(nf90_put_var(myncid, nctk_idname(myncid, "qp_pade_gaps"), qp_pade_gaps))
6988 0 : NCF_CHECK(nf90_put_var(myncid, nctk_idname(myncid, "sigc_it_mat"), c2r(sigc_it_mat)))
6989 0 : NCF_CHECK(nf90_put_var(myncid, nctk_idname(myncid, "sigc_iw_mat"), c2r(gwr%sigc_iw_mat)))
6990 0 : NCF_CHECK(nf90_put_var(myncid, nctk_idname(myncid, "sigxc_rw_diag"), c2r(sigxc_rw_diag)))
6991 0 : NCF_CHECK(nf90_put_var(myncid, nctk_idname(myncid, "spfunc_diag"), spfunc_diag))
6992 :
6993 0 : end subroutine ncwrite_sigmac
6994 :
6995 : end subroutine gwr_build_sigmac
6996 : !!***
6997 :
6998 : !!****f* m_gwr/write_notations
6999 : !! NAME
7000 : !! write_notations
7001 : !!
7002 : !! FUNCTION
7003 : !! Write the meaning of the different columns.
7004 : !!
7005 : !! SOURCE
7006 :
7007 0 : subroutine write_notations(units)
7008 : integer,intent(in) :: units(:)
7009 : integer :: ii, unt
7010 :
7011 0 : do ii=1,size(units)
7012 0 : unt = units(ii)
7013 0 : write(unt,"(a)")repeat("=", 80)
7014 0 : write(unt,"(a)")" QP results (energies in eV)"
7015 0 : write(unt,"(a)")" Notations:"
7016 0 : write(unt,"(a)")" E0: Kohn-Sham energy"
7017 0 : write(unt,"(a)")" <VxcDFT>: Matrix elements of Vxc[n_val] without non-linear core correction (if any)"
7018 0 : write(unt,"(a)")" SigX: Matrix elements of Sigma_x"
7019 0 : write(unt,"(a)")" SigC(E0): Matrix elements of Sigma_c at E0"
7020 0 : write(unt,"(a)")" Z: Renormalization factor"
7021 0 : write(unt,"(a)")" E-E0: Difference between the QP and the KS energy."
7022 0 : write(unt,"(a)")" E-Eprev: Difference between QP energy at iteration i and i-1"
7023 0 : write(unt,"(a)")" E: Quasi-particle energy"
7024 0 : write(unt,"(a)")" Occ(E): Occupancy of QP state"
7025 : !write(unt,"(a)")" SE1(eKS): Real part of the self-energy computed at the KS energy, SE2 for imaginary part."
7026 0 : write(unt,"(a)")" "
7027 0 : write(unt,"(a)")" "
7028 : end do
7029 0 : end subroutine write_notations
7030 : !!***
7031 :
7032 : !----------------------------------------------------------------------
7033 :
7034 : !!****f* m_gwr/sig_braket_ur
7035 : !! NAME
7036 : !! sig_braket_ur
7037 : !!
7038 : !! FUNCTION
7039 : !! Integrate self-energy matrix elements in the unit cell.
7040 : !!
7041 : !! INPUTS
7042 : !!
7043 : !! OUTPUT
7044 : !!
7045 : !! SOURCE
7046 :
7047 0 : subroutine sig_braket_ur(sig_rpr, nfftsp, ur_bra_glob, ur_ket_glob, sigm_pm, loc_cwork)
7048 :
7049 : !Arguments ------------------------------------
7050 : type(__slkmat_t),intent(in) :: sig_rpr(2,2)
7051 : integer,intent(in) :: nfftsp
7052 : complex(gwp),intent(in) :: ur_bra_glob(nfftsp)
7053 : complex(gwp),intent(in) :: ur_ket_glob(nfftsp)
7054 :
7055 : complex(gwp),intent(out) :: sigm_pm(2)
7056 : complex(gwp),intent(inout) :: loc_cwork(sig_rpr(1,1)%size_local(2))
7057 :
7058 : !Local variables-------------------------------
7059 : integer :: ipm, ir1, il_r1, nrows, ncols, itim
7060 : !complex(gwp),allocatable :: loc_cwork(:)
7061 : ! *************************************************************************
7062 :
7063 : ABI_NVTX_START_RANGE(NVTX_GWR_BRAKET_UR)
7064 :
7065 : ! (r',r) with r' local and r-index PBLAS-distributed.
7066 0 : sigm_pm = czero_gw
7067 0 : do itim=1,2
7068 0 : do ipm=1,2
7069 0 : associate (rp_r => sig_rpr(itim,ipm))
7070 : ! Integrate over r'
7071 : !ABI_CHECK_IEQ(nfftsp, rp_r%size_local(1), "First dimension should be local to each MPI proc!")
7072 : !ABI_MALLOC(loc_cwork, (rp_r%size_local(2)))
7073 : !loc_cwork(:) = matmul(transpose(rp_r%buffer_cplx), ur_glob)
7074 :
7075 0 : nrows = rp_r%size_local(1); ncols = rp_r%size_local(2)
7076 0 : call xgemv('T', nrows, ncols, cone_gw, rp_r%buffer_cplx, nrows, ur_ket_glob, 1, czero_gw, loc_cwork, 1)
7077 :
7078 : ! Integrate over r. Note complex conjugate.
7079 0 : do il_r1=1,rp_r%size_local(2)
7080 0 : ir1 = rp_r%loc2gcol(il_r1)
7081 0 : if (itim == 1) then
7082 0 : sigm_pm(ipm) = sigm_pm(ipm) + conjg(ur_bra_glob(ir1)) * loc_cwork(il_r1)
7083 : else
7084 0 : sigm_pm(ipm) = sigm_pm(ipm) + ur_bra_glob(ir1) * conjg(loc_cwork(il_r1))
7085 : end if
7086 : end do
7087 : !ABI_FREE(loc_cwork)
7088 : end associate
7089 : end do
7090 : end do
7091 :
7092 : ABI_NVTX_END_RANGE()
7093 :
7094 0 : end subroutine sig_braket_ur
7095 : !!***
7096 :
7097 : !----------------------------------------------------------------------
7098 :
7099 : !!****f* m_gwr/gwr_rpa_energy
7100 : !! NAME
7101 : !! gwr_rpa_energy
7102 : !!
7103 : !! FUNCTION
7104 : !! Compute the correlated part of the total energy within ACFDT.
7105 : !!
7106 : !! INPUTS
7107 : !!
7108 : !! OUTPUT
7109 : !!
7110 : !! SOURCE
7111 :
7112 0 : subroutine gwr_rpa_energy(gwr)
7113 :
7114 : !Arguments ------------------------------------
7115 : class(gwr_t),target,intent(inout) :: gwr
7116 :
7117 : !Local variables-------------------------------
7118 : !scalars
7119 : integer,parameter :: master = 0
7120 : integer :: my_is, my_iqi, my_it, itau, spin, iq_ibz, ii, ierr, ig, ncut, icut, mat_size
7121 : integer :: il_g1, il_g2, ig1, ig2, npw_q, ig0, ncid, ncerr
7122 : logical :: q_is_gamma, print_time
7123 : real(dp) :: weight, qq_ibz(3), estep, aa, bb, rmsq, ecut_soft, damp, tsec(2)
7124 : real(dp) :: cpu_all, wall_all, gflops_all, cpu_q, wall_q, gflops_q, cpu_cut, wall_cut, gflops_cut
7125 : complex(dp) :: vcs_g1, vcs_g2
7126 : type(desc_t),pointer :: desc_q
7127 : character(len=500) :: msg
7128 : !arrays
7129 0 : type(__slkmat_t) :: chi_tmp, dummy_vec, chi_4diag
7130 : type(slk_processor_t) :: proc_4diag
7131 0 : real(gwp),allocatable :: eig(:)
7132 0 : real(dp),allocatable :: kin_qg(:), ec_rpa(:), ec_mp2(:), ecut_chi(:)
7133 : ! *************************************************************************
7134 :
7135 0 : call gwr%build_chi0_head_and_wings()
7136 0 : call gwr%build_green(free_ugb=.True.)
7137 0 : call gwr%build_tchi()
7138 :
7139 : ! Compute RPA energy for ncut cutoff energies in order to extrapolate for ecuteps --> oo
7140 : ! See also calc_rpa_functional in m_screening_driver
7141 0 : ncut = max(1, gwr%dtset%gwr_rpa_ncut) ! Usually 5
7142 0 : estep = -gwr%dtset%ecuteps * 0.05_dp
7143 :
7144 0 : call cwtime(cpu_all, wall_all, gflops_all, "start")
7145 0 : call timab(1928, 1, tsec)
7146 0 : call wrtout(std_out, sjoin(" Begin computation of RPA energy with gwr_rpa_ncut:", itoa(ncut), " ..."))
7147 0 : ABI_CHECK(gwr%tchi_space == "iomega", sjoin("tchi_space:", gwr%tchi_space, "!= iomega"))
7148 :
7149 0 : ABI_CALLOC(ec_rpa, (ncut))
7150 0 : ABI_CALLOC(ec_mp2, (ncut))
7151 0 : ABI_MALLOC(ecut_chi, (ncut))
7152 0 : ecut_chi = arth(gwr%dtset%ecuteps + tol12, estep, ncut)
7153 :
7154 : ! Polarizability has been summed over spins inside build_tchi.
7155 : ! The loop over spins is needed to parallelize the loop over my_iqi if nsppol == 2.
7156 0 : do my_is=1,gwr%my_nspins
7157 0 : spin = gwr%my_spins(my_is)
7158 0 : if (gwr%spin_comm%nproc == 1 .and. spin == 2) cycle
7159 :
7160 0 : do my_iqi=1,gwr%my_nqibz
7161 0 : if (gwr%spin_comm%skip(my_iqi)) cycle
7162 0 : print_time = gwr%comm%me == 0 .and. (my_iqi < LOG_MODK .or. mod(my_iqi, LOG_MODK) == 0)
7163 0 : if (print_time) call cwtime(cpu_q, wall_q, gflops_q, "start")
7164 :
7165 0 : iq_ibz = gwr%my_qibz_inds(my_iqi); qq_ibz = gwr%qibz(:, iq_ibz)
7166 0 : q_is_gamma = normv(qq_ibz, gwr%cryst%gmet, "G") < GW_TOLQ0
7167 : !if (q_is_gamma) then
7168 : ! call wrtout([std_out, ab_out], "RPA: Ignoring q==0"); cycle
7169 : !end if
7170 :
7171 : ! iq_ibz might be replicated inside gwr%kpt_comm.
7172 0 : if (.not. gwr%itreat_iqibz(iq_ibz)) cycle
7173 :
7174 0 : desc_q => gwr%tchi_desc_qibz(iq_ibz)
7175 0 : ABI_CHECK(desc_q%kin_sorted, "g-vectors are not sorted by |q+g|^2/2 !")
7176 0 : npw_q = desc_q%npw; ig0 = desc_q%ig0
7177 :
7178 0 : ABI_MALLOC(kin_qg, (npw_q))
7179 0 : do ig=1,npw_q
7180 0 : kin_qg(ig) = half * normv(qq_ibz + desc_q%gvec(:,ig), gwr%cryst%gmet, "G") ** 2
7181 : end do
7182 :
7183 0 : do my_it=1,gwr%my_ntau
7184 0 : itau = gwr%my_itaus(my_it)
7185 0 : associate (tchi => gwr%tchi_qibz(iq_ibz, itau, spin))
7186 0 : if (my_it == 1) then
7187 : ! Allocate workspace. NB: npw_q is the total number of PWs for this q.
7188 0 : call tchi%copy(chi_tmp)
7189 : !ABI_CHECK_IEQ(npw_q, tchi%sizeb_global(1), "npw_q")
7190 0 : ABI_MALLOC(eig, (npw_q))
7191 : end if
7192 :
7193 0 : do icut=1,ncut
7194 0 : call cwtime(cpu_cut, wall_cut, gflops_cut, "start")
7195 :
7196 : ! Damp Coulomb kernel in order to have smooth E(V).
7197 : ! See also https://www.vasp.at/wiki/index.php/ENCUTGWSOFT
7198 : ! and Harl's PhD thesis available at: https://utheses.univie.ac.at/detail/2259
7199 0 : ecut_soft = 0.8_dp * ecut_chi(icut)
7200 :
7201 : ! TODO: Contribution due to the head for q --> 0 is ignored.
7202 : ! This is not optimal but consistent with calc_rpa_functional
7203 0 : do il_g2=1,tchi%size_local(2)
7204 : !ig2 = mod(tchi%loc2gcol(il_g2) - 1, desc_q%npw) + 1
7205 0 : ig2 = tchi%loc2gcol(il_g2)
7206 0 : damp = one
7207 : !if (kin_qg(ig2) > ecut_soft) then
7208 : ! damp = sqrt(half * (one + cos(pi * (kin_qg(ig2) - ecut_soft) / (ecut_chi(icut) - ecut_soft))))
7209 : !end if
7210 0 : vcs_g2 = desc_q%vc_sqrt_eps(ig2) * damp
7211 0 : if (q_is_gamma .and. ig2 == ig0) vcs_g2 = zero
7212 :
7213 0 : do il_g1=1,tchi%size_local(1)
7214 : !ig1 = mod(tchi%loc2grow(il_g1) - 1, desc_q%npw) + 1
7215 0 : ig1 = tchi%loc2grow(il_g1)
7216 0 : damp = one
7217 : !if (kin_qg(ig1) > ecut_soft) then
7218 : ! damp = sqrt(half * (one + cos(pi * (kin_qg(ig1) - ecut_soft) / (ecut_chi(icut) - ecut_soft))))
7219 : !end if
7220 0 : vcs_g1 = desc_q%vc_sqrt_eps(ig1) * damp
7221 0 : if (q_is_gamma .and. ig1 == ig0) vcs_g1 = zero
7222 :
7223 0 : chi_tmp%buffer_cplx(il_g1, il_g2) = tchi%buffer_cplx(il_g1, il_g2) * vcs_g1 * vcs_g2
7224 : end do
7225 : end do
7226 :
7227 : ! Diagonalize sub-matrix and perform integration in imaginary frequency.
7228 : ! Eq (6) in 10.1103/PhysRevB.81.115126
7229 : ! NB: have to build chi_tmp inside loop over icut as matrix is destroyed by pzheev.
7230 0 : mat_size = bisect(kin_qg, ecut_chi(icut))
7231 :
7232 : ! Change size block and, if possible, use 2D rectangular grid of processors for diagonalization
7233 0 : call proc_4diag%init(chi_tmp%processor%comm)
7234 0 : call chi_tmp%change_size_blocs(chi_4diag, processor=proc_4diag)
7235 : !call chi_4diag%copy(dummy_vec)
7236 0 : call chi_4diag%heev("N", "U", dummy_vec, eig, mat_size=mat_size)
7237 0 : call chi_4diag%free()
7238 : !call dummy_vec%free()
7239 0 : call proc_4diag%free()
7240 :
7241 : ! TODO: ELPA
7242 : !call compute_eigen_problem(processor, matrix, results, eigen, comm, istwf_k, nev)
7243 :
7244 0 : if (xmpi_comm_rank(chi_tmp%processor%comm) == 0) then
7245 0 : weight = gwr%wtq(iq_ibz) * gwr%iw_wgs(itau) / two_pi
7246 0 : do ii=1,mat_size
7247 0 : ec_rpa(icut) = ec_rpa(icut) + weight * (log(one - eig(ii)) + eig(ii))
7248 : ! second order Moeller Plesset.
7249 0 : ec_mp2(icut) = ec_mp2(icut) - weight * eig(ii) ** 2 / two
7250 : !if (eig(ii) > zero) then
7251 : ! write(msg, "(a, es16.8)")"Positive eigenvalue:", eig(ii)
7252 : ! ABI_ERROR(msg)
7253 : !end if
7254 : end do
7255 : end if
7256 :
7257 0 : write(msg,'(4x,2(a,i0),a)')"icut [", icut, "/", ncut, "]"
7258 0 : call cwtime_report(msg, cpu_cut, wall_cut, gflops_cut)
7259 : end do ! icut
7260 :
7261 0 : if (my_it == gwr%my_ntau) then
7262 : ! Free workspace
7263 0 : call chi_tmp%free()
7264 0 : ABI_FREE(eig)
7265 : end if
7266 : end associate
7267 : end do ! my_it
7268 :
7269 0 : ABI_FREE(kin_qg)
7270 0 : if (print_time) then
7271 0 : write(msg,'(4x,2(a,i0),a)')"My iqi [", my_iqi, "/", gwr%my_nqibz, "]"
7272 0 : call cwtime_report(msg, cpu_q, wall_q, gflops_q)
7273 : end if
7274 : end do ! my_iqi
7275 : end do ! my_is
7276 :
7277 : ! Collect results on the master node.
7278 0 : call xmpi_sum_master(ec_rpa, master, gwr%comm%value, ierr)
7279 0 : call xmpi_sum_master(ec_mp2, master, gwr%comm%value, ierr)
7280 :
7281 0 : if (gwr%comm%me == master) then
7282 : ! Print results to ab_out.
7283 : ! TODO: Add metadata: nband, nqbz...
7284 0 : write(ab_out, "(4a16)")"ecut_chi", "ecut_chi^(-3/2)", "RPA Ec (eV)", "RPA Ec (Ha)"
7285 0 : do icut=ncut,1,-1
7286 0 : write(ab_out, "(*(es16.8))") ecut_chi(icut), ecut_chi(icut) ** (-three/two), ec_rpa(icut) * Ha_eV, ec_rpa(icut)
7287 : end do
7288 0 : if (ncut > 1) then
7289 : ! Add last line with extrapolated value.
7290 0 : rmsq = linfit(ncut, ecut_chi(:) ** (-three/two), ec_rpa, aa, bb)
7291 0 : write(ab_out, "(2a16,*(es16.8))") "oo", "0", bb * Ha_eV, bb
7292 : end if
7293 :
7294 : ! ======================
7295 : ! Add results to GWR.nc
7296 : ! ======================
7297 0 : if (gwr%gwrnc_write) then
7298 0 : NCF_CHECK(nctk_open_modify(ncid, gwr%gwrnc_path, xmpi_comm_self))
7299 0 : ncerr = nctk_def_dims(ncid, [nctkdim_t("ncut", ncut)], defmode=.True.)
7300 0 : NCF_CHECK(ncerr)
7301 :
7302 : ncerr = nctk_def_arrays(ncid, [ &
7303 : nctkarr_t("ecut_chi", "dp", "ncut"), &
7304 : nctkarr_t("ec_rpa_ecut", "dp", "ncut"), &
7305 : nctkarr_t("ec_mp2_ecut", "dp", "ncut") &
7306 0 : ])
7307 0 : NCF_CHECK(ncerr)
7308 :
7309 : ! Write data.
7310 0 : NCF_CHECK(nctk_set_datamode(ncid))
7311 0 : NCF_CHECK(nf90_put_var(ncid, vid("ecut_chi"), ecut_chi))
7312 0 : NCF_CHECK(nf90_put_var(ncid, vid("ec_rpa_ecut"), ec_rpa))
7313 0 : NCF_CHECK(nf90_put_var(ncid, vid("ec_mp2_ecut"), ec_mp2))
7314 : end if
7315 : end if ! master
7316 :
7317 0 : ABI_FREE(ec_rpa)
7318 0 : ABI_FREE(ec_mp2)
7319 0 : ABI_FREE(ecut_chi)
7320 :
7321 0 : call cwtime_report(" gwr_rpa_energy:", cpu_all, wall_all, gflops_all)
7322 0 : call timab(1928, 2, tsec)
7323 :
7324 : contains
7325 0 : integer function vid(vname)
7326 : character(len=*),intent(in) :: vname
7327 0 : vid = nctk_idname(ncid, vname)
7328 : end function vid
7329 :
7330 : end subroutine gwr_rpa_energy
7331 : !!***
7332 :
7333 : !----------------------------------------------------------------------
7334 :
7335 : !!****f* m_gwr/gwr_run_g0w0
7336 : !! NAME
7337 : !! gwr_run_g0w0
7338 : !!
7339 : !! FUNCTION
7340 : !! Driver to compute QP energies within the G0W0 approximation and minimax meshes along the imaginary axis.
7341 : !!
7342 : !! INPUTS
7343 : !! [free_ugb]: True if array with empty KS states should be freed as soon as possibile. Default: True
7344 : !!
7345 : !! OUTPUT
7346 : !!
7347 : !! SOURCE
7348 :
7349 0 : subroutine gwr_run_g0w0(gwr, free_ugb)
7350 :
7351 : !Arguments ------------------------------------
7352 : class(gwr_t),intent(inout) :: gwr
7353 : logical,optional,intent(in) :: free_ugb
7354 :
7355 : !Local variables-------------------------------
7356 : logical :: free_ugb__
7357 : ! *************************************************************************
7358 :
7359 : ! Use ugb wavefunctions and the Lehmann representation to compute head/wings and Sigma_x matrix elements.
7360 0 : call gwr%build_chi0_head_and_wings()
7361 0 : call gwr%build_sigxme()
7362 :
7363 : ! Now compute G(itau) from ugb and start the GWR algorithm.
7364 0 : free_ugb__ = .True.; if (present(free_ugb)) free_ugb__ = free_ugb
7365 0 : call gwr%build_green(free_ugb=free_ugb__)
7366 0 : call gwr%build_tchi()
7367 0 : call gwr%build_wc()
7368 0 : call gwr%build_sigmac()
7369 :
7370 0 : end subroutine gwr_run_g0w0
7371 : !!***
7372 :
7373 : !!****f* m_gwr/gwr_run_chi0
7374 : !! NAME
7375 : !! gwr_run_chi0
7376 : !!
7377 : !! FUNCTION
7378 : !! Driver to compute CHI0 along the imaginary axis.
7379 : !!
7380 : !! INPUTS
7381 : !! [free_ugb]: True if array with empty KS states should freed as soon as possibile. Default: True
7382 : !!
7383 : !! OUTPUT
7384 : !!
7385 : !! SOURCE
7386 :
7387 0 : subroutine gwr_run_chi0(gwr, free_ugb)
7388 :
7389 : !Arguments ------------------------------------
7390 : class(gwr_t),intent(inout) :: gwr
7391 : logical,optional,intent(in) :: free_ugb
7392 :
7393 : !Local variables-------------------------------
7394 : logical :: free_ugb__
7395 : ! *************************************************************************
7396 :
7397 : ! Use ugb wavefunctions and the Lehmann representation to compute head/wings.
7398 0 : call gwr%build_chi0_head_and_wings()
7399 :
7400 : ! Now compute G(itau) from ugb and start the GWR algorithm for chi.
7401 0 : free_ugb__ = .True.; if (present(free_ugb)) free_ugb__ = free_ugb
7402 0 : call gwr%build_green(free_ugb=free_ugb__)
7403 0 : call gwr%build_tchi()
7404 :
7405 0 : end subroutine gwr_run_chi0
7406 : !!***
7407 :
7408 : !----------------------------------------------------------------------
7409 :
7410 : !!****f* m_gwr/gwr_run_energy_scf
7411 : !! NAME
7412 : !! gwr_run_energy_scf
7413 : !!
7414 : !! FUNCTION
7415 : !! Compute QP energies within energy-only self-consistent GW approximation
7416 : !! and minimax meshes along the imaginary axis.
7417 : !!
7418 : !! INPUTS
7419 : !!
7420 : !! OUTPUT
7421 : !!
7422 : !! SOURCE
7423 :
7424 0 : subroutine gwr_run_energy_scf(gwr)
7425 :
7426 : !Arguments ------------------------------------
7427 : class(gwr_t),intent(inout) :: gwr
7428 :
7429 : !Local variables-------------------------------
7430 : integer,parameter :: master = 0
7431 : integer :: units(2)
7432 : logical :: converged
7433 : character(len=500) :: msg
7434 : ! *************************************************************************
7435 :
7436 : ! TODO:
7437 : ! To implement restart capabilities we need to read scf_iteration, qp_ebands and gwr_task from GWR.nc
7438 : ! build_sigmac should be responsible for writing checkpoint data with qp_ebands at each iteration.
7439 0 : units = [std_out, ab_out]
7440 :
7441 0 : ABI_CHECK_IEQ(gwr%nkcalc, gwr%nkibz, "For energy-only GW, one should include all k-points in the IBZ")
7442 :
7443 0 : select case (gwr%dtset%gwr_task)
7444 : case ("EGEW")
7445 0 : converged = .False.
7446 0 : call wrtout(units, " Begin energy-only self-consistency in both G and W (EGEW)")
7447 0 : do while (.not. converged .and. gwr%scf_iteration <= gwr%dtset%gwr_nstep)
7448 0 : call gwr%run_g0w0(free_ugb=.False.)
7449 0 : gwr%scf_iteration = gwr%scf_iteration + 1
7450 0 : call gwr%check_scf_cycle(converged)
7451 : end do
7452 :
7453 : case ("EGW0")
7454 0 : call wrtout(units, " Begin energy-only self-consistency in G (EGW0)")
7455 0 : call gwr%run_g0w0(free_ugb=.False.)
7456 0 : converged = .False.
7457 0 : do while (.not. converged .and. gwr%scf_iteration <= gwr%dtset%gwr_nstep)
7458 0 : gwr%scf_iteration = gwr%scf_iteration + 1
7459 0 : call gwr%build_green(free_ugb=.False.)
7460 0 : call gwr%build_sigxme() ! NB: This should not change in semiconductors
7461 0 : call gwr%build_sigmac()
7462 0 : call gwr%check_scf_cycle(converged)
7463 : end do
7464 :
7465 : case ("G0EW")
7466 : ! This is more difficult to implement as we need to store G0 and eG
7467 : ! and then use G only for chi and not in Sigma
7468 0 : call wrtout(units, " Begin energy-only self-consistency in W (G0EW)")
7469 0 : ABI_ERROR("G0EW is not yet implemented")
7470 0 : call gwr%run_g0w0(free_ugb=.False.)
7471 0 : converged = .False.
7472 0 : do while (.not. converged .and. gwr%scf_iteration <= gwr%dtset%gwr_nstep)
7473 0 : gwr%scf_iteration = gwr%scf_iteration + 1
7474 : !call gwr%build_green(free_ugb=.False.)
7475 0 : call gwr%build_chi0_head_and_wings()
7476 0 : call gwr%build_tchi()
7477 0 : call gwr%build_wc()
7478 0 : call gwr%build_sigmac()
7479 0 : call gwr%check_scf_cycle(converged)
7480 : end do
7481 :
7482 : case default
7483 0 : ABI_ERROR(sjoin("Invalid gwr_task:", gwr%dtset%gwr_task))
7484 : end select
7485 :
7486 0 : if (gwr%comm%me == master) then
7487 0 : if (converged) then
7488 : write(msg, "(1x,4a,i0,a,f8.3,a)") &
7489 0 : trim(gwr%dtset%gwr_task), " self-consistent loop:", ch10, &
7490 0 : " Convergence achieved at iteration: ", gwr%scf_iteration, &
7491 0 : " with gwr_tolqpe: ",gwr%dtset%gwr_tolqpe * Ha_meV, " (meV)"
7492 0 : call wrtout(units, msg)
7493 : else
7494 : write(msg, "(1x,4a,f8.3,3a,i0,a)") &
7495 0 : trim(gwr%dtset%gwr_task), " self-consistent loop:", ch10, &
7496 0 : " WARNING: Could not converge with gwr_tolqpe: ",gwr%dtset%gwr_tolqpe * Ha_meV, " (meV)", ch10, &
7497 0 : " after: ", gwr%dtset%gwr_nstep, " steps"
7498 0 : call wrtout(units, msg)
7499 : end if
7500 : end if
7501 :
7502 0 : end subroutine gwr_run_energy_scf
7503 : !!***
7504 :
7505 : !----------------------------------------------------------------------
7506 :
7507 : !!****f* m_gwr/check_scf_cyle
7508 : !! NAME
7509 : !! check_scf_cycle
7510 : !!
7511 : !! FUNCTION
7512 : !!
7513 : !! INPUTS
7514 : !!
7515 : !! OUTPUT
7516 : !!
7517 : !! SOURCE
7518 :
7519 0 : subroutine gwr_check_scf_cycle(gwr, converged)
7520 :
7521 : !Arguments ------------------------------------
7522 : class(gwr_t),intent(in) :: gwr
7523 : logical,intent(out) :: converged
7524 :
7525 : !Local variables-------------------------------
7526 : integer,parameter :: master = 0
7527 : integer :: spin, ikcalc, ik_ibz, band, ib, jb
7528 : character(len=500) :: msg
7529 0 : real(dp) :: max_adiff, adiff(gwr%qp_ebands%mband)
7530 : integer :: units(2)
7531 : ! *************************************************************************
7532 :
7533 0 : max_adiff = -one; converged = .True.; units = [std_out, ab_out]
7534 :
7535 0 : if (gwr%comm%me == master) then
7536 0 : call wrtout(units, sjoin(" Checking for convergence at iteration:", itoa(gwr%scf_iteration)))
7537 : end if
7538 :
7539 : associate (now => gwr%qp_ebands, prev => gwr%qp_ebands_prev)
7540 0 : do spin=1,gwr%nsppol
7541 0 : do ikcalc=1,gwr%nkcalc ! TODO: Should be spin dependent!
7542 : ! Compute max abs difference between QP at iteration i and i-1.
7543 0 : ik_ibz = gwr%kcalc2ibz(ikcalc, 1)
7544 0 : ib = gwr%bstart_ks(ikcalc, spin); jb = gwr%bstop_ks(ikcalc, spin)
7545 0 : adiff = zero; adiff(ib:jb) = abs(now%eig(ib:jb, ik_ibz, spin) - prev%eig(ib:jb, ik_ibz, spin))
7546 0 : band = maxloc(adiff, dim=1)
7547 0 : max_adiff = max(max_adiff, adiff(band))
7548 0 : if (adiff(band) > gwr%dtset%gwr_tolqpe) converged = .False.
7549 0 : if (gwr%comm%me == master) then
7550 : ! Write info
7551 0 : write(msg, "(a,i0,1x,2a,i0)") " For k-point: ", ik_ibz, trim(ktoa(now%kptns(:,ik_ibz))),", spin: ", spin
7552 0 : call wrtout(units, msg)
7553 0 : write(msg, "(4x,a,es12.5,a,i0)")"max(abs(E_i - E_{i-1})): ", adiff(band) * Ha_meV, " (meV) for band: ", band
7554 0 : call wrtout(units, msg)
7555 : end if
7556 : end do
7557 : end do
7558 : end associate
7559 :
7560 : ! Make sure that all MPI procs agree on this!
7561 0 : call xmpi_land(converged, gwr%comm%value)
7562 :
7563 0 : if (gwr%comm%me == master) then
7564 0 : write(msg, "(a,i0,a)") "QP gaps at iteration: ",gwr%scf_iteration," (Fermi energy set to zero)"
7565 0 : call gwr%qp_ebands%print_gaps(units, header=msg)
7566 0 : if (.not. converged) then
7567 0 : call wrtout(units," Not converged --> start new iteration ...")
7568 : !else
7569 : ! call wrtout(units, sjoin(" Convergence achieved at iteration", itoa(gwr%scf_iteration)))
7570 : end if
7571 : ! TODO: Increment scf_iteration in GWR.nc
7572 : end if
7573 :
7574 0 : end subroutine gwr_check_scf_cycle
7575 : !!***
7576 :
7577 : !----------------------------------------------------------------------
7578 :
7579 : !!****f* m_gwr/gwr_ncwrite_tchi_wc
7580 : !! NAME
7581 : !! gwr_ncwrite_tchi_wc
7582 : !!
7583 : !! FUNCTION
7584 : !! Write tchi or wc to netcdf file
7585 : !!
7586 : !! INPUTS
7587 : !! what: "tchi" or "wc"
7588 : !! wt_space: "omega" or "tau"
7589 : !!
7590 : !! OUTPUT
7591 : !!
7592 : !! SOURCE
7593 :
7594 0 : subroutine gwr_ncwrite_tchi_wc(gwr, what, wt_space, keep_file, filepath)
7595 :
7596 : !Arguments ------------------------------------
7597 : class(gwr_t),target,intent(in) :: gwr
7598 : logical,intent(in) :: keep_file
7599 : character(len=*),intent(in) :: what, wt_space, filepath
7600 :
7601 : !Local variables-------------------------------
7602 : !scalars
7603 : integer,parameter :: master = 0
7604 : integer :: my_is, my_iqi, my_it, spin, iq_ibz, itau, npwtot_q, my_ncols, my_gcol_start, ncid, ncerr, var_id !, ierr
7605 : real(dp) :: cpu, wall, gflops
7606 : !arrays
7607 0 : real(dp), contiguous, pointer :: fptr(:,:,:)
7608 0 : type(__slkmat_t), pointer :: mats(:)
7609 : ! *************************************************************************
7610 :
7611 : ! Cannot reuse SCR.nc/SUSC.nc fileformat as:
7612 : ! - hscr_new requires ep% instance
7613 : ! - old file formats assume Gamma-centered G vectors.
7614 :
7615 0 : call cwtime(cpu, wall, gflops, "start")
7616 :
7617 0 : if (gwr%comm%me == master) then
7618 0 : call wrtout(std_out, sjoin(" Writing", what, "with wt_space:", wt_space, "to:", filepath))
7619 0 : if (keep_file) then
7620 0 : NCF_CHECK(nctk_open_modify(ncid, filepath, xmpi_comm_self))
7621 : else
7622 0 : NCF_CHECK(nctk_open_create(ncid, filepath, xmpi_comm_self))
7623 : end if
7624 :
7625 : ! Write structure and qp_ebands
7626 0 : NCF_CHECK(gwr%cryst%ncwrite(ncid))
7627 0 : NCF_CHECK(gwr%qp_ebands%ncwrite(ncid))
7628 :
7629 : ! Add dimensions.
7630 : ncerr = nctk_def_dims(ncid, [ &
7631 : nctkdim_t("nsppol", gwr%nsppol), nctkdim_t("ntau", gwr%ntau), nctkdim_t("mpw", gwr%tchi_mpw), &
7632 : nctkdim_t("nqibz", gwr%nqibz), nctkdim_t("nqbz", gwr%nqbz)], &
7633 0 : defmode=.True.)
7634 0 : NCF_CHECK(ncerr)
7635 :
7636 : ncerr = nctk_def_iscalars(ncid, [character(len=nctk_slen) :: &
7637 : "gwr_completed" &
7638 0 : ])
7639 :
7640 : ! Define arrays with results.
7641 : ! TODO: Add metadata for mats: spin sum, vc cutoff, t/w mesh, handle nspinor 2
7642 : ncerr = nctk_def_arrays(ncid, [ &
7643 : nctkarr_t("ngkpt", "int", "three"), &
7644 : nctkarr_t("ngqpt", "int", "three"), &
7645 : nctkarr_t("qibz", "dp", "three, nqibz"), &
7646 : nctkarr_t("wtq", "dp", "nqibz"), &
7647 : nctkarr_t("tau_mesh", "dp", "ntau"), &
7648 : nctkarr_t("tau_wgs", "dp", "ntau"), &
7649 : nctkarr_t("iw_mesh", "dp", "ntau"), &
7650 : nctkarr_t("iw_wgs", "dp", "ntau"), &
7651 : nctkarr_t("gvecs", "int", "three, mpw, nqibz"), &
7652 : nctkarr_t("chinpw_qibz", "int", "nqibz") &
7653 0 : ])
7654 0 : NCF_CHECK(ncerr)
7655 :
7656 0 : if (wt_space == "omega") then
7657 0 : NCF_CHECK(nctk_def_arrays(ncid, [nctkarr_t("mats_w", "dp", "two, mpw, mpw, ntau, nqibz, nsppol")]))
7658 0 : else if (wt_space == "tau") then
7659 0 : NCF_CHECK(nctk_def_arrays(ncid, [nctkarr_t("mats_tau", "dp", "two, mpw, mpw, ntau, nqibz, nsppol")]))
7660 : end if
7661 :
7662 : ! Write global arrays.
7663 0 : NCF_CHECK(nctk_set_datamode(ncid))
7664 :
7665 : ncerr = nctk_write_iscalars(ncid, [character(len=nctk_slen) :: &
7666 : "gwr_completed"], &
7667 0 : [0])
7668 0 : NCF_CHECK(ncerr)
7669 :
7670 0 : NCF_CHECK(nf90_put_var(ncid, vid("ngkpt"), gwr%ngkpt))
7671 0 : NCF_CHECK(nf90_put_var(ncid, vid("ngqpt"), gwr%ngqpt))
7672 0 : NCF_CHECK(nf90_put_var(ncid, vid("qibz"), gwr%qibz))
7673 0 : NCF_CHECK(nf90_put_var(ncid, vid("wtq"), gwr%wtq))
7674 0 : NCF_CHECK(nf90_put_var(ncid, vid("tau_mesh"), gwr%tau_mesh))
7675 0 : NCF_CHECK(nf90_put_var(ncid, vid("tau_wgs"), gwr%tau_wgs))
7676 0 : NCF_CHECK(nf90_put_var(ncid, vid("iw_mesh"), gwr%iw_mesh))
7677 0 : NCF_CHECK(nf90_put_var(ncid, vid("iw_wgs"), gwr%iw_wgs))
7678 0 : NCF_CHECK(nf90_put_var(ncid, vid("chinpw_qibz"), gwr%chinpw_qibz))
7679 0 : NCF_CHECK(nf90_close(ncid))
7680 : end if
7681 :
7682 0 : call xmpi_barrier(gwr%comm%value)
7683 :
7684 : ! Reopen the file in gwr%comm.
7685 0 : NCF_CHECK(nctk_open_modify(ncid, filepath, gwr%comm%value))
7686 :
7687 0 : if (wt_space == "omega") then
7688 0 : NCF_CHECK(nctk_prepare_mpiio(ncid, "mats_w"))
7689 0 : else if (wt_space == "tau") then
7690 0 : NCF_CHECK(nctk_prepare_mpiio(ncid, "mats_tau"))
7691 : end if
7692 :
7693 0 : do my_is=1,gwr%my_nspins
7694 0 : spin = gwr%my_spins(my_is)
7695 0 : do my_iqi=1,gwr%my_nqibz
7696 0 : iq_ibz = gwr%my_qibz_inds(my_iqi)
7697 :
7698 : ! The same q-point in the IBZ might be stored on different pools.
7699 : ! To avoid writing the same array multiple times, we use itreat_qibz
7700 : ! to select the procs inside gwr%kpt_comm who are gonna write this iq_ibz q-point.
7701 0 : if (.not. gwr%itreat_iqibz(iq_ibz)) cycle
7702 :
7703 0 : associate (desc_q => gwr%tchi_desc_qibz(iq_ibz))
7704 0 : npwtot_q = desc_q%npw
7705 :
7706 0 : if (spin == 1 .and. gwr%gtau_comm%me == 0) then
7707 : ! Write all G-vectors for this q
7708 0 : NCF_CHECK(nf90_put_var(ncid, vid("gvecs"), desc_q%gvec, start=[1,1,iq_ibz], count=[3,npwtot_q,1]))
7709 : end if
7710 :
7711 0 : mats => null()
7712 0 : if (what == "tchi") mats => gwr%tchi_qibz(iq_ibz, :, spin)
7713 0 : if (what == "wc") mats => gwr%wc_qibz(iq_ibz, :, spin)
7714 0 : ABI_CHECK(associated(mats), sjoin("Invalid value for what:", what))
7715 :
7716 0 : do my_it=1,gwr%my_ntau
7717 0 : itau = gwr%my_itaus(my_it)
7718 :
7719 : ! FIXME: Assuming PBLAS matrix distributed in contiguous blocks along the column index.
7720 : ! This part must be changed if we use round robin distribution.
7721 0 : my_ncols = mats(itau)%size_local(2)
7722 0 : my_gcol_start = mats(itau)%loc2gcol(1)
7723 :
7724 : ! FIXME: This is wrong if spc
7725 : !call c_f_pointer(c_loc(mats(itau)%buffer_cplx), fptr, shape=[2, npwtot_q, my_ncols])
7726 0 : ABI_MALLOC(fptr, (2, npwtot_q, my_ncols))
7727 0 : fptr(1,:,:) = dble(mats(itau)%buffer_cplx)
7728 0 : fptr(2,:,:) = aimag(mats(itau)%buffer_cplx)
7729 :
7730 0 : if (wt_space == "omega") then
7731 0 : var_id = vid("mats_w")
7732 0 : else if (wt_space == "tau") then
7733 0 : var_id = vid("mats_tau")
7734 : else
7735 0 : ABI_ERROR(sjoin("Invalid wt_space:", wt_space))
7736 : end if
7737 :
7738 : ncerr = nf90_put_var(ncid, var_id, fptr, &
7739 : start=[1, 1, my_gcol_start, itau, iq_ibz, spin], &
7740 0 : count=[2, npwtot_q, my_ncols, 1, 1, 1])
7741 : !stride=[1, gwr%g_comm%nproc, 1, 1, 1])
7742 0 : ABI_FREE(fptr)
7743 0 : NCF_CHECK(ncerr)
7744 : end do
7745 : end associate
7746 : end do ! my_iqi
7747 : end do ! my_is
7748 :
7749 0 : NCF_CHECK(nf90_put_var(ncid, vid("gwr_completed"), 1))
7750 0 : NCF_CHECK(nf90_close(ncid))
7751 0 : call cwtime_report(" gwr_ncwrite_tchi_wc:", cpu, wall, gflops)
7752 :
7753 : contains
7754 0 : integer function vid(vname)
7755 : character(len=*),intent(in) :: vname
7756 0 : vid = nctk_idname(ncid, vname)
7757 : end function vid
7758 :
7759 : end subroutine gwr_ncwrite_tchi_wc
7760 : !!***
7761 :
7762 : !----------------------------------------------------------------------
7763 :
7764 : !!****f* m_gwr/gsph2box
7765 : !! NAME
7766 : !! gsph2box
7767 : !!
7768 : !! FUNCTION
7769 : !! Insert cg_k array defined on the k-centered g-sphere with npw vectors inside the FFT box.
7770 : !! The main difference wrt to sphere is that cfft is not initialized to zero. See notes below.
7771 : !!
7772 : !! INPUTS
7773 : !! ngfft:
7774 : !! n1,n2,n3=physical dimension of the FFT box
7775 : !! n4,n5,n6=memory dimension of cfft
7776 : !! npw=number of G vectors in basis at this k point
7777 : !! ndat=number of items to process
7778 : !! kg_k(3,npw)=integer coordinates of G vectors in basis sphere
7779 : !! cg(npw*ndat)= contains values for npw G vectors in basis sphere
7780 : !!
7781 : !! OUTPUT
7782 : !! cfft(n4,n5,n6*ndat) = array on FFT box filled with cg data
7783 : !! Note that cfft is intent(inout) so that we can add contributions from different k-points.
7784 : !!
7785 : !! SOURCE
7786 :
7787 : subroutine gsph2box(ngfft, npw, ndat, kg_k, cg, cfft)
7788 :
7789 : !Arguments ------------------------------------
7790 : !scalars
7791 : integer,intent(in) :: ngfft(6), npw, ndat
7792 : !arrays
7793 : integer,intent(in) :: kg_k(3, npw)
7794 : complex(gwp),intent(in) :: cg(npw * ndat)
7795 : complex(gwp),target,intent(inout) :: cfft(ngfft(4)*ngfft(5)*ngfft(6)*ndat)
7796 :
7797 : !Local variables-------------------------------
7798 : integer :: n1, n2, n3, n4, n5, n6, i1, i2, i3, idat, ipw
7799 : complex(gwp),contiguous,pointer :: cfft_ptr(:,:,:,:)
7800 : ! *************************************************************************
7801 :
7802 : !call timab(1931, 1, tsec)
7803 : n1 = ngfft(1); n2 = ngfft(2); n3 = ngfft(3)
7804 : n4 = ngfft(4); n5 = ngfft(5); n6 = ngfft(6)
7805 : call c_f_pointer(c_loc(cfft), cfft_ptr, shape=[n4, n5, n6, ndat])
7806 :
7807 : ! Insert cg into cfft
7808 : !$OMP PARALLEL DO PRIVATE(i1, i2, i3) IF (ndat > 1)
7809 : do idat=1,ndat
7810 : do ipw=1,npw
7811 : i1 = modulo(kg_k(1, ipw), n1) + 1
7812 : i2 = modulo(kg_k(2, ipw), n2) + 1
7813 : i3 = modulo(kg_k(3, ipw), n3) + 1
7814 : !if (any(kg_k(:,ipw) > ngfft(1:3)/2) .or. any(kg_k(:,ipw) < -(ngfft(1:3)-1)/2) ) then
7815 : ! ABI_ERROR(sjoin("The G-vector: ",ltoa(kg_k(:, ipw))," falls outside the FFT box. Increase boxcutmin (?)"))
7816 : !end if
7817 : cfft_ptr(i1,i2,i3,idat) = cg(ipw+npw*(idat-1))
7818 : end do
7819 : end do
7820 : !call timab(1931, 2, tsec)
7821 :
7822 : end subroutine gsph2box
7823 : !!***
7824 :
7825 : !----------------------------------------------------------------------
7826 :
7827 : !!****f* m_gwr/box2gsph
7828 : !! NAME
7829 : !! box2gsph
7830 : !!
7831 : !! FUNCTION
7832 : !! Extract cg_k array defined on the k-centered g-sphere with npw vectors from the FFT box.
7833 : !!
7834 : !! INPUTS
7835 : !! op_type: OP_COPY to transfer data, OP_ACC to transfer and accumulate
7836 : !! ngfft:
7837 : !! n1,n2,n3=physical dimension of the FFT box
7838 : !! n4,n5,n6=memory dimension of cfft
7839 : !! npw=number of G vectors in basis at this k point
7840 : !! ndat=number of items to process
7841 : !! kg_k(3,npw)=integer coordinates of G vectors in basis sphere
7842 : !! cfft(n4,n5,n6, ndat) = array on FFT box
7843 : !!
7844 : !! SIZE
7845 : !! cg(npw*ndat)= contains values for npw G vectors in basis sphere. See also op_type
7846 : !!
7847 : !! SOURCE
7848 :
7849 0 : subroutine box2gsph(op_type, ngfft, npw, ndat, kg_k, cfft, cg)
7850 :
7851 : !Arguments ------------------------------------
7852 : !scalars
7853 : integer,intent(in) :: op_type, ngfft(6), npw, ndat
7854 : !arrays
7855 : integer,intent(in) :: kg_k(3, npw)
7856 : complex(gwp),target,intent(in) :: cfft(ngfft(4)*ngfft(5)*ngfft(6)*ndat)
7857 : complex(gwp),intent(inout) :: cg(npw*ndat)
7858 :
7859 : !Local variables-------------------------------
7860 : integer :: n1, n2, n3, n4, n5, n6, i1, i2, i3, idat, ipw, icg
7861 0 : complex(gwp),contiguous,pointer :: cfft_ptr(:,:,:,:)
7862 : ! *************************************************************************
7863 :
7864 0 : n1 = ngfft(1); n2 = ngfft(2); n3 = ngfft(3)
7865 0 : n4 = ngfft(4); n5 = ngfft(5); n6 = ngfft(6)
7866 0 : call c_f_pointer(c_loc(cfft), cfft_ptr, shape=[n4, n5, n6, ndat])
7867 :
7868 0 : select case (op_type)
7869 :
7870 : case (OP_COPY)
7871 : ! Extract cg from cfft, ignoring components outside range of cg sphere
7872 : !$OMP PARALLEL DO PRIVATE(i1, i2, i3, icg) IF (ndat > 1)
7873 0 : do idat=1,ndat
7874 0 : do ipw=1,npw
7875 0 : i1 = modulo(kg_k(1, ipw), n1) + 1
7876 0 : i2 = modulo(kg_k(2, ipw), n2) + 1
7877 0 : i3 = modulo(kg_k(3, ipw), n3) + 1
7878 : !if (any(kg_k(:,ipw) > ngfft(1:3)/2) .or. any(kg_k(:,ipw) < -(ngfft(1:3)-1)/2) ) then
7879 : ! ABI_ERROR(sjoin("The G-vector: ",ltoa(kg_k(:, ipw))," falls outside the FFT box. Increase boxcutmin (?)"))
7880 : !end if
7881 0 : icg = ipw + (idat - 1) * npw
7882 0 : cg(icg) = cfft_ptr(i1, i2, i3, idat)
7883 : end do
7884 : end do
7885 :
7886 : case (OP_ACC)
7887 : ! Extract cg from cfft, ignoring components outside range of cg sphere and accumulate
7888 : !$OMP PARALLEL DO PRIVATE(i1, i2, i3, icg) IF (ndat > 1)
7889 0 : do idat=1,ndat
7890 0 : do ipw=1,npw
7891 0 : i1 = modulo(kg_k(1, ipw), n1) + 1
7892 0 : i2 = modulo(kg_k(2, ipw), n2) + 1
7893 0 : i3 = modulo(kg_k(3, ipw), n3) + 1
7894 : !if (any(kg_k(:,ipw) > ngfft(1:3)/2) .or. any(kg_k(:,ipw) < -(ngfft(1:3)-1)/2) ) then
7895 : ! ABI_ERROR(sjoin("The G-vector: ",ltoa(kg_k(:, ipw))," falls outside the FFT box. Increase boxcutmin (?)"))
7896 : !end if
7897 0 : icg = ipw + (idat - 1) * npw
7898 0 : cg(icg) = cg(icg) + cfft_ptr(i1, i2, i3, idat)
7899 : end do
7900 : end do
7901 :
7902 : case default
7903 0 : ABI_BUG(sjoin("Invalid op_type:" ,itoa(op_type)))
7904 : end select
7905 :
7906 0 : end subroutine box2gsph
7907 : !!***
7908 :
7909 : !----------------------------------------------------------------------
7910 :
7911 : !!****f* m_gwr/gwr_build_chi0_head_and_wings
7912 : !! NAME
7913 : !! gwr_build_chi0_head_and_wings
7914 : !!
7915 : !! FUNCTION
7916 : !! Compute head and wings of chi0 on the minimax frequency grid.
7917 : !!
7918 : !! SOURCE
7919 :
7920 0 : subroutine gwr_build_chi0_head_and_wings(gwr)
7921 :
7922 : !Arguments ------------------------------------
7923 : class(gwr_t),target,intent(inout) :: gwr
7924 :
7925 : !Local variables-------------------------------
7926 : !scalars
7927 : integer,parameter :: two_poles = 2, one_pole = 1, gwcomp0 = 0, spmeth0 = 0
7928 : integer :: nsppol, nspinor, ierr, my_is, spin, my_ikf, itau, my_it
7929 : integer :: ik_bz, ik_ibz, isym_k, trev_k, g0_k(3)
7930 : !integer :: iq_bz, iq_ibz, isym_q, trev_q, g0_q(3)
7931 : integer :: nkpt_summed, use_umklp, band1, band2, band1_start, band1_stop, band1_max
7932 : integer :: ib, il_b2, nb, block_size, ii, mband, block_counter !,idir !, iab
7933 : integer :: istwf_ki, npw_ki, istwf_kf, nI, nJ, nomega, io, iq, nq, dim_rtwg !ig,
7934 : integer :: npwe, u_nfft, u_mgfft, u_mpw
7935 : logical :: isirr_k, use_tr, is_metallic, print_time, use_ddk
7936 : real(dp) :: spin_fact, weight, deltaf_b1b2, deltaeGW_b1b2, gwr_boxcutmin_c, zcut, qlen, eig_nk, eig_mk, e0
7937 : real(dp) :: cpu_all, wall_all, gflops_all, cpu_k, wall_k, gflops_k
7938 : complex(dp) :: deltaeKS_b1b2
7939 : type(__slkmat_t),pointer :: ugb_kibz
7940 : character(len=5000) :: msg
7941 : type(crystal_t),pointer :: cryst
7942 : type(dataset_type),pointer :: dtset
7943 : type(ebands_t),pointer :: now_ebands
7944 0 : type(littlegroup_t) :: ltg_q
7945 : type(desc_t),pointer :: desc_ki
7946 : !arrays
7947 : integer :: gmax(3), u_ngfft(18), work_ngfft(18), units(2) !, spinor_pad(2,4), spad1, spad2 !, ! g0(3),
7948 0 : integer,contiguous, pointer :: kg_ki(:,:)
7949 0 : integer,allocatable :: gvec_q0(:,:), gbound_q0(:,:), u_gbound(:,:)
7950 : real(dp) :: kk_ibz(3), kk_bz(3), tsec(2) !, rtmp(2)
7951 0 : real(dp),contiguous, pointer :: qp_eig(:,:,:), qp_occ(:,:,:), ks_eig(:,:,:)
7952 0 : real(dp),allocatable :: work(:,:,:,:), qdirs(:,:)
7953 0 : logical :: gradk_not_done(gwr%nkibz)
7954 0 : logical,allocatable :: bbp_mask(:,:)
7955 : complex(dp) :: chq(3)
7956 0 : complex(gwp) :: rhotwx(3, gwr%nspinor**2)
7957 0 : complex(gwp),allocatable :: ug2(:), ur1_kibz(:), ur2_kibz(:), ur_prod(:), rhotwg(:), ug1_block(:,:), ug1(:)
7958 0 : complex(dp) :: green_w(gwr%ntau), omega(gwr%ntau)
7959 0 : complex(dp),allocatable :: chi0_lwing(:,:,:), chi0_uwing(:,:,:), chi0_head(:,:,:), head_qvals(:)
7960 0 : real(dp), allocatable :: ddk_ug1(:,:,:), cg2_dp(:,:)
7961 0 : type(vkbr_t),allocatable :: vkbr(:)
7962 0 : type(gsphere_t) :: gsph
7963 0 : type(ddkop_t) :: ddkop
7964 0 : type(pawcprj_type),allocatable :: cwaveprj(:,:)
7965 : ! *************************************************************************
7966 :
7967 0 : units = [std_out, ab_out]
7968 0 : call timab(1927, 1, tsec)
7969 0 : call cwtime(cpu_all, wall_all, gflops_all, "start")
7970 0 : call wrtout(units, sjoin(" Computing chi0 head and wings with inclvkb:", itoa(gwr%dtset%inclvkb)), pre_newlines=1)
7971 :
7972 0 : nspinor = gwr%nspinor; nsppol = gwr%nsppol; dtset => gwr%dtset; cryst => gwr%cryst
7973 0 : use_tr = gwr%dtset%awtr == 1; zcut = gwr%dtset%zcut ! well, it's not used in g0w0 when omega is complex.
7974 :
7975 : ! Use KS or QP energies depending on the iteration state.
7976 0 : if (gwr%scf_iteration == 1) then
7977 0 : call wrtout(units, " Using KS orbitals and KS energies...", newlines=1, do_flush=.True.)
7978 0 : qp_eig => gwr%ks_ebands%eig; qp_occ => gwr%ks_ebands%occ
7979 0 : now_ebands => gwr%ks_ebands
7980 : else
7981 0 : call wrtout(units, " Using KS orbitals and QP energies...", newlines=1, do_flush=.True.)
7982 0 : qp_eig => gwr%qp_ebands%eig; qp_occ => gwr%qp_ebands%occ
7983 0 : now_ebands => gwr%qp_ebands
7984 : end if
7985 :
7986 0 : ks_eig => gwr%ks_ebands%eig
7987 0 : mband = gwr%ks_ebands%mband
7988 :
7989 0 : is_metallic = now_ebands%has_metal_scheme()
7990 :
7991 : ! Setup weight (2 for spin unpolarized systems, 1 for polarized).
7992 : ! spin_fact is used to normalize the occupation factors to one.
7993 : ! Consider also the AFM case.
7994 0 : select case (nsppol)
7995 : case (1)
7996 0 : weight = two / gwr%nkbz; spin_fact = half
7997 0 : if (gwr%nspden == 2) then
7998 0 : weight = one / gwr%nkbz; spin_fact = half
7999 : end if
8000 0 : if (nspinor == 2) then
8001 0 : weight = one / gwr%nkbz; spin_fact = one
8002 : end if
8003 : case (2)
8004 0 : weight = one / gwr%nkbz; spin_fact = one
8005 : case default
8006 0 : ABI_BUG(sjoin("Wrong nsppol:", itoa(nsppol)))
8007 : end select
8008 :
8009 : ! TODO: Replace vkbr with ddk and factorize calls to DDK |bra>
8010 0 : ABI_MALLOC(vkbr, (gwr%nkibz))
8011 0 : gradk_not_done = .TRUE.
8012 :
8013 : ! TODO: Big allocation. Might become 1b
8014 0 : ABI_MALLOC(bbp_mask, (mband, mband))
8015 :
8016 : ! =========================================
8017 : ! Find FFT mesh and max number of g-vectors
8018 : ! =========================================
8019 : ! TODO: Can be decreased. Consider also fftgw
8020 0 : gwr_boxcutmin_c = two
8021 : !gwr_boxcutmin_c = one
8022 0 : call gwr%get_u_ngfft(gwr_boxcutmin_c, u_ngfft, u_nfft, u_mgfft, u_mpw, gmax)
8023 :
8024 : ! Init work_ngfft
8025 0 : gmax = gmax + 4 ! FIXME: this is to account for umklapp, should also consider Gamma-only and istwfk
8026 0 : gmax = 2 * gmax + 1
8027 0 : call ngfft_seq(work_ngfft, gmax)
8028 : !write(std_out,*)"work_ngfft(1:3): ",work_ngfft(1:3)
8029 0 : ABI_MALLOC(work, (2, work_ngfft(4), work_ngfft(5), work_ngfft(6)))
8030 :
8031 0 : if (gwr%comm%me == 0) call print_ngfft([std_out], u_ngfft, header="FFT mesh for chi0 head/wings computation")
8032 :
8033 : ! Need to broadcast G-vectors at q = 0 if k/q-point parallelism is activated.
8034 0 : if (gwr%kpt_comm%me == 0) then
8035 0 : npwe = gwr%tchi_desc_qibz(1)%npw
8036 0 : ABI_CHECK(gwr%tchi_desc_qibz(1)%kin_sorted, "g-vectors are not sorted by |q+g|^2/2 !")
8037 : end if
8038 0 : call xmpi_bcast(npwe, 0, gwr%kpt_comm%value, ierr)
8039 0 : ABI_MALLOC(gvec_q0, (3, npwe))
8040 0 : if (gwr%kpt_comm%me == 0) gvec_q0 = gwr%tchi_desc_qibz(1)%gvec
8041 0 : call xmpi_bcast(gvec_q0, 0, gwr%kpt_comm%value, ierr)
8042 :
8043 : ! This is needed to call accumulate_head_wings_imagw
8044 0 : call gsph%init(cryst, npwe, gvec_q0)
8045 :
8046 0 : ABI_MALLOC(gbound_q0, (2 * u_mgfft + 8, 2))
8047 0 : call sphereboundary(gbound_q0, istwfk1, gvec_q0, u_mgfft, npwe)
8048 :
8049 : ! Init little group to find IBZ_q
8050 0 : use_umklp = 0
8051 0 : call ltg_q%init([zero, zero, zero], gwr%nkbz, gwr%kbz, cryst, use_umklp, npwe) !, gvec=gvec_kss)
8052 :
8053 0 : nkpt_summed = gwr%nkbz
8054 0 : if (dtset%symchi /= 0) then
8055 0 : nkpt_summed = ltg_q%nibz_ltg
8056 0 : call ltg_q%print([std_out], prtvol=dtset%prtvol)
8057 : end if
8058 0 : call wrtout(std_out, sjoin(' Calculation status: ', itoa(nkpt_summed), ' k-points to be completed'))
8059 :
8060 : ! ============================================
8061 : ! === Begin big fat loop over transitions ====
8062 : ! ============================================
8063 :
8064 : ! NB: One might reduce the number of bands as head and wings converge fast wrt nband and slow wrt k-mesh.
8065 : ! Should introduce a tolerance on the frequency part computed at the first minimax frequency and
8066 : ! compute max_nband from this.
8067 :
8068 : ! Find band1_max from gwr_max_hwtene
8069 0 : band1_max = gwr%ugb_nband
8070 0 : if (gwr%dtset%gwr_max_hwtene > zero) then
8071 : ! Set e0 to top of valence band if semiconductor else Fermi level
8072 0 : e0 = now_ebands%fermie
8073 0 : if (all(gwr%ks_gaps%ierr == 0)) e0 = minval(gwr%ks_gaps%vb_max)
8074 0 : do band1_start=1, gwr%ugb_nband
8075 0 : if (all(qp_eig(band1_start,:,:) - e0 > gwr%dtset%gwr_max_hwtene)) then
8076 0 : band1_max = band1_start; exit
8077 : end if
8078 : end do
8079 : !else if (gwr%dtset%gwr_max_hwtene < zero) then
8080 : ! band1_max = min(nint(-gwr%dtset%gwr_max_hwtene) gwr%ugb_nband)
8081 : end if
8082 :
8083 0 : call wrtout(std_out, sjoin(" gwr_max_hwtene:", ftoa(gwr%dtset%gwr_max_hwtene * Ha_eV), " (eV)"))
8084 0 : call wrtout(std_out, sjoin(" Using: ", itoa(band1_max), "/", itoa(gwr%ugb_nband), "bands for chi0 head and wings."))
8085 :
8086 : ! Loop on spin to calculate $\chi_{\up,\up} + \chi_{\down,\down}$
8087 : ! TODO: nspinor 2
8088 0 : nI = 1; nJ = 1; nomega = gwr%ntau
8089 0 : omega(:) = j_dpc * gwr%iw_mesh(:)
8090 0 : ABI_CALLOC(chi0_lwing, (npwe*nI, nomega, 3))
8091 0 : ABI_CALLOC(chi0_uwing, (npwe*nJ, nomega, 3))
8092 0 : ABI_CALLOC(chi0_head, (3, 3, nomega))
8093 :
8094 0 : ABI_MALLOC(u_gbound, (2 * u_mgfft + 8, 2))
8095 0 : ABI_MALLOC(ur1_kibz, (u_nfft * nspinor))
8096 0 : ABI_MALLOC(ur2_kibz, (u_nfft * nspinor))
8097 0 : ABI_MALLOC(ur_prod, (u_nfft * nspinor))
8098 0 : dim_rtwg = 1; if (nspinor == 2) dim_rtwg = 2 ! Can reduce size depending on Ep%nI and Ep%nj
8099 0 : ABI_MALLOC(rhotwg, (npwe * dim_rtwg))
8100 :
8101 : ! TODO: use ddkop instead of commutator so that we can handle SOC terms.
8102 : use_ddk = .False.
8103 0 : use_ddk = gwr%dtset%userie == 432
8104 0 : use_ddk = .True.
8105 : if (use_ddk) then
8106 0 : call wrtout(std_out, " Using DDK to compute the commutator matrix elements.")
8107 0 : call ddkop%init(dtset, gwr%cryst, gwr%pawtab, gwr%psps, gwr%mpi_enreg, u_mpw, u_ngfft)
8108 : end if
8109 :
8110 0 : ABI_CHECK_IEQ(dtset%symchi, 1, "symchi 0 not implemented")
8111 : if (dtset%nspinor == 2 .and. .not. use_ddk) then
8112 : ABI_CHECK_IEQ(dtset%inclvkb, 0, "inclvkb must be 0 when nspinor == 2 as SOC term is not coded.")
8113 : end if
8114 :
8115 : ! Loop over collinear spins.
8116 0 : do my_is=1,gwr%my_nspins
8117 0 : spin = gwr%my_spins(my_is)
8118 :
8119 : ! Loop over my k-points in the BZ.
8120 0 : do my_ikf=1,gwr%my_nkbz
8121 0 : ik_bz = gwr%my_kbz_inds(my_ikf); kk_bz = gwr%kbz(:, ik_bz)
8122 0 : istwf_kf = 1
8123 : !istwf_kf = gwt% ???
8124 :
8125 0 : if (dtset%symchi == 1 .and. ltg_q%ibzq(ik_bz) /= 1) CYCLE ! Only IBZ_q
8126 0 : print_time = gwr%comm%me == 0 .and. (my_ikf <= LOG_MODK .or. mod(my_ikf, LOG_MODK) == 0)
8127 0 : if (print_time) call cwtime(cpu_k, wall_k, gflops_k, "start")
8128 : !write(*, *)" For kpoint:", trim(ktoa(kk_bz))
8129 :
8130 : ! FIXME: Be careful with the symmetry conventions here! and the interplay between umklapp in q and FFT
8131 : ! Also, the assembly_chi0 routines assume symrec and trev_k in [1, 2]
8132 0 : ik_ibz = gwr%kbz2ibz_symrel(1, ik_bz); isym_k = gwr%kbz2ibz_symrel(2, ik_bz)
8133 0 : trev_k = gwr%kbz2ibz_symrel(6, ik_bz); g0_k = gwr%kbz2ibz_symrel(3:5, ik_bz)
8134 : isirr_k = (isym_k == 1 .and. trev_k == 0 .and. all(g0_k == 0))
8135 0 : kk_ibz = gwr%kibz(:, ik_ibz)
8136 :
8137 0 : ugb_kibz => gwr%ugb(ik_ibz, spin)
8138 0 : desc_ki => gwr%green_desc_kibz(ik_ibz)
8139 0 : npw_ki = desc_ki%npw
8140 0 : istwf_ki = desc_ki%istwfk
8141 0 : kg_ki => desc_ki%gvec
8142 :
8143 0 : ABI_MALLOC(ug1, (npw_ki * nspinor))
8144 0 : ABI_MALLOC(ug2, (npw_ki * nspinor))
8145 0 : ABI_MALLOC(cg2_dp, (2, npw_ki * nspinor))
8146 :
8147 0 : call sphereboundary(u_gbound, istwf_ki, kg_ki, u_mgfft, npw_ki)
8148 :
8149 0 : if (gwr%usepaw == 0 .and. dtset%inclvkb /= 0 .and. gradk_not_done(ik_ibz)) then
8150 : ! Include term <n,k|[Vnl,iqr]|n"k>' for q -> 0.
8151 0 : call vkbr_init(vkbr(ik_ibz), cryst, gwr%psps, dtset%inclvkb, istwf_ki, npw_ki, kk_ibz, kg_ki)
8152 0 : gradk_not_done(ik_ibz) = .FALSE.
8153 : end if
8154 :
8155 : if (use_ddk) then
8156 0 : call ddkop%setup_spin_kpoint(gwr%dtset, gwr%cryst, gwr%psps, spin, kk_ibz, istwf_ki, npw_ki, kg_ki)
8157 : end if
8158 :
8159 : call chi0_bbp_mask(ik_ibz, ik_ibz, spin, spin_fact, use_tr, &
8160 0 : gwcomp0, spmeth0, gwr%ugb_nband, mband, now_ebands, bbp_mask)
8161 : !bbp_mask = .True.
8162 :
8163 : ! FIXME: This part should be tested with tau/g-para
8164 : ! TODO:
8165 : ! 1) Logic to determine block_size from memory.
8166 : ! 2) Add support for symchi = 0
8167 : ! 3) Invert the loops
8168 :
8169 0 : block_size = min(48, gwr%ugb_nband)
8170 :
8171 0 : block_counter = 0
8172 0 : do band1_start=1, gwr%ugb_nband, block_size
8173 0 : block_counter = block_counter + 1
8174 : ! Distribute blocks inside tau_comm as wavefunctions are replicated.
8175 0 : if (gwr%tau_comm%skip(block_counter)) cycle
8176 :
8177 0 : if (all(.not. bbp_mask(band1_start:, :))) then
8178 : !print *, "exiting band1_start loop"
8179 : exit
8180 : end if
8181 :
8182 : !print *, "band1_start, gwr%ugb_nband, block_size", band1_start, gwr%ugb_nband, block_size
8183 0 : nb = blocked_loop(band1_start, gwr%ugb_nband, block_size)
8184 0 : band1_stop = band1_start + nb - 1
8185 0 : if (band1_stop > band1_max) exit
8186 :
8187 : ! Collect nb bands starting from band1_start on each proc.
8188 0 : call ugb_kibz%collect_cplx(npw_ki * nspinor, nb, [1, band1_start], ug1_block)
8189 :
8190 : ! Precompute DH_DK |psi_b1>.
8191 0 : ABI_MALLOC(ddk_ug1, (2, npw_ki * nspinor, 3))
8192 :
8193 : ! Loop over "conduction" states.
8194 : !do band1=band1_start, band1_stop
8195 0 : do ib=1,nb
8196 0 : band1 = band1_start + ib - 1
8197 0 : eig_nk = gwr%ks_ebands%eig(band1, ik_ibz, spin)
8198 :
8199 : ! FFT band1 from g to r
8200 0 : ug1 = ug1_block(:, ib)
8201 0 : call fft_ug(npw_ki, u_nfft, nspinor, ndat1, u_mgfft, u_ngfft, istwf_ki, kg_ki, u_gbound, ug1, ur1_kibz)
8202 :
8203 : if (use_ddk) then
8204 : ! Compute DH_DK |psi_k,bi>, store results in ddk_ug1
8205 0 : ddk_ug1(1,:,1) = real(ug1)
8206 0 : ddk_ug1(2,:,1) = aimag(ug1)
8207 0 : call ddkop%apply(eig_nk, npw_ki, nspinor, ddk_ug1(:,:,1), cwaveprj)
8208 : end if
8209 :
8210 : ! Loop over "valence" states.
8211 : !do band2=1,gwr%ugb_nband
8212 0 : do il_b2=1, ugb_kibz%size_local(2)
8213 0 : band2 = ugb_kibz%loc2gcol(il_b2)
8214 :
8215 0 : eig_mk = gwr%ks_ebands%eig(band2, ik_ibz, spin)
8216 :
8217 0 : deltaeKS_b1b2 = ks_eig(band1, ik_ibz, spin) - ks_eig(band2, ik_ibz, spin)
8218 0 : deltaf_b1b2 = spin_fact * (qp_occ(band1, ik_ibz, spin) - qp_occ(band2, ik_ibz, spin))
8219 0 : deltaeGW_b1b2 = qp_eig(band1, ik_ibz, spin) - qp_eig(band2, ik_ibz, spin)
8220 :
8221 : ! Skip negligible transitions.
8222 0 : if (abs(deltaf_b1b2) < GW_TOL_DOCC) CYCLE
8223 : ! Adler-Wiser expression.
8224 : ! Add small imaginary of the Time-Ordered response function but only for non-zero real omega
8225 : ! FIXME What about metals?
8226 0 : if (.not. use_tr) then
8227 : ! Adler-Wiser without time-reversal.
8228 0 : do io=1,nomega
8229 0 : green_w(io) = g0g0w(omega(io), deltaf_b1b2, deltaeGW_b1b2, zcut, GW_TOL_W0, one_pole)
8230 : end do
8231 :
8232 : else
8233 0 : if (band1 < band2) CYCLE ! Here we GAIN a factor ~2
8234 :
8235 0 : do io=1,nomega
8236 : ! Rangel: In metals, the intra-band transitions term does not contain the antiresonant part
8237 : ! if(abs(deltaeGW_b1b2)>GW_TOL_W0) green_w(io) = g0g0w(omega(io),deltaf_b1b2,deltaeGW_b1b2,zcut,GW_TOL_W0)
8238 0 : if (band1 == band2) green_w(io) = g0g0w(omega(io), deltaf_b1b2, deltaeGW_b1b2, zcut, GW_TOL_W0, one_pole)
8239 0 : if (band1 /= band2) green_w(io) = g0g0w(omega(io), deltaf_b1b2, deltaeGW_b1b2, zcut, GW_TOL_W0, two_poles)
8240 : end do
8241 : end if
8242 :
8243 : ! FFT band2 from g to r
8244 0 : ug2 = ugb_kibz%buffer_cplx(:, il_b2)
8245 0 : call fft_ug(npw_ki, u_nfft, nspinor, ndat1, u_mgfft, u_ngfft, istwf_ki, kg_ki, u_gbound, ug2, ur2_kibz)
8246 :
8247 0 : ur_prod(:) = conjg(ur1_kibz(:)) * ur2_kibz
8248 0 : call fft_ur(npwe, u_nfft, nspinor, ndat1, u_mgfft, u_ngfft, istwfk1, gvec_q0, gbound_q0, ur_prod, rhotwg)
8249 : ! if nspinor == 2, sum 11, 22 terms in spin space
8250 0 : if (nspinor == 2) rhotwg(1:npwe) = rhotwg(1:npwe) + rhotwg(npwe+1:2*npwe)
8251 :
8252 : if (.not. use_ddk) then
8253 : if (gwr%usepaw == 0 ) then
8254 : ! Matrix elements of i[H,r] for NC pseudopotentials.
8255 : ! NB ug1 and ug2 are kind=gwp
8256 : rhotwx = nc_ihr_comm(vkbr(ik_ibz), cryst, gwr%psps, npw_ki, nspinor, istwf_ki, gwr%dtset%inclvkb, &
8257 : kk_ibz, ug1, ug2, kg_ki)
8258 : end if
8259 : else
8260 0 : cg2_dp(1,:) = real(ug2)
8261 0 : cg2_dp(2,:) = aimag(ug2)
8262 :
8263 : ! DH_DK operator is Hermitian.
8264 0 : call ddkop%get_ihr_comm(cryst, eig_mk, istwf_ki, npw_ki, nspinor, cg2_dp, rhotwx)
8265 0 : rhotwx = conjg(rhotwx)
8266 :
8267 : ! debug section
8268 : !do idir=1,3
8269 : ! write(std_out, "(a, *(es12.5,2x))")"rhotwx: ", rhotwx(:, 1)
8270 : ! write(std_out, "(a, *(es12.5,2x))")"new_rhotwx:", new_rhotwx(:, 1)
8271 : ! !write(std_out, "(a, *(es12.5,2x))")"ratio old/new:", rhotwx(:, 1) / new_rhotwx(:, 1)
8272 : ! do iab=1,gwr%nspinor**2
8273 : ! if (abs(rhotwx(iab,1) - new_rhotwx(iab,1)) > tol6 .and. &
8274 : ! (abs(rhotwx(iab,1)) > tol6 .or. abs(new_rhotwx(iab,1)) > tol6)) then
8275 : ! write(std_out, "(a, *(es12.5,2x))")"rhotwx: ", rhotwx(iab, 1)
8276 : ! write(std_out, "(a, *(es12.5,2x))")"new_rhotwx:", new_rhotwx(iab, 1)
8277 : ! ABI_ERROR("Too large diff")
8278 : ! end if
8279 : ! end do
8280 : !end do
8281 : end if ! use_ddk
8282 :
8283 : ! Treat a possible degeneracy between v and c.
8284 : ! Adler-Wiser expression, to be consistent here we use the KS eigenvalues (?)
8285 0 : if (abs(deltaeKS_b1b2) > GW_TOL_W0) then
8286 0 : rhotwx = -rhotwx / deltaeKS_b1b2
8287 : else
8288 0 : rhotwx = czero_gw
8289 : end if
8290 :
8291 : ! NB: Using symrec conventions here
8292 0 : ik_ibz = gwr%kbz2ibz(1, ik_bz); isym_k = gwr%kbz2ibz(2, ik_bz)
8293 0 : trev_k = gwr%kbz2ibz(6, ik_bz); g0_k = gwr%kbz2ibz(3:5, ik_bz)
8294 0 : trev_k = trev_k + 1 ! NB: GW routines assume trev in [1, 2]
8295 :
8296 : ! TODO: Metals
8297 : ! Note: if nspinor == 2, only rhotgw(1:npwe) with the 11 + 22 sum is used.
8298 : call accumulate_head_wings_imagw( &
8299 : npwe, nomega, nI, nJ, dtset%symchi, &
8300 : is_metallic, ik_bz, isym_k, trev_k, nspinor, cryst, ltg_q, gsph, &
8301 0 : rhotwx, rhotwg, green_w, chi0_head, chi0_lwing, chi0_uwing)
8302 : end do ! band2
8303 : end do ! band1
8304 :
8305 0 : ABI_FREE(ug1_block)
8306 0 : ABI_SFREE(ddk_ug1)
8307 : end do ! band1_start
8308 :
8309 0 : ABI_FREE(ug1)
8310 0 : ABI_FREE(ug2)
8311 0 : ABI_FREE(cg2_dp)
8312 :
8313 0 : if (print_time) then
8314 0 : write(msg,'(4x,3(a,i0),a)')"my_ikf [", my_ikf, "/", gwr%my_nkbz, "] (tot: ", gwr%nkbz, ")"
8315 0 : call cwtime_report(msg, cpu_k, wall_k, gflops_k); if (my_ikf == LOG_MODK) call wrtout(std_out, " ...")
8316 : end if
8317 : end do ! my_ikf
8318 : end do ! my_is
8319 :
8320 0 : ABI_FREE(bbp_mask)
8321 0 : ABI_FREE(gvec_q0)
8322 0 : ABI_FREE(gbound_q0)
8323 0 : ABI_FREE(work)
8324 0 : ABI_FREE(ur1_kibz)
8325 0 : ABI_FREE(ur2_kibz)
8326 0 : ABI_FREE(ur_prod)
8327 0 : ABI_FREE(rhotwg)
8328 0 : ABI_FREE(u_gbound)
8329 :
8330 0 : if (use_ddk) call ddkop%free()
8331 0 : call vkbr_free(vkbr)
8332 0 : ABI_FREE(vkbr)
8333 :
8334 : ! Collect head and wings.
8335 0 : call xmpi_sum(chi0_head, gwr%comm%value, ierr)
8336 0 : call xmpi_sum(chi0_lwing, gwr%comm%value, ierr)
8337 0 : call xmpi_sum(chi0_uwing, gwr%comm%value, ierr)
8338 :
8339 0 : chi0_head = chi0_head * weight / cryst%ucvol
8340 : ! Tensor in terms of reciprocal lattice vectors.
8341 0 : do io=1,nomega
8342 0 : chi0_head(:,:,io) = matmul(chi0_head(:,:,io), cryst%gmet) * (two_pi**2)
8343 : end do
8344 0 : chi0_lwing = chi0_lwing * weight / cryst%ucvol
8345 0 : chi0_uwing = chi0_uwing * weight / cryst%ucvol
8346 :
8347 : ! ===============================================
8348 : ! ==== Symmetrize chi0 in case of AFM system ====
8349 : ! ===============================================
8350 : ! Reconstruct $chi0{\down,\down}$ from $chi0{\up,\up}$.
8351 : ! Works only in the case of magnetic group Shubnikov type IV.
8352 0 : if (cryst%use_antiferro) then
8353 : call symmetrize_afm_chi0(Cryst, gsph, ltg_q, npwe, nomega, &
8354 0 : chi0_head=chi0_head, chi0_lwing=chi0_lwing, chi0_uwing=chi0_uwing)
8355 : end if
8356 :
8357 0 : if (gwr%comm%me == 0 .and. gwr%dtset%prtvol >= 1) then
8358 : ! Construct head and wings from the tensor and output results.
8359 0 : qlen = tol3
8360 0 : call cryst%get_redcart_qdirs(nq, qdirs, qlen=qlen)
8361 0 : ABI_MALLOC(head_qvals, (nq))
8362 0 : call wrtout(units, " Head of the irreducible polarizability for q --> 0", pre_newlines=1)
8363 0 : call wrtout(units, sjoin(" q0_len:", ftoa(qlen), "(Bohr^-1)"))
8364 0 : write(msg, "(*(a14))") "iomega (eV)", "[100]", "[010]", "[001]", "x", "y", "z"
8365 0 : call wrtout(units, msg)
8366 0 : do io=1,nomega
8367 0 : do iq=1,nq
8368 0 : chq = matmul(chi0_head(:,:,io), qdirs(:,iq))
8369 0 : head_qvals(iq) = vdotw(qdirs(:, iq), chq, cryst%gmet, "G")
8370 : end do
8371 0 : write(msg, "(*(es12.5,2x))") gwr%iw_mesh(io) * Ha_eV, real(head_qvals(:))
8372 0 : call wrtout(units, msg)
8373 : ! Write imag part to std_out only
8374 0 : write(msg, "(*(es12.5,2x))") gwr%iw_mesh(io) * Ha_eV, aimag(head_qvals(:))
8375 0 : call wrtout(std_out, msg)
8376 : end do
8377 0 : call wrtout(units, " ")
8378 0 : ABI_FREE(qdirs)
8379 0 : ABI_FREE(head_qvals)
8380 : end if
8381 :
8382 : ! Save quantities for later use as this routine must be called before build_tchi.
8383 0 : if (gwr%kpt_comm%me == 0) then
8384 0 : ABI_REMALLOC(gwr%chi0_head_myw, (3, 3, gwr%my_ntau) )
8385 0 : ABI_REMALLOC(gwr%chi0_uwing_myw, (3, npwe, gwr%my_ntau) )
8386 0 : ABI_REMALLOC(gwr%chi0_lwing_myw, (3, npwe, gwr%my_ntau) )
8387 :
8388 0 : do my_it=1,gwr%my_ntau
8389 0 : itau = gwr%my_itaus(my_it)
8390 0 : gwr%chi0_head_myw(:,:,my_it) = chi0_head(:,:,itau)
8391 0 : do ii=1,3
8392 0 : gwr%chi0_uwing_myw(ii,:,my_it) = chi0_uwing(:,itau,ii)
8393 0 : gwr%chi0_lwing_myw(ii,:,my_it) = chi0_lwing(:,itau,ii)
8394 : end do
8395 : end do
8396 : end if
8397 :
8398 0 : ABI_FREE(chi0_lwing)
8399 0 : ABI_FREE(chi0_uwing)
8400 0 : ABI_FREE(chi0_head)
8401 0 : call ltg_q%free()
8402 0 : call gsph%free()
8403 :
8404 0 : call cwtime_report(" gwr_build_chi0_head_and_wings:", cpu_all, wall_all, gflops_all)
8405 0 : call timab(1927, 2, tsec)
8406 :
8407 : !if (use_ddk) stop "gwr_build_chi0_head_and_wings"
8408 :
8409 0 : end subroutine gwr_build_chi0_head_and_wings
8410 : !!***
8411 :
8412 : !----------------------------------------------------------------------
8413 :
8414 : !!****f* m_gwr/gwr_build_sigxme
8415 : !! NAME
8416 : !! gwr_build_sigxme
8417 : !!
8418 : !! FUNCTION
8419 : !! Compute matrix elements of the exchange part.
8420 : !!
8421 : !! INPUTS
8422 : !!
8423 : !! OUTPUT
8424 : !!
8425 : !! SOURCE
8426 :
8427 0 : subroutine gwr_build_sigxme(gwr, compute_qp)
8428 :
8429 : !Arguments ------------------------------------
8430 : class(gwr_t),target,intent(inout) :: gwr
8431 : logical,optional,intent(in) :: compute_qp
8432 :
8433 : !Local variables-------------------------------
8434 : !scalars
8435 : integer :: nsppol, nspinor, ierr, my_ikf, band_sum, ii, jj, kb, il_b, iab !ig_start, ig,
8436 : integer :: my_is, ikcalc, ikcalc_ibz, bmin, bmax, band, istwf_k, npw_k
8437 : integer :: spin, jb, is_idx, use_umklp, spad, wtqm, wtqp, irow, spadx1, spadx2, npwx, u_nfft, u_mgfft, u_mpw
8438 : integer :: ik_bz, ik_ibz, isym_k, trev_k, g0_k(3)
8439 : integer :: iq_bz, iq_ibz, isym_q, trev_q, g0_q(3)
8440 : logical :: isirr_k, isirr_q, sigc_is_herm, compute_qp__
8441 : real(dp) :: fact_spin, theta_mu_minus_esum, theta_mu_minus_esum2, tol_empty, tol_empty_in, gwr_boxcutmin_x, i_sz
8442 : real(dp) :: cpu_k, wall_k, gflops_k, cpu_all, wall_all, gflops_all
8443 : complex(gwp) :: gwpc_sigxme, gwpc_sigxme2, xdot_tmp, ctmp
8444 : character(len=5000) :: msg
8445 : logical :: q_is_gamma
8446 : type(__slkmat_t),pointer :: ugb_kibz
8447 : type(crystal_t),pointer :: cryst
8448 : type(dataset_type),pointer :: dtset
8449 0 : type(littlegroup_t) :: ltg_k
8450 : type(desc_t),pointer :: desc_ki
8451 : !arrays
8452 : integer :: g0(3), gmax(3), spinor_padx(2,4), u_ngfft(18), work_ngfft(18), units(2)
8453 0 : integer,allocatable :: gbound_kcalc(:,:), gvec_x(:,:), gbound_x(:,:), kg_k(:,:), gbound_ksum(:,:)
8454 : real(dp) :: ksum(3), kk_ibz(3), kgw(3), kgw_m_ksum(3), qq_bz(3), tsec(2) !, kk_bz(3), q0(3) !, spinrot_kbz(4), spinrot_kgw(4)
8455 0 : real(dp),contiguous, pointer :: ks_eig(:,:,:), qp_eig(:,:,:), qp_occ(:,:,:), cg2_ptr(:,:) ! cg1_ptr(:,:),
8456 0 : real(dp),allocatable :: work(:,:,:,:), cg1_ibz(:,:) !, cg2_bz(:,:)
8457 0 : complex(gwp),allocatable :: vc_sqrt_qbz(:), ur_bdgw(:,:)
8458 0 : complex(gwp),allocatable :: rhotwg(:), rhotwgp(:), rhotwg_ki(:,:), ur_ksum(:), ur_prod(:), eig0r(:)!, ugb_kcalcibz(:)
8459 0 : complex(gwp),allocatable :: ug_ksum(:)
8460 0 : complex(dp),target,allocatable :: ug_ksum_dp(:)
8461 0 : complex(dp),allocatable :: sigxme_tmp(:,:,:), sigx(:,:,:,:)
8462 0 : type(sigijtab_t),allocatable :: Sigxij_tab(:,:), Sigcij_tab(:,:)
8463 : type(yamldoc_t) :: ydoc
8464 : ! *************************************************************************
8465 :
8466 0 : call timab(1920, 1, tsec)
8467 0 : call cwtime(cpu_all, wall_all, gflops_all, "start")
8468 :
8469 0 : units = [std_out, ab_out]
8470 0 : if (gwr%sig_diago) then
8471 0 : call wrtout(units, " Computing diagonal matrix elements of Sigma_x", pre_newlines=1)
8472 : else
8473 0 : call wrtout(units, " Computing diagonal + off-diagonal matrix elements of Sigma_x", pre_newlines=1)
8474 : end if
8475 :
8476 0 : if (gwr%scf_iteration /= 1) then
8477 : associate (now => gwr%qp_ebands, prev => gwr%qp_ebands_prev)
8478 0 : if (all(now%occ == prev%occ)) then
8479 0 : call wrtout(units, " Occupations have not changed since last iteration, skipping Sigma_x matrix elements computation...", pre_newlines=1)
8480 : else
8481 0 : call wrtout(units, " Occupations have changed since last iteration, recomputing Sigma_x matrix elements...", pre_newlines=1)
8482 : end if
8483 : end associate
8484 : goto 10
8485 : end if
8486 :
8487 0 : if (gwr%has_vcgen_sigma) then
8488 0 : call gwr%vcgen_sigma%print(units, " Info on Coulomb term used in Sigma_x", gwr%dtset%prtvol)
8489 : else
8490 0 : call gwr%vcgen_eps%print(units, " Info on Coulomb term used in Sigma_x", dtset%prtvol)
8491 : end if
8492 :
8493 0 : nsppol = gwr%nsppol; nspinor = gwr%nspinor; cryst => gwr%cryst; dtset => gwr%dtset
8494 :
8495 : ! Table for \Sigmax_ij matrix elements.
8496 0 : sigc_is_herm = .False.
8497 : call sigtk_sigma_tables(gwr%nkcalc, gwr%nkibz, gwr%nsppol, gwr%bstart_ks, gwr%bstop_ks, gwr%kcalc2ibz(:,1), &
8498 0 : gwr%sig_diago, sigc_is_herm, sigxij_tab, sigcij_tab)
8499 :
8500 0 : call sigijtab_free(Sigcij_tab)
8501 0 : ABI_FREE(Sigcij_tab)
8502 :
8503 : ! Allocate array with Sigma_x matrix elements depending on sig_diago
8504 0 : ii = gwr%b1gw; jj = gwr%b2gw
8505 0 : if (gwr%sig_diago) then
8506 0 : ii = 1; jj = 1
8507 : end if
8508 0 : ABI_RECALLOC(gwr%sigx_mat, (gwr%b1gw:gwr%b2gw, ii:jj, gwr%nkcalc, gwr%nsppol*gwr%nsig_ab))
8509 :
8510 0 : ks_eig => gwr%ks_ebands%eig
8511 0 : if (gwr%scf_iteration == 1) then
8512 0 : call wrtout(units, " Using KS orbitals and KS energies...", newlines=1, do_flush=.True.)
8513 0 : qp_eig => gwr%ks_ebands%eig; qp_occ => gwr%ks_ebands%occ
8514 : else
8515 0 : call wrtout(units, " Using KS orbitals and QP energies...", newlines=1, do_flush=.True.)
8516 0 : qp_eig => gwr%qp_ebands%eig; qp_occ => gwr%qp_ebands%occ
8517 : end if
8518 :
8519 : ! Set tolerance used to decide if a band is empty
8520 0 : tol_empty_in = 0.01
8521 0 : call get_fact_spin_tol_empty(nsppol, nspinor, tol_empty_in, fact_spin, tol_empty)
8522 :
8523 : ! =========================================
8524 : ! Find FFT mesh and max number of g-vectors
8525 : ! =========================================
8526 0 : gwr_boxcutmin_x = two
8527 0 : call gwr%get_u_ngfft(gwr_boxcutmin_x, u_ngfft, u_nfft, u_mgfft, u_mpw, gmax)
8528 :
8529 0 : if (gwr%comm%me == 0) call print_ngfft([std_out], u_ngfft, header="FFT mesh for Sigma_x")
8530 :
8531 : ! Init work_ngfft
8532 0 : gmax = gmax + 4 ! FIXME: this is to account for umklapp, should also consider Gamma-only and istwfk
8533 0 : gmax = 2 * gmax + 1
8534 0 : call ngfft_seq(work_ngfft, gmax)
8535 : !write(std_out,*)"work_ngfft(1:3): ",work_ngfft(1:3)
8536 0 : ABI_MALLOC(work, (2, work_ngfft(4), work_ngfft(5), work_ngfft(6)))
8537 :
8538 0 : do my_is=1,gwr%my_nspins
8539 0 : spin = gwr%my_spins(my_is)
8540 0 : do ikcalc=1,gwr%nkcalc ! TODO: Should be spin dependent!
8541 0 : call cwtime(cpu_k, wall_k, gflops_k, "start")
8542 0 : ikcalc_ibz = gwr%kcalc2ibz(ikcalc, 1)
8543 0 : kgw = gwr%kcalc(:, ikcalc)
8544 0 : bmin = gwr%bstart_ks(ikcalc, spin); bmax = gwr%bstop_ks(ikcalc, spin)
8545 :
8546 : ! ==============================================================
8547 : ! ==== Find little group of the k-points for GW corrections ====
8548 : ! ==============================================================
8549 : ! * The little group is used only if symsigma == 1
8550 : ! * If use_umklp == 1 then symmetries requiring an umklapp to preserve k_gw are included as well.
8551 0 : use_umklp = 1
8552 0 : call ltg_k%init(kgw, gwr%nqbz, gwr%qbz, cryst, use_umklp, npwe=0)
8553 : !if (gwr%comm%me == 0) call ltg_k%print([std_out], prtvol=gwr%dtset%prtvol)
8554 :
8555 0 : write(msg,'(5a)') ch10, &
8556 0 : ' Calculating <nk|Sigma_x|nk> at k: ',trim(ktoa(kgw)), ", for band range: ", trim(ltoa([bmin, bmax]))
8557 0 : call wrtout(std_out, msg)
8558 :
8559 : ! ===============================================
8560 : ! Load wavefunctions for Sigma_x matrix elements
8561 : ! ===============================================
8562 : ! All procs need ur_bdgw but the IBZ is distributed and, possibly, replicated in gwr%kpt_comm.
8563 : ! Here we select the right procs, fill the buffer with the FFT results and then use
8564 : ! a dumb xmpi_sum + rescaling to gather the results.
8565 : ! FIXME: g-vectors from Green's descriptor or use another array to be able to deal with istwfk == 2?
8566 :
8567 0 : ABI_MALLOC_OR_DIE(ur_bdgw, (u_nfft * nspinor, bmin:bmax), ierr)
8568 0 : ur_bdgw = czero_gw
8569 :
8570 0 : if (any(ikcalc_ibz == gwr%my_kibz_inds)) then
8571 : associate (desc_kcalc => gwr%green_desc_kibz(ikcalc_ibz), ugb_kcalc => gwr%ugb(ikcalc_ibz, spin))
8572 0 : ABI_MALLOC(gbound_kcalc, (2 * u_mgfft + 8, 2))
8573 0 : call sphereboundary(gbound_kcalc, desc_kcalc%istwfk, desc_kcalc%gvec, u_mgfft, desc_kcalc%npw)
8574 :
8575 0 : do il_b=1,ugb_kcalc%size_local(2)
8576 0 : band = ugb_kcalc%loc2gcol(il_b); if (band < bmin .or. band > bmax) CYCLE
8577 : call fft_ug(desc_kcalc%npw, u_nfft, nspinor, ndat1, &
8578 : u_mgfft, u_ngfft, desc_kcalc%istwfk, desc_kcalc%gvec, gbound_kcalc, &
8579 : gwr%ugb(ikcalc_ibz, spin)%buffer_cplx(:, il_b), & ! in
8580 0 : ur_bdgw(:, band)) ! out
8581 : end do
8582 0 : ABI_FREE(gbound_kcalc)
8583 : end associate
8584 : end if
8585 :
8586 : ! Collect and rescale
8587 : !call xmpi_sum(ur_bdgw, gwr%kgt_comm%value, ierr)
8588 0 : call xmpi_sum(ur_bdgw, gwr%kg_comm%value, ierr)
8589 0 : ur_bdgw = ur_bdgw / gwr%np_kibz(ikcalc_ibz)
8590 :
8591 0 : ABI_MALLOC(ur_prod, (u_nfft * nspinor))
8592 0 : ABI_MALLOC(ur_ksum, (u_nfft * nspinor))
8593 0 : ABI_MALLOC(eig0r, (u_nfft * nspinor))
8594 :
8595 0 : ABI_CALLOC(sigxme_tmp, (bmin:bmax, bmin:bmax, nsppol * gwr%nsig_ab))
8596 0 : ABI_CALLOC(sigx, (2, bmin:bmax, bmin:bmax, nsppol * gwr%nsig_ab))
8597 :
8598 : ! ========================================
8599 : ! ==== Sum over my k-points in the BZ ====
8600 : ! ========================================
8601 :
8602 0 : do my_ikf=1,gwr%my_nkbz
8603 0 : ik_bz = gwr%my_kbz_inds(my_ikf)
8604 0 : ksum = gwr%kbz(:, ik_bz)
8605 :
8606 : ! Find the symmetrical image of ksum in the IBZ
8607 : ! FIXME: Be careful with the symmetry conventions here and the interplay between umklapp in q and FFT
8608 0 : ik_ibz = gwr%kbz2ibz_symrel(1, ik_bz); isym_k = gwr%kbz2ibz_symrel(2, ik_bz)
8609 0 : trev_k = gwr%kbz2ibz_symrel(6, ik_bz); g0_k = gwr%kbz2ibz_symrel(3:5, ik_bz)
8610 0 : isirr_k = (isym_k == 1 .and. trev_k == 0 .and. all(g0_k == 0))
8611 0 : kk_ibz = gwr%kibz(:, ik_ibz)
8612 :
8613 : ! Identify q and G0 where q + G0 = k_GW - ksum
8614 0 : kgw_m_ksum = kgw - ksum
8615 0 : call findqg0(iq_bz, g0, kgw_m_ksum, gwr%nqbz, gwr%qbz, gwr%mG0)
8616 : !ABI_CHECK(all(g0 == 0), sjoin("g0 = ", ltoa(g0)))
8617 :
8618 0 : call calc_ceigr(g0, u_nfft, nspinor, u_ngfft, eig0r)
8619 :
8620 : ! If symmetries are exploited, only q-points in the IBZ_k are computed.
8621 : ! In this case elements are weighted according to wtqp and wtqm. wtqm is for time-reversal.
8622 0 : wtqp = 1; wtqm = 0
8623 : !if (can_symmetrize(spin)) then
8624 0 : if (gwr%dtset%symsigma == 1) then
8625 0 : if (ltg_k%ibzq(iq_bz) /= 1) CYCLE
8626 0 : wtqp = sum(ltg_k%wtksym(1,:,iq_bz))
8627 0 : wtqm = sum(ltg_k%wtksym(2,:,iq_bz))
8628 : end if
8629 :
8630 0 : qq_bz = gwr%qbz(:, iq_bz)
8631 0 : iq_ibz = gwr%qbz2ibz(1, iq_bz); isym_q = gwr%qbz2ibz(2, iq_bz)
8632 0 : trev_q = gwr%qbz2ibz(6, iq_bz); g0_q = gwr%qbz2ibz(3:5, iq_bz)
8633 : isirr_q = (isym_q == 1 .and. trev_q == 0 .and. all(g0_q == 0))
8634 :
8635 : ! Find the corresponding irreducible q-point.
8636 : ! NB: non-zero umklapp G_o is not allowed. There's a check in setup_sigma
8637 : !call qmesh%get_BZ_item(iq_bz, qbz, iq_ibz, isym_q, itim_q)
8638 0 : q_is_gamma = normv(qq_bz, cryst%gmet, "G") < GW_TOLQ0
8639 0 : call get_kg(qq_bz, istwfk1, dtset%ecutsigx, cryst%gmet, npwx, gvec_x)
8640 :
8641 0 : ABI_MALLOC(gbound_x, (2*u_mgfft + 8, 2))
8642 0 : call sphereboundary(gbound_x, istwfk1, gvec_x, u_mgfft, npwx)
8643 :
8644 0 : ABI_MALLOC(rhotwg_ki, (npwx * nspinor, bmin:bmax))
8645 0 : ABI_MALLOC(rhotwg, (npwx * nspinor))
8646 0 : ABI_MALLOC(rhotwgp, (npwx * nspinor))
8647 0 : ABI_MALLOC(vc_sqrt_qbz, (npwx))
8648 0 : spinor_padx = reshape([0, 0, npwx, npwx, 0, npwx, npwx, 0], [2, 4])
8649 :
8650 : ! Get Fourier components of the Coulomb interaction in the BZ
8651 : ! In 3D systems, neglecting umklapp, vc(Sq,sG)=vc(q,G)=4pi/|q+G|
8652 : ! The same relation holds for 0-D systems, but not in 1-D or 2D systems. It depends on S.
8653 0 : if (gwr%has_vcgen_sigma) then
8654 0 : call gwr%vcgen_sigma%get_vc_sqrt(qq_bz, npwx, gvec_x, gwr%q0, gwr%cryst, vc_sqrt_qbz, gwr%gtau_comm%value)
8655 : else
8656 0 : call gwr%vcgen_eps%get_vc_sqrt(qq_bz, npwx, gvec_x, gwr%q0, gwr%cryst, vc_sqrt_qbz, gwr%gtau_comm%value)
8657 : end if
8658 :
8659 0 : desc_ki => gwr%green_desc_kibz(ik_ibz)
8660 :
8661 : ! Get npw_k and kg_k for this k.
8662 0 : if (isirr_k) then
8663 0 : istwf_k = desc_ki%istwfk; npw_k = desc_ki%npw
8664 0 : ABI_MALLOC(kg_k, (3, npw_k))
8665 0 : kg_k(:,:) = desc_ki%gvec
8666 : else
8667 0 : istwf_k = 1
8668 0 : call get_kg(ksum, istwf_k, dtset%ecutwfn, cryst%gmet, npw_k, kg_k)
8669 : end if
8670 :
8671 0 : ABI_MALLOC(ug_ksum, (npw_k * nspinor))
8672 0 : ABI_MALLOC(ug_ksum_dp, (npw_k * nspinor))
8673 : !ABI_MALLOC(ugb_kcalcibz, (npw_k * nspinor))
8674 0 : ABI_MALLOC(cg1_ibz, (2, desc_ki%npw * nspinor))
8675 : !ABI_MALLOC(cg2_bz, (2, npw_k * nspinor))
8676 :
8677 0 : ABI_MALLOC(gbound_ksum, (2*u_mgfft+8, 2))
8678 0 : call sphereboundary(gbound_ksum, istwf_k, kg_k, u_mgfft, npw_k)
8679 :
8680 : ! ==========================
8681 : ! Sum over (occupied) bands
8682 : ! ==========================
8683 0 : ugb_kibz => gwr%ugb(ik_ibz, spin)
8684 :
8685 0 : do il_b=1,ugb_kibz%size_local(2)
8686 : ! Distribute bands inside tau_comm as wavefunctions are replicated
8687 0 : if (gwr%tau_comm%skip(il_b)) cycle
8688 0 : band_sum = ugb_kibz%loc2gcol(il_b)
8689 :
8690 : ! Skip empty states. MRM: allow negative occ numbers.
8691 0 : if (abs(qp_occ(band_sum, ik_ibz, spin)) < tol_empty) CYCLE
8692 :
8693 : ! Compute ur_ksum(r) from the symmetrical image.
8694 : ! I should rotate the g-vectors outside the loop and rotate ug here
8695 : ! but at present I cannot use cgtk_rotate due to the symrel^T convention.
8696 :
8697 0 : if (isirr_k) then
8698 : !call wfd%copy_cg(ibsum_kq, ikq_ibz, spin, bra_kq)
8699 0 : ug_ksum(:) = ugb_kibz%buffer_cplx(:, il_b)
8700 : else
8701 : ! Reconstruct u_kq(G) from the IBZ image.
8702 :
8703 : ! FIXME: This is wrong if spc
8704 0 : call c_f_pointer(c_loc(ug_ksum_dp), cg2_ptr, shape=[2, npw_k * nspinor])
8705 :
8706 : !call c_f_pointer(c_loc(ugb_kibz%buffer_cplx(:, il_b)), cg1_ptr, shape=[2, desc_ki%npw * nspinor])
8707 : !call cgtk_rotate(cryst, kk_ibz, isym_k, trev_k, g0_k, nspinor, ndat1, &
8708 : ! desc_ki%npw, desc_ki%gvec, &
8709 : ! npw_k, kg_k, desc_ki%istwfk, istwf_k, cg1_ptr, cg2_ptr, work_ngfft, work)
8710 :
8711 0 : cg1_ibz(1,:) = real(ugb_kibz%buffer_cplx(:, il_b), kind=dp)
8712 0 : cg1_ibz(2,:) = real(aimag(ugb_kibz%buffer_cplx(:, il_b)), kind=dp)
8713 : call cgtk_rotate(cryst, kk_ibz, isym_k, trev_k, g0_k, nspinor, ndat1, &
8714 : desc_ki%npw, desc_ki%gvec, &
8715 0 : npw_k, kg_k, desc_ki%istwfk, istwf_k, cg1_ibz, cg2_ptr, work_ngfft, work)
8716 0 : ug_ksum(:) = ug_ksum_dp(:)
8717 : end if
8718 :
8719 0 : call fft_ug(npw_k, u_nfft, nspinor, ndat1, u_mgfft, u_ngfft, istwf_k, kg_k, gbound_ksum, ug_ksum, ur_ksum)
8720 :
8721 0 : if (any(g0 /= 0)) ur_ksum = ur_ksum * conjg(eig0r)
8722 :
8723 : ! Get all <k-q,band_sum,s|e^{-i(q+G).r}|s,jb,k>
8724 0 : do jb=bmin,bmax
8725 :
8726 : ! FIXME: nspinor 2 is wrong as we have a 2x2 matrix
8727 0 : ur_prod(:) = conjg(ur_ksum(:)) * ur_bdgw(:,jb)
8728 0 : call fft_ur(npwx, u_nfft, nspinor, ndat1, u_mgfft, u_ngfft, istwfk1, gvec_x, gbound_x, ur_prod, rhotwg_ki(:,jb))
8729 :
8730 : ! Multiply by the square root of the Coulomb term
8731 : ! In 3-D systems, the factor sqrt(4pi) is included
8732 0 : do ii=1,nspinor
8733 0 : spad = (ii-1) * npwx
8734 0 : rhotwg_ki(spad+1:spad+npwx,jb) = rhotwg_ki(spad+1:spad + npwx,jb) * vc_sqrt_qbz(1:npwx)
8735 : end do
8736 :
8737 0 : if (q_is_gamma) then
8738 : !if (ik_bz == jk_bz) then
8739 : ! Treat analytically the case q --> 0:
8740 : !
8741 : ! * The oscillator is evaluated at q = 0 as it is considered constant in the small cube around Gamma
8742 : ! while the Colulomb term is integrated out.
8743 : ! * If nspinor == 1, we have nonzero contribution only if band_sum == jb
8744 : ! * If nspinor == 2, we evaluate <band_sum,up|jb,up> and <band_sum,dwn|jb,dwn>,
8745 : ! and impose orthonormalization since npwwfn might be < npwvec.
8746 : ! * Note the use of i_sz_resid and not i_sz, to account for the possibility
8747 : ! to have generalized KS basis set from hybrid
8748 :
8749 0 : i_sz = gwr%vcgen_eps%i_sz
8750 0 : if (gwr%has_vcgen_sigma) i_sz = gwr%vcgen_sigma%i_sz
8751 :
8752 0 : if (nspinor == 1) then
8753 0 : rhotwg_ki(1, jb) = czero_gw
8754 0 : if (band_sum == jb) rhotwg_ki(1,jb) = cmplx(sqrt(i_sz), 0.0_gwp)
8755 : !rhotwg_ki(1,jb) = czero_gw ! DEBUG
8756 :
8757 : else
8758 0 : rhotwg_ki(1, jb) = zero; rhotwg_ki(npwx+1, jb) = zero
8759 0 : if (band_sum == jb) then
8760 : associate(ugb_kcalcibz => gwr%ugb(ikcalc_ibz, spin)%buffer_cplx(:,il_b))
8761 0 : ABI_CHECK(size(ug_ksum) == size(ugb_kcalcibz), "Size mismatch in Sigma_x")
8762 0 : ctmp = xdotc(npw_k, ug_ksum(1:), 1, ugb_kcalcibz(1:), 1)
8763 0 : rhotwg_ki(1, jb) = cmplx(sqrt(i_sz), 0.0_gwp) * real(ctmp)
8764 0 : ctmp = xdotc(npw_k, ug_ksum(npw_k+1:), 1, ugb_kcalcibz(npw_k+1:), 1)
8765 0 : rhotwg_ki(npwx+1, jb) = cmplx(sqrt(i_sz), 0.0_gwp) * real(ctmp)
8766 : end associate
8767 : end if
8768 : !!!rhotwg_ki(1, jb) = zero; rhotwg_ki(npwx+1, jb) = zero
8769 : !!! PAW is missing
8770 : end if
8771 : end if
8772 :
8773 : end do ! jb Got all matrix elements from bmin up to bmax.
8774 :
8775 0 : theta_mu_minus_esum = fact_spin * qp_occ(band_sum, ik_ibz, spin)
8776 : theta_mu_minus_esum2 = sqrt(abs(fact_spin * qp_occ(band_sum, ik_ibz, spin))) ! MBB Nat. orb. funct. approx. sqrt(occ)
8777 :
8778 0 : if (abs(theta_mu_minus_esum / fact_spin) >= tol_empty) then ! MRM: allow negative occ numbers
8779 0 : do kb=bmin,bmax
8780 :
8781 : ! Copy the ket Sigma_x |phi_{k,kb}>.
8782 0 : rhotwgp(:) = rhotwg_ki(:, kb)
8783 :
8784 : ! Loop over the non-zero row elements of this column.
8785 : ! If gwcalctyp < 20: only diagonal elements since QP == KS.
8786 : ! If gwcalctyp >= 20:
8787 : ! * Only off-diagonal elements connecting states with same character.
8788 : ! * Only the upper triangle if HF, SEX, or COHSEX.
8789 :
8790 0 : do irow=1,Sigxij_tab(ikcalc, spin)%col(kb)%size1
8791 0 : jb = Sigxij_tab(ikcalc, spin)%col(kb)%bidx(irow)
8792 0 : rhotwg(:) = rhotwg_ki(:,jb)
8793 :
8794 : ! Calculate bare exchange <phi_jb|Sigma_x|phi_kb>.
8795 : ! Do the scalar product only if band_sum is occupied.
8796 0 : do iab=1,gwr%nsig_ab
8797 0 : spadx1 = spinor_padx(1, iab); spadx2 = spinor_padx(2, iab)
8798 0 : xdot_tmp = -XDOTC(npwx, rhotwg(spadx1+1:), 1, rhotwgp(spadx2+1:), 1)
8799 0 : gwpc_sigxme = xdot_tmp * theta_mu_minus_esum
8800 0 : gwpc_sigxme2 = xdot_tmp * theta_mu_minus_esum2
8801 :
8802 : ! Accumulate and symmetrize Sigma_x matrix elements.
8803 : ! -wtqm comes from time-reversal (exchange of band indices)
8804 0 : is_idx = spin; if (nspinor == 2) is_idx = iab
8805 : sigxme_tmp(jb, kb, is_idx) = sigxme_tmp(jb, kb, is_idx) + &
8806 0 : (wtqp + wtqm) * DBLE(gwpc_sigxme) + (wtqp - wtqm) * j_dpc * AIMAG(gwpc_sigxme)
8807 :
8808 0 : sigx(1, jb, kb, is_idx) = sigx(1, jb, kb, is_idx) + wtqp * gwpc_sigxme
8809 0 : sigx(2, jb, kb, is_idx) = sigx(2, jb, kb, is_idx) + wtqm *CONJG(gwpc_sigxme)
8810 : end do
8811 : end do ! irow
8812 :
8813 : end do ! kb
8814 : end if
8815 : end do ! band_sum
8816 :
8817 0 : ABI_FREE(gbound_x)
8818 0 : ABI_FREE(kg_k)
8819 0 : ABI_FREE(ug_ksum)
8820 0 : ABI_FREE(ug_ksum_dp)
8821 : !ABI_FREE(ugb_kcalcibz)
8822 0 : ABI_FREE(cg1_ibz)
8823 : !ABI_FREE(cg2_bz)
8824 0 : ABI_FREE(gbound_ksum)
8825 0 : ABI_FREE(gvec_x)
8826 0 : ABI_FREE(rhotwg_ki)
8827 0 : ABI_FREE(rhotwg)
8828 0 : ABI_FREE(rhotwgp)
8829 0 : ABI_FREE(vc_sqrt_qbz)
8830 : end do ! my_ikf Got all diagonal (off-diagonal) matrix elements.
8831 :
8832 : ! Gather contributions from all the CPUs.
8833 0 : call xmpi_sum(sigxme_tmp, gwr%kgt_comm%value, ierr)
8834 0 : call xmpi_sum(sigx, gwr%kgt_comm%value, ierr)
8835 :
8836 : ! Multiply by constants. For 3D systems sqrt(4pi) is included in vc_sqrt_qbz.
8837 0 : sigxme_tmp = (one / (cryst%ucvol * gwr%nkbz)) * sigxme_tmp ! * Sigp%sigma_mixing
8838 0 : sigx = (one / (cryst%ucvol * gwr%nkbz)) * sigx ! * Sigp%sigma_mixing
8839 :
8840 : ! If we have summed over the IBZ_q, we have to average over degenerate states.
8841 : ! Presently only diagonal terms are considered
8842 : ! Note that here we pass ks_eig to sigx_symmetrize instead of qp_eig.
8843 : ! The reason is that we use the eigenvalues to detect degeneracies before averaging
8844 : ! and qp_eig may break degeneracies while ks_eig are much more accurate.
8845 : ! Most of the breaking comes from the correlated part, likey due to the treatment of q --> 0.
8846 :
8847 : ! TODO QP-SCGW required a more involved approach, there is a check in sigma
8848 : ! TODO it does not work if nspinor == 2.
8849 :
8850 0 : if (gwr%dtset%symsigma == 1) then
8851 0 : call sigx_symmetrize(ikcalc_ibz, spin, bmin, bmax, nsppol, nspinor, gwr%nsig_ab, gwr%dtset%symsigma_de, ks_eig, sigx, sigxme_tmp)
8852 : !do ii=bmin, bmax; print *, "qp_eig:", ii, qp_eig(ii, ikcalc_ibz, spin) * Ha_eV; end do
8853 : !call sigx_symmetrize(ikcalc_ibz, spin, bmin, bmax, nsppol, nspinor, gwr%nsig_ab, gwr%dtset%symsigma_de, qp_eig, sigx, sigxme_tmp)
8854 : end if
8855 :
8856 : ! Reconstruct the full sigma_x matrix from the upper triangle.
8857 0 : if (gwr%nsig_ab == 1) then
8858 0 : call hermitianize(sigxme_tmp(:,:,spin), "Upper")
8859 : else
8860 0 : ABI_WARNING("Should hermitianize non-collinear sigma!")
8861 : end if
8862 :
8863 : ! Save exchange matrix in gwr%sigx_mat taking into account sig_diago.
8864 0 : if (gwr%nsig_ab == 1) then
8865 0 : if (gwr%sig_diago) then
8866 0 : do jb=bmin,bmax
8867 0 : gwr%sigx_mat(jb, 1, ikcalc, spin) = sigxme_tmp(jb,jb,spin)
8868 : end do
8869 : else
8870 0 : gwr%sigx_mat(bmin:bmax, bmin:bmax, ikcalc, spin) = sigxme_tmp(bmin:bmax, bmin:bmax, spin)
8871 : end if
8872 : else
8873 0 : if (gwr%sig_diago) then
8874 0 : do iab=1,gwr%nsig_ab
8875 0 : do jb=bmin,bmax
8876 0 : gwr%sigx_mat(jb, 1, ikcalc, iab) = sigxme_tmp(jb,jb,iab)
8877 : end do
8878 : end do
8879 : else
8880 0 : gwr%sigx_mat(bmin:bmax, bmin:bmax, ikcalc, :) = sigxme_tmp(bmin:bmax, bmin:bmax, :)
8881 : end if
8882 : end if
8883 :
8884 0 : ABI_FREE(ur_bdgw)
8885 0 : ABI_FREE(ur_prod)
8886 0 : ABI_FREE(ur_ksum)
8887 0 : ABI_FREE(eig0r)
8888 0 : ABI_FREE(sigxme_tmp)
8889 0 : ABI_FREE(sigx)
8890 0 : call ltg_k%free()
8891 0 : call cwtime_report(" Sigx_nk:", cpu_k, wall_k, gflops_k)
8892 : end do ! ikcalc
8893 : end do ! my_is
8894 :
8895 0 : if (gwr%spin_comm%nproc > 1) call xmpi_sum(gwr%sigx_mat, gwr%spin_comm%value, ierr)
8896 0 : if (gwr%nspinor == 2) gwr%sigx_mat(:,:,:,1) = sum(gwr%sigx_mat(:,:,:,:), dim=4)
8897 :
8898 0 : ABI_FREE(work)
8899 0 : call sigijtab_free(Sigxij_tab)
8900 0 : ABI_FREE(Sigxij_tab)
8901 :
8902 : ! Compute QP results. Done usually when gwr_task == G0v i.e. Hartree-Fock with KS states.
8903 0 : compute_qp__ = .False.; if (present(compute_qp)) compute_qp__ = compute_qp
8904 0 : if (compute_qp__ .and. gwr%comm%me == 0) then
8905 0 : call write_notations(units)
8906 0 : do spin=1,gwr%nsppol
8907 0 : do ikcalc=1,gwr%nkcalc
8908 0 : ik_ibz = gwr%kcalc2ibz(ikcalc, 1)
8909 0 : ydoc = yamldoc_open('GWR_SelfEnergy_ee', width=11, real_fmt='(3f8.3)')
8910 0 : call ydoc%add_real1d('kpoint', gwr%kcalc(:, ikcalc))
8911 0 : call ydoc%add_int('spin', spin, int_fmt="(i1)")
8912 0 : call ydoc%add_int('gwr_scf_iteration', gwr%scf_iteration)
8913 0 : call ydoc%add_string('gwr_task', gwr%dtset%gwr_task)
8914 :
8915 : call ydoc%add_real('KS_gap', &
8916 : (gwr%ks_ebands%eig(gwr%ks_vbik(ik_ibz, spin)+1, ik_ibz, spin) - &
8917 0 : gwr%ks_ebands%eig(gwr%ks_vbik(ik_ibz, spin), ik_ibz, spin)) * Ha_eV)
8918 0 : call ydoc%open_tabular('data') !, tag='SigmaeeData')
8919 0 : write(msg, "(a5, *(a9))") "Band", "E0", "SigX", "Occ(E)"
8920 0 : call ydoc%add_tabular_line(msg)
8921 :
8922 0 : do band=gwr%bstart_ks(ikcalc, spin), gwr%bstop_ks(ikcalc, spin)
8923 : write(msg,'(i5, *(f9.3))') &
8924 0 : band, & ! Band
8925 0 : gwr%ks_ebands%eig(band, ik_ibz, spin) * Ha_eV, & ! E0
8926 0 : real(gwr%sigx_mat(band, merge(1, band, gwr%sig_diago), ikcalc, spin), kind=dp) * Ha_eV, & ! SigX
8927 0 : gwr%qp_ebands%occ(band, ik_ibz, spin) ! Occ(E)
8928 0 : call ydoc%add_tabular_line(msg)
8929 : end do
8930 :
8931 0 : call ydoc%write_units_and_free([std_out, ab_out])
8932 : end do ! ikcalc
8933 : end do ! spin
8934 : end if
8935 :
8936 : 10 continue
8937 0 : call cwtime_report(" gwr_build_sigxme:", cpu_all, wall_all, gflops_all)
8938 0 : call timab(1920, 2, tsec)
8939 :
8940 0 : end subroutine gwr_build_sigxme
8941 : !!***
8942 :
8943 : !----------------------------------------------------------------------
8944 :
8945 : !!****f* m_gwr/gwr_get_u_ngfft
8946 : !! NAME
8947 : !! gwr_get_u_ngfft
8948 : !!
8949 : !! FUNCTION
8950 : !! Compute FFT mesh from boxcutmin.
8951 : !!
8952 : !! INPUTS
8953 : !!
8954 : !! OUTPUT
8955 : !!
8956 : !! SOURCE
8957 :
8958 0 : subroutine gwr_get_u_ngfft(gwr, boxcutmin, u_ngfft, u_nfft, u_mgfft, u_mpw, gmax)
8959 :
8960 : !Arguments ------------------------------------
8961 : class(gwr_t),intent(in) :: gwr
8962 : real(dp),intent(in) :: boxcutmin
8963 : integer,intent(out) :: u_ngfft(18), u_nfft, u_mgfft, u_mpw, gmax(3)
8964 :
8965 : !Local variables-------------------------------
8966 : integer :: ik_bz, npw_, ig, ii
8967 : real(dp) :: kk_bz(3)
8968 0 : integer,allocatable :: gvec_(:,:)
8969 : ! *************************************************************************
8970 :
8971 : ! All MPI procs in gwr%comm execute this part.
8972 : ! Note the loops over the full BZ to compute u_mpw
8973 : ! FIXME: umklapp, ecutsigx and q-centered G-sphere
8974 : ! TODO: Write new routine to compute best FFT mesh for ecut1 + ecut1. See set_mesh from GW code.
8975 :
8976 0 : u_ngfft = gwr%dtset%ngfft ! This to allow users to specify fftalg
8977 :
8978 0 : u_mpw = -1; gmax = 0
8979 0 : do ik_bz=1,gwr%nkbz
8980 0 : kk_bz = gwr%kbz(:, ik_bz)
8981 0 : call get_kg(kk_bz, istwfk1, gwr%dtset%ecutwfn, gwr%cryst%gmet, npw_, gvec_)
8982 0 : u_mpw = max(u_mpw, npw_)
8983 : ! TODO: g0 umklapp here can enter into play gmax may not be large enough!
8984 0 : do ig=1,npw_
8985 0 : do ii=1,3
8986 0 : gmax(ii) = max(gmax(ii), abs(gvec_(ii, ig)))
8987 : end do
8988 : end do
8989 0 : ABI_FREE(gvec_)
8990 : call getng(boxcutmin, gwr%dtset%chksymtnons, gwr%dtset%ecutwfn, gwr%cryst%gmet, &
8991 : kk_bz, me_fft0, u_mgfft, u_nfft, u_ngfft, nproc_fft1, gwr%cryst%nsym, paral_fft0, &
8992 0 : gwr%cryst%symrel, gwr%cryst%tnons, gpu_option=gwr%dtset%gpu_option, unit=dev_null)
8993 : end do
8994 :
8995 0 : end subroutine gwr_get_u_ngfft
8996 : !!***
8997 :
8998 : !----------------------------------------------------------------------
8999 :
9000 : !!****f* m_gwr/get_1d_sc_phases
9001 : !! NAME
9002 : !! get_1d_sc_phases
9003 : !!
9004 : !! FUNCTION
9005 : !! Compute one-dimensional factors in the supercell.
9006 : !!
9007 : !! INPUTS
9008 : !! sc_shape(3)=Supercell shape.
9009 : !! nkpt=Number of k-points
9010 : !! kpts(3,nkpt)=K-points in reduced coordinates.
9011 : !!
9012 : !! OUTPUT
9013 : !! ph1d(maxval(sc_shape), 3, nkpt))
9014 : !!
9015 : !! SOURCE
9016 :
9017 0 : subroutine get_1d_sc_phases(sc_shape, nkpt, kpts, ph1d)
9018 :
9019 : !Arguments ------------------------------------
9020 : integer,intent(in) :: sc_shape(3), nkpt
9021 : real(dp),intent(in) :: kpts(3, nkpt)
9022 : complex(gwp),allocatable,intent(out) :: ph1d(:,:,:)
9023 :
9024 : !Local variables-------------------------------
9025 : integer :: ikpt, ix, iy, iz
9026 : real(dp) :: arg, fact, kk(3)
9027 : ! *************************************************************************
9028 :
9029 0 : ABI_MALLOC(ph1d, (maxval(sc_shape), 3, nkpt))
9030 :
9031 0 : do ikpt=1,nkpt
9032 0 : kk = kpts(:, ikpt)
9033 0 : fact = two_pi * kk(1)
9034 0 : do ix=0,sc_shape(1) - 1
9035 0 : arg = fact * ix
9036 0 : ph1d(ix + 1, 1, ikpt) = cmplx(cos(arg), sin(arg), kind=gwp)
9037 : end do
9038 0 : fact = two_pi * kk(2)
9039 0 : do iy=0,sc_shape(2) - 1
9040 0 : arg = fact * iy
9041 0 : ph1d(iy + 1, 2, ikpt) = cmplx(cos(arg), sin(arg), kind=gwp)
9042 : end do
9043 0 : fact = two_pi * kk(3)
9044 0 : do iz=0,sc_shape(3) - 1
9045 0 : arg = fact * iz
9046 0 : ph1d(iz + 1, 3, ikpt) = cmplx(cos(arg), sin(arg), kind=gwp)
9047 : end do
9048 : end do ! ikpt
9049 :
9050 0 : end subroutine get_1d_sc_phases
9051 : !!***
9052 :
9053 : !!****f* m_gwr/sc_sum
9054 : !! NAME
9055 : !! sc_sum
9056 : !!
9057 : !! FUNCTION
9058 : !! Compute matrix elements of the self-energy Sigma_nk in the supercell at fixed rr.
9059 : !!
9060 : !! INPUTS
9061 : !! sc_shape(3)=Supercell shape.
9062 : !! uc_ngfft(18)=Info on the FFT mesh in the unit cell.
9063 : !! nspinor=Number of spinor componenets.
9064 : !! ph1d=1d phase factors in the supercell
9065 : !! k_is_gamma=Tru if k is gamma.
9066 : !! alpha=Coeffient
9067 : !! sc_data=Values in the supercell
9068 : !! uc_psi=Wavefunction in the unit cell
9069 : !!
9070 : !! OUTPUT
9071 : !! cout=Partial contribution to integral.
9072 : !!
9073 : !! SOURCE
9074 :
9075 0 : subroutine sc_sum(sc_shape, uc_ngfft, ph1d, k_is_gamma, alpha, sc_data, uc_psi, cout)
9076 :
9077 : !Arguments ------------------------------------
9078 : integer,intent(in) :: sc_shape(3), uc_ngfft(18)
9079 : complex(gwp),intent(in) :: ph1d(maxval(sc_shape), 3)
9080 : logical,intent(in) :: k_is_gamma
9081 : complex(gwp),target,intent(in) :: alpha, uc_psi(uc_ngfft(1)*uc_ngfft(2)*uc_ngfft(3))
9082 : complex(gwp),target,intent(in) :: &
9083 : sc_data(uc_ngfft(1)*sc_shape(1)*uc_ngfft(2)*sc_shape(2)*uc_ngfft(3)*sc_shape(3))
9084 : complex(gwp),intent(out) :: cout
9085 :
9086 : !Local variables-------------------------------
9087 : integer :: il1, il2, il3, uc_n1, uc_n2, uc_n3, ix, iy, iz !, idat
9088 : complex(gwp) :: cphase, phl32, phl3
9089 0 : complex(gwp),contiguous,pointer :: uc_psi_ptr(:,:,:), sc_data_ptr(:,:,:,:,:,:)
9090 : ! *************************************************************************
9091 :
9092 0 : uc_n1 = uc_ngfft(1); uc_n2 = uc_ngfft(2); uc_n3 = uc_ngfft(3)
9093 :
9094 0 : call c_f_pointer(c_loc(uc_psi), uc_psi_ptr, shape=[uc_n1, uc_n2, uc_n3])
9095 : call c_f_pointer(c_loc(sc_data), sc_data_ptr, &
9096 0 : shape=[uc_n1, sc_shape(1), uc_n2, sc_shape(2), uc_n3, sc_shape(3)])
9097 :
9098 0 : cout = zero
9099 :
9100 0 : if (k_is_gamma) then
9101 : ! Don't need to multiply by e^{ik.L}
9102 0 : do il3=1,sc_shape(3)
9103 0 : do iz=1,uc_n3
9104 0 : do il2=1,sc_shape(2)
9105 0 : do iy=1,uc_n2
9106 0 : do il1=1,sc_shape(1)
9107 0 : do ix=1,uc_n1
9108 0 : cout = cout + uc_psi_ptr(ix, iy, iz) * sc_data_ptr(ix, il1, iy, il2, iz, il3)
9109 : end do
9110 : end do
9111 : end do
9112 : end do
9113 : end do
9114 : end do
9115 :
9116 : else
9117 : ! Need to multiply by e^{ik.L}
9118 0 : do il3=1,sc_shape(3)
9119 0 : phl3 = ph1d(il3, 3)
9120 0 : do iz=1,uc_n3
9121 0 : do il2=1,sc_shape(2)
9122 0 : phl32 = phl3 * ph1d(il2, 2)
9123 0 : do iy=1,uc_n2
9124 0 : do il1=1,sc_shape(1)
9125 0 : cphase = phl32 * ph1d(il1, 1) ! e^{ik.L}
9126 0 : do ix=1,uc_n1
9127 0 : cout = cout + cphase * uc_psi_ptr(ix, iy, iz) * sc_data_ptr(ix, il1, iy, il2, iz, il3)
9128 : end do
9129 : end do
9130 : end do
9131 : end do
9132 : end do
9133 : end do
9134 : end if
9135 :
9136 0 : cout = alpha * cout
9137 :
9138 0 : end subroutine sc_sum
9139 : !!***
9140 :
9141 : !!****f* m_gwr/memb_limited_step
9142 : !! NAME
9143 : !! memb_limited_step
9144 : !!
9145 : !! FUNCTION
9146 : !! Compute the amount of memory needed to process all the data between start and stop,
9147 : !! and limits the number of steps to avoid exceeding maxmem_mb.
9148 : !!
9149 : !! INPUTS
9150 : !! start, stop: integer range of indices.
9151 : !! num_items: number of data items processed per index.
9152 : !! bsize: size in bytes per data item.
9153 : !! maxmem_mb: maximum allowed memory usage (in megabytes)
9154 : !!
9155 : !! OUTPUT
9156 : !!
9157 : !! SOURCE
9158 :
9159 : integer pure function memb_limited_step(start, stop, num_items, bsize, maxmem_mb) result(step)
9160 : integer,intent(in) :: start, stop, num_items, bsize
9161 : real(dp),intent(in) :: maxmem_mb
9162 :
9163 : !Local variables-------------------------------
9164 : real(dp) :: totmem_mb
9165 : ! *************************************************************************
9166 :
9167 : totmem_mb = one * (stop - start + 1) * num_items * bsize
9168 : step = stop - start + 1
9169 : if (totmem_mb > maxmem_mb) step = floor(totmem_mb / maxmem_mb)
9170 :
9171 : end function memb_limited_step
9172 : !!***
9173 :
9174 : !----------------------------------------------------------------------
9175 :
9176 : !!****f* m_gwr/gwr_gamma_gw
9177 : !! NAME
9178 : !! gwr_gamma_gw
9179 : !!
9180 : !! FUNCTION
9181 : !!
9182 : !! INPUTS
9183 : !! vpsp(nfft)=local psp (Hartree)
9184 : !!
9185 : !! OUTPUT
9186 : !!
9187 : !! SOURCE
9188 :
9189 0 : subroutine gwr_gamma_gw(gwr, nfftf, ngfftf, vpsp)
9190 :
9191 : use m_gwrdm, only : calc_rdmx,calc_rdmc,natoccs,update_hdr_bst,print_tot_occ,get_chkprdm,&
9192 : print_chkprdm,change_matrix,print_total_energy,print_band_energies
9193 : use m_spacepar, only : hartre
9194 :
9195 : !Arguments ------------------------------------
9196 : class(gwr_t),target,intent(inout) :: gwr
9197 : integer,intent(in) :: nfftf
9198 : !arrays
9199 : integer,intent(in) :: ngfftf(18)
9200 : real(dp),intent(in) :: vpsp(nfftf)
9201 :
9202 : !Local variables-------------------------------
9203 : !scalars
9204 : integer,parameter :: master = 0, cplex1 = 1, tim_fourdp5 = 5
9205 : integer :: spin, ikcalc, ik_ibz, ib, ib1, ib2, nkibz, nsppol, mband, ierr, b1gw, b2gw
9206 : !real(dp) :: cpu, wall, gflops
9207 : real(dp) :: evext_energy,den_int !,coef_hyb,exc_mbb_energy eh_energy, ekin_energy,
9208 : real(dp) :: gsqcut,boxcut,ecutf
9209 : character(len=500) :: msg
9210 0 : type(hdr_type) :: Hdr_sigma
9211 : !arrays
9212 : integer :: units(2)
9213 : real(dp),parameter :: k0(3) = zero
9214 : !real(dp) :: kgw(3) ! kk_ibz(3),
9215 0 : real(dp),allocatable :: nat_occs(:,:), gw_rhor(:,:), gw_rhog(:,:), gw_vhartr(:)
9216 0 : complex(dp),allocatable :: xrdm_k_full(:,:,:), rdm_k(:,:), pot_k(:,:), nateigv(:,:,:,:), old_ks_purex(:,:), new_hartr(:,:)
9217 0 : complex(dp) :: omega_i(gwr%ntau)
9218 0 : complex(dp),allocatable :: sigcme_k(:,:,:,:)
9219 : ! *************************************************************************
9220 :
9221 0 : call gwr%run_g0w0(free_ugb=.False.)
9222 : ! TODO: Might release some PBLAS memory for W at this point
9223 :
9224 : ! This section is copied from m_sigma_driver with small changes in order to intergrate it with the gwr% object.
9225 : associate (dtset => gwr%dtset, qp_ebands => gwr%qp_ebands, ks_me => gwr%ks_me, psps => gwr%psps, &
9226 : Wfd_nato_master => gwr%kcalc_wfd, dtfil => gwr%dtfil, cryst => gwr%cryst)
9227 :
9228 0 : units = [std_out, ab_out]
9229 0 : nkibz = gwr%nkibz; nsppol = gwr%nsppol; b1gw = gwr%b1gw; b2gw = gwr%b2gw
9230 : ! Don't take mband from ks_ebands but compute it from gwr%bstop_ks
9231 0 : mband = maxval(gwr%bstop_ks) !; mband = gwr%ks_ebands%mband
9232 :
9233 : ! Note: all subroutines of 70_gw/m_gwrdm.F90 are implemented assuming nsppol == 1
9234 0 : ABI_CHECK(dtset%nsppol == 1, "1-RDM GW correction only implemented for restricted closed-shell calculations!")
9235 0 : ABI_CHECK(.not. gwr%sig_diago, "sig_diago should be false")
9236 :
9237 0 : ABI_CALLOC(nateigv, (mband, mband, nkibz, nsppol))
9238 0 : ABI_CALLOC(nat_occs, (mband, nkibz))
9239 0 : ABI_CALLOC(xrdm_k_full, (b1gw:b2gw, b1gw:b2gw, nkibz))
9240 :
9241 0 : write(msg,'(a34,2i9)')' Bands used for the GW 1RDM arrays',b1gw,b2gw
9242 0 : call wrtout(units, msg)
9243 :
9244 0 : do ik_ibz=1,nkibz
9245 0 : do ib=b1gw,b2gw
9246 0 : xrdm_k_full(ib,ib,ik_ibz) = qp_ebands%occ(ib,ik_ibz,1)
9247 : end do
9248 0 : do ib=1,mband
9249 : ! Copy initial occ numbers (in principle 2 or 0 from KS-DFT)
9250 0 : nat_occs(ib,ik_ibz) = qp_ebands%occ(ib,ik_ibz,1)
9251 : ! Set to identity matrix
9252 0 : nateigv(ib,ib,ik_ibz,1) = cone
9253 : end do
9254 : end do
9255 :
9256 0 : omega_i = j_dpc * gwr%iw_mesh
9257 :
9258 0 : do spin=1,gwr%nsppol
9259 0 : do ikcalc=1,gwr%nkcalc ! TODO: Should be spin dependent!
9260 : ! Index of the irred k-point
9261 0 : ik_ibz = gwr%kcalc2ibz(ikcalc, 1)
9262 : !kgw = gwr%kcalc(:, ikcalc)
9263 : ! min and max band indices for GW corrections (for this k-point)
9264 0 : ib1 = gwr%bstart_ks(ikcalc, spin); ib2 = gwr%bstop_ks(ikcalc, spin)
9265 :
9266 : ! Compute Sigma_x - Vxc or DELTA Sigma_x - Vxc
9267 : ! where DELTA Sigma_x = Sigma_x - hyb_parameter Vx^exact for hyb Functionals.
9268 : ! NB: Only restricted closed-shell calcs are implemented here
9269 0 : ABI_CALLOC(pot_k, (ib1:ib2, ib1:ib2))
9270 0 : ABI_CALLOC(rdm_k, (ib1:ib2, ib1:ib2))
9271 0 : pot_k(ib1:ib2,ib1:ib2) = gwr%sigx_mat(ib1:ib2,ib1:ib2,ik_ibz,spin) - ks_me%vxcval(ib1:ib2,ib1:ib2,ik_ibz,spin)
9272 0 : call calc_rdmx(ib1, ib2, ik_ibz, pot_k, rdm_k, qp_ebands)
9273 :
9274 : ! Update the full 1RDM with the exchange corrected one for this k-point
9275 0 : xrdm_k_full(ib1:ib2,ib1:ib2,ik_ibz) = xrdm_k_full(ib1:ib2,ib1:ib2,ik_ibz) + rdm_k(ib1:ib2,ib1:ib2)
9276 :
9277 : ! Compute NAT ORBS for exchange corrected 1-RDM
9278 : ! Only restricted closed-shell calcs
9279 0 : do ib=ib1,ib2
9280 0 : rdm_k(ib,ib) = rdm_k(ib,ib) + qp_ebands%occ(ib,ik_ibz,1)
9281 : end do
9282 0 : call natoccs(ib1, ib2, rdm_k, nateigv, nat_occs, qp_ebands, ik_ibz, iinfo=0)
9283 :
9284 : ! ================
9285 : ! Correlation part
9286 : ! ================
9287 : ! TODO
9288 : !ABI_CALLOC(sigcme_k, (gwr%ntau, ib2-ib1+1, ib2-ib1+1, nsppol*gwr%nsig_ab))
9289 : !gwr%sigc_iw_mat((gwr%ntau, ib1:, ib1:, nsppol*gwr%nsig_ab))
9290 0 : call calc_rdmc(ib1, ib2, ik_ibz, omega_i, gwr%iw_wgs, sigcme_k, qp_ebands, rdm_k)
9291 : !ABI_FREE(sigcme_k)
9292 :
9293 : ! Update the full 1RDM with the GW corrected one for this k-point
9294 : ! Only restricted closed-shell calcs
9295 0 : rdm_k(ib1:ib2,ib1:ib2) = xrdm_k_full(ib1:ib2,ib1:ib2,ik_ibz) + rdm_k(ib1:ib2,ib1:ib2)
9296 : ! Compute nat orbs and occ numbers at k-point ik_ibz
9297 0 : call natoccs(ib1, ib2, rdm_k, nateigv, nat_occs, qp_ebands, ik_ibz, iinfo=1)
9298 :
9299 0 : ABI_FREE(pot_k)
9300 0 : ABI_FREE(rdm_k)
9301 : end do ! ikcalc
9302 : end do ! spin
9303 :
9304 0 : ABI_CALLOC(gw_rhor, (nfftf, dtset%nspden))
9305 0 : call gwr%wfk_hdr%copy(hdr_sigma)
9306 :
9307 : ! NRM WARNING: only the master has bands on Wfd_nato_master so it prints everything and computes gw_rhor
9308 : !
9309 : ! All procs. update the qp_ebands and the Hdr_sigma
9310 0 : call update_hdr_bst(Wfd_nato_master, nat_occs, b1gw, b2gw, qp_ebands, Hdr_sigma, Dtset%ngfft(1:3))
9311 :
9312 : ! Compute unit cell (averaged) occ = \sum _k weight_k occ_k
9313 0 : call print_tot_occ(qp_ebands)
9314 :
9315 0 : if (gwr%comm%me == master) then
9316 0 : call Wfd_nato_master%rotate(cryst, nateigv) !, bmask=bdm_mask) ! Let it use bdm_mask and build NOs
9317 0 : call Wfd_nato_master%mkrho(cryst, psps, qp_ebands, ngfftf, nfftf, gw_rhor) ! Construct the density
9318 0 : if (dtset%prtwf == 1) then
9319 : ! Print WFK file, here qp_ebands contains nat. orb. occs.
9320 0 : call Wfd_nato_master%write_wfk(Hdr_sigma, qp_ebands, dtfil%fnameabo_wfk, wfknocheck=.True.)
9321 : end if
9322 0 : if (dtset%prtden == 1) then
9323 : ! Print DEN file
9324 : call fftdatar_write("density",dtfil%fnameabo_den,dtset%iomode,Hdr_sigma,&
9325 0 : Cryst,ngfftf,cplex1,nfftf,dtset%nspden,gw_rhor,gwr%mpi_enreg,ebands=qp_ebands)
9326 : end if
9327 : end if
9328 0 : call xmpi_bcast(gw_rhor, master, gwr%comm%value, ierr)
9329 0 : call hdr_sigma%free()
9330 :
9331 : ! Compute energies only if all k-points are available
9332 : ! We need the hole 1-RDM to build Fock[GW.1RDM]!
9333 0 : ABI_CALLOC(old_ks_purex, (b1gw:b2gw, gwr%nkcalc))
9334 0 : ABI_CALLOC(new_hartr, (b1gw:b2gw, gwr%nkcalc))
9335 0 : ABI_CALLOC(gw_rhog, (2, nfftf))
9336 0 : ABI_CALLOC(gw_vhartr, (nfftf))
9337 : !
9338 : ! A) Compute Evext = int rho(r) vext(r) dr -> simply dot product on the FFT grid
9339 : ! Only restricted closed-shell calcs
9340 : !
9341 0 : den_int = sum(gw_rhor(:,1)) * cryst%ucvol / nfftf
9342 0 : evext_energy = sum(gw_rhor(:,1) * vpsp(:)) * cryst%ucvol / nfftf
9343 : !
9344 : ! B) Coulomb <KS_i|Vh[NO]|KS_j>
9345 : !
9346 : ! FFT to build gw_rhog
9347 0 : call fourdp(1, gw_rhog, gw_rhor(:,1), -1, gwr%mpi_enreg, nfftf, ndat1, ngfftf, tim_fourdp5)
9348 :
9349 0 : ecutf = dtset%ecutwfn
9350 0 : if (psps%usepaw == 1) then
9351 0 : ecutf = dtset%pawecutdg
9352 0 : call wrtout(std_out, ch10//' FFT (fine) grid used in PAW GW update:')
9353 : end if
9354 :
9355 0 : call getcut(boxcut, ecutf, cryst%gmet, gsqcut, dtset%iboxcut, std_out, k0, ngfftf)
9356 : call hartre(1, gsqcut, dtset%icutcoul, psps%usepaw, gwr%mpi_enreg, nfftf, ngfftf, dtset%nkpt, dtset%rcut, &
9357 0 : gw_rhog, cryst%rprimd, dtset%vcutgeo, gw_vhartr)
9358 :
9359 : ! TODO
9360 0 : ABI_FREE(nateigv)
9361 0 : ABI_FREE(nat_occs)
9362 0 : ABI_FREE(xrdm_k_full)
9363 0 : ABI_FREE(gw_rhor)
9364 0 : ABI_FREE(old_ks_purex)
9365 0 : ABI_FREE(new_hartr)
9366 0 : ABI_FREE(gw_rhog)
9367 0 : ABI_FREE(gw_vhartr)
9368 : end associate
9369 :
9370 0 : end subroutine gwr_gamma_gw
9371 : !!***
9372 :
9373 0 : end module m_gwr
9374 : !!***
|