LCOV - code coverage report
Current view: top level - src/94_scfcv - m_gwr.F90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 3391 0
Test Date: 2026-09-21 19:39:32 Functions: 0.0 % 60 0

            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              : !!***
        

Generated by: LCOV version 2.3-1