LCOV - code coverage report
Current view: top level - src/78_eph - m_gstore.F90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 56.7 % 2768 1570
Test Date: 2026-09-19 17:42:43 Functions: 72.3 % 47 34

            Line data    Source code
       1              : !!****m* ABINIT/m_gstore
       2              : !! NAME
       3              : !! m_gstore
       4              : !!
       5              : !! FUNCTION
       6              : !!  This module implements the gstore_t object that allows one to **precompute"" the e-ph matrix elements g
       7              : !!  and store them in memory with a MPI-distributed data structure.
       8              : !!  This approach is the most CPU-efficient one when one has to deal with
       9              : !!  algorithms in which the same g(q, k) is required several (many) times.
      10              : !!  Typical examples are iterative solvers for non-linear equations that are called inside a loop over T.
      11              : !!  At each iteration, indeed, we need g(q, k) and computing these quantities from scratch
      12              : !!  would be very expensive.
      13              : !!
      14              : !!  Note that g depends on the two wave vectors (q, k), two electron band indices (m, n),
      15              : !!  phonon mode nu with crystalline momentum q and spin index if nsppol == 2 (collinear case).
      16              : !!
      17              : !!  g(q, k) is therefore a sloppy notation for:
      18              : !!
      19              : !!          g(q, k) = <k+q,m,spin| \Delta_{q,\nu} V^{spin}_{scf} |k,n,spin>
      20              : !!
      21              : !!  There are lots of technical details that should be discussed but, roughly speaking,
      22              : !!  the gstore API allows one to:
      23              : !!
      24              : !!   - select whether q or k should be in the IBZ or in the BZ.
      25              : !!     NB: It is not possible to use the IBZ both for q and k as g(Sk, q) = g(k, S^{-1}q)
      26              : !!     thus one has to select the appropriate zones beforehand.
      27              : !!
      28              : !!   - filter bands and/or k/q wavevectors according to some criterion.
      29              : !!     In superconductors, for instance, only k/k+q states on the Fermi surface are usually needed.
      30              : !!     In semiconductors, one can include only k, k+q inside an energy window around the band edge.
      31              : !!     for transport properties or just the |n,k,spin> states at the band edges while <k+q,m,spin|
      32              : !!     have q in the BZ and m=1,nband.
      33              : !!
      34              : !!  - whether the code should compute and store the complex valued g or |g|^2.
      35              : !!    Expression depending of |g|^2 are gauge-invariant provided that all degenerate states are summed over.
      36              : !!    On the contrary, the complex valued g is gauge-dependent and hic sunt leones.
      37              : !!    In Abinit, the g elements are computed within the same gauge by reconstructing Bloch states
      38              : !!    in the BZ from the IBZ by using a deterministic symmetrization algorithm
      39              : !!    Client code reading the e-ph matrix elements produced by ABINIT is expected to follow the
      40              : !!    same conventions, especially if one needs to mix g with wavefunctions in the BZ.
      41              : !!
      42              : !!  At the level of the API, we have three different routines.
      43              : !!
      44              : !!      1) gstore_init builds the object, defines the BZ sampling type (e.g. k in the IBZ, q in the BZ)
      45              : !!         and implements filtering techniques. The MPI grid is automatically generated at this level.
      46              : !!
      47              : !!      2) gstore_compute evaluates the KS e-ph matrix elements in parallel and dumps the results to GSTORE.nc.
      48              : !!
      49              : !!      3) gstore%from_ncpath reconstructs the object from a GSTORE.nc file.
      50              : !!
      51              : !!  In a typical scenario, one uses eph_task 11 to generate GSTORE.nc i.e. steps 1) and 2).
      52              : !!  Then one introduces a new value of eph_task in which we read the object from file and call
      53              : !!  a specialized routine that implements the "post-processing" steps needed
      54              : !!  to compute the physical properties of interest.
      55              : !!
      56              : !!  Last but not least, the GSTORE.nc file can also produced by gwpt_run (eph_task 17).
      57              : !!  In this case, gvals are the matrix elements computed with the variation of the self-energy
      58              : !!  instead of the KS Hamiltonian.
      59              : !!
      60              : !!  Now, let us discuss the MPI-distribution.
      61              : !!
      62              : !!  The (q, k) matrix is distributed inside a 2D cartesian grid using block distribution.
      63              : !!  This is schematic representation for MPI 4 procs with 2 procs for k and 2 procs for q:
      64              : !!
      65              : !!                 k-axis (kpt_comm)
      66              : !!              |--------------------
      67              : !!              |         |         |
      68              : !!              |   P00   |   P01   |
      69              : !!              |         |         |
      70              : !!    q-axis    |--------------------
      71              : !!  (qpt_comm)  |         |         |
      72              : !!              |   P10   |   P11   |
      73              : !!              |         |         |
      74              : !!              |--------------------
      75              : !!
      76              : !!  Each MPI processor stores all the (band_kq, band_k) transitions for a given (q, k) pair.
      77              : !!
      78              : !!  Perturbations can be optionally distributed along a third axis (pert_comm).
      79              : !!  Note, however, that the parallelism over perturbations is not expected to be the most efficient
      80              : !!  although it allows one to reduce the memory required to store the scattering potential in the supercell
      81              : !!  as we can distribute W(r, R, 3 * natom) over the last dimension.
      82              : !!
      83              : !!  For electronic properties, one usually uses k-points in the IBZ and q-points in the BZ.
      84              : !!  hence the parallelism over q-points is the most efficient one in terms of wall-time.
      85              : !!  Keep in mind, however, that the k-point parallelism allows one to reduce the memory allocated for the
      86              : !!  wavefunctions. Using some procs for k-points is also beneficial in terms of performance
      87              : !!  as we can reduce load imbalance is the number of procs in qpt_comm does not divide nqbz.
      88              : !!
      89              : !!  NB: If nsppol == 2, we create two gqk instances, one for each spin.
      90              : !!  The reason is that dimensions such as the number of effective bands/q-points/k-points
      91              : !!  depends on the collinear spin when filters are employed.
      92              : !!
      93              : !! TODO
      94              : !!  - Implement possibility of reading a subset of data (bands) from a larger gstore ?
      95              : !!  - Optimize v^1_loc|psi_nk> by precomputing <r|psi_nk> before the loop over my_npert
      96              : !!    Big speedup is expected, especially if one loops first over k and then q, provided
      97              : !!    the interpolation of v^1_q does not start to dominate.
      98              : !!  - Use similar trick in dfpt_cgw for H^0 |psi_nk>.
      99              : !!  - Operate on multiple n states in getgh1c (new version of getgh1c allows it).
     100              : !!  - Write IFC to faciliate interporability with external codes (DONE)
     101              : !!  - Save alpha parameters so that external codes can handle the short range part of the IFCs (DONE)
     102              : !!  - Move to atom representation and add symmetry tables qbz --> qibz to fix the gauge in the ph displacements.
     103              : !!  - Write GSTORE tutorial to explain all the relevant combinations.
     104              : !!
     105              : !! COPYRIGHT
     106              : !!  Copyright (C) 2008-2026 ABINIT group (MG)
     107              : !!  This file is distributed under the terms of the
     108              : !!  GNU General Public License, see ~abinit/COPYING
     109              : !!  or http://www.gnu.org/copyleft/gpl.txt .
     110              : !!
     111              : !! SOURCE
     112              : 
     113              : #if defined HAVE_CONFIG_H
     114              : #include "config.h"
     115              : #endif
     116              : 
     117              : #include "abi_common.h"
     118              : 
     119              : module m_gstore
     120              : 
     121              :  use, intrinsic :: iso_c_binding
     122              :  use defs_basis
     123              :  use m_abicore
     124              :  use m_clib
     125              :  use m_xmpi
     126              :  use m_errors
     127              :  use m_htetra
     128              :  use libtetrabz
     129              :  use netcdf
     130              :  use m_nctk
     131              :  use m_ddb
     132              :  use m_ddk
     133              :  use m_dvdb
     134              :  use m_fft
     135              :  use m_hamiltonian
     136              :  use m_pawcprj
     137              :  use m_ephtk
     138              :  use m_mkffnl
     139              :  use m_sigtk
     140              : 
     141              :  use defs_abitypes,    only : mpi_type
     142              :  use defs_datatypes,   only : pseudopotential_type
     143              :  use m_dtset,          only : dataset_type
     144              :  use m_dtfil,          only : datafiles_type
     145              :  use m_time,           only : cwtime, cwtime_report, sec2str
     146              :  use m_fstrings,       only : tolower, itoa, ftoa, sjoin, ktoa, ltoa, strcat, replace_ch0, yesno, string_in
     147              :  use m_numeric_tools,  only : arth, get_diag, isdiagmat, safe_div, r2c
     148              :  use m_krank,          only : krank_t, get_ibz2bz, star_from_ibz_idx
     149              :  use m_io_tools,       only : iomode_from_fname, file_exists
     150              :  use m_special_funcs,  only : gaussian
     151              :  use m_geometry,       only : phdispl_cart2red_nmodes
     152              :  use m_copy,           only : alloc_copy
     153              :  use m_fftcore,        only : ngfft_seq, get_kg, sphereboundary
     154              :  use m_cgtools,        only : cg_zdotc, cg_p_psi
     155              :  use m_kg,             only : getph
     156              :  use m_crystal,        only : crystal_t
     157              :  use m_hdr,            only : hdr_type, fform_from_ext
     158              :  use m_matrix,         only : mati3inv, matr3inv
     159              :  use m_kpts,           only : kpts_ibz_from_kptrlatt, kpts_timrev_from_kptopt, kpts_map, kpts_sort, kpts_pack_in_stars, &
     160              :                               kptrlatt_from_ngkpt
     161              :  use m_ebands,         only : ebands_t, gaps_t
     162              :  use m_lgroup,         only : lgroup_t
     163              :  use m_bz_mesh,        only : kmesh_t, isamek
     164              :  use m_getgh1c,        only : getgh1c, rf_transgrid_and_pack
     165              :  use m_ifc,            only : ifc_type
     166              :  use m_phonons,        only : pheigvec_rotate
     167              :  use m_wfd,            only : wfd_t
     168              :  use m_pawang,         only : pawang_type
     169              :  use m_pawrad,         only : pawrad_type
     170              :  use m_pawtab,         only : pawtab_type
     171              :  use m_pawfgr,         only : pawfgr_type
     172              :  use m_mlwfovlp,       only : wan_t, wan_interp_ebands
     173              :  use m_pstat,          only : pstat_proc
     174              :  use m_io_screening,   only : hscr_t, get_hscr_qmesh_gsph
     175              :  use m_gsphere,        only : gsphere_t
     176              :  use m_abi_linalg,     only : abi_gpu_xgemm_d
     177              :  use m_classify_bands, only : dmats_t
     178              : 
     179              :  implicit none
     180              : 
     181              :  private
     182              : 
     183              :  character(len=abi_slen),public,parameter :: GSTORE_GMODE_ATOM   = "atom"
     184              :  character(len=abi_slen),public,parameter :: GSTORE_GMODE_PHONON = "phonon"
     185              :  character(len=abi_slen),public,parameter :: GSTORE_GTYPE_KS     = "KS"
     186              :  character(len=abi_slen),public,parameter :: GSTORE_GTYPE_GWPT   = "gwpt"
     187              : 
     188              :  ! Flags
     189              :  integer, public :: GSTORE_KQ_MISSING = 0        ! (k, q, spin) has not been computed.
     190              :  integer, public :: GSTORE_KQ_COMPUTED = 1       ! (k, q, spin) has been computed.
     191              :  integer, public :: GSTORE_KQ_SYMMETRIZED = 2    ! (k, q, spin) has been reconstructed by symmetry.
     192              : 
     193              :  ! Rank of the MPI Cartesian grid.
     194              :  integer,private,parameter :: ndims = 6
     195              : !!***
     196              : 
     197              : !----------------------------------------------------------------------
     198              : 
     199              : !!****t* m_gstore/gqk_t
     200              : !! NAME
     201              : !! gqk_t
     202              : !!
     203              : !! FUNCTION
     204              : !!  This object stores MPI-distributed e-ph matrix elements for
     205              : !!  a given spin index (if collinear magnetism i.e. nsppol 2).
     206              : !!  Local dimensions and arrays start with `my_`, global dimensions start with `glob_`
     207              : !!
     208              : !! SOURCE
     209              : 
     210              : type, public :: gqk_t
     211              : 
     212              :   integer :: cplex = -1
     213              :   ! 1 if |g|^2 is stored
     214              :   ! 2 if complex-valued g are stored (mind the gauge)
     215              : 
     216              :   integer :: spin = -1
     217              :   ! Spin index.
     218              : 
     219              :   integer :: natom3 = -1
     220              :   ! 3 * natom
     221              :   ! Mainly used to dimension arrays
     222              : 
     223              :   integer :: nb_kq = -1, nb_k = -1
     224              :   ! Number of bands included in the calculation at k+q and k, for this spin.
     225              :   ! Global as these dimensions are NOT DISTRIBUTED with MPI
     226              :   ! NB: nb_kq and nb_k are not necessarily equal to nband.
     227              :   ! Use bstar_kq and bstart_k to get the band index, e.g.:
     228              :   !
     229              :   ! do in_k=1,gqk%nb_k
     230              :   !   band_k = in_k + gqk%bstart_k - 1
     231              :   !
     232              :   ! do imq_k=1,gqk%nb_kq
     233              :   !   band_kq = im_kq + gqk%bstart_kq - 1
     234              : 
     235              :   integer :: bstart_k = -1, bstop_k = -1
     236              :   integer :: bstart_kq = -1, bstop_kq = -1
     237              :   ! The first band at k starts at bstart_k.
     238              :   ! The last band at k is bstop_k (NB: These are global indices)
     239              :   ! Same meaning for bstart_kq and bstop_kq.
     240              : 
     241              :   integer :: my_npert = -1
     242              :   ! Number of perturbations treated by this MPI rank.
     243              : 
     244              :   integer :: my_pert_start = -1
     245              :   ! Initial perturbation treated by this MPI proc
     246              : 
     247              :   integer :: glob_nk = -1, glob_nq = -1
     248              :   ! Total number of k/q points in global matrix.
     249              :   ! Note that k-points/q-points can be filtered. Use kzone, qzone and kfilter to interpret these dimensions.
     250              : 
     251              :   integer :: my_nk = -1, my_nq = -1
     252              :   ! Number of k/q points treated by this MPI proc. Used to loop and allocate local arrays.
     253              : 
     254              :   integer :: my_kstart = -1, my_qstart = -1
     255              :   ! Index of the first k/q point in the global matrix treated by this MPI proc
     256              : 
     257              :   integer,allocatable :: my_k2ibz(:,:)
     258              :   ! (6, my_nk)
     259              :   ! Mapping my_kpoints --> kibz (symrel conventions)
     260              : 
     261              :   !integer,allocatable :: my_k2bz(:,:)
     262              :   ! (my_nk)
     263              :   ! Mapping my_kpoints --> ik_bz
     264              : 
     265              :   real(dp),allocatable :: my_kpts(:,:)
     266              :   ! (3, my_nkpt)
     267              :   ! k-points treated by this MPI proc.
     268              : 
     269              :   real(dp),allocatable :: my_wtk(:)
     270              :   ! (my_nkpt)
     271              :   ! Weights for the k-points treated by this MPI proc.
     272              : 
     273              :   integer,allocatable :: my_q2ibz(:,:)
     274              :   ! (6, my_nq)
     275              :   ! Mapping my_qpoints --> qibz
     276              :   ! symrel conventions
     277              : 
     278              :   integer,allocatable :: my_q2bz(:)
     279              :   ! (my_nq)
     280              :   ! Mapping my_iq index --> iq_bz index in the full BZ
     281              : 
     282              :   integer,allocatable :: my_k2glob(:)
     283              :   ! (my_nk)
     284              :   ! Mapping my_ik index --> global index in the g(q, k) matrix.
     285              : 
     286              :   integer,allocatable :: my_q2glob(:)
     287              :   ! (my_nq)
     288              :   ! Mapping my_iq index --> global index in the g(q, k) matrix.
     289              : 
     290              :   real(dp),allocatable :: vnk_cart_ibz(:,:,:)
     291              :   ! (3, nb_k, nkibz)
     292              :   ! Diagonal v_{n,k} for k in the IBZ.
     293              :   ! Values in the BZ can be reconstructed by symmetry.
     294              :   ! Allocated if gstore%with_vk == 1
     295              :   ! TODO: Here I should decide how to treat nb_k, nk_kq
     296              : 
     297              :   real(dp),allocatable :: vnk_mat_cart_ibz(:,:,:,:,:)
     298              :   ! (3, nb_k, nb_k, nkibz)
     299              :   ! v_{m, n,k} for the k in the IBZ
     300              :   ! Allocated if gstore%with_vk in (1, 2)
     301              :   ! TODO: Here I should decide how to treat nb_k, nk_kq
     302              : 
     303              :   integer,allocatable :: my_pertcases(:)
     304              :   ! (my_npert)
     305              :   ! List of perturbation indices treated by this MPI proc.
     306              :   ! Contiguous indices.
     307              : 
     308              :   logical :: has_both_g = .False.
     309              :   ! True if my_g_ks pointer is allocated and use to store the KS matrix elements
     310              :   ! In this case, my_g stores the GWPT matrix elements.
     311              : 
     312              :   complex(dp), allocatable :: my_g(:,:,:,:,:)
     313              :   complex(dp), contiguous, pointer  :: my_g_ks(:,:,:,:,:) => null()
     314              :   ! (my_npert, nb_kq, my_nq, nb_k, my_nk)
     315              :   ! (       p, b1_kq,     q, b2_k, k)  -->  <k+q, b1| D_{q,p}H |k, b2>
     316              :   ! e-ph matrix elements g (local buffer). Allocated if cplex == 2
     317              : 
     318              :   real(dp), allocatable :: my_g2(:,:,:,:,:)
     319              :   real(dp), contiguous, pointer :: my_g2_ks(:,:,:,:,:) => null()
     320              :   ! (my_npert, nb_kq, my_nq, nb_k, my_nk)
     321              :   ! e-ph matrix elements g^2 (local buffer).
     322              : 
     323              :   real(dp), allocatable :: my_gdw2(:,:,:,:,:)
     324              :   real(dp), contiguous, pointer :: my_gdw2_ks(:,:,:,:,:) => null()
     325              :   ! (my_npert, nb_kq, my_nq, nb_k, my_nk)
     326              :   ! gDW^2 (local buffer) (only for diagonal DW self-energy in the RIA)
     327              : 
     328              :   complex(dp), allocatable :: my_iv1p_comm(:,:,:,:,:)
     329              :    ! (nb_k, nb_k, 3, my_npert, my_nk))
     330              :    ! Stores i <psi_mk[V1_q0ka, p]|psi_nk> in reduced coordinates.
     331              :    ! Can be used to compute non-diagonal DW self-energy in the RIA. See [[cite:Lihm2020]], PhysRevB.101.121102
     332              :    ! Note that in the present implementation both m and n indices run from bstart_k to bstop_k.
     333              : 
     334              :   integer :: coords_qkpb_sumbp(ndims) = 0
     335              :   ! Coordinates of this processor in the (q, k, pert, band, band_sum, pp_sum) Cartesian grid.
     336              : 
     337              :   type(xcomm_t) :: kpt_comm
     338              :    ! MPI communicator over k-points
     339              : 
     340              :   type(xcomm_t) :: qpt_comm
     341              :    ! MPI communicator over q-points
     342              : 
     343              :   type(xcomm_t) :: qpt_kpt_comm
     344              :    ! MPI communicator over k/q subgrid
     345              : 
     346              :   type(xcomm_t) :: pert_comm
     347              :    ! MPI communicator over atomic perturbations.
     348              : 
     349              :   type(xcomm_t) :: band_comm
     350              :    ! MPI communicator for band distribution.
     351              : 
     352              :   type(xcomm_t) :: bsum_comm
     353              :    ! MPI communicator over bands in summation. NB: It is not used to distribute
     354              :    ! the memory for the g but to distribute a possible sum over bands as done in the GWPT code.
     355              : 
     356              :   type(xcomm_t) :: pp_sum_comm
     357              :    ! MPI communicator over wavevector summation. NB: It not used to distribute
     358              :    ! the memory for the g but to distribute a possible sum over wavevectors as done in the GWPT code.
     359              : 
     360              :   type(xcomm_t) :: qpt_pert_comm
     361              :    ! MPI communicator over the 2d grid (qpt, atomic perturbations)
     362              : 
     363              :   type(xcomm_t) :: pert_ppsum_comm
     364              :    ! MPI communicator over the 2d grid (atomic perturbations, pp_sum) used in GWPT
     365              : 
     366              :   type(xcomm_t) :: pert_ppsum_bsum_comm
     367              :    ! MPI communicator over the 3d grid (atomic perturbations, pp_sum, band_sum) used in GWPT
     368              : 
     369              :   type(xcomm_t) :: comm
     370              :    ! MPI communicator for full grid of procs treating this spin.
     371              : 
     372              :   type(wan_t) :: wan
     373              :    ! Object used to interpolate the e-ph matrix elements with Wannier.
     374              : 
     375              :   real(dp),allocatable :: my_wnuq(:,:)
     376              :   ! (my_npert, my_nq)
     377              :   ! Phonon frequencies in Ha (MPI distributed).
     378              : 
     379              :   real(dp),allocatable :: my_displ_cart(:,:,:,:,:)
     380              :   ! (2, 3, natom, my_npert, my_nq))
     381              :   ! Phonon displacements (MPI distributed).
     382              :   ! Reconstructed by symmetry from the IBZ (see pheigvec_rotate)
     383              :   ! Don't use ifc%fourq as this would break the gauge.
     384              : 
     385              :  contains
     386              : 
     387              :   procedure :: gather => gqk_gather
     388              :   ! Gather the MPI-distributed matrix elements for a given k/q-point index
     389              : 
     390              :   procedure :: get_erange_mask => gqk_get_erange_mask
     391              :   ! Compute MPI-distributed & global mask for electronic states allowed by energy filtering
     392              : 
     393              :   procedure :: filter_erange => gqk_filter_erange
     394              :   ! Nullify all matrix elements connecting electronic states outside of specified erange
     395              : 
     396              :   procedure :: myqpt => gqk_myqpt
     397              :   ! Return the q-point and the weight from my local index my_iq
     398              : 
     399              :   procedure :: dbldelta_qpt => gqk_dbldelta_qpt
     400              :   ! Compute weights for the double delta.
     401              : 
     402              :   procedure :: free => gqk_free
     403              :   ! Free memory
     404              : 
     405              :  end type gqk_t
     406              : !!***
     407              : 
     408              : !----------------------------------------------------------------------
     409              : 
     410              : !!****t* m_gstore/gstore_t
     411              : !! NAME
     412              : !! gstore_t
     413              : !!
     414              : !! FUNCTION
     415              : !! This object stores:
     416              : !!
     417              : !!    - pointers to the crystal structure, the KS bands, the IFCs.
     418              : !!    - arrays that do not depend on the spin such as the IBZ and weights for k/q-points.
     419              : !!    - metadata such as kzone, qzone and kfilter that are needed to interpret
     420              : !!      the storage mode used for the g(k,q).
     421              : !!
     422              : !! NB: the e-ph matrix elements are stored in gstore%gqk(my_is) where my_is counts
     423              : !!     the number of collinear spins treated by this MPI processor.
     424              : !!
     425              : !! SOURCE
     426              : 
     427              : type, public :: gstore_t
     428              : 
     429              :   integer :: nsppol
     430              :    ! Number of independent spin polarizations.
     431              : 
     432              :   integer :: my_nspins = 0
     433              :    ! Number of collinear spins treated by this MPI rank
     434              : 
     435              :   integer :: nkibz = -1, nqibz = -1
     436              :   ! Number of k/q points in the IBZ.
     437              : 
     438              :   integer :: nkbz = -1, nqbz = -1
     439              :   ! Number of k/q points in the BZ.
     440              : 
     441              :   integer :: comm
     442              :    ! Global communicator
     443              :    ! Inherited by the caller thus we don't free it in gstore_free.
     444              : 
     445              :   integer :: with_vk = 0
     446              :   ! 0 if group velocities should not be computed
     447              :   ! 1 to compute diagonal terms only
     448              :   ! 2 to compute diagonal and off-diagonal terms
     449              : 
     450              :   integer :: qptopt = -1
     451              :   ! option for the generation of q points (defines whether spatial symmetries and/or time-reversal can be used)
     452              : 
     453              :   integer :: has_used_lgk = 0
     454              :   ! value of use_lgk used to generate GSTORE.nc (read from file).
     455              : 
     456              :   integer :: has_used_lgq = 0
     457              :   ! value of use_lgq used to generate GSTORE.nc (read from file).
     458              : 
     459              :   character(len=fnlen) :: path = " "
     460              :   ! Path to the nc file associated to the gstore
     461              : 
     462              :   character(len=fnlen) :: wfk0_path = " "
     463              : 
     464              :   character(len=abi_slen) :: kzone = " ", qzone = " "
     465              :    ! Specifies whether k- or q-points are in the BZ or in the IBZ.
     466              :    ! Possible values are "ibz" or "bz".
     467              :    ! Note that the combination ("ibz", "ibz") is not allowed.
     468              : 
     469              :   character(len=abi_slen) :: kfilter = "none"
     470              :   ! Specifies the technique used to filter k-points.
     471              :   ! Possible values: "none", "fs_tetra", "erange", "qprange"
     472              : 
     473              :   character(len=abi_slen) :: gmode = "atom"
     474              :   ! "phonon" or "atom"
     475              : 
     476              :   character(len=abi_slen) :: gtype = GSTORE_GTYPE_KS
     477              :   ! Formalism used to compute g(k,q). Either KS or GWPT
     478              : 
     479              :   real(dp),allocatable :: erange_spin(:, :)
     480              :   ! (2, nsppol)
     481              :   ! Energy window. zero if not used. Requires kfilter == "erange"
     482              : 
     483              :   type(crystal_t), pointer :: cryst => null()
     484              :   ! Crystalline structure
     485              : 
     486              :   type(ebands_t), pointer :: ebands => null()
     487              :   ! Electron bands
     488              : 
     489              :   logical :: has_wannier = .False.
     490              :   ! True when electronic bands and e-ph matrix elements are obtained with
     491              :   ! Wannier interpolation from ABIWAN.nc and GWAN.nc.
     492              : 
     493              :   type(ifc_type), pointer :: ifc => null()
     494              :   ! interatomic force constants.
     495              : 
     496              :   type(dataset_type), pointer :: dtset => null()
     497              :   ! Reference to the dataset.
     498              : 
     499              :   type(krank_t) :: krank_ibz, qrank_ibz
     500              :   ! Object used to find k-points or q-points in the IBZ and map BZ to IBZ.
     501              : 
     502              :   integer :: ngqpt(3) = 0
     503              :   ! Number of grid points for q-points (either from ddb_ngqpt or eph_ngqpt_fine)
     504              : 
     505              :   integer,allocatable :: my_spins(:)
     506              :    ! (%my_nspins)
     507              :    ! Indirect table giving the spin indices treated by this MPI rank.
     508              :    ! Used only in the collinear case with nsppol = 2 and nspinor == 1
     509              : 
     510              :   integer,allocatable :: brange_k_spin(:, :)
     511              :   integer,allocatable :: brange_kq_spin(:, :)
     512              :   ! (2, nsppol)
     513              :   ! Range of bands for each spin at k and k+q.
     514              :   ! These are a global variable
     515              : 
     516              :   !integer :: max_nb = -1
     517              :   ! Max number of bands over spin
     518              : 
     519              :   integer,allocatable :: glob_nk_spin(:), glob_nq_spin(:)
     520              :   ! (nsppol)
     521              :   ! Total number of k/q points for each spin after filtering (if any).
     522              : 
     523              :   integer,allocatable :: kglob2bz(:,:)
     524              :   ! (max_nk, nsppol))
     525              :   ! Mapping ik_glob to BZ index for k-points.
     526              : 
     527              :   !integer,allocatable qglob2bz(:,:)
     528              :   ! (max_nq, nsppol))
     529              :   ! Mapping iq_glob to BZ index for q-points.
     530              : 
     531              :   integer,allocatable :: kbz2ibz(:,:)
     532              :   ! (6, gstore%nkbz))
     533              :   ! Mapping BZ --> IBZ (symrel conventions that can be used to symmetrize wavefunctions)
     534              : 
     535              :   real(dp), contiguous, pointer :: kibz(:,:)
     536              :   ! k-points in the IBZ. Points to ebands%kptns
     537              :   ! (3, nkibz)
     538              : 
     539              :   real(dp),allocatable :: delta_ef_kibz_spin(:,:,:)
     540              :   ! (nb, gstore%nkibz, nsppol))
     541              :   ! Tetrahedron weights at eF in the IBZ.
     542              : 
     543              :   real(dp), allocatable :: qibz(:,:)
     544              :   ! (3, nqibz)
     545              :   ! q-points in the IBZ in reduced coordinates.
     546              : 
     547              :   real(dp), allocatable :: wtq(:)
     548              :   ! (nqibz)
     549              :   ! q-points weights in the IBZ
     550              : 
     551              :   real(dp),allocatable :: qbz(:,:)
     552              :   ! q-points in the BZ.
     553              :   ! TODO: Use MPI shared memory?
     554              : 
     555              :   real(dp),allocatable :: kbz(:,:)
     556              :   ! k-points in the BZ.
     557              :   ! TODO: Use MPI shared memory?
     558              : 
     559              :   integer :: with_cplex = -1
     560              :   ! Representation of the e-ph matrix elements materialized in memory:
     561              :   ! 0: no matrix elements, 1: squared moduli in gqk%my_g2, 2: complex values in gqk%my_g.
     562              :   ! This state is independent of the representation stored in a GSTORE.nc file.
     563              : 
     564              :   !integer :: qptrlatt(3, 3) = -1  ! kptrlatt(3, 3) = -1,
     565              :    ! k-mesh and q-mesh
     566              : 
     567              :   !real(dp),allocatable :: kshift(:, :), qshift(:, :)
     568              :   ! k/q-mesh shift (well, q-mesh is usually gamma-centered)
     569              : 
     570              :   type(gqk_t), allocatable :: gqk(:)
     571              :   ! (my_nspins)
     572              :   ! Datastructure storing e-ph matrix elements for the collinear spins treated by this MPI proc.
     573              : 
     574              : contains
     575              : 
     576              :   procedure :: fill_bks_mask => gstore_fill_bks_mask
     577              :   ! Fill the table used to read (b, k, s) wavefunctions from the WFK file
     578              :   ! keeping into account the distribution of the e-ph matrix elements.
     579              : 
     580              :   procedure :: fill_bks_mask_pp_mesh => gstore_fill_bks_mask_pp_mesh
     581              :   ! Fill the table used to read (b, k, s) wavefunctions from the WFK file
     582              :   ! keeping into account the distribution of the e-ph matrix elements in the GWPT code
     583              :   ! and the parallel distribution of the pp momenta.
     584              : 
     585              :   procedure :: get_mpw_gmax => gstore_get_mpw_gmax
     586              :   ! Compute the maximum number of PWs for all possible k+q treated.
     587              : 
     588              :   procedure :: spin2my_is => gstore_spin2my_is
     589              :   !  Return the local spin index from the global spin index.
     590              :   !  0 if this spin is not treated by this MPI proc.
     591              : 
     592              :   procedure :: free => gstore_free
     593              :   ! Free memory
     594              : 
     595              :   procedure :: print => gstore_print
     596              :   ! Print info on the object.
     597              : 
     598              :   procedure :: check_little_group => gstore_check_little_group
     599              :    !  Check consistency between little group options from file and from input.
     600              : 
     601              :   procedure, private :: distribute_spins__ => gstore_distribute_spins
     602              :   ! Distribute spins, create indirect mapping to spin index and init %brange_k_spin
     603              : 
     604              :   procedure, private :: set_mpi_grid__ => gstore_set_mpi_grid__
     605              :   ! Set the MPI cartesian grid
     606              : 
     607              :   procedure, private :: malloc__ => gstore_malloc__
     608              :   ! Allocate local buffers once the MPI grid has been initialized.
     609              : 
     610              :   procedure, private :: filter_fs_tetra__ => gstore_filter_fs_tetra__
     611              :   ! Select k-points on the FS using the tetrahedron method
     612              : 
     613              :   procedure, private :: filter_kptgw__ => gstore_filter_kptgw__
     614              :   ! Select k-points using kptgw input variable. Useful for ZPR for user-specified k-points.
     615              : 
     616              :   procedure, private :: filter_erange__ => gstore_filter_erange__
     617              :   ! Select k-points inside an energy window.
     618              : 
     619              :   procedure, private :: filter_gw_qprange__ => gstore_filter_gw_qprange__
     620              :   ! Select k-points according to gw_qprange
     621              : 
     622              :   procedure :: compute => gstore_compute
     623              :   ! Compute e-ph matrix elements.
     624              : 
     625              :   procedure :: from_ncpath => gstore_from_ncpath
     626              :   ! Reconstruct object from netcdf file.
     627              : 
     628              :   procedure :: init => gstore_init
     629              :   ! Build object from scratch
     630              : 
     631              :   procedure :: init_or_from_ncpath => gstore_init_or_from_ncpath
     632              :   ! Build object either from a pre-existent GSTORE.nc file (getgstore_filepath) or,
     633              :   ! alternatively, via on-the-fly Wannier interpolation from ABIWAN.nc + GWAN.nc
     634              :   ! (getabiwan_filepath + getgwan_filepath), possibly on a denser k/q-mesh.
     635              : 
     636              :   procedure :: same_nbands => gstore_same_nbands
     637              :   ! Returns True if nb_k == nb_kq
     638              : 
     639              :   procedure :: has_matrix_elements => gstore_has_matrix_elements
     640              :   ! True if e-ph matrix elements have been materialized in memory.
     641              : 
     642              :   procedure :: has_complex_matrix_elements => gstore_has_complex_matrix_elements
     643              :   ! True if complex e-ph matrix elements have been materialized in memory.
     644              : 
     645              :   procedure :: get_missing_qbz_spin => gstore_get_missing_qbz_spin
     646              :   ! Return the number of (q-points, spin) entries that have been computed
     647              : 
     648              :   procedure :: set_perts_distrib => gstore_set_perts_distrib
     649              :   ! Activate parallelism over perturbations at the level of the DVDB file.
     650              : 
     651              :   procedure :: print_for_abitests => gstore_print_for_abitests
     652              :   ! Print subset of results to ab_out for testing purposes.
     653              : 
     654              :   procedure :: check_cplex_qkzone_gmode => gstore_check_cplex_qkzone_gmode
     655              :   ! Perform consistency checks.
     656              : 
     657              :   procedure :: wannierize_and_write_gwan => gstore_wannierize_and_write_gwan
     658              :   ! Compute g(R_e,R_ph) from g(k,q) and save results to GWAN.nc file
     659              : 
     660              :   procedure :: compute_and_write_ph => gstore_compute_and_write_ph
     661              :   ! Compute phonon frequencies and eigenvectors in the IBZ. Write results to disk
     662              : 
     663              :   procedure :: compute_and_write_vk => gstore_compute_and_write_vk
     664              :   ! Compute electronic group velocities in the IBZ. Write results to disk
     665              : 
     666              :   procedure :: compute_and_write_commutator => gstore_compute_and_write_commutator
     667              :   ! Compute matrix elements of the commutator. Write results to disk
     668              : 
     669              : end type gstore_t
     670              : !!***
     671              : 
     672              : public :: gstore_check_restart ! Check whether restart is possible.
     673              : public :: gstore_read_gtype    ! Read the value of "gstore_gtype" from the NetCDF file.
     674              : public :: gstore_symmetrize    ! Reconstruct the electron-phonon matrix elements g(k,q) in the full BZ.
     675              : 
     676              : !----------------------------------------------------------------------
     677              : 
     678              : contains
     679              : !!***
     680              : 
     681              : !----------------------------------------------------------------------
     682              : 
     683              : !!****f* m_gstore/gstore_init
     684              : !! NAME
     685              : !! gstore_init
     686              : !!
     687              : !! FUNCTION
     688              : !! Initialize the object
     689              : !!
     690              : !! INPUTS
     691              : !! path=Filename of the output GSTORE.nc file
     692              : !! with_cplex=Optional, only relevant when e-ph matrix elements are interpolated on the fly via
     693              : !!   Wannier (i.e. getabiwan_filepath + getgwan_filepath are used): 0 to allocate no matrix
     694              : !!   elements, 1 to store |g|^2, 2 to store the complex g. Default: 2. Ignored otherwise.
     695              : !!
     696              : !! SOURCE
     697              : 
     698            8 : subroutine gstore_init(gstore, path, dtset, dtfil, wfk0_hdr, cryst, ebands, ifc, comm, &
     699              :                        gtype, with_cplex) ! optional
     700              : 
     701              : !Arguments ------------------------------------
     702              : !scalars
     703              :  class(gstore_t),target,intent(out) :: gstore
     704              :  character(len=*),intent(in) :: path
     705              :  type(dataset_type),target,intent(in) :: dtset
     706              :  type(datafiles_type),intent(in) :: dtfil
     707              :  type(hdr_type),intent(in) :: wfk0_hdr
     708              :  class(crystal_t),target,intent(in) :: cryst
     709              :  class(ebands_t),target,intent(in) :: ebands
     710              :  class(ifc_type),target,intent(in) :: ifc
     711              :  integer,intent(in) :: comm
     712              :  character(len=*),optional,intent(in) :: gtype
     713              :  integer,optional,intent(in) :: with_cplex
     714              : 
     715              : !Local variables-------------------------------
     716              : !scalars
     717              :  integer,parameter :: master = 0, gstore_has_ifcs = 1
     718              :  integer :: all_nproc, my_rank, ierr, my_nshiftq, nsppol, spin, natom3, cnt, timrev_q, gqk_cplex
     719              :  integer :: ik_ibz, ik_bz, iq_bz, iq_ibz, max_nq, max_nk, ncid, spin_ncid, ncerr, gstore_fform
     720              :  integer :: gap_err, nkcalc
     721              :  logical :: keep_umats, has_abiwan, has_gwan, write_gstore, has_both_g
     722              :  real(dp) :: cpu, wall, gflops, gstore_fill_dp
     723              :  character(len=5000) :: msg
     724            8 :  type(gaps_t) :: gaps
     725              : !arrays
     726              :  integer :: ngqpt(3), qptrlatt(3,3), intp_kptrlatt(3,3)
     727           24 :  integer :: comm_spin(ebands%nsppol), nproc_spin(ebands%nsppol), units(2)
     728              :  integer :: gstore_brange_kq(2, 2), gstore_brange_k(2, 2)
     729            8 :  integer,allocatable :: qbz2ibz(:,:), kibz2bz(:), qibz2bz(:), qglob2bz(:,:)
     730            8 :  integer,allocatable :: bstart_ks(:,:), nbcalc_ks(:,:), select_qbz_spin(:,:), select_kbz_spin(:,:)
     731            8 :  real(dp),allocatable :: kcalc(:,:)
     732              :  real(dp):: my_shiftq(3,1)
     733            8 :  real(dp),allocatable :: wtk(:), kibz(:,:)
     734          304 :  type(wan_t),target :: wan_spin(ebands%nsppol)
     735              : !----------------------------------------------------------------------
     736              : 
     737            8 :  call cwtime(cpu, wall, gflops, "start")
     738            8 :  all_nproc = xmpi_comm_size(comm); my_rank = xmpi_comm_rank(comm)
     739            8 :  natom3 = 3 * cryst%natom; nsppol = ebands%nsppol
     740           24 :  units = [std_out, ab_out]
     741              : 
     742            8 :  call wrtout(std_out, " gstore_init: initialize gstore_t instance...")
     743            8 :  call pstat_proc%print(_PSTAT_ARGS_)
     744              : 
     745              :  ! Set basic parameters.
     746            8 :  gstore%comm = comm; gstore%nsppol = nsppol; gstore%path = path
     747            8 :  if (present(gtype)) gstore%gtype = gtype
     748            8 :  ABI_CHECK(gstore%gtype == GSTORE_GTYPE_KS .or. gstore%gtype == GSTORE_GTYPE_GWPT, sjoin("Invalid gstore gtype:", gstore%gtype))
     749              : 
     750            8 :  has_both_g = gstore%gtype == GSTORE_GTYPE_GWPT
     751              : 
     752              :  ! Get references to other data structures.
     753            8 :  gstore%dtset => dtset; gstore%cryst => cryst; gstore%ebands => ebands; gstore%ifc => ifc
     754            8 :  gstore%has_wannier = .False.
     755              : 
     756              :  ! Handle possible wannierization.
     757            8 :  has_abiwan = .False.; has_gwan = .False.; keep_umats = .False.
     758            8 :  if (dtfil%filabiwanin /= ABI_NOFILE) then
     759            0 :    has_abiwan = .True.
     760            0 :    call wrtout(units, sjoin(" Reading set of bands to be included in gstore computation from ABIWAN file:", dtfil%filabiwanin))
     761            0 :    do spin=1,ebands%nsppol
     762            0 :      call wan_spin(spin)%from_abiwan(dtfil%filabiwanin, spin, ebands%nsppol, keep_umats, dtfil%filnam_ds(4), comm)
     763            0 :      call wan_spin(spin)%print(units)
     764              :    end do
     765            0 :    if (dtfil%filgwanin /= ABI_NOFILE) then
     766            0 :      has_gwan = .True.
     767            0 :      ABI_CHECK(all(dtset%eph_ngkpt_fine > 0), "eph_ngkpt_fine must contain three positive integers when GWAN is used")
     768            0 :      ABI_CHECK(allocated(dtset%eph_shiftk_fine), "eph_shiftk_fine is not allocated")
     769            0 :      ABI_CHECK(size(dtset%eph_shiftk_fine, dim=2) == dtset%eph_nshiftk_fine, "Inconsistent eph_nshiftk_fine and eph_shiftk_fine")
     770            0 :      call kptrlatt_from_ngkpt(dtset%eph_ngkpt_fine, intp_kptrlatt)
     771              : 
     772            0 :      nullify(gstore%ebands)
     773            0 :      ABI_MALLOC_SCALAR(gstore%ebands)
     774              :      call wan_interp_ebands(wan_spin, cryst, ebands, intp_kptrlatt, dtset%eph_nshiftk_fine, &
     775            0 :                             dtset%eph_shiftk_fine, gstore%ebands, comm)
     776            0 :      gstore%has_wannier = .True.
     777              :    end if
     778              :  end if
     779              : 
     780              :  ! Set metadata and set initial value of kfilter from dtset.
     781            8 :  gstore%kibz => gstore%ebands%kptns
     782            8 :  gstore%kzone = dtset%gstore_kzone; gstore%qzone = dtset%gstore_qzone; gstore%kfilter = dtset%gstore_kfilter
     783            8 :  gstore%with_vk = dtset%gstore_with_vk; gstore%gmode = GSTORE_GMODE_ATOM
     784              : 
     785           48 :  ABI_CALLOC(gstore%erange_spin, (2, nsppol))
     786           40 :  gstore%erange_spin = dtset%gstore_erange(:, 1:nsppol)
     787              : 
     788           30 :  if (any(gstore%erange_spin /= zero)) then
     789            1 :    ABI_CHECK(gstore%kfilter == "none", sjoin("kfilter should be none when erange is used while it is:", gstore%kfilter))
     790            1 :    gstore%kfilter = "erange"
     791              :  end if
     792              : 
     793            8 :  if (gstore%kzone == "ibz" .and. gstore%qzone == "ibz") then
     794            0 :    ABI_ERROR("The combination kzone: 'ibz' and qzone: 'ibz' is not allowed!")
     795              :  end if
     796              : 
     797              :  ! TODO
     798              :  !gstore%kptrlatt(3, 3); gstore%kshift(3, 1); gstore%qptrlatt(3, 3); gstore%qshift(3, 1)
     799              : 
     800              :  ! Distribute spins, create indirect mapping to spin index and init %brange_k_spin from dtset
     801              :  ! TODO Should I introduce dtset%gstore_brange_kq or compute it automatically
     802            8 :  if (.not. has_gwan) then
     803            8 :    ABI_CHECK_ILEQ(dtset%mband, gstore%ebands%mband, "dtset%mband > ebands%mband")
     804              :  end if
     805              : 
     806           56 :  gstore_brange_k = dtset%gstore_brange
     807           56 :  gstore_brange_kq = dtset%gstore_brange
     808              : 
     809            8 :  if (gstore%kfilter == "qprange") then
     810              :    ! Assume ZPR calculations requiring virtual k+q transitions from 1 up to nband unless gstore_brange is given.
     811           28 :    if (all(gstore_brange_kq == 0)) then
     812           12 :      gstore_brange_kq(:,1) = [1, dtset%mband]
     813           12 :      gstore_brange_kq(:,2) = [1, dtset%mband]
     814              :    end if
     815              : 
     816              :    ! The same set of calls is found in gstore_filter_gw_qprange__
     817              :    ! The main difference is that here we set the bands while gstore_filter_gw_qprange__ sets the the k-points.
     818            4 :    gaps = gstore%ebands%get_gaps(gap_err)
     819              : 
     820              :    ! Compute nkcalc, kcalc, bstart_ks, nbcalc_ks
     821            4 :    if (dtset%gw_qprange /= 0) then
     822            0 :      call sigtk_kcalc_from_qprange(dtset, gstore%cryst, gstore%ebands, dtset%gw_qprange, nkcalc, kcalc, bstart_ks, nbcalc_ks)
     823              : 
     824              :    else
     825              :      ! gw_qprange is not specified in the input.
     826              :      ! Include direct and fundamental KS gap or include states depending on the position wrt band edges.
     827            4 :      call sigtk_kcalc_from_gaps(dtset, gstore%ebands, gaps, nkcalc, kcalc, bstart_ks, nbcalc_ks)
     828              :    end if
     829              : 
     830              :    ! Convert to stop values
     831           18 :    nbcalc_ks = bstart_ks + nbcalc_ks - 1
     832              : 
     833              :    ! Set brange_k
     834              :    ! FIXME: Handle degeneracies
     835            8 :    do spin=1,nsppol
     836           10 :      gstore_brange_k(1, spin) = minval(bstart_ks(1:nkcalc, spin))
     837           14 :      gstore_brange_k(2, spin) = maxval(nbcalc_ks(1:nkcalc, spin))
     838              :    end do
     839              : 
     840            4 :    ABI_FREE(kcalc)
     841            4 :    ABI_FREE(bstart_ks)
     842            4 :    ABI_FREE(nbcalc_ks)
     843            4 :    call gaps%free()
     844              :  end if
     845              : 
     846            8 :  if (dtset%nkptgw /= 0) then
     847              :    ! Allow user to specify k-points with kptgw and bdgw.
     848              : 
     849            0 :    if (gstore%kfilter /= "none") then
     850            0 :      ABI_ERROR("gstore_kfilter and nkptgw != 0 cannot be used together!")
     851              :    end if
     852              : 
     853              :    ! Assume ZPR calculations requiring virtual k+q transitions from 1 up to nband unless gstore_brange is given.
     854            0 :    gstore_brange_kq = dtset%gstore_brange
     855            0 :    if (all(gstore_brange_kq == 0)) then
     856            0 :      gstore_brange_kq(:,1) = [1, dtset%mband]
     857            0 :      gstore_brange_kq(:,2) = [1, dtset%mband]
     858              :    end if
     859              : 
     860            0 :    call sigtk_kcalc_from_nkptgw(dtset, dtset%mband, nkcalc, kcalc, bstart_ks, nbcalc_ks)
     861              : 
     862              :    ! Convert to stop values
     863            0 :    nbcalc_ks = bstart_ks + nbcalc_ks - 1
     864              : 
     865              :    ! Set brange_k
     866              :    ! FIXME: Handle degeneracies
     867            0 :    do spin=1,nsppol
     868            0 :      gstore_brange_k(1, spin) = minval(bstart_ks(1:nkcalc, spin))
     869            0 :      gstore_brange_k(2, spin) = maxval(nbcalc_ks(1:nkcalc, spin))
     870              :    end do
     871              : 
     872            0 :    ABI_FREE(kcalc)
     873            0 :    ABI_FREE(bstart_ks)
     874            0 :    ABI_FREE(nbcalc_ks)
     875              :  end if
     876              : 
     877            8 :  if (has_gwan) then
     878              :    ! Interpolated e-ph matrix elements are Wannier-gauge quantities (nwan x nwan,
     879              :    ! obtained by diagonalizing the interpolated H(k)), not literal DFT band indices,
     880              :    ! so nb_k/nb_kq must be set to nwan exactly -- NOT to the (possibly larger)
     881              :    ! disentanglement outer window [bmin, bmax] -- so that the results returned by
     882              :    ! wan%interp_eph_manyq (shape (nwan, nwan, my_npert, nq)) fit gqk%my_g exactly,
     883              :    ! for both the disentangled and disentanglement-free cases.
     884            0 :    do spin=1,gstore%nsppol
     885            0 :      gstore_brange_k(:, spin) = [1, wan_spin(spin)%nwan]
     886            0 :      gstore_brange_kq(:, spin) = [1, wan_spin(spin)%nwan]
     887              :    end do
     888            8 :  else if (has_abiwan) then
     889              :    ! Here we set brange_k_spin to be consistent with the wannierization step.
     890            0 :    do spin=1,gstore%nsppol
     891            0 :      gstore_brange_k(:, spin) = [wan_spin(spin)%bmin, wan_spin(spin)%bmax]
     892            0 :      gstore_brange_kq(:, spin) = [wan_spin(spin)%bmin, wan_spin(spin)%bmax]
     893              :    end do
     894              :  end if
     895              : 
     896            8 :  call gstore%distribute_spins__(gstore%ebands%mband, gstore_brange_kq, gstore_brange_k, nproc_spin, comm_spin, comm)
     897              : 
     898              :  ! Free wan_spin
     899           16 :  do spin=1,ebands%nsppol
     900           16 :    call wan_spin(spin)%free()
     901              :  end do
     902              : 
     903              :  ! Define q-mesh: either from DVDB (no interpolation) or eph_ngqpt_fine (Fourier interpolation)
     904              :  ! Save it in gstore for future reference.
     905           56 :  ngqpt = dtset%ddb_ngqpt; my_nshiftq = 1; my_shiftq(:,1) = dtset%ddb_shiftq
     906           23 :  if (all(dtset%eph_ngqpt_fine /= 0)) then
     907           20 :    ngqpt = dtset%eph_ngqpt_fine; my_shiftq = 0
     908              :  end if
     909           32 :  gstore%ngqpt(:) = ngqpt(:)
     910              : 
     911              :  ! TODO: Should fix bz2ibz to use the same conventions as krank and listkk
     912              :  ! NB: only sigmaph seems to be using this optional argument
     913              : 
     914              :  ! Setup qIBZ, weights and BZ.
     915              :  ! Assume qptopt == kptopt unless value is specified in input
     916            8 :  qptrlatt = 0; qptrlatt(1, 1) = ngqpt(1); qptrlatt(2, 2) = ngqpt(2); qptrlatt(3, 3) = ngqpt(3)
     917            8 :  gstore%qptopt = gstore%ebands%kptopt; if (dtset%qptopt /= 0) gstore%qptopt = dtset%qptopt
     918              :  timrev_q = kpts_timrev_from_kptopt(gstore%qptopt)
     919              : 
     920            8 :  call wrtout(std_out, sjoin(" Generating q-mesh with ngqpt:", ltoa(ngqpt), " and qptopt:", itoa(gstore%qptopt)))
     921              :  call kpts_ibz_from_kptrlatt(cryst, qptrlatt, gstore%qptopt, my_nshiftq, my_shiftq, &
     922            8 :                              gstore%nqibz, gstore%qibz, gstore%wtq, gstore%nqbz, gstore%qbz)
     923              :                              !new_kptrlatt=gstore%qptrlatt, new_shiftk=gstore%qshift,
     924              :                              !bz2ibz=new%ind_qbz2ibz)  # FIXME
     925              : 
     926              :  ! HM: the bz2ibz produced above is incomplete, I do it here using listkk
     927           24 :  ABI_MALLOC(qbz2ibz, (6, gstore%nqbz))
     928            8 :  call gstore%qrank_ibz%from_kptrlatt(gstore%nqibz, gstore%qibz, qptrlatt, compute_invrank=.False.)
     929              : 
     930            8 :  if (kpts_map("symrec", gstore%qptopt, cryst, gstore%qrank_ibz, gstore%nqbz, gstore%qbz, qbz2ibz) /= 0) then
     931            0 :    ABI_ERROR("Cannot map qBZ to IBZ!")
     932              :  end if
     933              : 
     934              :  ! Order qbz by stars and rearrange entries in qbz2ibz table.
     935            8 :  call kpts_pack_in_stars(gstore%nqbz, gstore%qbz, qbz2ibz)
     936              : 
     937              :  !call kpts_print_kmap(std_out, qibz, gstore%qbz, qbz2ibz)
     938              :  !do iq_bz=1,gstore%nqbz
     939              :  !  print *, "iq_bz -> iq_ibz", qbz2ibz(1, iq_bz), gstore%qbz(:, iq_bz)
     940              :  !end do
     941              : 
     942            8 :  call get_ibz2bz(gstore%nqibz, gstore%nqbz, qbz2ibz, qibz2bz, msg, ierr)
     943            8 :  ABI_CHECK(ierr == 0, sjoin("Something wrong in symmetry tables for q-points!", ch10, msg))
     944              : 
     945              :  ! Get full BZ associated to ebands
     946            8 :  call wrtout(std_out, sjoin(" Generating k-mesh with ngkpt:", ltoa(get_diag(gstore%ebands%kptrlatt)), " and kptopt:", itoa(gstore%ebands%kptopt)))
     947              :  call kpts_ibz_from_kptrlatt(cryst, gstore%ebands%kptrlatt, gstore%ebands%kptopt, gstore%ebands%nshiftk, gstore%ebands%shiftk, &
     948            8 :                              gstore%nkibz, kibz, wtk, gstore%nkbz, gstore%kbz) !, bz2ibz=bz2ibz)
     949              :                              !new_kptrlatt=gstore%kptrlatt, new_shiftk=gstore%kshift,
     950              :                              !bz2ibz=new%ind_qbz2ibz)  # FIXME
     951              : 
     952              :  ! In principle kibz should be equal to ebands%kptns
     953            8 :  ABI_CHECK(gstore%nkibz == gstore%ebands%nkpt, "nkibz != ebands%nkpt")
     954          540 :  ABI_CHECK(all(abs(gstore%kibz - kibz) < tol12), "ebands%kibz != kibz")
     955            8 :  ABI_FREE(kibz)
     956              : 
     957              :  ! Note symrel and use_symrec=.False. in get_mapping.
     958              :  ! This means that this table can be used to symmetrize wavefunctions in cgtk_rotate.
     959              :  ! TODO This ambiguity should be removed. Change cgtk_rotate so that we can use the symrec convention.
     960              : 
     961           24 :  ABI_MALLOC(gstore%kbz2ibz, (6, gstore%nkbz))
     962            8 :  call gstore%krank_ibz%from_kptrlatt(gstore%nkibz, gstore%kibz, gstore%ebands%kptrlatt, compute_invrank=.False.)
     963            8 :  if (kpts_map("symrel", gstore%ebands%kptopt, cryst, gstore%krank_ibz, gstore%nkbz, gstore%kbz, gstore%kbz2ibz) /= 0) then
     964            0 :    ABI_ERROR("Cannot map kBZ to IBZ!")
     965              :  end if
     966              : 
     967              :  ! TODO:
     968              :  ! Order kbz by stars and rearrange entries in kbz2ibz table.
     969              :  !call kpts_pack_in_stars(gstore%nkbz, kbz, gstore%kbz2ibz)
     970              : 
     971            8 :  call get_ibz2bz(gstore%nkibz, gstore%nkbz, gstore%kbz2ibz, kibz2bz, msg, ierr)
     972            8 :  ABI_CHECK(ierr == 0, sjoin("Something wrong in symmetry tables for k-points", ch10, msg))
     973              : 
     974              :  ! These tables are used to exclude q/k points.
     975              :  ! We use the full BZ because this mask can be also used when points are restricted to the IBZ
     976              :  ! provided we convert from ik_ibz to ik_bz. Note that both arrays are initialized with zeros.
     977         2597 :  ABI_ICALLOC(select_qbz_spin, (gstore%nqbz, nsppol))
     978         2597 :  ABI_ICALLOC(select_kbz_spin, (gstore%nkbz, nsppol))
     979              : 
     980            4 :  select case (gstore%kzone)
     981              :  case ("ibz")
     982            8 :    do spin=1,nsppol
     983           35 :      do ik_ibz=1,gstore%nkibz
     984           31 :        ik_bz = kibz2bz(ik_ibz); select_kbz_spin(ik_bz, spin) = 1
     985              :      end do
     986              :    end do
     987              : 
     988              :  case ("bz")
     989         2421 :    select_kbz_spin = 1
     990              : 
     991              :  case default
     992            8 :    ABI_ERROR(sjoin("Invalid kzone:", gstore%kzone))
     993              :  end select
     994              : 
     995            8 :  select case (gstore%qzone)
     996              :  case ("ibz")
     997            0 :    do spin=1,nsppol
     998            0 :      do iq_ibz=1, gstore%nqibz
     999            0 :        iq_bz = qibz2bz(iq_ibz); select_qbz_spin(iq_bz, spin) = 1
    1000              :      end do
    1001              :    end do
    1002              : 
    1003              :  case ("bz")
    1004         2573 :    select_qbz_spin = 1
    1005              : 
    1006              :  case default
    1007            8 :    ABI_ERROR(sjoin("Invalid qzone:", gstore%qzone))
    1008              :  end select
    1009              : 
    1010              :  ! Here we filter the electronic wavevectors k and recompute select_qbz_spin and select_kbz_spin according to kfilter.
    1011           11 :  select case (gstore%kfilter)
    1012              :  case ("none")
    1013            3 :    if (dtset%nkptgw /= 0) then
    1014              :      ! Use kptgw input variable. Useful for ZPR for user-specified k-points.
    1015            0 :      call gstore%filter_kptgw__(dtset, qbz2ibz, qibz2bz, kibz2bz, select_qbz_spin, select_kbz_spin)
    1016              :    end if
    1017              : 
    1018              :  case ("erange")
    1019              :    ! Use energy range: transport in semiconductors/metals or superconducting propertiea.
    1020            1 :    call gstore%filter_erange__(qbz2ibz, qibz2bz, kibz2bz, select_qbz_spin, select_kbz_spin)
    1021              : 
    1022              :  case ("qprange")
    1023              :    ! Use gw_qprange input variable. Useful for ZPR
    1024            4 :    call gstore%filter_gw_qprange__(dtset, qbz2ibz, qibz2bz, kibz2bz, select_qbz_spin, select_kbz_spin)
    1025              : 
    1026              :  case ("fs_tetra")
    1027              :    ! Use the tetrahedron method to filter k- and k+q points on the FS in metals
    1028              :    ! and define gstore%brange_k_spin automatically.
    1029              :    ! Useful for transport in metals or superconducting propertiea.
    1030            0 :    call gstore%filter_fs_tetra__(qbz2ibz, qibz2bz, kibz2bz, select_qbz_spin, select_kbz_spin)
    1031              : 
    1032              :  case default
    1033            8 :    ABI_ERROR(sjoin("Invalid gstore%kfilter:", gstore%kfilter))
    1034              :  end select
    1035              : 
    1036              :  ! Total number of k/q points for each spin after filtering (if any)
    1037           24 :  ABI_MALLOC(gstore%glob_nk_spin, (nsppol))
    1038           16 :  ABI_MALLOC(gstore%glob_nq_spin, (nsppol))
    1039         2581 :  gstore%glob_nk_spin(:) = count(select_kbz_spin > 0, dim=1)
    1040         2581 :  gstore%glob_nq_spin(:) = count(select_qbz_spin > 0, dim=1)
    1041              : 
    1042              :  ! We need another table mapping the global index in the gqk matrix to the q/k index in the BZ
    1043              :  ! so that one can extract the symmetry tables computed above.
    1044              :  ! Again this is needed as the global sizes of the gqk matrix
    1045              :  ! is not necessarily equal to the size of the BZ/IBZ if we have filtered the wave vectors.
    1046              : 
    1047           16 :  max_nq = maxval(gstore%glob_nq_spin) ! Max dim over spin
    1048           16 :  max_nk = maxval(gstore%glob_nk_spin)
    1049          997 :  ABI_ICALLOC(qglob2bz, (max_nq, nsppol))
    1050          351 :  ABI_ICALLOC(gstore%kglob2bz, (max_nk, nsppol))
    1051              : 
    1052           16 :  do spin=1,nsppol
    1053            8 :    cnt = 0
    1054         2565 :    do iq_bz=1,gstore%nqbz
    1055         2565 :      if (select_qbz_spin(iq_bz, spin) /= 0) then
    1056          957 :        cnt = cnt + 1; qglob2bz(cnt, spin) = iq_bz
    1057              :      end if
    1058              :    end do
    1059              : 
    1060            8 :    cnt = 0
    1061         2573 :    do ik_bz=1,gstore%nkbz
    1062         2565 :      if (select_kbz_spin(ik_bz, spin) /= 0) then
    1063          311 :        cnt = cnt + 1; gstore%kglob2bz(cnt, spin) = ik_bz
    1064              :      end if
    1065              :    end do
    1066              :  end do
    1067              : 
    1068              :  ! =============================================
    1069              :  ! Initialize gqk basic dimensions and MPI grid
    1070              :  ! =============================================
    1071            8 :  call gstore%set_mpi_grid__(dtfil, nproc_spin, comm_spin)
    1072            8 :  call xmpi_comm_free(comm_spin)
    1073              : 
    1074              :  ! At this point, we have the Cartesian grid (one per spin if any),
    1075              :  ! and we can finally allocate and distribute other arrays.
    1076              :  ! Note gqk_cplex = 0 --> matrix elements are not allocated here.
    1077            8 :  gqk_cplex = 0
    1078            8 :  if (has_gwan) then
    1079            0 :    gqk_cplex = 2
    1080            0 :    if (present(with_cplex)) gqk_cplex = with_cplex
    1081              :  end if
    1082            8 :  ABI_CHECK(gqk_cplex >= 0 .and. gqk_cplex <= 2, sjoin("Invalid with_cplex:", itoa(gqk_cplex)))
    1083            8 :  gstore%with_cplex = gqk_cplex
    1084            8 :  call gstore%malloc__(gqk_cplex, has_both_g, max_nq, qglob2bz, max_nk, gstore%kglob2bz, qbz2ibz, gstore%kbz2ibz)
    1085              : 
    1086              :  ! Initialize GSTORE.nc file i.e. define dimensions and arrays
    1087              :  ! Entries such as the e-ph matrix elements will be filled afterwards in gstore_compute.
    1088              :  ! Master node defines dimensions and variables.
    1089              : 
    1090            8 :  write_gstore = .True.
    1091            8 :  if (has_gwan) write_gstore = .False.
    1092              : 
    1093            8 :  if (my_rank == master .and. write_gstore) then
    1094            8 :    NCF_CHECK(nctk_open_create(ncid, gstore%path, xmpi_comm_self))
    1095              : 
    1096              :    ! Write the abinit header with metadata, structure and occupancies.
    1097            8 :    gstore_fform = fform_from_ext("GSTORE.nc")
    1098            8 :    NCF_CHECK(wfk0_hdr%ncwrite(ncid, gstore_fform, spinat=dtset%spinat, nc_define=.True.))
    1099              : 
    1100              :    ! Add crystalline structure.
    1101            8 :    NCF_CHECK(gstore%cryst%ncwrite(ncid))
    1102              :    ! Add eigenvalues and occupations.
    1103            8 :    NCF_CHECK(gstore%ebands%ncwrite(ncid))
    1104              : 
    1105              :    ! Write gstore dimensions
    1106              :    ncerr = nctk_def_dims(ncid, [ &
    1107              :       nctkdim_t("gstore_nkibz", gstore%nkibz), &
    1108              :       nctkdim_t("gstore_nkbz", gstore%nkbz), &
    1109              :       nctkdim_t("gstore_nqibz", gstore%nqibz), &
    1110              :       nctkdim_t("gstore_nqbz", gstore%nqbz), &
    1111              :       nctkdim_t("gstore_max_nq", max_nq), &
    1112              :       nctkdim_t("gstore_max_nk", max_nk), &
    1113              :       nctkdim_t("gstore_max_nb", maxval(gstore%brange_k_spin(2, :) - gstore%brange_k_spin(1, :) + 1) ), &
    1114              :       nctkdim_t("nrpt", ifc%nrpt), &
    1115              :       nctkdim_t("ifc_nqbz", size(ifc%dynmat, dim=6)), &
    1116              :       nctkdim_t("natom", gstore%cryst%natom), &
    1117              :       nctkdim_t("natom3", 3 * gstore%cryst%natom), &
    1118              :       nctkdim_t("gstore_cplex", 2), &
    1119              :       nctkdim_t("ifc_nqbz", ifc%nqbz) &
    1120          120 :    ], defmode=.True.)
    1121            8 :    NCF_CHECK(ncerr)
    1122              : 
    1123              :    ncerr = nctk_def_iscalars(ncid, [character(len=nctk_slen) :: &
    1124              :      "gstore_with_vk", "gstore_qptopt", "gstore_completed", &
    1125              :      "gstore_use_lgk", "gstore_use_lgq", "gstore_has_ifcs", "gwpt_wmode"  &
    1126           64 :    ])
    1127            8 :    NCF_CHECK(ncerr)
    1128              :    ncerr = nctk_def_dpscalars(ncid, [character(len=nctk_slen) :: &
    1129              :      "ifc_eta" &
    1130           16 :    ])
    1131            8 :    NCF_CHECK(ncerr)
    1132              : 
    1133              :    ncerr = nctk_def_arrays(ncid, [ &
    1134              :      nctkarr_t("gstore_qibz", "dp", "three, gstore_nqibz"), &
    1135              :      nctkarr_t("gstore_qbz", "dp", "three, gstore_nqbz"), &
    1136              :      nctkarr_t("gstore_wtq", "dp", "gstore_nqibz"), &
    1137              :      nctkarr_t("gstore_kbz", "dp", "three, gstore_nkbz"), &
    1138              :      nctkarr_t("gstore_kzone", "c", "character_string_length"), &
    1139              :      nctkarr_t("gstore_qzone", "c", "character_string_length"), &
    1140              :      nctkarr_t("gstore_kfilter", "c", "character_string_length"), &
    1141              :      nctkarr_t("gstore_gmode", "c", "character_string_length"), &
    1142              :      nctkarr_t("gstore_gtype", "c", "character_string_length"), &
    1143              :      nctkarr_t("gstore_wfk0_path", "c", "fnlen"), &
    1144              :      nctkarr_t("gstore_brange_k_spin", "i", "two, number_of_spins"), &
    1145              :      nctkarr_t("gstore_brange_kq_spin", "i", "two, number_of_spins"), &
    1146              :      nctkarr_t("gstore_erange_spin", "dp", "two, number_of_spins"), &
    1147              :      nctkarr_t("gstore_ngqpt", "i", "three"), &
    1148              :      nctkarr_t("phfreqs_ibz", "dp", "natom3, gstore_nqibz"), &
    1149              :      nctkarr_t("pheigvec_cart_ibz", "dp", "two, three, natom, natom3, gstore_nqibz"), &
    1150              :      nctkarr_t("gstore_glob_nq_spin", "i", "number_of_spins"), &
    1151              :      nctkarr_t("gstore_glob_nk_spin", "i", "number_of_spins"), &
    1152              :      nctkarr_t("gstore_done_qbz_spin", "i", "gstore_nqbz, number_of_spins"), &
    1153              :      nctkarr_t("gstore_kbz2ibz", "i", "six, gstore_nkbz"), &
    1154              :      nctkarr_t("gstore_qbz2ibz", "i", "six, gstore_nqbz"), &
    1155              :      nctkarr_t("gstore_qglob2bz", "i", "gstore_max_nq, number_of_spins"), &
    1156              :      nctkarr_t("gstore_kglob2bz", "i", "gstore_max_nk, number_of_spins"), &
    1157              :      ! Table with status of (k, q, spin) entry, used to symmetrize matrix-elements.
    1158              :      nctkarr_t("gstore_glob_state_kqs", "i", "gstore_max_nk, gstore_max_nq, number_of_spins"), &
    1159              :      !
    1160              :      ! These quantities are needed to interface GSTORE.nc with external codes.
    1161              :      ! For the meaning of the different variables and conventions see m_ifc module.
    1162              :      nctkarr_t("ifc_zeff", "dp", "three, three, number_of_atoms"), &
    1163              :      nctkarr_t("ifc_qdrp_cart", "dp", "three, three, three, number_of_atoms") &
    1164          216 :    ])
    1165            8 :    NCF_CHECK(ncerr)
    1166              : 
    1167              :    if (gstore_has_ifcs /= 0) then
    1168              :      ! Define arrays for IFCs.
    1169              :      ! For the meaning of the different variables and conventions see m_ifc module.
    1170              :      ncerr = nctk_def_arrays(ncid, [ &
    1171              :         nctkarr_t("ifc_rpt", "dp", "three, nrpt"), &
    1172              :         nctkarr_t("ifc_wghatm", "dp", "natom, natom, nrpt"), &
    1173              :         nctkarr_t("ifc_dynmat", "dp", "two, three, natom, three, natom, ifc_nqbz"), &
    1174              :         nctkarr_t("ifc_short_atmfrc", "dp", "three, natom, three, natom, nrpt") &
    1175           40 :      ])
    1176            8 :      NCF_CHECK(ncerr)
    1177              :    end if
    1178              : 
    1179              :    ! Internal table used to restart computation. Initialized with zeros.
    1180              :    !  0 --> (ib_bz, spin) has not been computed.
    1181              :    !  1 --> (iq_bz, spin) has been computed.
    1182              :    ! In order to check if the whole generation is completed, one should test if "gstore_completed" == 1
    1183            8 :    NCF_CHECK(nf90_def_var_fill(ncid, vid("gstore_done_qbz_spin"), NF90_FILL, 0))
    1184              : 
    1185            8 :    NCF_CHECK(nf90_def_var_fill(ncid, vid("gstore_glob_state_kqs"), NF90_FILL, GSTORE_KQ_MISSING))
    1186              : 
    1187              :    ! Optional arrays
    1188            8 :    if (allocated(gstore%delta_ef_kibz_spin)) then
    1189              :      ncerr = nctk_def_arrays(ncid, &
    1190            0 :        nctkarr_t("gstore_delta_ef_kibz_spin", "dp", "gstore_max_nb, gstore_nkibz, number_of_spins"))
    1191              :    end if
    1192            8 :    NCF_CHECK(ncerr)
    1193              : 
    1194              :    ! Write data
    1195            8 :    NCF_CHECK(nctk_set_datamode(ncid))
    1196            8 :    NCF_CHECK(nf90_put_var(ncid, vid("gstore_with_vk"), gstore%with_vk))
    1197            8 :    NCF_CHECK(nf90_put_var(ncid, vid("gstore_qptopt"), gstore%qptopt))
    1198            8 :    NCF_CHECK(nf90_put_var(ncid, vid("gstore_use_lgk"), dtset%gstore_use_lgk))
    1199            8 :    NCF_CHECK(nf90_put_var(ncid, vid("gstore_use_lgq"), dtset%gstore_use_lgq))
    1200            8 :    NCF_CHECK(nf90_put_var(ncid, vid("gstore_has_ifcs"), gstore_has_ifcs))
    1201            8 :    NCF_CHECK(nf90_put_var(ncid, vid("gwpt_wmode"), dtset%gwpt_wmode))
    1202            8 :    NCF_CHECK(nf90_put_var(ncid, vid("gstore_completed"), 0))
    1203            8 :    NCF_CHECK(nf90_put_var(ncid, vid("gstore_kzone"), trim(gstore%kzone)))
    1204            8 :    NCF_CHECK(nf90_put_var(ncid, vid("gstore_qzone"), trim(gstore%qzone)))
    1205            8 :    NCF_CHECK(nf90_put_var(ncid, vid("gstore_kfilter"), trim(gstore%kfilter)))
    1206            8 :    NCF_CHECK(nf90_put_var(ncid, vid("gstore_gmode"), trim(gstore%gmode)))
    1207            8 :    NCF_CHECK(nf90_put_var(ncid, vid("gstore_gtype"), trim(gstore%gtype)))
    1208              : 
    1209              :    ! NB: kibz has been already written by ebands%ncwrite
    1210            8 :    NCF_CHECK(nf90_put_var(ncid, vid("gstore_qibz"), gstore%qibz))
    1211            8 :    NCF_CHECK(nf90_put_var(ncid, vid("gstore_qbz"), gstore%qbz))
    1212            8 :    NCF_CHECK(nf90_put_var(ncid, vid("gstore_wtq"), gstore%wtq))
    1213            8 :    NCF_CHECK(nf90_put_var(ncid, vid("gstore_kbz"), gstore%kbz))
    1214            8 :    NCF_CHECK(nf90_put_var(ncid, vid("gstore_brange_k_spin"), gstore%brange_k_spin))
    1215            8 :    NCF_CHECK(nf90_put_var(ncid, vid("gstore_brange_kq_spin"), gstore%brange_kq_spin))
    1216            8 :    NCF_CHECK(nf90_put_var(ncid, vid("gstore_erange_spin"), gstore%erange_spin))
    1217            8 :    NCF_CHECK(nf90_put_var(ncid, vid("gstore_ngqpt"), gstore%ngqpt))
    1218            8 :    NCF_CHECK(nf90_put_var(ncid, vid("gstore_glob_nq_spin"), gstore%glob_nq_spin))
    1219            8 :    NCF_CHECK(nf90_put_var(ncid, vid("gstore_glob_nk_spin"), gstore%glob_nk_spin))
    1220            8 :    NCF_CHECK(nf90_put_var(ncid, vid("gstore_kbz2ibz"), gstore%kbz2ibz))
    1221            8 :    NCF_CHECK(nf90_put_var(ncid, vid("gstore_qbz2ibz"), qbz2ibz))
    1222            8 :    NCF_CHECK(nf90_put_var(ncid, vid("gstore_qglob2bz"), qglob2bz))
    1223            8 :    NCF_CHECK(nf90_put_var(ncid, vid("gstore_kglob2bz"), gstore%kglob2bz))
    1224              : 
    1225              :    ! These quantities are needed to interface GSTORE.nc with external codes.
    1226            8 :    NCF_CHECK(nf90_put_var(ncid, vid("ifc_zeff"), ifc%zeff))
    1227            8 :    NCF_CHECK(nf90_put_var(ncid, vid("ifc_qdrp_cart"), ifc%qdrp_cart))
    1228            8 :    NCF_CHECK(nf90_put_var(ncid, vid("ifc_eta"), ifc%eta))
    1229              :    if (gstore_has_ifcs /= 0) then
    1230            8 :      NCF_CHECK(nf90_put_var(ncid, vid("ifc_rpt"), ifc%rpt))
    1231            8 :      NCF_CHECK(nf90_put_var(ncid, vid("ifc_wghatm"), ifc%wghatm))
    1232            8 :      NCF_CHECK(nf90_put_var(ncid, vid("ifc_dynmat"), ifc%dynmat))
    1233            8 :      NCF_CHECK(nf90_put_var(ncid, vid("ifc_short_atmfrc"), ifc%short_atmfrc))
    1234              :    end if
    1235              : 
    1236            8 :    if (allocated(gstore%delta_ef_kibz_spin)) then
    1237            0 :      NCF_CHECK(nf90_put_var(ncid, vid("gstore_delta_ef_kibz_spin"), gstore%delta_ef_kibz_spin))
    1238              :    end if
    1239              : 
    1240           16 :    do spin=1,gstore%nsppol
    1241              :      ! Create hdf group for this spin.
    1242            8 :      NCF_CHECK(nf90_def_grp(ncid, strcat("gqk", "_spin", itoa(spin)), spin_ncid))
    1243              : 
    1244              :      ! Dimensions in gqk_spin group
    1245              :      ncerr = nctk_def_dims(spin_ncid, [ &
    1246              :         nctkdim_t("nb_k", gstore%brange_k_spin(2, spin) - gstore%brange_k_spin(1, spin) + 1), &
    1247              :         nctkdim_t("nb_kq", gstore%brange_kq_spin(2, spin) - gstore%brange_kq_spin(1, spin) + 1), &
    1248              :         nctkdim_t("glob_nk", gstore%glob_nk_spin(spin)), &
    1249              :         nctkdim_t("glob_nq", gstore%glob_nq_spin(spin))  &
    1250           40 :      ], defmode=.True.)
    1251            8 :      NCF_CHECK(ncerr)
    1252              : 
    1253              :      ! Define scalars
    1254           24 :      ncerr = nctk_def_iscalars(spin_ncid, [character(len=nctk_slen) :: "bstart_k", "bstart_kq"])
    1255            8 :      NCF_CHECK(ncerr)
    1256              : 
    1257              :      ! arrays in gqk_spin group with the precious stuff. Note global dimensions.
    1258              :      ncerr = nctk_def_arrays(spin_ncid, [ &
    1259              :        nctkarr_t("gvals", "dp", "gstore_cplex, nb_kq, nb_k, natom3, glob_nk, glob_nq") &
    1260           16 :      ])
    1261            8 :      NCF_CHECK(ncerr)
    1262              : 
    1263              :      ! Compress gvals to reduce size on disk.
    1264              :      !NCF_CHECK(nf90_def_var_deflate(spin_ncid, spin_vid("gvals"), shuffle=1, deflate=1, deflate_level=5))
    1265              : 
    1266              :      ! IMPORTANT: Init gvals with zeros.
    1267              :      ! Default value for entries in gvals, vnk_cart_ibz and vnk_mat_cart_ibz arrays that have not been written.
    1268              :      ! This can happen only if we have filtered wavevectors.
    1269            8 :      gstore_fill_dp = zero
    1270            8 :      if (gstore%kfilter == "none") gstore_fill_dp = -huge(one)
    1271            8 :      NCF_CHECK(nf90_def_var_fill(spin_ncid, spin_vid("gvals"), NF90_FILL, gstore_fill_dp))
    1272              : 
    1273              :      ! In GWPT gvals is used for g^Sigma so we declare another array to store g^KS.
    1274            8 :      if (dtset%eph_task == 17) then
    1275              :        ncerr = nctk_def_arrays(spin_ncid, [ &
    1276              :          nctkarr_t("gvals_ks", "dp", "gstore_cplex, nb_kq, nb_k, natom3, glob_nk, glob_nq") &
    1277            6 :        ])
    1278            3 :        NCF_CHECK(ncerr)
    1279              :        ! Compress gvals to reduce size on disk.
    1280              :        !NCF_CHECK(nf90_def_var_deflate(spin_ncid, spin_vid("gvals_ks"), shuffle=1, deflate=1, deflate_level=5))
    1281            3 :        NCF_CHECK(nf90_def_var_fill(spin_ncid, spin_vid("gvals_ks"), NF90_FILL, gstore_fill_dp))
    1282              :      end if
    1283              : 
    1284           16 :      select case(gstore%with_vk)
    1285              :      case (1)
    1286              :        ! Diagonal terms only
    1287            8 :        NCF_CHECK(nctk_def_arrays(spin_ncid, nctkarr_t("vk_cart_ibz", "dp", "three, nb_k, gstore_nkibz")))
    1288            8 :        NCF_CHECK(nf90_def_var_fill(spin_ncid, spin_vid("vk_cart_ibz"), NF90_FILL, gstore_fill_dp))
    1289              : 
    1290              :      case (2)
    1291              :        ! Full (nb_k x nb_k) matrix.
    1292            0 :        NCF_CHECK(nctk_def_arrays(spin_ncid, nctkarr_t("vnk_mat_cart_ibz", "dp", "two, three, nb_k, nb_k, gstore_nkibz")))
    1293            8 :        NCF_CHECK(nf90_def_var_fill(spin_ncid, spin_vid("vnk_mat_cart_ibz"), NF90_FILL, gstore_fill_dp))
    1294              :      end select
    1295              : 
    1296              :      ! Write (small) data
    1297            8 :      NCF_CHECK(nctk_set_datamode(spin_ncid))
    1298            8 :      NCF_CHECK(nf90_put_var(spin_ncid, spin_vid("bstart_k"), gstore%brange_k_spin(1, spin)))
    1299           16 :      NCF_CHECK(nf90_put_var(spin_ncid, spin_vid("bstart_kq"), gstore%brange_kq_spin(1, spin)))
    1300              :    end do ! spin
    1301              : 
    1302            8 :    NCF_CHECK(nf90_close(ncid))
    1303              :  end if ! master
    1304              : 
    1305              :  ! Make sure GSTORE.nc has been written by master.
    1306            8 :  call xmpi_barrier(gstore%comm)
    1307              : 
    1308            8 :  ABI_FREE(wtk)
    1309            8 :  ABI_FREE(qibz2bz)
    1310            8 :  ABI_FREE(kibz2bz)
    1311            8 :  ABI_FREE(select_qbz_spin)
    1312            8 :  ABI_FREE(select_kbz_spin)
    1313            8 :  ABI_FREE(qglob2bz)
    1314            8 :  ABI_FREE(qbz2ibz)
    1315              : 
    1316            8 :  call cwtime_report(" gstore_init:", cpu, wall, gflops)
    1317           32 :  call pstat_proc%print(_PSTAT_ARGS_)
    1318              : 
    1319              :  ! NOTE: When has_gwan is True, gqk%my_g/my_g2 have been allocated above (gqk_cplex) but are not
    1320              :  ! filled here. The actual Wannier interpolation of the e-ph matrix elements is performed by the
    1321              :  ! caller, gstore_init_or_from_ncpath, where with_gmode/gvals_name/with_g2dw are available.
    1322              : 
    1323              : contains
    1324          280 :  integer function vid(var_name)
    1325              :    character(len=*),intent(in) :: var_name
    1326          280 :    vid = nctk_idname(ncid, var_name)
    1327              :  end function vid
    1328           35 :  integer function spin_vid(var_name)
    1329              :    character(len=*),intent(in) :: var_name
    1330           35 :    spin_vid = nctk_idname(spin_ncid, var_name)
    1331              :  end function spin_vid
    1332              : 
    1333              : end subroutine gstore_init
    1334              : !!***
    1335              : 
    1336              : !----------------------------------------------------------------------
    1337              : 
    1338              : !!****f* m_gstore/gstore_init_or_from_ncpath
    1339              : !! NAME
    1340              : !! gstore_init_or_from_ncpath
    1341              : !!
    1342              : !! FUNCTION
    1343              : !! Build a gstore_t object either by reading a pre-existent GSTORE.nc file
    1344              : !! (getgstore_filepath) or, alternatively, by interpolating e-ph matrix elements
    1345              : !! on the fly from ABIWAN.nc + GWAN.nc (getabiwan_filepath + getgwan_filepath),
    1346              : !! e.g. on a k/q-mesh denser than the one used to compute the GWAN.nc file.
    1347              : !! In the latter case, no GSTORE.nc file is read or written: gqk%my_g is filled
    1348              : !! entirely in memory (see the has_gwan branch in gstore_init).
    1349              : !!
    1350              : !! from_file (output): set to .True. if gstore was built from a
    1351              : !! pre-existent GSTORE.nc file, .False. if built on the fly via Wannier
    1352              : !! interpolation. Callers can use this to report which path was taken.
    1353              : !!
    1354              : !! SOURCE
    1355              : 
    1356           16 : subroutine gstore_init_or_from_ncpath(gstore, with_cplex, dtset, dtfil, wfk0_hdr, cryst, ebands, ifc, &
    1357              :                                       with_gmode, gvals_name, with_g2dw, comm, from_file)
    1358              : 
    1359              : !Arguments ------------------------------------
    1360              : !scalars
    1361              :  class(gstore_t),target,intent(out) :: gstore
    1362              :  integer,intent(in) :: with_cplex
    1363              :  type(dataset_type),target,intent(in) :: dtset
    1364              :  type(datafiles_type),intent(in) :: dtfil
    1365              :  type(hdr_type),intent(in) :: wfk0_hdr
    1366              :  class(crystal_t),target,intent(in) :: cryst
    1367              :  class(ebands_t),target,intent(in) :: ebands
    1368              :  class(ifc_type),target,intent(in) :: ifc
    1369              :  character(len=*),intent(in) :: with_gmode, gvals_name
    1370              :  logical,intent(in) :: with_g2dw
    1371              :  integer,intent(in) :: comm
    1372              :  logical,intent(out) :: from_file
    1373              : 
    1374              : !Local variables-------------------------------
    1375              : !scalars
    1376              :  integer :: natom, natom3, spin, my_is, my_ik, my_iq, iq_ibz, isym_q, trev_q, ipc, nu, nwan, ierr
    1377              :  integer :: ik_start, ik_stop, ikb, nkb, nk_batch
    1378              :  real(dp) :: weight_q, cpu, wall, gflops
    1379              :  character(len=500) :: msg
    1380              :  character(len=fnlen) :: gstore_path
    1381              :  type(gqk_t),pointer :: gqk
    1382              : !arrays
    1383              :  real(dp) :: qpt(3)
    1384           16 :  real(dp),allocatable :: phfrq_ibz(:,:), displ_cart_dum(:,:,:,:), gatm_real(:,:,:,:), gnu_real(:,:,:,:)
    1385           16 :  real(dp),allocatable :: eigvec_ibz(:,:,:,:,:), eigvec_qbz(:,:,:,:), displ_cart_qbz(:,:,:,:), displ_red_qbz(:,:,:,:)
    1386           16 :  complex(dp),allocatable :: intp_gatm(:,:,:,:), gatm_full(:,:,:,:), g_req(:,:,:,:)
    1387              : !----------------------------------------------------------------------
    1388              : 
    1389           16 :  if (dtfil%filgstorein /= ABI_NOFILE) then
    1390              :    call gstore%from_ncpath(dtfil%filgstorein, with_cplex, dtset, dtfil, cryst, ebands, ifc, &
    1391           16 :                            with_gmode, gvals_name, with_g2dw, comm)
    1392           16 :    from_file = .True.
    1393              : 
    1394            0 :  else if (dtfil%filabiwanin /= ABI_NOFILE .and. dtfil%filgwanin /= ABI_NOFILE) then
    1395              :    ! Build gstore on the fly via Wannier interpolation from ABIWAN.nc + GWAN.nc.
    1396            0 :    call cwtime(cpu, wall, gflops, "start")
    1397              :    ! with_cplex=0 prepares the Wannier interpolator and gstore metadata without materializing g(k,q).
    1398              :    ! with_cplex=1/2 stores |g|^2/complex g, respectively. Debye-Waller and gvals_ks are unsupported.
    1399            0 :    msg = sjoin("Invalid with_cplex:", itoa(with_cplex), "only 0, 1 or 2 are supported")
    1400            0 :    ABI_CHECK(with_cplex >= 0 .and. with_cplex <= 2, msg)
    1401            0 :    if (with_g2dw) then
    1402            0 :      ABI_ERROR("with_g2dw = .True. is not yet supported when building gstore via Wannier interpolation (ABIWAN.nc + GWAN.nc)")
    1403              :    end if
    1404            0 :    if (gvals_name == "gvals_ks") then
    1405            0 :      ABI_ERROR("gvals_name = 'gvals_ks' is not supported when building gstore via Wannier interpolation (ABIWAN.nc + GWAN.nc)")
    1406              :    end if
    1407            0 :    if (with_gmode /= GSTORE_GMODE_PHONON) then
    1408            0 :      ABI_ERROR(sjoin("with_gmode:", with_gmode, "is not yet supported when building gstore via Wannier"))
    1409              :    end if
    1410              : 
    1411            0 :    gstore_path = strcat(dtfil%filnam_ds(4), "_GSTORE.nc")
    1412            0 :    call gstore%init(gstore_path, dtset, dtfil, wfk0_hdr, cryst, ebands, ifc, comm, with_cplex=with_cplex)
    1413              : 
    1414            0 :    if (with_cplex == 0) then
    1415            0 :      call wrtout([std_out, ab_out], " Preparing on-demand Wannier interpolation of e-ph matrix elements ...", pre_newlines=1)
    1416              :    else
    1417            0 :      call wrtout([std_out, ab_out], " Using Wannier interpolation to compute and store e-ph matrix elements ...", pre_newlines=1)
    1418              :    end if
    1419            0 :    from_file = .False.
    1420            0 :    natom = cryst%natom; natom3 = 3 * natom
    1421              : 
    1422              :    ! Precompute phonon frequencies/eigenvectors in the IBZ once (spin-independent).
    1423              :    ! NB: The phonon eigenvector gauge must be fixed from a single IBZ representative + symmetry
    1424              :    ! rotation (pheigvec_rotate), exactly as done when g(k,q) is read from a pre-existent GSTORE.nc
    1425              :    ! file (see gstore_from_ncpath). Calling ifc%fourq directly at each interpolated BZ q would give
    1426              :    ! an independently-diagonalized (and hence potentially differently gauged) eigenbasis for
    1427              :    ! degenerate modes and would break the e(-q) = e(q)^* convention used elsewhere in the code.
    1428            0 :    ABI_MALLOC(phfrq_ibz, (natom3, gstore%nqibz))
    1429            0 :    ABI_MALLOC(eigvec_ibz, (2, 3, natom, natom3, gstore%nqibz))
    1430            0 :    ABI_MALLOC(displ_cart_dum, (2, 3, natom, natom3))
    1431            0 :    do iq_ibz=1,gstore%nqibz
    1432              :      call ifc%fourq(cryst, gstore%qibz(:,iq_ibz), phfrq_ibz(:,iq_ibz), displ_cart_dum, &
    1433            0 :                     out_eigvec=eigvec_ibz(:,:,:,:,iq_ibz))
    1434              :    end do
    1435            0 :    ABI_FREE(displ_cart_dum)
    1436              : 
    1437            0 :    ABI_MALLOC(eigvec_qbz, (2, 3, natom, natom3))
    1438            0 :    ABI_MALLOC(displ_cart_qbz, (2, 3, natom, natom3))
    1439            0 :    ABI_MALLOC(displ_red_qbz, (2, 3, natom, natom3))
    1440              : 
    1441              :    ! Interpolate g(k,q) and store data in memory.
    1442            0 :    do my_is=1,gstore%my_nspins
    1443            0 :      spin = gstore%my_spins(my_is); gqk => gstore%gqk(my_is); nwan = gqk%nb_k
    1444              : 
    1445              :      ! Build gqk%wan for this spin from the ABIWAN.nc file and load g(R_e, R_p) from GWAN.nc.
    1446            0 :      call gqk%wan%from_abiwan(dtfil%filabiwanin, spin, gstore%nsppol, .False., "", gqk%comm%value)
    1447            0 :      gqk%wan%my_pert_start = gqk%my_pert_start; gqk%wan%my_npert = gqk%my_npert; gqk%wan%pert_comm => gqk%pert_comm
    1448            0 :      call gqk%wan%load_gwan(dtfil%filgwanin, cryst, spin, gstore%nsppol, gqk%comm)
    1449              : 
    1450            0 :      ABI_MALLOC(gqk%my_wnuq, (gqk%my_npert, gqk%my_nq))
    1451            0 :      ABI_MALLOC(gqk%my_displ_cart, (2, 3, natom, gqk%my_npert, gqk%my_nq))
    1452              : 
    1453            0 :      if (with_cplex > 0) then
    1454              :        ! Bound the two temporary complex atomic-vertex arrays to the default
    1455              :        ! 64 MiB workspace. The low-level selector also accepts a custom limit.
    1456            0 :        nk_batch = gqk%wan%eph_kbatch_size(gqk%my_nk, natom3)
    1457            0 :        ABI_MALLOC(intp_gatm, (nwan, nwan, gqk%my_npert, nk_batch))
    1458            0 :        ABI_MALLOC(gatm_full, (nwan, nwan, natom3, nk_batch))
    1459            0 :        ABI_MALLOC(g_req, (gqk%wan%nr_e, nwan, nwan, gqk%my_npert))
    1460            0 :        ABI_MALLOC(gatm_real, (2, nwan, nwan, natom3))
    1461            0 :        ABI_MALLOC(gnu_real, (2, nwan, nwan, natom3))
    1462              :      end if
    1463              : 
    1464            0 :      do my_iq=1,gqk%my_nq
    1465            0 :        call gqk%myqpt(my_iq, gstore, weight_q, qpt)
    1466            0 :        iq_ibz = gqk%my_q2ibz(1, my_iq); isym_q = gqk%my_q2ibz(2, my_iq); trev_q = gqk%my_q2ibz(6, my_iq)
    1467              : 
    1468              :        ! Rotate the phonon eigenvector from the IBZ to this BZ q-point (fixes the gauge).
    1469              :        call pheigvec_rotate(cryst, gstore%qibz(:,iq_ibz), isym_q, trev_q, eigvec_ibz(:,:,:,:,iq_ibz), &
    1470            0 :                             eigvec_qbz, displ_cart_qbz, displ_red_qbz=displ_red_qbz)
    1471              : 
    1472              :        ! Fill my arrays with ph data.
    1473            0 :        gqk%my_wnuq(:,my_iq) = phfrq_ibz(gqk%my_pertcases(:), iq_ibz)
    1474            0 :        gqk%my_displ_cart(:,:,:,:,my_iq) = displ_cart_qbz(:,:,:,gqk%my_pertcases(:))
    1475              : 
    1476            0 :        if (with_cplex == 0) cycle
    1477              : 
    1478              :        ! The R_p -> q transform is independent of k and is reused by every
    1479              :        ! bounded k block below.
    1480            0 :        call gqk%wan%prepare_eph_q(qpt, g_req)
    1481              : 
    1482            0 :        do ik_start=1,gqk%my_nk,nk_batch
    1483            0 :          ik_stop = min(gqk%my_nk, ik_start + nk_batch - 1); nkb = ik_stop - ik_start + 1
    1484              : 
    1485              :          call gqk%wan%interp_eph_manyk_from_q(cryst, nkb, gqk%my_kpts(:,ik_start:ik_stop), qpt, &
    1486            0 :                                               g_req, intp_gatm(:,:,:,1:nkb))
    1487              : 
    1488              :          ! Complete all atomic perturbations for the block with one collective
    1489              :          ! instead of one pert_comm reduction per k point.
    1490            0 :          gatm_full(:,:,:,1:nkb) = czero
    1491            0 :          do ikb=1,nkb
    1492            0 :            do ipc=1,gqk%my_npert
    1493            0 :              gatm_full(:,:,gqk%my_pertcases(ipc),ikb) = intp_gatm(:,:,ipc,ikb)
    1494              :            end do
    1495              :          end do
    1496            0 :          if (gqk%pert_comm%nproc > 1) call xmpi_sum(gatm_full(:,:,:,1:nkb), gqk%pert_comm%value, ierr)
    1497              : 
    1498            0 :          do ikb=1,nkb
    1499            0 :            my_ik = ik_start + ikb - 1
    1500            0 :            gatm_real(1,:,:,:) = real(gatm_full(:,:,:,ikb), kind=dp)
    1501            0 :            gatm_real(2,:,:,:) = aimag(gatm_full(:,:,:,ikb))
    1502            0 :            call ephtk_gkknu_from_atm(nwan, nwan, 1, natom, gatm_real, phfrq_ibz(:,iq_ibz), displ_red_qbz, gnu_real)
    1503              : 
    1504            0 :            do ipc=1,gqk%my_npert
    1505            0 :              nu = gqk%my_pertcases(ipc)
    1506            0 :              if (with_cplex == 2) then
    1507            0 :                gqk%my_g(ipc,:,my_iq,:,my_ik) = gnu_real(1,:,:,nu) + j_dpc * gnu_real(2,:,:,nu)
    1508              :              else
    1509            0 :                gqk%my_g2(ipc,:,my_iq,:,my_ik) = gnu_real(1,:,:,nu)**2 + gnu_real(2,:,:,nu)**2
    1510              :              end if
    1511              :            end do
    1512              :          end do ! ikb
    1513              :        end do ! ik_start
    1514              :      end do ! my_iq
    1515              : 
    1516            0 :      if (with_cplex > 0) then
    1517            0 :        ABI_FREE(intp_gatm)
    1518            0 :        ABI_FREE(gatm_full)
    1519            0 :        ABI_FREE(g_req)
    1520            0 :        ABI_FREE(gatm_real)
    1521            0 :        ABI_FREE(gnu_real)
    1522              :      end if
    1523              :    end do ! my_is
    1524              : 
    1525            0 :    ABI_FREE(phfrq_ibz)
    1526            0 :    ABI_FREE(eigvec_ibz)
    1527            0 :    ABI_FREE(eigvec_qbz)
    1528            0 :    ABI_FREE(displ_cart_qbz)
    1529            0 :    ABI_FREE(displ_red_qbz)
    1530              : 
    1531              :    ! We interpolated (and converted to) the phonon representation.
    1532            0 :    gstore%gmode = GSTORE_GMODE_PHONON
    1533            0 :    call cwtime_report(" Wannier interpolation of GSTORE matrix elements", cpu, wall, gflops)
    1534              : 
    1535              :  else
    1536              :    write(msg, "(3a)") &
    1537            0 :      "Cannot build gstore object: either getgstore_filepath or both ", &
    1538            0 :      "getabiwan_filepath and getgwan_filepath must be provided in the input file.", ch10
    1539            0 :    ABI_ERROR(msg)
    1540              :  end if
    1541              : 
    1542           16 : end subroutine gstore_init_or_from_ncpath
    1543              : !!***
    1544              : 
    1545              : !----------------------------------------------------------------------
    1546              : 
    1547            0 : logical function gstore_has_matrix_elements(gstore) result(has_g)
    1548              : 
    1549              :  class(gstore_t),intent(in) :: gstore
    1550              : 
    1551            0 :  has_g = gstore%with_cplex > 0
    1552              : 
    1553            0 : end function gstore_has_matrix_elements
    1554              : 
    1555              : !----------------------------------------------------------------------
    1556              : 
    1557            0 : logical function gstore_has_complex_matrix_elements(gstore) result(has_complex_g)
    1558              : 
    1559              :  class(gstore_t),intent(in) :: gstore
    1560              : 
    1561            0 :  has_complex_g = gstore%with_cplex == 2
    1562              : 
    1563            0 : end function gstore_has_complex_matrix_elements
    1564              : 
    1565              : !----------------------------------------------------------------------
    1566              : 
    1567              : !!****f* m_gstore/gstore_same_nbands
    1568              : !! NAME
    1569              : !! gstore_same_nbands
    1570              : !!
    1571              : !! FUNCTION
    1572              : !!  True if nb_k == nb_kq.
    1573              : !!
    1574              : !! SOURCE
    1575              : 
    1576            9 : logical function gstore_same_nbands(gstore, msg) result(same)
    1577              : 
    1578              :  class(gstore_t),intent(in) :: gstore
    1579              :  character(len=*),intent(out) :: msg
    1580              : 
    1581              : !Local variables-------------------------------
    1582              :  integer :: my_is
    1583              : !----------------------------------------------------------------------
    1584              : 
    1585            9 :  same = .True.; msg = ""
    1586           18 :  do my_is=1,gstore%my_nspins
    1587            9 :    associate (gqk => gstore%gqk(my_is))
    1588            9 :    if (gqk%nb_k /= gqk%nb_kq) then
    1589            0 :      same = .False.; msg = sjoin("gstore has different nb_kq, nb_k", itoa(gqk%nb_kq), itoa(gqk%nb_k))
    1590              :    end if
    1591              :    end associate
    1592              :  end do
    1593              : 
    1594            9 : end function gstore_same_nbands
    1595              : !!***
    1596              : 
    1597              : !----------------------------------------------------------------------
    1598              : 
    1599              : !!****f* m_gstore/gstore_distribute_spins
    1600              : !! NAME
    1601              : !! gstore_distribute_spins
    1602              : !!
    1603              : !! FUNCTION
    1604              : !!  Distribute spins. Also create and return indirect mapping to spin index and init %brange_k_spin
    1605              : !!
    1606              : !! INPUTS
    1607              : !!
    1608              : !! OUTPUT
    1609              : !!
    1610              : !! NOTES
    1611              : !!  What works:
    1612              : !!
    1613              : !!  - Setting gstore_kfilter = "qprange" works.
    1614              : !!    With this, bands (nb_k) and k-points are automatically filtered, including only the VBM and CBM.
    1615              : !!    This is useful for calculating the ZPR of the fundamental gap.
    1616              : !!    Manual specification of bands (nb_k) and k-points also works by setting gstore_kfilter = "none" (default)
    1617              : !!    and providing the values via kptgw and bdgw.
    1618              : !!
    1619              : !!  What does not work:
    1620              : !!
    1621              : !!  - There is currently no effective way to control nb_kq directly.
    1622              : !!    The only workaround is using gstore_brange. For example, gstore_brange = '1, 8' sets nb_k = nb_kq = 8.
    1623              : !!    However, gstore_brange has the lowest priority: if gstore_kfilter
    1624              : !!    is set or kptgw/bdgw are provided, gstore_brange is ignored and nb_kq defaults to nband.
    1625              : !!
    1626              : !!  Notes on use cases:
    1627              : !!      For ZPR calculations, the current schemes are sufficient.
    1628              : !!      For tasks comparing g between GWPT and FD, the current schemes are not very convenient.
    1629              : !!      For instance, to compare g at k=q=Gamma for the first 8 bands of diamond,
    1630              : !!      ideally we would restrict the calculation to nb_k = nb_kq = {1..8} and k=q=Gamma. But currently
    1631              : !!
    1632              : !!  Using gstore_brange triggers unnecessary k-point calculations (ngkpt is usually a dense k-grid).
    1633              : !!
    1634              : !!  Using kptgw and bdgw triggers unnecessary band calculations (nb_kq = nband is usually a big number).
    1635              : !!
    1636              : !!  Potential improvement (?):
    1637              : !!      Maybe we could give gstore_brange higher priority to control nb_kq(?). To avoid conflicts:
    1638              : !!      If gstore_brange is provided and gstore_kfilter = "none", we do
    1639              : !!      bstart_k = bdgw[1], nb_k = min(nband, bdgw[2] - bdgw[1])
    1640              : !!      bstart_kq = gstore_brange[1], nb_kq = min(nband, gstore_brange[2] - gstore_brange[1])
    1641              : !!      If gstore_brange is NOT provided and gstore_kfilter = "none", we do
    1642              : !!      bstart_kq = bstart_k = bdgw[1], nb_kq = nb_k = max(nband, bdgw[2] - bdgw[1])
    1643              : !!
    1644              : !! SOURCE
    1645              : 
    1646           24 : subroutine gstore_distribute_spins(gstore, mband, brange_kq, brange_k, nproc_spin, comm_spin, comm)
    1647              : 
    1648              : !Arguments ------------------------------------
    1649              : !scalars
    1650              :  class(gstore_t),target,intent(inout) :: gstore
    1651              :  integer,intent(in) :: mband, comm, brange_kq(2, gstore%nsppol), brange_k(2, gstore%nsppol)
    1652              :  integer,intent(out) :: nproc_spin(gstore%nsppol), comm_spin(gstore%nsppol)
    1653              : 
    1654              : !Local variables-------------------------------
    1655              : !scalars
    1656              :  integer :: spin, my_rank, ierr, color, nsppol, nprocs
    1657              : !arrays
    1658              :  integer :: buff_spin(2)
    1659              : !----------------------------------------------------------------------
    1660              : 
    1661           24 :  nprocs = xmpi_comm_size(comm); my_rank = xmpi_comm_rank(comm)
    1662           24 :  nsppol = gstore%nsppol
    1663              : 
    1664           24 :  gstore%my_nspins = 0
    1665           72 :  ABI_MALLOC(gstore%brange_k_spin, (2, nsppol))
    1666           48 :  ABI_MALLOC(gstore%brange_kq_spin, (2, nsppol))
    1667              : 
    1668           48 :  do spin=1,nsppol
    1669              :    ! NB: If MPI_UNDEFINED is passed as the colour value, the subgroup in which
    1670              :    ! the calling MPI process will be placed is MPI_COMM_NULL
    1671           24 :    color = 1
    1672           24 :    if (nsppol == 2 .and. nprocs > 1) then
    1673            0 :      color = xmpi_undefined
    1674            0 :      if (spin == 1 .and. my_rank <= (nprocs - 1) / 2) color = 1
    1675            0 :      if (spin == 2 .and. my_rank >  (nprocs - 1) / 2) color = 1
    1676              :    end if
    1677              : 
    1678           24 :    call xmpi_comm_split(comm, color, my_rank, comm_spin(spin), ierr)
    1679           24 :    if (comm_spin(spin) /= xmpi_comm_null) then
    1680           24 :      gstore%my_nspins = gstore%my_nspins + 1
    1681           24 :      buff_spin(gstore%my_nspins) = spin
    1682              :    end if
    1683              : 
    1684           24 :    nproc_spin(spin) = xmpi_comm_size(comm_spin(spin))
    1685              : 
    1686              :    ! Default values for brange at k, k+q from mband
    1687           72 :    gstore%brange_k_spin(:, spin) = [1, mband]
    1688           72 :    gstore%brange_kq_spin(:, spin) = [1, mband]
    1689              : 
    1690              :    ! Optionally take values from input brange_k, brange_kq
    1691          139 :    if (all(brange_k  /= 0)) gstore%brange_k_spin(:, spin) = brange_k(:, spin)
    1692          139 :    if (all(brange_kq /= 0)) gstore%brange_kq_spin(:, spin) = brange_kq(:, spin)
    1693              : 
    1694              :    ! Validate against input mband.
    1695           24 :    ABI_CHECK_IRANGE(gstore%brange_k_spin(1, spin), 1, mband, "brange_k(1, spin)")
    1696           24 :    ABI_CHECK_IRANGE(gstore%brange_k_spin(2, spin), 1, mband, "brange_k(2, spin)")
    1697           24 :    ABI_CHECK(gstore%brange_k_spin(1, spin) <= gstore%brange_k_spin(2, spin), "brange_k_spin(1, spin) <= brange_k_spin(2, spin)")
    1698              : 
    1699           24 :    ABI_CHECK_IRANGE(gstore%brange_kq_spin(1, spin), 1, mband, "brange_k(1, spin)")
    1700           24 :    ABI_CHECK_IRANGE(gstore%brange_kq_spin(2, spin), 1, mband, "brange_k(2, spin)")
    1701           72 :    ABI_CHECK(gstore%brange_kq_spin(1, spin) <= gstore%brange_kq_spin(2, spin), "brange_kq_spin(1, spin) <= brange_kq_spin(2, spin)")
    1702              :  end do
    1703              : 
    1704           72 :  ABI_MALLOC(gstore%my_spins, (gstore%my_nspins))
    1705           72 :  gstore%my_spins = buff_spin(1:gstore%my_nspins)
    1706          384 :  ABI_MALLOC(gstore%gqk, (gstore%my_nspins))
    1707              : 
    1708           24 : end subroutine gstore_distribute_spins
    1709              : !!***
    1710              : 
    1711              : !----------------------------------------------------------------------
    1712              : 
    1713              : !!****f* m_gstore/gstore_set_mpi_grid__
    1714              : !! NAME
    1715              : !! gstore_set_mpi_grid__
    1716              : !!
    1717              : !! FUNCTION
    1718              : !!
    1719              : !! INPUTS
    1720              : !!
    1721              : !! OUTPUT
    1722              : !!
    1723              : !! SOURCE
    1724              : 
    1725           24 : subroutine gstore_set_mpi_grid__(gstore, dtfil, nproc_spin, comm_spin)
    1726              : 
    1727              : !Arguments ------------------------------------
    1728              : !scalars
    1729              :  class(gstore_t),target,intent(inout) :: gstore
    1730              :  type(datafiles_type),intent(in) :: dtfil
    1731              :  integer,intent(in) :: nproc_spin(gstore%nsppol)
    1732              :  integer,intent(inout) :: comm_spin(gstore%nsppol)
    1733              : !Local variables-------------------------------
    1734              : !scalars
    1735              :  integer,parameter :: master = 0
    1736              :  integer :: spin, my_is, np, my_rank, ierr, npp_bz, units(2), bstart_k, bstop_k, nb_k, bstart_kq, bstop_kq, nb_kq
    1737              :  integer :: comm_cart, me_cart, dims(ndims)
    1738              :  type(gqk_t),pointer :: gqk
    1739              :  character(len=5000) :: msg
    1740              :  character(len=10) :: order, priority
    1741              :  character(len=fnlen) :: screen_filepath
    1742              :  logical :: reorder, periods(ndims), keepdim(ndims)
    1743          312 :  type(kmesh_t) :: pp_mesh
    1744           24 :  type(gsphere_t) :: gsph_c
    1745           24 :  real(dp),allocatable :: qlwl(:,:)
    1746           96 :  type(hscr_t),target :: hscr
    1747              : !----------------------------------------------------------------------
    1748              : 
    1749           72 :  units = [std_out, ab_out]
    1750              : 
    1751              :  associate (dtset => gstore%dtset)
    1752           48 :  my_rank = xmpi_comm_rank(gstore%comm)
    1753              : 
    1754           48 :  do my_is=1,gstore%my_nspins
    1755           24 :    spin = gstore%my_spins(my_is); gqk => gstore%gqk(my_is)
    1756           24 :    gqk%spin = spin; gqk%natom3 = 3 * gstore%cryst%natom; gqk%cplex = 2
    1757              : 
    1758              :    ! Compute bstart_k and nb_k for this spin.
    1759           24 :    bstart_k = gstore%brange_k_spin(1, spin)
    1760           24 :    bstop_k = gstore%brange_k_spin(2, spin)
    1761           24 :    nb_k = gstore%brange_k_spin(2, spin) - gstore%brange_k_spin(1, spin) + 1
    1762              : 
    1763              :    ! Compute bstart_kq and nb_kq for this spin.
    1764           24 :    bstart_kq = gstore%brange_kq_spin(1, spin)
    1765           24 :    bstop_kq = gstore%brange_kq_spin(2, spin)
    1766           24 :    nb_kq = gstore%brange_kq_spin(2, spin) - gstore%brange_kq_spin(1, spin) + 1
    1767              : 
    1768              :    ! Here we set nb_k and nb_kq
    1769           24 :    gqk%nb_k = nb_k; gqk%bstart_k = bstart_k; gqk%bstop_k = bstop_k
    1770           24 :    gqk%nb_kq = nb_kq; gqk%bstart_kq = bstart_kq; gqk%bstop_kq = bstop_kq
    1771              : 
    1772              :    ! Store global shape of the q/k matrix for this spin.
    1773           24 :    gqk%glob_nq = gstore%glob_nq_spin(spin)
    1774           48 :    gqk%glob_nk = gstore%glob_nk_spin(spin)
    1775              :  end do
    1776              : 
    1777           48 :  do my_is=1,gstore%my_nspins
    1778           24 :    spin = gstore%my_spins(my_is); gqk => gstore%gqk(my_is)
    1779              : 
    1780              :    ! Init for sequential execution.
    1781           24 :    gqk%my_npert = gqk%natom3
    1782           24 :    gqk%qpt_comm%nproc = 1; gqk%kpt_comm%nproc = 1; gqk%pert_comm%nproc = 1; gqk%band_comm%nproc = 1
    1783              :    ! NB: The communicators below are only used in GWPT.
    1784           24 :    gqk%bsum_comm%nproc = 1; gqk%pp_sum_comm%nproc = 1
    1785              : 
    1786           24 :    np = nproc_spin(spin)
    1787              : 
    1788           24 :    if (dtset%eph_task /= 17) then
    1789              :      ! =============================
    1790              :      ! For all eph_tasks except GWPT
    1791              :      ! =============================
    1792              : 
    1793          126 :      if (any(dtset%eph_np_pqbks /= 0)) then
    1794              :        ! Use parameters from input file. Need to perform sanity check though.
    1795            0 :        gqk%pert_comm%nproc = dtset%eph_np_pqbks(1)
    1796            0 :        gqk%qpt_comm%nproc  = dtset%eph_np_pqbks(2)
    1797            0 :        gqk%band_comm%nproc  = dtset%eph_np_pqbks(3)
    1798            0 :        ABI_CHECK(dtset%eph_np_pqbks(3) == 1, "Band parallelism not yet implemented in gstore")
    1799            0 :        gqk%kpt_comm%nproc = dtset%eph_np_pqbks(4)
    1800              :        !gqk%spin_comm%nproc = dtset%eph_np_pqbks(5)
    1801            0 :        gqk%my_npert = gqk%natom3 / gqk%pert_comm%nproc
    1802            0 :        ABI_CHECK(gqk%my_npert > 0, "pert_comm_nproc cannot be greater than 3*natom.")
    1803            0 :        ABI_CHECK(mod(gqk%natom3, gqk%pert_comm%nproc) == 0, "pert_comm_nproc must divide 3*natom.")
    1804              : 
    1805              :      else
    1806              :        ! Automatic grid generation (hopefully smart)
    1807              :        ! Keep in mind that in gstore_compute, the first loop is over q-points
    1808              :        ! in order to reduce the number of interpolations of the DFPT potentials in q-space
    1809              :        ! hence the q-point parallelism is expected to be more efficient.
    1810              :        ! On the other hand, the k-point parallelism and the perturbation parallelism
    1811              :        ! allow one to reduce the memory requirements associated to the wavefunctions (kpt) and
    1812              :        ! the scattering potentials in the supercell (perturbations).
    1813              :        ! Here we try to optimize performance but it's clear that for large systems the user
    1814              :        ! should specify dtset%eph_np_pqbks in the input file.
    1815              : 
    1816            5 :        select case (dtset%eph_task)
    1817              :        case (11)
    1818            5 :          priority = "qk"
    1819              :        case (12, -12)
    1820            0 :          priority = "q"
    1821              :        case (13)
    1822            9 :          priority = "q"
    1823              :        case (14, 17)
    1824            0 :          priority = "kq"
    1825              :        case (24)
    1826            7 :          priority = "qk"
    1827              :        case default
    1828           21 :          ABI_ERROR(sjoin("Please register default priority for eph_task:", itoa(dtset%eph_task)))
    1829              :        end select
    1830              : 
    1831            9 :        select case (priority)
    1832              :        case ("q")
    1833            9 :          order = "1"
    1834              :        case ("k")
    1835            0 :          order = "2"
    1836              :        case ("kq")
    1837            0 :          order = "21"
    1838              :        case ("qk")
    1839           12 :          order = "12"
    1840              :        case default
    1841           21 :          ABI_ERROR(sjoin("Wrong priority:", priority))
    1842              :        end select
    1843              : 
    1844           21 :        if (gqk%glob_nk == 1) order = "21"
    1845           21 :        if (gqk%glob_nq == 1) order = "12"
    1846           21 :        call xmpi_distrib_2d(np, order, gqk%glob_nq, gqk%glob_nk, gqk%qpt_comm%nproc, gqk%kpt_comm%nproc, ierr)
    1847           21 :        ABI_CHECK(ierr == 0, sjoin("Cannot distribute nprocs:", itoa(np), " with priority: ", priority))
    1848              :      end if
    1849              : 
    1850              :    else if (dtset%eph_task == 17) then
    1851              :      ! =========================
    1852              :      ! MPI distribution for GWPT
    1853              :      ! =========================
    1854              : 
    1855           21 :      if (any(dtset%gwpt_np_wpqbks /= 0)) then
    1856              :        ! Use parameters from input file. Need to perform sanity check though.
    1857            0 :        gqk%pp_sum_comm%nproc  = dtset%gwpt_np_wpqbks(1)
    1858            0 :        gqk%pert_comm%nproc = dtset%gwpt_np_wpqbks(2)
    1859            0 :        gqk%qpt_comm%nproc  = dtset%gwpt_np_wpqbks(3)
    1860            0 :        gqk%bsum_comm%nproc  = dtset%gwpt_np_wpqbks(4)
    1861            0 :        gqk%kpt_comm%nproc = dtset%gwpt_np_wpqbks(5)
    1862              :        !gqk%spin_comm%nproc = dtset%gwpt_np_wpqbks(6)
    1863            0 :        gqk%my_npert = gqk%natom3 / gqk%pert_comm%nproc
    1864            0 :        ABI_CHECK(gqk%my_npert > 0, "pert_comm_nproc cannot be greater than 3*natom.")
    1865            0 :        ABI_CHECK(mod(gqk%natom3, gqk%pert_comm%nproc) == 0, "pert_comm_nproc must divide 3*natom.")
    1866              : 
    1867              :      else
    1868              :        ! Automatic grid generation for GWPT (hopefully smart)
    1869              : 
    1870              :        ! In GWPT, the loop over pp-wavevectors is always in the BZ and is expected to be the most efficient
    1871              :        ! Note however that the p-mesh is not necessarly equal to the k-mesh hence we have to read it from the SCR file.
    1872              :        !npp_bz = product(get_diag(gstore%dtset%kptrlatt))
    1873              : 
    1874            3 :        screen_filepath = dtfil%fnameabi_scr
    1875            3 :        ABI_CHECK(dtfil%fnameabi_scr /= ABI_NOFILE, "SCR file must be specified")
    1876            3 :        call get_hscr_qmesh_gsph(screen_filepath, gstore%dtset, gstore%cryst, hscr, pp_mesh, gsph_c, qlwl, comm_spin(spin))
    1877            3 :        npp_bz = pp_mesh%nbz
    1878            3 :        call hscr%free(); call pp_mesh%free(); call gsph_c%free()
    1879            3 :        ABI_SFREE(qlwl)
    1880              : 
    1881            3 :        if (np <= npp_bz * gqk%natom3) then
    1882              :          ! "Small" np. Give higher priority to npp_bz and then perturbations.
    1883            3 :          order = "12"
    1884            3 :          call xmpi_distrib_2d(np, order, npp_bz, gqk%natom3, gqk%pp_sum_comm%nproc, gqk%pert_comm%nproc, ierr)
    1885            3 :          ABI_CHECK(ierr == 0, sjoin("Cannot distribute nprocs:", itoa(np), " with priority: ", priority, " Please use gwpt_np_wpqbks"))
    1886              :        else
    1887              :          ! "Large" np. Activate parallelism over k-points or q-points depending on gstore input variables.
    1888            0 :          ABI_ERROR("Your number of MPI procs is too large for the automatic GWPT parallelization. Please use gwpt_np_wpqbks")
    1889              :        end if
    1890              :      end if
    1891              : 
    1892              :    else
    1893              :      ABI_ERROR(sjoin("Invalid eph_task", itoa(dtset%eph_task)))
    1894              :    end if
    1895              : 
    1896              :    ! Consistency check.
    1897           24 :    if (gqk%pert_comm%nproc * gqk%qpt_comm%nproc * gqk%kpt_comm%nproc * gqk%band_comm%nproc * &
    1898           24 :        gqk%bsum_comm%nproc * gqk%pp_sum_comm%nproc /= nproc_spin(spin)) then
    1899              :      write(msg, "(a,i0,3a, 7(a,1x,i0))") &
    1900            0 :        "Cannot create Cartesian grid with total nproc: ", nproc_spin(spin), ch10, &
    1901            0 :        "Idle processes are not supported. The product of the `nproc_*` vars should be equal to nproc.", ch10, &
    1902            0 :        "qpt_nproc (", gqk%qpt_comm%nproc, ") x kpt_nproc (", gqk%kpt_comm%nproc, ") x pert_nproc", gqk%pert_comm%nproc, &
    1903            0 :        "x band_nproc (", gqk%band_comm%nproc, "x bsum_nproc (", gqk%bsum_comm%nproc, ") x psum_nproc (", gqk%pp_sum_comm%nproc, &
    1904            0 :        ") != ", nproc_spin(spin)
    1905            0 :      ABI_ERROR(msg)
    1906              :    end if
    1907              : 
    1908              :  end do ! my_is
    1909              : 
    1910              :  ! For each spin treated by this rank, create Cartesian communicator of rank ndims.
    1911           24 :  periods(:) = .False.; reorder = .False.
    1912              : 
    1913           48 :  do my_is=1,gstore%my_nspins
    1914           24 :    spin = gstore%my_spins(my_is); gqk => gstore%gqk(my_is)
    1915              : 
    1916              :    ! TODO: Should change order for GWPT.
    1917              :    dims = [gqk%qpt_comm%nproc, gqk%kpt_comm%nproc, gqk%pert_comm%nproc, gqk%band_comm%nproc, &
    1918          168 :            gqk%bsum_comm%nproc, gqk%pp_sum_comm%nproc]
    1919              : 
    1920              :    ! Note comm_spin(spin).
    1921           24 :    gqk%comm = xcomm_from_mpi_int(comm_spin(spin))
    1922          168 :    gqk%coords_qkpb_sumbp = 0
    1923              : 
    1924              : #ifdef HAVE_MPI
    1925           24 :    call MPI_CART_CREATE(gqk%comm, ndims, dims, periods, reorder, comm_cart, ierr)
    1926              :    ! Find the index and coordinates of the current processor
    1927           24 :    call MPI_COMM_RANK(comm_cart, me_cart, ierr)
    1928           24 :    call MPI_CART_COORDS(comm_cart, me_cart, ndims, gqk%coords_qkpb_sumbp, ierr)
    1929              : 
    1930              :    ! Communicator for q-points in g(k,q)
    1931           24 :    keepdim = .False.; keepdim(1) = .True.; call gqk%qpt_comm%from_cart_sub(comm_cart, keepdim)
    1932              :    ! Communicator for k-points in g(k,q)
    1933           24 :    keepdim = .False.; keepdim(2) = .True.; call gqk%kpt_comm%from_cart_sub(comm_cart, keepdim)
    1934              :    ! Communicator for the (qpt, kpt) 2D grid
    1935           24 :    keepdim = .False.; keepdim(1) = .True.; keepdim(2) = .True.; call gqk%qpt_kpt_comm%from_cart_sub(comm_cart, keepdim)
    1936              :    ! Communicator for perturbations in g(k,q)
    1937           24 :    keepdim = .False.; keepdim(3) = .True.; call gqk%pert_comm%from_cart_sub(comm_cart, keepdim)
    1938              :    ! 2d Communicator for the (qpt, pert) grid
    1939           24 :    keepdim = .False.; keepdim(1) = .True.; keepdim(3) = .True.; call gqk%qpt_pert_comm%from_cart_sub(comm_cart, keepdim)
    1940              :    ! Communicator for band in g(k,q)
    1941           24 :    keepdim = .False.; keepdim(4) = .True.; call gqk%band_comm%from_cart_sub(comm_cart, keepdim)
    1942              :    ! Communicator for bsum (GWPT mode)
    1943           24 :    keepdim = .False.; keepdim(5) = .True.; call gqk%bsum_comm%from_cart_sub(comm_cart, keepdim)
    1944              :    ! Communicator for pp_sum (GWPT mode)
    1945           24 :    keepdim = .False.; keepdim(6) = .True.; call gqk%pp_sum_comm%from_cart_sub(comm_cart, keepdim)
    1946              :    ! 2d Communicator for the (pert, pp_sum) 2D grid
    1947           24 :    keepdim = .False.; keepdim(3) = .True.; keepdim(6) = .True.; call gqk%pert_ppsum_comm%from_cart_sub(comm_cart, keepdim)
    1948              :    ! 3d Communicator for the (pert, pp_sum, band_sum) 3D grid (GWPT mode)
    1949           24 :    keepdim = .False.; keepdim(3) = .True.; keepdim(5) = .True.; keepdim(6) = .True.
    1950           24 :    call gqk%pert_ppsum_bsum_comm%from_cart_sub(comm_cart, keepdim)
    1951           24 :    call xmpi_comm_free(comm_cart)
    1952              : #endif
    1953              : 
    1954              :    ! Distribute perturbations inside pert_comm using block distribution.
    1955           24 :    call xmpi_split_block(gqk%natom3, gqk%pert_comm%value, gqk%my_npert, gqk%my_pertcases)
    1956           24 :    gqk%my_pert_start = gqk%my_pertcases(1)
    1957              : 
    1958           24 :    call wrtout(units, sjoin("P qpt_comm can use shmem:", yesno(gqk%qpt_comm%can_use_shmem())))
    1959           24 :    call wrtout(units, sjoin("P kpt_comm can use shmem:", yesno(gqk%kpt_comm%can_use_shmem())))
    1960           24 :    call wrtout(units, sjoin("P bsum_comm can use shmem:", yesno(gqk%bsum_comm%can_use_shmem())))
    1961           48 :    call wrtout(units, sjoin("P pp_sum_comm can use shmem:", yesno(gqk%pp_sum_comm%can_use_shmem())), newlines=1)
    1962              :  end do ! my_is
    1963              : 
    1964           96 :  if (my_rank == master) call gstore%print([std_out, ab_out])
    1965              : 
    1966              :  end associate
    1967              : 
    1968           24 : end subroutine gstore_set_mpi_grid__
    1969              : !!***
    1970              : 
    1971              : !----------------------------------------------------------------------
    1972              : 
    1973              : !!****f* m_gstore/gstore_print
    1974              : !! NAME
    1975              : !! gstore_print
    1976              : !!
    1977              : !! FUNCTION
    1978              : !!  Print info on the gstore object.
    1979              : !!
    1980              : !! INPUTS
    1981              : !!  units: Unit numbers.
    1982              : !!  [header]: header string
    1983              : !!  [prtvol]: Verbosity level.
    1984              : !!
    1985              : !! SOURCE
    1986              : 
    1987           32 : subroutine gstore_print(gstore, units, header, prtvol)
    1988              : 
    1989              : !Arguments ------------------------------------
    1990              :  class(gstore_t),intent(inout) :: gstore
    1991              :  integer,intent(in) :: units(:)
    1992              :  character(len=*),optional,intent(in) :: header
    1993              :  integer,optional,intent(in) :: prtvol
    1994              : 
    1995              : !Local variables ------------------------------
    1996              :  integer,parameter :: max_nk=10
    1997              :  integer :: my_is, my_prtvol, ik_calc, ik_bz, ik_ibz !, iq_calc, iq_bz, iq_ibz
    1998              :  real(dp) :: rtot_num_g
    1999              :  character(len=500) :: msg
    2000              : !----------------------------------------------------------------------
    2001              : 
    2002           32 :  my_prtvol = 0; if (present(prtvol)) my_prtvol = prtvol
    2003              : 
    2004           32 :  if (present(header)) then
    2005            0 :    call wrtout(units, header)
    2006              :  else
    2007           32 :    call wrtout(units, " === Gstore parameters ===")
    2008              :  end if
    2009              : 
    2010           32 :  call wrtout(units, sjoin(" kzone:", gstore%kzone))
    2011           32 :  call wrtout(units, sjoin(" kfilter:", gstore%kfilter))
    2012           32 :  call wrtout(units, sjoin(" nkibz:", itoa(gstore%nkibz)))
    2013           32 :  call wrtout(units, sjoin(" nkbz:", itoa(gstore%nkbz)))
    2014           32 :  call wrtout(units, sjoin(" glob_nk_spin:", ltoa(gstore%glob_nk_spin)))
    2015           32 :  call wrtout(units, sjoin(" qzone:", gstore%qzone))
    2016           32 :  call wrtout(units, sjoin(" nqibz:", itoa(gstore%nqibz)))
    2017           32 :  call wrtout(units, sjoin(" nqbz:", itoa(gstore%nqbz)))
    2018           32 :  call wrtout(units, sjoin(" glob_nq_spin:", ltoa(gstore%glob_nq_spin)))
    2019           32 :  call wrtout(units, sjoin(" kptopt:", itoa(gstore%ebands%kptopt)))
    2020           32 :  call wrtout(units, sjoin(" qptopt:", itoa(gstore%qptopt)))
    2021           32 :  call wrtout(units, sjoin(" has_used_lgk:", itoa(gstore%has_used_lgk)))
    2022           32 :  call wrtout(units, sjoin(" has_used_lgq:", itoa(gstore%has_used_lgq)))
    2023           32 :  call wrtout(units, sjoin(" with_vk:", itoa(gstore%with_vk)))
    2024              : 
    2025           64 :  do my_is=1,gstore%my_nspins
    2026           32 :    associate (spin => gstore%my_spins(my_is), gqk => gstore%gqk(my_is))
    2027           32 :    call wrtout(units, sjoin(" gqk_cplex:", itoa(gqk%cplex)), pre_newlines=1)
    2028           32 :    call wrtout(units, sjoin(" gqk_bstart_k:", itoa(gqk%bstart_k)))
    2029           32 :    call wrtout(units, sjoin(" gqk_bstart_kq:", itoa(gqk%bstart_kq)))
    2030           32 :    call wrtout(units, sjoin(" gqk_bstop_k:", itoa(gqk%bstop_k)))
    2031           32 :    call wrtout(units, sjoin(" gqk_bstop_kq:", itoa(gqk%bstop_kq)))
    2032           32 :    call wrtout(units, sjoin(" gqk_nb_k:", itoa(gqk%nb_k)))
    2033           32 :    call wrtout(units, sjoin(" gqk_nb_kq:", itoa(gqk%nb_kq)))
    2034           32 :    rtot_num_g = (one * gqk%nb_kq * gqk%nb_k) * (gqk%glob_nk * gqk%glob_nq * one) * gqk%natom3
    2035              :    !call wrtout(units, sjoin(" total number of g(k,q) elements:", ftoa(rtot_num_g)))
    2036           32 :    call wrtout(units, sjoin(" gqk_my_npert:", itoa(gqk%my_npert)))
    2037           32 :    call wrtout(units, sjoin("P gqk_my_nk:", itoa(gqk%my_nk)))
    2038           32 :    call wrtout(units, sjoin("P gqk_my_nq:", itoa(gqk%my_nq)))
    2039           32 :    call wrtout(units, sjoin(ch10, " === MPI distribution ==="))
    2040           32 :    call wrtout(units, sjoin("P Number of CPUs for parallelism over perturbations: ", itoa(gqk%pert_comm%nproc)))
    2041           32 :    call wrtout(units, sjoin("P Number of perturbations treated by this CPU: ",  itoa(gqk%my_npert)))
    2042           32 :    call wrtout(units, sjoin("P Number of CPUs for parallelism over q-points: ", itoa(gqk%qpt_comm%nproc)))
    2043           32 :    call wrtout(units, sjoin("P Number of CPUs for parallelism over k-points: ", itoa(gqk%kpt_comm%nproc)))
    2044              :    ! This only for GWPT calculations.
    2045           32 :    if (gqk%bsum_comm%nproc /= 1) then
    2046            0 :      call wrtout(units, sjoin("P Number of CPUs for parallelism over band summation: ", itoa(gqk%bsum_comm%nproc)))
    2047              :    end if
    2048           32 :    if (gqk%pp_sum_comm%nproc /= 1) then
    2049            0 :      call wrtout(units, sjoin("P Number of CPUs for parallelism over wavevector summation: ", itoa(gqk%pp_sum_comm%nproc)))
    2050              :    end if
    2051              : 
    2052              :    ! Print k-points
    2053           32 :    call wrtout(units, " k-points included in gstore:")
    2054          226 :    do ik_calc=1,gqk%glob_nk
    2055          211 :      ik_bz = gstore%kglob2bz(ik_calc, spin)
    2056          211 :      ik_ibz = gstore%kbz2ibz(1, ik_bz)
    2057          211 :      call wrtout(units, sjoin(itoa(ik_calc), ":", ktoa(gstore%kbz(:, ik_bz))))
    2058          226 :      if (ik_calc > max_nk .and. my_prtvol == 0) then
    2059           17 :        call wrtout(units, sjoin(" Max", itoa(max_nk), " k-points will be written. Use prtvol > 0 to print all of them."))
    2060           17 :        exit
    2061              :      end if
    2062              :    end do
    2063              :    !call wrtout(units, " ")
    2064              : 
    2065              :    ! Print q-points
    2066              :    !call wrtout(units, " q-points included in gstore:")
    2067              :    !do iq_calc=1,gqk%glob_nq
    2068              :    !  iq_bz = gstore%qglob2bz(iq_calc, spin)
    2069              :    !  iq_ibz = gstore%qbz2ibz(1, iq_bz)
    2070              :    !  call wrtout(units, sjoin(itoa(iq_calc), ":", ktoa(gstore%qbz(:, iq_bz))))
    2071              :    !  if (iq_calc > max_nk .and. my_prtvol == 0) then
    2072              :    !    call wrtout(units, sjoin(" Max", itoa(max_nk), " q-points will be written. Use prtvol > 0 to print all of them."))
    2073              :    !    exit
    2074              :    !  end if
    2075              :    !end do
    2076              : 
    2077              :    ! Print memory
    2078           32 :    if (allocated(gqk%my_g2)) then
    2079            0 :      write(msg,'(a,f8.1,a)')'- Local memory allocated for |g|^2 array: ',ABI_MEM_MB(gqk%my_g2),' [mb] <<< mem'
    2080            0 :      call wrtout(units, msg)
    2081              :    end if
    2082           32 :    if (gqk%has_both_g .and. associated(gqk%my_g2_ks)) then
    2083            0 :      write(msg,'(a,f8.1,a)')'- Local memory allocated for |g_KS|^2 array: ',ABI_MEM_MB(gqk%my_g2_ks),' [mb] <<< mem'
    2084            0 :      call wrtout(units, msg)
    2085              :    end if
    2086           32 :    if (allocated(gqk%my_g)) then
    2087            0 :      write(msg,'(a,f8.1,a)')'- Local memory allocated for g array: ',ABI_MEM_MB(gqk%my_g),' [Mb] <<< MEM'
    2088            0 :      call wrtout(units, msg)
    2089              :    end if
    2090           32 :    if (gqk%has_both_g .and. associated(gqk%my_g_ks)) then
    2091            0 :       write(msg,'(a,f8.1,a)')'- Local memory allocated for g_KS array: ',ABI_MEM_MB(gqk%my_g_ks),' [Mb] <<< MEM'
    2092            0 :       call wrtout(units, msg)
    2093              :    end if
    2094           32 :    if (allocated(gqk%my_gdw2)) then
    2095            0 :      write(msg,'(a,f8.1,a)')'- Local memory allocated for gDW^2 array: ',ABI_MEM_MB(gqk%my_gdw2),' [mb] <<< mem'
    2096              :    end if
    2097           32 :    if (gqk%has_both_g .and. associated(gqk%my_gdw2_ks)) then
    2098            0 :      write(msg,'(a,f8.1,a)')'- Local memory allocated for gDW^2_KS array: ',ABI_MEM_MB(gqk%my_gdw2_ks),' [mb] <<< mem'
    2099              :    end if
    2100              : 
    2101           32 :    if (allocated(gqk%vnk_cart_ibz)) then
    2102            0 :      write(msg,'(a,f8.1,a)')'- Local memory allocated for vnk_cart_ibz: ',ABI_MEM_MB(gqk%vnk_cart_ibz),' [Mb] <<< MEM'
    2103            0 :      call wrtout(units, msg)
    2104              :    end if
    2105           32 :    if (allocated(gqk%vnk_mat_cart_ibz)) then
    2106            0 :      write(msg,'(a,f8.1,a)')'- Local memory allocated for vnk_mat_cart_ibz: ',ABI_MEM_MB(gqk%vnk_mat_cart_ibz),' [Mb] <<< MEM'
    2107            0 :      call wrtout(units, msg)
    2108              :    end if
    2109           64 :    if (allocated(gqk%my_iv1p_comm)) then
    2110            0 :      write(msg,'(a,f8.1,a)')'- Local memory allocated for <mk|i[V1,p]|nk> array: ',ABI_MEM_MB(gqk%my_iv1p_comm),' [mb] <<< mem'
    2111              :    end if
    2112              :    end associate
    2113              :  end do
    2114              : 
    2115           32 :  if (my_prtvol > 0) then
    2116            0 :    call gstore%ebands%print(units, header="Electron bands in GSTORE", prtvol=my_prtvol)
    2117              :  end if
    2118           32 :  call wrtout(units, " ")
    2119              : 
    2120           32 : end subroutine gstore_print
    2121              : !!***
    2122              : 
    2123              : !!****f* m_gstore/gstore_check_little_group
    2124              : !! NAME
    2125              : !! gstore_check_little_group
    2126              : !!
    2127              : !! FUNCTION
    2128              : !!  Check consistency between little group options read from file and from input.
    2129              : !!
    2130              : !! INPUTS
    2131              : !!
    2132              : !! SOURCE
    2133              : 
    2134            7 : integer function gstore_check_little_group(gstore, dtset, msg) result(ierr)
    2135              : 
    2136              : !Arguments ------------------------------------
    2137              :  class(gstore_t),intent(in) :: gstore
    2138              :  type(dataset_type),intent(in) :: dtset
    2139              :  character(len=*),intent(out) :: msg
    2140              : !----------------------------------------------------------------------
    2141              : 
    2142            7 :  ierr = 0; msg = ""
    2143              : 
    2144            7 :  if (dtset%gstore_use_lgk /= 0) then
    2145              :    ! Cannot use IBZ_k if we have used IBZ_q.
    2146            0 :    if (gstore%has_used_lgq /= 0) then
    2147            0 :      msg = sjoin("Input var gstore_use_lgq: ", itoa(dtset%gstore_use_lgq), ", but GSTORE file has:", itoa(gstore%has_used_lgq))
    2148            0 :      ABI_ERROR_NOSTOP(msg, ierr)
    2149              :    end if
    2150              :    ! Using IBZ_k when GSTORE has full BZ is OK but inefficient.
    2151            0 :    if (gstore%has_used_lgk == 0) then
    2152            0 :      msg = sjoin("Input var gstore_use_lgk: ", itoa(dtset%gstore_use_lgk), ", but GSTORE file has:", itoa(gstore%has_used_lgk))
    2153            0 :      ABI_COMMENT(msg)
    2154              :    end if
    2155              :  end if
    2156              : 
    2157            7 :  if (dtset%gstore_use_lgq /= 0) then
    2158              :    ! Cannot use IBZ_q if we have used IBZ_k.
    2159            0 :    if (gstore%has_used_lgk /= 0) then
    2160            0 :      msg = sjoin("Input var gstore_use_lgk: ", itoa(dtset%gstore_use_lgk), ", but GSTORE file has:", itoa(gstore%has_used_lgk))
    2161            0 :      ABI_ERROR_NOSTOP(msg, ierr)
    2162              :    end if
    2163              :    ! Using IBZ_q when GSTORE has full BZ is OK but inefficient.
    2164            0 :    if (gstore%has_used_lgq == 0) then
    2165            0 :      msg = sjoin("Input var gstore_use_lgq: ", itoa(dtset%gstore_use_lgq), ", but GSTORE file has:", itoa(gstore%has_used_lgq))
    2166            0 :      ABI_COMMENT(msg)
    2167              :    end if
    2168              :  end if
    2169              : 
    2170            7 : end function gstore_check_little_group
    2171              : !!***
    2172              : 
    2173              : !----------------------------------------------------------------------
    2174              : 
    2175              : !!****f* m_gstore/gstore_malloc__
    2176              : !! NAME
    2177              : !! gstore_malloc__
    2178              : !!
    2179              : !! FUNCTION
    2180              : !! Allocate local buffers once the MPI grid has been initialized.
    2181              : !!
    2182              : !! INPUTS
    2183              : !!
    2184              : !! OUTPUT
    2185              : !!
    2186              : !! SOURCE
    2187              : 
    2188           24 : subroutine gstore_malloc__(gstore, with_cplex, has_both_g, max_nq, qglob2bz, max_nk, kglob2bz, qbz2ibz, kbz2ibz)
    2189              : 
    2190              : !Arguments ------------------------------------
    2191              : !scalars
    2192              :  class(gstore_t),target,intent(inout) :: gstore
    2193              :  integer,intent(in) :: with_cplex, max_nq, max_nk
    2194              :  logical,intent(in) :: has_both_g
    2195              :  integer,intent(in) :: qglob2bz(max_nq, gstore%nsppol), kglob2bz(max_nk, gstore%nsppol)
    2196              :  integer,intent(in) :: qbz2ibz(6, gstore%nqbz), kbz2ibz(6, gstore%nkbz)
    2197              : 
    2198              : !Local variables-------------------------------
    2199              : !scalars
    2200              :  integer :: my_is, ierr, my_iq, my_ik, iq_glob, iq_bz, ik_glob, ik_bz
    2201              :  integer :: ik_ibz, isym_k, trev_k, tsign_k, g0_k(3), nb_k, nb_kq
    2202              :  logical :: isirr_k
    2203              :  real(dp) :: mem_mb
    2204              :  type(gqk_t), pointer :: gqk
    2205              : !----------------------------------------------------------------------
    2206              : 
    2207           24 :  ABI_CHECK(with_cplex >= 0 .and. with_cplex <= 2, sjoin("Invalid with_cplex:", itoa(with_cplex)))
    2208           24 :  gstore%with_cplex = with_cplex
    2209              : 
    2210           48 :  do my_is=1,gstore%my_nspins
    2211           24 :    associate (spin => gstore%my_spins(my_is))
    2212           24 :    gqk => gstore%gqk(my_is)
    2213           24 :    nb_k = gqk%nb_k; nb_kq = gqk%nb_kq
    2214           24 :    gqk%has_both_g = has_both_g
    2215              : 
    2216              :    ! Split q-points and transfer symmetry tables.
    2217              :    ! Note that glob_nq and glob_nk does not necessarily correspond to the size of the BZ
    2218              :    ! First of all we have to consider kzone
    2219              :    ! Even if kzone == "bz" we may have filtered the wavevectors e.g. Fermi surface.
    2220           24 :    call xmpi_split_block(gqk%glob_nq, gqk%qpt_comm%value, gqk%my_nq, gqk%my_q2glob)
    2221           24 :    ABI_CHECK(gqk%my_nq > 0, sjoin("glob_nq:", itoa(gqk%glob_nq), ", qpt_comm%nproc:", itoa(gqk%qpt_comm%nproc), " => my_nq == 0"))
    2222           24 :    gqk%my_qstart = gqk%my_q2glob(1)
    2223              : 
    2224           72 :    ABI_MALLOC(gqk%my_q2ibz, (6, gqk%my_nq))
    2225           72 :    ABI_MALLOC(gqk%my_q2bz, (gqk%my_nq))
    2226              : 
    2227         2330 :    do my_iq=1,gqk%my_nq
    2228         2306 :      iq_glob = my_iq + gqk%my_qstart - 1
    2229         2306 :      iq_bz = qglob2bz(iq_glob, spin)
    2230        16142 :      gqk%my_q2ibz(:, my_iq) = qbz2ibz(:, iq_bz)
    2231         2330 :      gqk%my_q2bz(my_iq) = iq_bz
    2232              :    end do
    2233              : 
    2234              :    ! Split k-points and transfer symmetry tables
    2235           24 :    call xmpi_split_block(gqk%glob_nk, gqk%kpt_comm%value, gqk%my_nk, gqk%my_k2glob)
    2236           24 :    ABI_CHECK(gqk%my_nk > 0, sjoin("glob_nk:", itoa(gqk%glob_nk), ", kpt_comm%nproc:", itoa(gqk%kpt_comm%nproc), " => my_nk == 0"))
    2237           24 :    gqk%my_kstart = gqk%my_k2glob(1)
    2238              : 
    2239           72 :    ABI_MALLOC(gqk%my_k2ibz, (6, gqk%my_nk))
    2240              :    !ABI_MALLOC(gqk%my_k2bz, (gqk%my_nk))
    2241           72 :    ABI_MALLOC(gqk%my_kpts, (3, gqk%my_nk))
    2242           72 :    ABI_MALLOC(gqk%my_wtk, (gqk%my_nk))
    2243              : 
    2244         1020 :    do my_ik=1,gqk%my_nk
    2245          996 :      ik_glob = my_ik + gqk%my_kstart - 1
    2246          996 :      ik_bz = kglob2bz(ik_glob, spin)
    2247         6972 :      gqk%my_k2ibz(:, my_ik) = kbz2ibz(:, ik_bz)
    2248              :      !gqk%my_k2bz(my_ik) = ik_bz
    2249              : 
    2250          996 :      ik_ibz = gqk%my_k2ibz(1, my_ik); isym_k = gqk%my_k2ibz(2, my_ik)
    2251         3984 :      trev_k = gqk%my_k2ibz(6, my_ik); g0_k = gqk%my_k2ibz(3:5, my_ik)
    2252              :      isirr_k = (isym_k == 1 .and. trev_k == 0 .and. all(g0_k == 0))
    2253          996 :      tsign_k = 1; if (trev_k == 1) tsign_k = -1
    2254              : 
    2255              :      ! Note symrel^T convention for k
    2256        30876 :      gqk%my_kpts(:, my_ik) = tsign_k * matmul(transpose(gstore%cryst%symrel(:,:,isym_k)), gstore%kibz(:, ik_ibz)) + g0_k
    2257              : 
    2258           24 :      select case(gstore%kzone)
    2259              :      case ("ibz")
    2260           18 :        gqk%my_wtk(my_ik) = gstore%ebands%wtk(ik_ibz)
    2261              :      case ("bz")
    2262          996 :        gqk%my_wtk(my_ik) = one / gstore%nkbz
    2263              :      end select
    2264              :    end do
    2265              : 
    2266              :    ! Allocate storage for MPI-distributed e-ph matrix elements.
    2267           48 :    if (with_cplex > 0) then
    2268           16 :      mem_mb = (one * with_cplex * gqk%my_npert) * gqk%my_nq * gqk%my_nk * nb_kq * nb_k * eight * b2Mb
    2269           16 :      call wrtout(std_out, sjoin(" Local memory for e-ph matrix elements:", ftoa(mem_mb, fmt="f8.1"), " [Mb] <<< MEM"))
    2270              : 
    2271              :      ! The initialization with zero is important as not all the g are computed when we filter in k-space.
    2272              :      ! Abinit postprocessing tools will operate of the full my_g array
    2273              :      ! and we don't want to trigger floating point exceptions.
    2274            6 :      select case (with_cplex)
    2275              :      case (1)
    2276           42 :        ABI_MALLOC_OR_DIE(gqk%my_g2, (gqk%my_npert, nb_kq, gqk%my_nq, nb_k, gqk%my_nk), ierr)
    2277        76305 :        gqk%my_g2 = zero
    2278              : 
    2279            6 :        gqk%my_g2_ks => gqk%my_g2
    2280            6 :        if (gqk%has_both_g) then
    2281           35 :          ABI_MALLOC_OR_DIE(gqk%my_g2_ks, (gqk%my_npert, nb_kq, gqk%my_nq, nb_k, gqk%my_nk), ierr)
    2282        40203 :          gqk%my_g2_ks = zero
    2283              :        end if
    2284              :      case (2)
    2285           70 :        ABI_MALLOC_OR_DIE(gqk%my_g, (gqk%my_npert, nb_kq, gqk%my_nq, nb_k, gqk%my_nk), ierr)
    2286      4224533 :        gqk%my_g = zero
    2287              : 
    2288           10 :        gqk%my_g_ks => gqk%my_g
    2289           10 :        if (gqk%has_both_g) then
    2290              :          !call wrtout(std_out, "Allocating my_g_ks") !; stop
    2291            7 :          ABI_MALLOC_OR_DIE(gqk%my_g_ks, (gqk%my_npert, nb_kq, gqk%my_nq, nb_k, gqk%my_nk), ierr)
    2292        18182 :          gqk%my_g_ks = zero
    2293              :        end if
    2294              :      case default
    2295           16 :        ABI_ERROR(sjoin("Wrong with_cplex:", itoa(with_cplex)))
    2296              :      end select
    2297              : 
    2298              :      ! Allocate storage for MPI-distributed dH/dk matrix elements.
    2299           16 :      if (any(gstore%with_vk == [1, 2])) then
    2300           16 :        mem_mb = 3 * gqk%nb_k * gqk%my_nk * eight * b2Mb
    2301           16 :        call wrtout(std_out, sjoin(" Memory for diagonal vnk_cart_ibz:", ftoa(mem_mb, fmt="f8.1"), " [Mb] <<< MEM"))
    2302           64 :        ABI_MALLOC_OR_DIE(gqk%vnk_cart_ibz, (3, gqk%nb_k, gstore%nkibz), ierr)
    2303         2087 :        gqk%vnk_cart_ibz = zero
    2304              :      end if
    2305              : 
    2306           16 :      if (gstore%with_vk == 2) then
    2307            0 :        mem_mb = two * 3 * gqk%nb_k**2 * gqk%my_nk * eight * b2Mb
    2308            0 :        call wrtout(std_out, sjoin(" Memory for vnk_mat_cart_ibz:", ftoa(mem_mb, fmt="f8.1"), " [Mb] <<< MEM"))
    2309            0 :        ABI_MALLOC_OR_DIE(gqk%vnk_mat_cart_ibz, (2, 3, gqk%nb_k, gqk%nb_k, gstore%nkibz), ierr)
    2310            0 :        gqk%vnk_mat_cart_ibz = zero
    2311              :      end if
    2312              :    end if
    2313              : 
    2314              :    end associate
    2315              :  end do ! my_is
    2316              : 
    2317           24 : end subroutine gstore_malloc__
    2318              : !!***
    2319              : 
    2320              : !----------------------------------------------------------------------
    2321              : 
    2322              : !!****f* m_gstore/gstore_filter_fs_tetra__
    2323              : !! NAME
    2324              : !! gstore_filter_fs_tetra__
    2325              : !!
    2326              : !! FUNCTION
    2327              : !!  Compute delta(e_k - e_F) with the tetrahedron method. Use weights to filter k-points.
    2328              : !!  Include only those q-points such that there exists at least one k on the FS with k + q on the FS.
    2329              : !!  Also, store and precompute gstore%delta_ef_kibz_spin(max_nb, gstore%nkibz, nsppol)
    2330              : !!  to be used to filter inside gstore%compute.
    2331              : !!
    2332              : !! INPUTS
    2333              : !!
    2334              : !! OUTPUT
    2335              : !!
    2336              : !! SOURCE
    2337              : 
    2338            0 : subroutine gstore_filter_fs_tetra__(gstore, qbz2ibz, qibz2bz, kibz2bz, select_qbz_spin, select_kbz_spin)
    2339              : 
    2340              : !Arguments ------------------------------------
    2341              : !scalars
    2342              :  class(gstore_t),intent(inout) :: gstore
    2343              :  integer,intent(in) :: qbz2ibz(6,gstore%nqbz), qibz2bz(gstore%nqibz)
    2344              :  integer,intent(in) :: kibz2bz(gstore%nkibz)
    2345              :  integer,intent(out) :: select_qbz_spin(gstore%nqbz, gstore%nsppol)
    2346              :  integer,intent(out) :: select_kbz_spin(gstore%nkbz, gstore%nsppol)
    2347              : 
    2348              : !Local variables-------------------------------
    2349              : !scalars
    2350              :  integer,parameter :: tetra_opt0 = 0
    2351              :  integer :: nsppol, ierr, cnt, spin, band, ib, ii, max_nb, all_nproc, my_rank, comm
    2352              :  integer :: ik_bz, ik_ibz, iflag, nk_in_star
    2353              :  real(dp) :: max_occ
    2354              :  character(len=80) :: error_string
    2355            0 :  type(htetra_t) :: ktetra
    2356              : !arrays
    2357            0 :  integer,allocatable :: indkk(:), kstar_bz_inds(:)
    2358              :  real(dp):: rlatt(3,3), klatt(3,3), delta_theta_ef(2) !, qpt(3)
    2359            0 :  real(dp),allocatable :: eig_ibz(:)
    2360              : !----------------------------------------------------------------------
    2361              : 
    2362              :  associate (cryst => gstore%cryst, ebands => gstore%ebands)
    2363              : 
    2364            0 :  comm = gstore%comm; all_nproc = xmpi_comm_size(comm); my_rank = xmpi_comm_rank(comm)
    2365            0 :  nsppol = gstore%nsppol
    2366              : 
    2367              :  !ABI_CHECK(gstore%same_nbands(msg), sjoin("VarPEq requires nb_k == nb_kq.", msg))
    2368              : 
    2369              :  ! Use the tetrahedron method to filter k- and k+q points on the FS in metals
    2370              :  ! and define gstore%brange_k_spin automatically.
    2371            0 :  call wrtout(std_out, sjoin(" Filtering k-points using:", gstore%kfilter))
    2372              : 
    2373              :  ! NB: here we precompute brange_k_spin
    2374              :  !     nb_kq == nb_k when FS filtering with tetra is used.
    2375            0 :  call ebands%get_bands_e0(ebands%fermie, gstore%brange_k_spin, ierr)
    2376            0 :  ABI_CHECK(ierr == 0, "Error in ebands_get_bands_e0")
    2377            0 :  gstore%brange_kq_spin = gstore%brange_k_spin
    2378              : 
    2379            0 :  ABI_MALLOC(indkk, (gstore%nkbz))
    2380            0 :  indkk(:) = gstore%kbz2ibz(1, :)
    2381              : 
    2382            0 :  rlatt = ebands%kptrlatt; call matr3inv(rlatt, klatt)
    2383              :  call ktetra%init(indkk, gstore%cryst%gprimd, klatt, gstore%kbz, gstore%nkbz, gstore%kibz, gstore%nkibz, &
    2384            0 :                   ierr, error_string, gstore%comm)
    2385            0 :  ABI_CHECK(ierr == 0, error_string)
    2386              : 
    2387            0 :  ABI_MALLOC(eig_ibz, (gstore%nkibz))
    2388            0 :  max_occ = two / (ebands%nspinor * nsppol)
    2389            0 :  select_kbz_spin = 0
    2390              : 
    2391            0 :  max_nb = maxval(gstore%brange_k_spin(2, :) - gstore%brange_k_spin(1, :) + 1)
    2392            0 :  ABI_CALLOC(gstore%delta_ef_kibz_spin, (max_nb, gstore%nkibz, gstore%nsppol))
    2393              : 
    2394              :  cnt = 0
    2395            0 :  do spin=1,nsppol
    2396            0 :    do band=gstore%brange_k_spin(1, spin), gstore%brange_k_spin(2, spin)
    2397            0 :      ib = band - gstore%brange_k_spin(1, spin) + 1
    2398            0 :      eig_ibz = ebands%eig(band, :, spin)
    2399              : 
    2400            0 :      do ik_ibz=1,gstore%nkibz
    2401            0 :        cnt = cnt + 1; if (mod(cnt, all_nproc) /= my_rank) cycle ! MPI parallelism inside comm
    2402              : 
    2403              :        call ktetra%get_onewk_wvals(ik_ibz, tetra_opt0, 1, [ebands%fermie], max_occ, &
    2404            0 :                                    gstore%nkibz, eig_ibz, delta_theta_ef)
    2405              : 
    2406            0 :        gstore%delta_ef_kibz_spin(ib, ik_ibz, spin) = delta_theta_ef(1)
    2407              : 
    2408            0 :        iflag = merge(1, 0, abs(delta_theta_ef(1)) > zero)
    2409              : 
    2410              :        ! Use iflag to filter k-points.
    2411            0 :        select case (gstore%kzone)
    2412              :        case ("ibz")
    2413            0 :          ik_bz = kibz2bz(ik_ibz)
    2414            0 :          select_kbz_spin(ik_bz, spin) = select_kbz_spin(ik_bz, spin) + iflag
    2415              : 
    2416              :        case ("bz")
    2417            0 :          call star_from_ibz_idx(ik_ibz, gstore%nkbz, gstore%kbz2ibz, nk_in_star, kstar_bz_inds)
    2418            0 :          ABI_CHECK(nk_in_star > 0, "Something wrong in star_from_ibz_idx")
    2419            0 :          do ii=1,nk_in_star
    2420            0 :            ik_bz = kstar_bz_inds(ii)
    2421            0 :            select_kbz_spin(ik_bz, spin) = select_kbz_spin(ik_bz, spin) + iflag
    2422              :          end do
    2423            0 :          ABI_FREE(kstar_bz_inds)
    2424              :        end select
    2425              :      end do
    2426              : 
    2427              :    end do
    2428              :  end do
    2429              : 
    2430              :  !call ktetra%print(std_out)
    2431            0 :  call xmpi_sum(select_kbz_spin, comm, ierr)
    2432            0 :  call xmpi_sum(gstore%delta_ef_kibz_spin, comm, ierr)
    2433              : 
    2434              :  ! Now the tricky part as we want to remove q-points that
    2435              :  ! do not lead to any scattering process between two states on the FS
    2436              :  ! Remember that k+q is always a sub-mesh of the input ebands k-mesh.
    2437              : 
    2438              :  call recompute_select_qbz_spin(gstore, gstore%qbz, qbz2ibz, qibz2bz, gstore%kbz, gstore%kibz, gstore%kbz2ibz, kibz2bz, &
    2439            0 :                                 select_kbz_spin, select_qbz_spin)
    2440              : 
    2441            0 :  ABI_FREE(eig_ibz)
    2442            0 :  ABI_FREE(indkk)
    2443            0 :  call ktetra%free()
    2444              :  end associate
    2445              : 
    2446            0 : end subroutine gstore_filter_fs_tetra__
    2447              : !!***
    2448              : 
    2449              : !----------------------------------------------------------------------
    2450              : 
    2451              : !!****f* m_gstore/gstore_filter_kptgw__
    2452              : !! NAME
    2453              : !! gstore_gw_filter_kptgw__
    2454              : !!
    2455              : !! FUNCTION
    2456              : !! Filter k-points according to the input variable kptgw. Useful for ZPR for user-specified k-points.
    2457              : !!
    2458              : !! INPUTS
    2459              : !!
    2460              : !! OUTPUT
    2461              : !!
    2462              : !! SOURCE
    2463              : 
    2464            0 : subroutine gstore_filter_kptgw__(gstore, dtset, qbz2ibz, qibz2bz, kibz2bz, select_qbz_spin, select_kbz_spin)
    2465              : 
    2466              : !Arguments ------------------------------------
    2467              : !scalars
    2468              :  class(gstore_t),intent(inout) :: gstore
    2469              :  type(dataset_type),intent(in) :: dtset
    2470              :  integer,intent(in) :: qbz2ibz(6,gstore%nqbz), qibz2bz(gstore%nqibz)
    2471              :  integer,intent(in) :: kibz2bz(gstore%nkibz)
    2472              :  integer,intent(out) :: select_qbz_spin(gstore%nqbz, gstore%nsppol)
    2473              :  integer,intent(out) :: select_kbz_spin(gstore%nkbz, gstore%nsppol)
    2474              : 
    2475              : !Local variables-------------------------------
    2476              : !scalars
    2477              :  integer :: spin, ik_bz, ik_ibz, ik_calc, nkcalc, mapl_kk(6), my_rank
    2478              : !arrays
    2479            0 :  integer,allocatable :: bstart_ks(:,:), nbcalc_ks(:,:)
    2480            0 :  real(dp),allocatable :: kcalc(:,:)
    2481              : !----------------------------------------------------------------------
    2482              : 
    2483              :  ABI_UNUSED(qbz2ibz)
    2484              :  ABI_UNUSED(qibz2bz)
    2485              : 
    2486              :  associate (cryst => gstore%cryst, ebands => gstore%ebands)
    2487              : 
    2488            0 :  my_rank = xmpi_comm_rank(gstore%comm)
    2489              : 
    2490            0 :  call wrtout(std_out, sjoin(" Filtering k-points using nkptgw:", itoa(dtset%nkptgw)))
    2491            0 :  if (gstore%qzone /= "bz") then
    2492            0 :    ABI_ERROR(sjoin('gw_qprange filtering requires gstore_qzone = "bz" while it is: ', gstore%qzone))
    2493              :  end if
    2494              : 
    2495              :  ! Compute nkcalc, kcalc, bstart_ks, nbcalc_ks
    2496            0 :  call sigtk_kcalc_from_nkptgw(dtset, dtset%mband, nkcalc, kcalc, bstart_ks, nbcalc_ks)
    2497              : 
    2498              :  ! TODO: kcalc should be spin-dependent to handle magnetic semiconductors.
    2499            0 :  select_kbz_spin = 0
    2500            0 :  do spin=1,gstore%nsppol
    2501            0 :    do ik_calc=1,nkcalc
    2502            0 :      if (kpts_map("symrel", ebands%kptopt, gstore%cryst, gstore%krank_ibz, 1, kcalc(:,ik_calc), mapl_kk) /= 0) then
    2503            0 :        ABI_ERROR(sjoin("Cannot map kcalc to IBZ with kcalc:", ktoa(kcalc(:,ik_calc))))
    2504              :      end if
    2505              :      ! Change select_kbz_spin
    2506            0 :      ik_ibz = mapl_kk(1)
    2507            0 :      ik_bz = kibz2bz(ik_ibz); select_kbz_spin(ik_bz, spin) = 1
    2508              :    end do
    2509              :  end do ! spin
    2510              : 
    2511              :  !call recompute_select_qbz_spin(gstore, gstore%qbz, qbz2ibz, qibz2bz, gstore%kbz, gstore%kibz, gstore%kbz2ibz, gstore%kibz2bz, &
    2512              :  !                               select_kbz_spin, select_qbz_spin)
    2513              : 
    2514            0 :  ABI_FREE(kcalc)
    2515            0 :  ABI_FREE(bstart_ks)
    2516            0 :  ABI_FREE(nbcalc_ks)
    2517              :  end associate
    2518              : 
    2519            0 : end subroutine gstore_filter_kptgw__
    2520              : !!***
    2521              : 
    2522              : !----------------------------------------------------------------------
    2523              : 
    2524              : !!****f* m_gstore/gstore_filter_erange__
    2525              : !! NAME
    2526              : !! gstore_filter_erange__
    2527              : !!
    2528              : !! FUNCTION
    2529              : !! Filter k-points and q-points according to an energy range.
    2530              : !!
    2531              : !! INPUTS
    2532              : !!
    2533              : !! OUTPUT
    2534              : !!
    2535              : !! SOURCE
    2536              : 
    2537            1 : subroutine gstore_filter_erange__(gstore, qbz2ibz, qibz2bz, kibz2bz, select_qbz_spin, select_kbz_spin)
    2538              : 
    2539              : !Arguments ------------------------------------
    2540              : !scalars
    2541              :  class(gstore_t),intent(inout) :: gstore
    2542              :  integer,intent(in) :: qbz2ibz(6,gstore%nqbz), qibz2bz(gstore%nqibz)
    2543              :  integer,intent(in) :: kibz2bz(gstore%nkibz)
    2544              :  integer,intent(out) :: select_qbz_spin(gstore%nqbz, gstore%nsppol)
    2545              :  integer,intent(out) :: select_kbz_spin(gstore%nkbz, gstore%nsppol)
    2546              : 
    2547              : !Local variables-------------------------------
    2548              : !scalars
    2549              :  integer,parameter :: tetra_opt0 = 0
    2550              :  integer :: nsppol, cnt, spin, ii, all_nproc, my_rank, comm, band ! ierr,
    2551              :  integer :: ik_bz, ik_ibz, iflag, nk_in_star, gap_err
    2552              :  logical :: assume_gap
    2553              :  real(dp) :: ee, abs_erange1, abs_erange2, vmax, cmin
    2554              :  type(gaps_t) :: gaps
    2555              : !arrays
    2556            1 :  integer,allocatable :: kstar_bz_inds(:)
    2557              : !----------------------------------------------------------------------
    2558              : 
    2559              :  associate (cryst => gstore%cryst, ebands => gstore%ebands)
    2560              : 
    2561            1 :  comm = gstore%comm; all_nproc = xmpi_comm_size(comm); my_rank = xmpi_comm_rank(comm)
    2562            1 :  nsppol = gstore%nsppol
    2563              : 
    2564              :  ! filter k and k + q points according to erange and define gstore%brange_spin_k automatically.
    2565              :  ! NB: here we recompute brange_k_spin
    2566              :  call wrtout(std_out, sjoin(" Filtering k-points using gstore_erange:", &
    2567            4 :                             ltoa(reshape(gstore%erange_spin, [2 * gstore%nsppol]) * Ha_eV), "(eV)"))
    2568              : 
    2569            1 :  assume_gap = .not. all(gstore%erange_spin < zero)
    2570            1 :  gaps = ebands%get_gaps(gap_err)
    2571            2 :  if (assume_gap) call gaps%print([std_out])
    2572              : 
    2573         2199 :  select_kbz_spin = 0; cnt = 0
    2574              : 
    2575            2 :  do spin=1,nsppol
    2576              :    ! Init brange. NB: nb_kq == nb_k when erange filtering is used.
    2577            3 :    gstore%brange_k_spin(:, spin) = [huge(1), -huge(1)]
    2578            3 :    gstore%brange_kq_spin(:, spin) = [huge(1), -huge(1)]
    2579            1 :    abs_erange1 = abs(gstore%erange_spin(1, spin))
    2580            1 :    abs_erange2 = abs(gstore%erange_spin(2, spin))
    2581              : 
    2582            1 :    if (assume_gap) then
    2583              :      ! Get CBM and VBM with some tolerance
    2584            1 :      vmax = gaps%vb_max(spin) + tol2 * eV_Ha
    2585            1 :      cmin = gaps%cb_min(spin) - tol2 * eV_Ha
    2586              :    else
    2587            0 :      vmax = ebands%fermie
    2588            0 :      cmin = ebands%fermie
    2589              :    end if
    2590              : 
    2591            7 :    do band=1, ebands%mband
    2592          511 :      do ik_ibz=1,gstore%nkibz
    2593              :        !cnt = cnt + 1; if (mod(cnt, all_nproc) /= my_rank) cycle ! MPI parallelism inside comm
    2594              : 
    2595              :        ! Use iflag to filter k-points.
    2596          504 :        ee = ebands%eig(band, ik_ibz, spin)
    2597          504 :        iflag = 0
    2598              : 
    2599          504 :        if (abs_erange1 > zero) then
    2600              :          ! Filter valence states.
    2601            0 :          if (ee <= vmax .and. vmax - ee <= abs_erange1) then
    2602          504 :            iflag = 1 !; write(std_out, *), "Adding valence band", band, " with ee [eV]: ", ee * Ha_eV
    2603              :          end if
    2604              :        end if
    2605          504 :        if (abs_erange2 > zero) then
    2606              :          ! Filter conduction states.
    2607          504 :          if (ee >= cmin .and. ee - cmin <= abs_erange2) then
    2608              :            iflag = 1 !; write(std_out, *)"Adding conduction band", band, " with ee [eV]: ", ee * Ha_eV
    2609              :          end if
    2610              :        end if
    2611              : 
    2612          502 :        if (iflag == 1) then
    2613            8 :          gstore%brange_k_spin(1, spin) = min(gstore%brange_k_spin(1, spin), band)
    2614            8 :          gstore%brange_k_spin(2, spin) = max(gstore%brange_k_spin(2, spin), band)
    2615            8 :          gstore%brange_kq_spin(1, spin) = min(gstore%brange_kq_spin(1, spin), band)
    2616            8 :          gstore%brange_kq_spin(2, spin) = max(gstore%brange_kq_spin(2, spin), band)
    2617              : 
    2618            0 :          select case (gstore%kzone)
    2619              :          case ("ibz")
    2620            0 :            ik_bz = kibz2bz(ik_ibz)
    2621            0 :            select_kbz_spin(ik_bz, spin) = iflag
    2622              : 
    2623              :          case ("bz")
    2624            8 :            call star_from_ibz_idx(ik_ibz, gstore%nkbz, gstore%kbz2ibz, nk_in_star, kstar_bz_inds)
    2625            8 :            ABI_CHECK(nk_in_star > 0, "Something wrong in star_from_ibz_idx")
    2626           97 :            do ii=1,nk_in_star
    2627           89 :              ik_bz = kstar_bz_inds(ii)
    2628           97 :              select_kbz_spin(ik_bz, spin) = iflag
    2629              :            end do
    2630           16 :            ABI_FREE(kstar_bz_inds)
    2631              :          end select
    2632              :        end if
    2633              : 
    2634              :      end do ! band
    2635              :    end do ! ik_ibz
    2636              : 
    2637              :    !call wrtout(std_out, sjoin("brange_k_spin:", ltoa(gstore%brange_k_spin(:, spin))))
    2638              :    !call wrtout(std_out, sjoin("count_select_kbz:", itoa(count(select_kbz_spin == 1))))
    2639              :    !call wrtout(std_out, sjoin("brange_kq_spin:", ltoa(gstore%brange_k_qspin(:, spin))))
    2640              :    !call wrtout(std_out, sjoin("count_select_kbz:", itoa(count(select_kbz_spin == 1))))
    2641              : 
    2642            3 :    if (any(gstore%brange_k_spin(:, spin) == [huge(1), -huge(1)])) then
    2643            0 :      ABI_ERROR("Empty list of states inside gstore_erange")
    2644              :    end if
    2645            4 :    if (any(gstore%brange_kq_spin(:, spin) == [huge(1), -huge(1)])) then
    2646            0 :      ABI_ERROR("Empty list of states inside gstore_erange")
    2647              :    end if
    2648              : 
    2649              :  end do ! spin
    2650              : 
    2651              :  !call xmpi_sum(select_kbz_spin, comm, ierr)
    2652              :  call recompute_select_qbz_spin(gstore, gstore%qbz, qbz2ibz, qibz2bz, gstore%kbz, gstore%kibz, gstore%kbz2ibz, kibz2bz, &
    2653            1 :                                 select_kbz_spin, select_qbz_spin)
    2654              : 
    2655            2 :  call gaps%free()
    2656              :  end associate
    2657              : 
    2658            1 : end subroutine gstore_filter_erange__
    2659              : !!***
    2660              : 
    2661              : !----------------------------------------------------------------------
    2662              : 
    2663              : !!****f* m_gstore/gstore_filter_gw_qprange__
    2664              : !! NAME
    2665              : !! gstore_gw_filter_qprange__
    2666              : !!
    2667              : !! FUNCTION
    2668              : !! Filter k-points according to the input variable gw_qprange. Useful for ZPR.
    2669              : !!
    2670              : !! INPUTS
    2671              : !!
    2672              : !! OUTPUT
    2673              : !!
    2674              : !! SOURCE
    2675              : 
    2676            4 : subroutine gstore_filter_gw_qprange__(gstore, dtset, qbz2ibz, qibz2bz, kibz2bz, select_qbz_spin, select_kbz_spin)
    2677              : 
    2678              : !Arguments ------------------------------------
    2679              : !scalars
    2680              :  class(gstore_t),intent(inout) :: gstore
    2681              :  type(dataset_type),intent(in) :: dtset
    2682              :  integer,intent(in) :: qbz2ibz(6,gstore%nqbz), qibz2bz(gstore%nqibz)
    2683              :  integer,intent(in) :: kibz2bz(gstore%nkibz)
    2684              :  integer,intent(out) :: select_qbz_spin(gstore%nqbz, gstore%nsppol)
    2685              :  integer,intent(out) :: select_kbz_spin(gstore%nkbz, gstore%nsppol)
    2686              : 
    2687              : !Local variables-------------------------------
    2688              : !scalars
    2689              :  integer :: spin, ik_bz, ik_ibz, gap_err, ik_calc, nkcalc, mapl_kk(6), my_rank
    2690            4 :  type(gaps_t) :: gaps
    2691              : !arrays
    2692            4 :  integer,allocatable :: bstart_ks(:,:), nbcalc_ks(:,:)
    2693            4 :  real(dp),allocatable :: kcalc(:,:)
    2694              : !----------------------------------------------------------------------
    2695              : 
    2696              :  ABI_UNUSED(qbz2ibz)
    2697              :  ABI_UNUSED(qibz2bz)
    2698              : 
    2699              :  associate (cryst => gstore%cryst, ebands => gstore%ebands)
    2700              : 
    2701            8 :  my_rank = xmpi_comm_rank(gstore%comm)
    2702              : 
    2703            4 :  call wrtout(std_out, sjoin(" Filtering k-points using gw_qprange:", itoa(dtset%gw_qprange)))
    2704            4 :  if (gstore%qzone /= "bz") then
    2705            0 :    ABI_ERROR(sjoin('gw_qprange filtering requires gstore_qzone = "bz" while it is: ', gstore%qzone))
    2706              :  end if
    2707              : 
    2708            4 :  gaps = ebands%get_gaps(gap_err)
    2709            8 :  if (my_rank == 0) call gaps%print([std_out])
    2710            4 :  if (gap_err /= 0) then
    2711            0 :    ABI_ERROR("Cannot compute fundamental and direct gap (likely metal).")
    2712              :  end if
    2713              : 
    2714              :  ! Use gw_qprange to select the interesting k-points and the corresponding bands.
    2715              :  !
    2716              :  !    0 --> Compute the QP corrections only for the fundamental and the direct gap.
    2717              :  ! +num --> Compute the QP corrections for all the k-points in the irreducible zone and include `num`
    2718              :  !          bands above and below the Fermi level.
    2719              :  ! -num --> Compute the QP corrections for all the k-points in the irreducible zone.
    2720              :  !          Include all occupied states and `num` empty states.
    2721              : 
    2722              :  ! Compute nkcalc, kcalc, bstart_ks, nbcalc_ks
    2723            4 :  if (dtset%gw_qprange /= 0) then
    2724            0 :    call sigtk_kcalc_from_qprange(dtset, gstore%cryst, ebands, dtset%gw_qprange, nkcalc, kcalc, bstart_ks, nbcalc_ks)
    2725              :  else
    2726              :    ! gw_qprange is not specified in the input.
    2727              :    ! Include direct and fundamental KS gap or include states depending on the position wrt band edges.
    2728            4 :    call sigtk_kcalc_from_gaps(dtset, ebands, gaps, nkcalc, kcalc, bstart_ks, nbcalc_ks)
    2729              :  end if
    2730              : 
    2731              :  ! TODO: kcalc should be spin-dependent to handle magnetic semiconductors.
    2732          152 :  select_kbz_spin = 0
    2733            8 :  do spin=1,gstore%nsppol
    2734           14 :    do ik_calc=1,nkcalc
    2735            6 :      if (kpts_map("symrel", ebands%kptopt, gstore%cryst, gstore%krank_ibz, 1, kcalc(:,ik_calc), mapl_kk) /= 0) then
    2736            0 :        ABI_ERROR(sjoin("Cannot map kcalc to IBZ with kcalc:", ktoa(kcalc(:,ik_calc))))
    2737              :      end if
    2738              :      ! Change select_kbz_spin
    2739            6 :      ik_ibz = mapl_kk(1)
    2740           10 :      ik_bz = kibz2bz(ik_ibz); select_kbz_spin(ik_bz, spin) = 1
    2741              :    end do
    2742              :  end do ! spin
    2743              : 
    2744              :  !call recompute_select_qbz_spin(gstore, gstore%qbz, qbz2ibz, qibz2bz, gstore%kbz, gstore%kibz, gstore%kbz2ibz, gstore%kibz2bz, &
    2745              :  !                               select_kbz_spin, select_qbz_spin)
    2746              : 
    2747            4 :  ABI_FREE(kcalc)
    2748            4 :  ABI_FREE(bstart_ks)
    2749            4 :  ABI_FREE(nbcalc_ks)
    2750            8 :  call gaps%free()
    2751              :  end associate
    2752              : 
    2753            4 : end subroutine gstore_filter_gw_qprange__
    2754              : !!***
    2755              : 
    2756              : !!****f* m_gstore/recompute_select_qbz_spin
    2757              : !! NAME
    2758              : !! recompute_select_qbz_spin
    2759              : !!
    2760              : !! FUNCTION
    2761              : !! Recompute select_qbz_spin table after the filtering on the k-points.
    2762              : !!
    2763              : !! INPUTS
    2764              : !!
    2765              : !! OUTPUT
    2766              : !!
    2767              : !! SOURCE
    2768              : 
    2769            1 : subroutine recompute_select_qbz_spin(gstore, qbz, qbz2ibz, qibz2bz, kbz, kibz, kbz2ibz, kibz2bz, &
    2770            1 :                                      select_kbz_spin, select_qbz_spin)
    2771              : 
    2772              : !Arguments ------------------------------------
    2773              : !scalars
    2774              :  class(gstore_t),intent(inout) :: gstore
    2775              : !arrays
    2776              :  real(dp),intent(in) :: qbz(3, gstore%nqbz)
    2777              :  integer,intent(in) :: qbz2ibz(6,gstore%nqbz), qibz2bz(gstore%nqibz)
    2778              :  integer,intent(in) :: kbz2ibz(6,gstore%nkbz), kibz2bz(gstore%nkibz)
    2779              :  real(dp),target,intent(in) :: kibz(3, gstore%nkibz), kbz(3, gstore%nkbz)
    2780              :  integer,intent(in) :: select_kbz_spin(gstore%nkbz, gstore%nsppol)
    2781              :  integer,intent(out) :: select_qbz_spin(gstore%nqbz, gstore%nsppol)
    2782              : 
    2783              : !Local variables-------------------------------
    2784              : !scalars
    2785              :  integer :: all_nproc, my_rank, ierr, ii, ik_bz, iq_bz, iq_ibz, ikq_ibz, ikq_bz, len_kpts_ptr, ebands_kptopt, spin
    2786              : !arrays
    2787            1 :  integer,allocatable :: map_kq(:,:)
    2788              :  real(dp) :: qpt(3)
    2789            1 :  real(dp),contiguous, pointer :: kpts_ptr(:,:)
    2790              : ! *************************************************************************
    2791              : 
    2792              :  ABI_UNUSED(kbz2ibz)
    2793              :  ABI_UNUSED(qbz2ibz)
    2794              : 
    2795            1 :  all_nproc = xmpi_comm_size(gstore%comm); my_rank = xmpi_comm_rank(gstore%comm)
    2796            1 :  ebands_kptopt = gstore%ebands%kptopt
    2797              : 
    2798         2199 :  select_qbz_spin = 0
    2799              : 
    2800            1 :  if (gstore%kzone == "ibz") kpts_ptr => kibz
    2801            1 :  if (gstore%kzone == "bz")  kpts_ptr => kbz
    2802            1 :  len_kpts_ptr = size(kpts_ptr, dim=2)
    2803            3 :  ABI_MALLOC(map_kq, (6, len_kpts_ptr))
    2804              : 
    2805            0 :  select case (gstore%qzone)
    2806              :  case ("ibz")
    2807            0 :    do iq_ibz=1,gstore%nqibz
    2808            0 :      if (mod(iq_ibz, all_nproc) /= my_rank) cycle ! MPI parallelism.
    2809            0 :      qpt = gstore%qibz(:, iq_ibz)
    2810            0 :      iq_bz = qibz2bz(iq_ibz)
    2811              :      ! k + q_ibz --> k IBZ --> k BZ
    2812              : 
    2813            0 :      if (kpts_map("symrel", ebands_kptopt, gstore%cryst, gstore%krank_ibz, len_kpts_ptr, kpts_ptr, map_kq, qpt=qpt) /= 0) then
    2814            0 :        ABI_ERROR("Cannot map k+q to IBZ!")
    2815              :      end if
    2816              : 
    2817            0 :      do ii=1,len_kpts_ptr
    2818              :        ! get the k-index in BZ
    2819            0 :        select case (gstore%kzone)
    2820              :        case ("bz")
    2821            0 :          ik_bz = ii
    2822              :        case ("ibz")
    2823            0 :          ik_bz = kibz2bz(ii)
    2824              :        end select
    2825              : 
    2826            0 :        do spin=1,gstore%nsppol
    2827            0 :          if (select_kbz_spin(ik_bz, spin) /= 0) then
    2828              :            ! now, see if q-point connects k-points inside the filtered zone
    2829            0 :            ikq_ibz = map_kq(1, ii)
    2830            0 :            ikq_bz = kibz2bz(ikq_ibz)
    2831            0 :            select_qbz_spin(iq_bz, :) = select_qbz_spin(iq_bz, :) + select_kbz_spin(ikq_bz, :)
    2832              :          end if
    2833              :        end do
    2834              :      end do
    2835              :    end do ! iq_ibz
    2836              : 
    2837              :  case ("bz")
    2838         2198 :    do iq_bz=1,gstore%nqbz
    2839         2197 :      if (mod(iq_bz, all_nproc) /= my_rank) cycle ! MPI parallelism.
    2840         8788 :      qpt = qbz(:, iq_bz)
    2841              :      !iq_ibz = qbz2ibz(1, iq_bz)
    2842              :      ! k + q_bz --> k IBZ --> k BZ
    2843              : 
    2844         2197 :      if (kpts_map("symrel", ebands_kptopt, gstore%cryst, gstore%krank_ibz, len_kpts_ptr, kpts_ptr, map_kq, qpt=qpt) /= 0) then
    2845            0 :        ABI_ERROR("Cannot map k+q to IBZ!")
    2846              :      end if
    2847              : 
    2848              :      ! here we loop over all k-points in iBZ (kzone="ibz") or BZ (kzone="bz")
    2849      4829007 :      do ii=1,len_kpts_ptr
    2850              :        ! but for each spin, we have to loop only over e-range filtered kpts
    2851              : 
    2852              :        ! get the k-index in BZ
    2853      9653618 :        select case (gstore%kzone)
    2854              :        case ("bz")
    2855      4826809 :          ik_bz = ii
    2856              :        case ("ibz")
    2857      4826809 :          ik_bz = kibz2bz(ii)
    2858              :        end select
    2859              : 
    2860      9655815 :        do spin=1,gstore%nsppol
    2861              :          ! Now, see if q-point connects k-points inside the filtered zone
    2862      9653618 :          if (select_kbz_spin(ik_bz, spin) /= 0) then
    2863       195533 :            ikq_ibz = map_kq(1, ii)
    2864       195533 :            ikq_bz = kibz2bz(ikq_ibz)
    2865       195533 :            select_qbz_spin(iq_bz, spin) = select_qbz_spin(iq_bz, spin) + select_kbz_spin(ikq_bz, spin)
    2866              :          end if
    2867              :        end do
    2868              : 
    2869              :      end do
    2870              :    end do
    2871              :  end select
    2872              : 
    2873            1 :  call xmpi_sum(select_qbz_spin, gstore%comm, ierr)
    2874              : 
    2875            1 :  ABI_FREE(map_kq)
    2876              : 
    2877            1 : end subroutine recompute_select_qbz_spin
    2878              : !!***
    2879              : 
    2880              : !!****f* m_gstore/gstore_spin2my_is
    2881              : !! NAME
    2882              : !! gstore_spin2my_is
    2883              : !!
    2884              : !! FUNCTION
    2885              : !!  Return the local spin index from the global spin index.
    2886              : !!  0 if this spin is not treated by this MPI proc.
    2887              : !!
    2888              : !! SOURCE
    2889              : 
    2890           16 : integer pure function gstore_spin2my_is(gstore, spin) result(my_is)
    2891              : 
    2892              : !Arguments ------------------------------------
    2893              :  class(gstore_t),intent(in) :: gstore
    2894              :  integer,intent(in) :: spin
    2895              : !----------------------------------------------------------------------
    2896              : 
    2897           16 :  do my_is=1,gstore%my_nspins
    2898           16 :    if (gstore%my_spins(my_is) == spin) return
    2899              :  end do
    2900           16 :  my_is = 0
    2901              : 
    2902              : end function gstore_spin2my_is
    2903              : !!***
    2904              : 
    2905              : !----------------------------------------------------------------------
    2906              : 
    2907              : !!****f* m_gstore/gstore_fill_bks_mask
    2908              : !! NAME
    2909              : !! gstore_fill_bks_mask
    2910              : !!
    2911              : !! FUNCTION
    2912              : !!  Fills the bks_mask array defining the set of wavefunctions that should be read
    2913              : !!  from the WFK file by this MPI rank when computing the KS e-ph matrix elements.
    2914              : !!
    2915              : !! INPUTS
    2916              : !!
    2917              : !! OUTPUT
    2918              : !!
    2919              : !! SOURCE
    2920              : 
    2921           12 : subroutine gstore_fill_bks_mask(gstore, mband, nkibz, nsppol, bks_mask)
    2922              : 
    2923              : !Arguments ------------------------------------
    2924              :  class(gstore_t),intent(inout) :: gstore
    2925              :  integer,intent(in) :: mband, nkibz, nsppol
    2926              :  logical,intent(out) :: bks_mask(mband, nkibz, nsppol)
    2927              : 
    2928              : !Local variables-------------------------------
    2929              : !scalars
    2930              :  integer :: my_is, my_ik, my_iq, spin, ik_ibz, ikq_ibz, ebands_kptopt, bstart_k, bstop_k, bstart_kq, bstop_kq
    2931              :  real(dp) :: weight_q, cpu, wall, gflops
    2932              : !arrays
    2933           12 :  integer,allocatable :: map_kq(:,:)
    2934              :  real(dp) :: qpt(3)
    2935              : !----------------------------------------------------------------------
    2936              : 
    2937           12 :  call cwtime(cpu, wall, gflops, "start")
    2938              :  associate (cryst => gstore%cryst, ebands => gstore%ebands)
    2939              : 
    2940         1992 :  bks_mask = .False.; ebands_kptopt = gstore%ebands%kptopt
    2941              : 
    2942           24 :  do my_is=1,gstore%my_nspins
    2943           12 :    associate (gqk => gstore%gqk(my_is))
    2944           12 :    spin = gstore%my_spins(my_is)
    2945           12 :    bstart_k = gqk%bstart_k; bstop_k = gqk%bstop_k
    2946           12 :    bstart_kq = gqk%bstart_kq; bstop_kq = gqk%bstop_kq
    2947              : 
    2948              :    ! Stop if dtset%nband < gstore%nband before sigfaulting.
    2949            0 :    ABI_CHECK_ILEQ(bstop_k, mband, "bstop_k should be smaller that mband present in WFK")
    2950           12 :    ABI_CHECK_ILEQ(bstop_kq, mband, "bstop_kq should be smaller that mband present in WFK")
    2951              : 
    2952              :    ! We need the image of this k-point in the IBZ.
    2953          330 :    do my_ik=1,gqk%my_nk
    2954          318 :      ik_ibz = gqk%my_k2ibz(1, my_ik)
    2955         1139 :      bks_mask(bstart_k:bstop_k, ik_ibz, spin) = .True.
    2956              :    end do
    2957              : 
    2958              :    ! As well as the image of k+q in the IBZ.
    2959           36 :    ABI_MALLOC(map_kq, (6, gqk%my_nk))
    2960              : 
    2961         1057 :    do my_iq=1,gqk%my_nq
    2962         1045 :      call gqk%myqpt(my_iq, gstore, weight_q, qpt)
    2963              : 
    2964         1045 :      if (kpts_map("symrel", ebands_kptopt, cryst, gstore%krank_ibz, gqk%my_nk, gqk%my_kpts, map_kq, qpt=qpt) /= 0) then
    2965            0 :        ABI_ERROR(sjoin("Cannot map k+q to IBZ with qpt:", ktoa(qpt)))
    2966              :      end if
    2967              : 
    2968        74912 :      do my_ik=1,gqk%my_nk
    2969        73855 :        ikq_ibz = map_kq(1, my_ik)
    2970       193527 :        bks_mask(bstart_kq:bstop_kq, ikq_ibz, spin) = .True.
    2971              :      end do
    2972              :    end do
    2973              : 
    2974           24 :    ABI_FREE(map_kq)
    2975              :    end associate
    2976              :  end do ! my_is
    2977              : 
    2978           12 :  call cwtime_report(" gstore_fill_bks_mask", cpu, wall, gflops)
    2979              :  end associate
    2980              : 
    2981           24 : end subroutine gstore_fill_bks_mask
    2982              : !!***
    2983              : 
    2984              : !----------------------------------------------------------------------
    2985              : 
    2986              : !!****f* m_gstore/gstore_fill_bks_mask_with_pp
    2987              : !! NAME
    2988              : !! gstore_fill_bks_mask_with_pp
    2989              : !!
    2990              : !! FUNCTION
    2991              : !!  Fill the bks_mask array defining the set of states that should be read from the WFK file
    2992              : !!  by this MPI rank when computing the GWPT e-ph matrix elements in which we have
    2993              : !!  to consider k+q, k-q and k+q-p as well as the sum over states (bsum).
    2994              : !!
    2995              : !! INPUTS
    2996              : !!
    2997              : !! OUTPUT
    2998              : !!
    2999              : !! SOURCE
    3000              : 
    3001            3 : subroutine gstore_fill_bks_mask_pp_mesh(gstore, ecut, mband, nkibz, nsppol, my_pp_start_spin, my_pp_stop_spin, pp_mesh, &
    3002            3 :                                         my_bsum_start, my_bsum_stop, bks_mask, mpw, gmax)
    3003              : 
    3004              : !Arguments ------------------------------------
    3005              :  class(gstore_t),target,intent(inout) :: gstore
    3006              :  real(dp),intent(in) :: ecut
    3007              :  integer,intent(in) :: mband, nkibz, nsppol
    3008              :  integer :: my_pp_start_spin(nsppol), my_pp_stop_spin(nsppol)
    3009              :  type(kmesh_t),intent(in) :: pp_mesh
    3010              :  integer,intent(in) :: my_bsum_start(nsppol), my_bsum_stop(nsppol)
    3011              :  logical,intent(out) :: bks_mask(mband, nkibz, nsppol)
    3012              :  integer,intent(out) :: mpw, gmax(3)
    3013              : 
    3014              : !Local variables-------------------------------
    3015              : !scalars
    3016              :  integer,parameter :: istwfk1 = 1
    3017              :  integer :: b1, b2, ebands_kptopt, ierr, ikq_ibz, ik_ibz, ipp_bz, my_ik, my_iq, spin, my_is, onpw, my_mpw, my_gmax(3)
    3018              :  real(dp) :: weight_q, cpu, wall, gflops
    3019              :  type(gqk_t),pointer :: gqk
    3020              :  type(crystal_t),pointer :: cryst
    3021              : !arrays
    3022            3 :  integer,allocatable :: map_kq(:,:), gtmp(:,:)
    3023              :  real(dp) :: qpt(3), pp(3), kk(3)
    3024              : !----------------------------------------------------------------------
    3025              : 
    3026            3 :  call cwtime(cpu, wall, gflops, "start")
    3027              : 
    3028              :  ! TODO: These loops can be parallelized using bsum_comm and pert_comm if needed.
    3029          237 :  bks_mask = .False.; cryst => gstore%cryst
    3030            3 :  ebands_kptopt = gstore%ebands%kptopt
    3031            3 :  mpw = 0; gmax = 0
    3032              : 
    3033            6 :  do my_is=1,gstore%my_nspins
    3034            3 :    gqk => gstore%gqk(my_is); spin = gstore%my_spins(my_is)
    3035              : 
    3036              :    ! These are the first and last band indices used in the sum over states (possibly MPI-distributed)
    3037            3 :    b1 = my_bsum_start(spin); b2 = my_bsum_stop(spin)
    3038              : 
    3039              :    ! Stop if dtset%nband < gstore%nband before sigfaulting.
    3040            3 :    ABI_CHECK_ILEQ(gqk%bstop_k, mband, "bstop_k should be smaller that mband present in WFK")
    3041            3 :    ABI_CHECK_ILEQ(gqk%bstop_kq, mband, "bstop_kq should be smaller that mband present in WFK")
    3042            3 :    ABI_CHECK_ILEQ(b2, mband, "max band index in sum should be smaller that mband present in WFK")
    3043              : 
    3044            9 :    ABI_MALLOC(map_kq, (6, gqk%my_nk))
    3045              : 
    3046            8 :    do my_ik=1,gqk%my_nk
    3047           20 :      kk = gqk%my_kpts(:, my_ik); ik_ibz = gqk%my_k2ibz(1, my_ik)
    3048              : 
    3049              :      ! We need the image of this k-point in the IBZ for the incoming state |psi_nk>.
    3050           33 :      bks_mask(gqk%bstart_k:gqk%bstop_k, ik_ibz, spin) = .True.
    3051              : 
    3052              :      ! We also need the image of k+q in the IBZ for the outgoing state <psi_mkq|.
    3053          104 :      do my_iq=1,gqk%my_nq
    3054           96 :        call gqk%myqpt(my_iq, gstore, weight_q, qpt)
    3055           96 :        if (kpts_map("symrel", ebands_kptopt, cryst, gstore%krank_ibz, 1, kk, map_kq, qpt=qpt) /= 0) then
    3056            0 :          ABI_ERROR(sjoin("Cannot map k+q to IBZ with qpt:", ktoa(qpt)))
    3057              :        end if
    3058           96 :        ikq_ibz = map_kq(1, 1)
    3059         1125 :        bks_mask(gqk%bstart_kq:gqk%bstop_kq, ikq_ibz, spin) = .True.
    3060              :      end do ! my_iq
    3061              : 
    3062              :    end do ! my_ok
    3063              : 
    3064              :    ! We also need the image of k-p in the IBZ for the pp wavevectors treated by this MPI rank.
    3065              :    ! These states are summed over so use b1 and b2.
    3066           83 :    do ipp_bz=my_pp_start_spin(spin), my_pp_stop_spin(spin)
    3067          320 :      pp = pp_mesh%bz(:,ipp_bz)
    3068          320 :      if (kpts_map("symrel", ebands_kptopt, cryst, gstore%krank_ibz, gqk%my_nk, gqk%my_kpts, map_kq, qpt=-pp) /= 0) then
    3069            0 :        ABI_ERROR(sjoin("Cannot map k-p to IBZ with qpt:", ktoa(qpt), "and pp:", ktoa(pp)))
    3070              :      end if
    3071              : 
    3072          179 :      do my_ik=1,gqk%my_nk
    3073           96 :        ikq_ibz = map_kq(1, my_ik)
    3074         1120 :        bks_mask(b1:b2, ikq_ibz, spin) = .True.
    3075              :        ! Compute g-sphere, returns onpw. Note istwfk == 1.
    3076          384 :        kk = gqk%my_kpts(:, my_ik)
    3077          384 :        call get_kg(kk-pp, istwfk1, ecut, gstore%cryst%gmet, onpw, gtmp, mpw=mpw, gmax=gmax)
    3078          176 :        ABI_FREE(gtmp)
    3079              :      end do
    3080              :    end do ! ipp_bz
    3081              : 
    3082              :    ! We also need the image of k+q-p in the IBZ for the pp wavevectors treated by this MPI rank.
    3083              :    ! These states are summed over so use b1 and b2.
    3084           83 :    do my_iq=1,gqk%my_nq
    3085           80 :      call gqk%myqpt(my_iq, gstore, weight_q, qpt)
    3086              : 
    3087         4307 :      do ipp_bz=my_pp_start_spin(spin), my_pp_stop_spin(spin)
    3088        16896 :        pp = pp_mesh%bz(:,ipp_bz)
    3089              : 
    3090        16896 :        if (kpts_map("symrel", ebands_kptopt, cryst, gstore%krank_ibz, gqk%my_nk, gqk%my_kpts, map_kq, qpt=qpt-pp) /= 0) then
    3091            0 :          ABI_ERROR(sjoin("Cannot map k+q-p to IBZ with qpt:", ktoa(qpt), "and pp:", ktoa(pp)))
    3092              :        end if
    3093              : 
    3094         8656 :        do my_ik=1,gqk%my_nk
    3095         4352 :          ikq_ibz = map_kq(1, my_ik)
    3096        48384 :          bks_mask(b1:b2, ikq_ibz, spin) = .True.
    3097              :          ! Compute g-sphere, returns onpw. Note istwfk = 1.
    3098        17408 :          kk = gqk%my_kpts(:, my_ik)
    3099        17408 :          call get_kg(kk+qpt-pp, istwfk1, ecut, gstore%cryst%gmet, onpw, gtmp, mpw=mpw, gmax=gmax)
    3100         8576 :          ABI_FREE(gtmp)
    3101              :        end do
    3102              :      end do ! ipp_bz
    3103              : 
    3104              :    end do ! my_iq
    3105              : 
    3106            6 :    ABI_FREE(map_kq)
    3107              :  end do ! my_is
    3108              : 
    3109            3 :  my_mpw = mpw; call xmpi_max(my_mpw, mpw, gstore%comm, ierr)
    3110            3 :  my_gmax = gmax; call xmpi_max(my_gmax, gmax, gstore%comm, ierr)
    3111              : 
    3112              :  ! TODO
    3113              :  !call gstore%get_mpw_gmax(ecut, mpw, gmax, pp_max=)
    3114              : 
    3115            3 :  call wrtout(std_out, sjoin(' Optimal value of mpw: ', itoa(mpw)))
    3116            3 :  call cwtime_report(" gstore_fill_bks_mask_pp_mesh", cpu, wall, gflops)
    3117              : 
    3118            3 : end subroutine gstore_fill_bks_mask_pp_mesh
    3119              : !!***
    3120              : 
    3121              : !----------------------------------------------------------------------
    3122              : 
    3123              : !!****f* m_gstore/gstore_get_mpw_gmax
    3124              : !! NAME
    3125              : !! gstore_get_mpw_gmax
    3126              : !!
    3127              : !! FUNCTION
    3128              : !! Compute the maximum number of PWs for all possible k+q treated.
    3129              : !!
    3130              : !! INPUTS
    3131              : !!
    3132              : !! OUTPUT
    3133              : !!
    3134              : !! SOURCE
    3135              : 
    3136           12 : subroutine gstore_get_mpw_gmax(gstore, ecut, mpw, gmax, pp_max)
    3137              : 
    3138              : !Arguments ------------------------------------
    3139              :  class(gstore_t),intent(in) :: gstore
    3140              :  real(dp),intent(in) :: ecut
    3141              :  integer,intent(out) :: mpw, gmax(3)
    3142              :  integer,optional,intent(in) :: pp_max
    3143              : 
    3144              : !Local variables-------------------------------
    3145              :  integer,parameter :: istwfk1 = 1
    3146              :  integer :: my_is, my_ik, my_iq, spin, onpw, ierr, my_mpw, ipx, ipy, ipz, nprocs, my_rank, pp_max__ !, cnt, i1, i2, i3,
    3147              :  real(dp) :: weight_q, cpu, wall, gflops
    3148              : !arrays
    3149              :  integer :: my_gmax(3)
    3150           12 :  integer,allocatable :: gtmp(:,:)
    3151              :  real(dp) :: kk(3), kq(3), qpt(3), pp(3) !, kq_max(3)
    3152              : !----------------------------------------------------------------------
    3153              : 
    3154              :  ! TODO: This is an hotspot due to the double loop over k and q. Should use a geometrical approach to compute mpw and gmax.
    3155           12 :  call wrtout(std_out, " Computing mpw. This may take some time for dense k/q meshes...", pre_newlines=1)
    3156           12 :  call cwtime(cpu, wall, gflops, "start")
    3157              : 
    3158           12 :  nprocs = xmpi_comm_size(gstore%comm); my_rank = xmpi_comm_rank(gstore%comm)
    3159           12 :  mpw = 0; gmax = 0
    3160           12 :  pp_max__ = 0; if (present(pp_max)) pp_max__ = pp_max
    3161              : 
    3162           24 :  do my_is=1,gstore%my_nspins
    3163           12 :    associate (gqk => gstore%gqk(my_is))
    3164           12 :    spin = gstore%my_spins(my_is)
    3165          330 :    do my_ik=1,gqk%my_nk
    3166         1272 :      kk = gqk%my_kpts(:, my_ik)
    3167              : 
    3168              :      ! Compute g-sphere, returns onpw. Note istwfk == 1.
    3169          318 :      call get_kg(kk, istwfk1, ecut, gstore%cryst%gmet, onpw, gtmp, mpw=mpw, gmax=gmax)
    3170          318 :      ABI_FREE(gtmp)
    3171              : 
    3172        74185 :      do my_iq=1,gqk%my_nq
    3173        73855 :        call gqk%myqpt(my_iq, gstore, weight_q, qpt)
    3174       295420 :        kq = kk + qpt
    3175              : 
    3176              :        ! TODO: g0 umklapp here can enter into play! gmax could not be large enough!
    3177       148028 :        do ipz=-pp_max__,pp_max__
    3178       221565 :           do ipy=-pp_max__,pp_max__
    3179       221565 :             do ipx=-pp_max__,pp_max__
    3180       295420 :              pp = [ipx, ipy, ipz] * half
    3181       295420 :              call get_kg(kq - pp, 1, ecut, gstore%cryst%gmet, onpw, gtmp, mpw=mpw, gmax=gmax)
    3182       147710 :              ABI_FREE(gtmp)
    3183              :            end do
    3184              :          end do
    3185              :        end do
    3186              :      end do ! my_iq
    3187              : 
    3188              :    end do ! my_ik
    3189              :    end associate
    3190              :  end do ! my_is
    3191              : 
    3192           12 :  my_mpw = mpw; call xmpi_max(my_mpw, mpw, gstore%comm, ierr)
    3193           12 :  my_gmax = gmax; call xmpi_max(my_gmax, gmax, gstore%comm, ierr)
    3194              : 
    3195           12 :  call wrtout(std_out, sjoin(' Optimal value of mpw: ', itoa(mpw), "with gmax:", ltoa(gmax)))
    3196           12 :  call cwtime_report(" gstore_get_mpw_gmax", cpu, wall, gflops)
    3197              : 
    3198           12 : end subroutine gstore_get_mpw_gmax
    3199              : !!***
    3200              : 
    3201              : !----------------------------------------------------------------------
    3202              : 
    3203              : !!****f* m_gstore/gstore_free
    3204              : !! NAME
    3205              : !! gstore_free
    3206              : !!
    3207              : !! FUNCTION
    3208              : !!  Free dynamic memory in gstore_t.
    3209              : !!
    3210              : !! SOURCE
    3211              : 
    3212           24 : subroutine gstore_free(gstore)
    3213              : 
    3214              : !Arguments ------------------------------------
    3215              :  class(gstore_t),intent(inout) :: gstore
    3216              : 
    3217              : !Local variables-------------------------------
    3218              :  integer :: my_is
    3219              : !----------------------------------------------------------------------
    3220              : 
    3221           48 :  do my_is=1,gstore%my_nspins
    3222           48 :    call gstore%gqk(my_is)%free()
    3223              :  end do
    3224           48 :  ABI_SFREE(gstore%gqk)
    3225              : 
    3226           24 :  ABI_SFREE(gstore%delta_ef_kibz_spin)
    3227           24 :  ABI_SFREE(gstore%qibz)
    3228           24 :  ABI_SFREE(gstore%wtq)
    3229           24 :  ABI_SFREE(gstore%my_spins)
    3230           24 :  ABI_SFREE(gstore%brange_k_spin)
    3231           24 :  ABI_SFREE(gstore%brange_kq_spin)
    3232           24 :  ABI_SFREE(gstore%glob_nk_spin)
    3233           24 :  ABI_SFREE(gstore%glob_nq_spin)
    3234           24 :  ABI_SFREE(gstore%kglob2bz)
    3235           24 :  ABI_SFREE(gstore%kbz2ibz)
    3236           24 :  ABI_SFREE(gstore%erange_spin)
    3237           24 :  ABI_SFREE(gstore%qbz)
    3238           24 :  ABI_SFREE(gstore%kbz)
    3239              : 
    3240           24 :  if (gstore%has_wannier) then
    3241            0 :    call gstore%ebands%free()
    3242            0 :    ABI_FREE_SCALAR(gstore%ebands)
    3243              :    nullify(gstore%ebands)
    3244              :  end if
    3245              : 
    3246           24 :  call gstore%krank_ibz%free()
    3247           24 :  call gstore%qrank_ibz%free()
    3248           24 :  gstore%with_cplex = -1
    3249              : 
    3250           24 : end subroutine gstore_free
    3251              : !!***
    3252              : 
    3253              : !----------------------------------------------------------------------
    3254              : 
    3255              : !!****f* m_gstore/gqk_myqpt
    3256              : !! NAME
    3257              : !! gqk_myqpt
    3258              : !!
    3259              : !! FUNCTION
    3260              : !!  Return the weight_q and the reduced coordinates of the q-point from the local index my_iq.
    3261              : !!
    3262              : !! INPUTS
    3263              : !!
    3264              : !! OUTPUT
    3265              : !!
    3266              : !! SOURCE
    3267              : 
    3268        77422 : pure subroutine gqk_myqpt(gqk, my_iq, gstore, weight_q, qpt)
    3269              : 
    3270              : !Arguments ------------------------------------
    3271              :  class(gqk_t),intent(in) :: gqk
    3272              :  class(gstore_t),intent(in) :: gstore
    3273              :  integer,intent(in) :: my_iq
    3274              :  real(dp),intent(out) :: weight_q, qpt(3)
    3275              : 
    3276              : !Local variables ------------------------------
    3277              :  integer :: iq_ibz, isym_q, trev_q, tsign_q, g0_q(3)
    3278              :  logical :: isirr_q
    3279              : !----------------------------------------------------------------------
    3280              : 
    3281              :  ! Symmetry tables for q-points.
    3282        77422 :  iq_ibz = gqk%my_q2ibz(1, my_iq); isym_q = gqk%my_q2ibz(2, my_iq)
    3283       309688 :  trev_q = gqk%my_q2ibz(6, my_iq); g0_q = gqk%my_q2ibz(3:5, my_iq)
    3284              :  isirr_q = (isym_q == 1 .and. trev_q == 0 .and. all(g0_q == 0))
    3285        77422 :  tsign_q = 1; if (trev_q == 1) tsign_q = -1
    3286              : 
    3287              :  ! NB: Use symrec convention for q
    3288      2167816 :  qpt = tsign_q * matmul(gstore%cryst%symrec(:,:,isym_q), gstore%qibz(:, iq_ibz)) + g0_q
    3289              : 
    3290            0 :  select case(gstore%qzone)
    3291              :  case ("ibz")
    3292            0 :    weight_q = gstore%wtq(iq_ibz)
    3293              :  case ("bz")
    3294        77422 :    weight_q = one / gstore%nqbz
    3295              :  end select
    3296              : 
    3297        77422 : end subroutine gqk_myqpt
    3298              : !!***
    3299              : 
    3300              : !----------------------------------------------------------------------
    3301              : 
    3302              : !!****f* m_gstore/gqk_dbldelta_qpt
    3303              : !! NAME
    3304              : !! gqk_dbldelta_qpt
    3305              : !!
    3306              : !! FUNCTION
    3307              : !!  Note that k/q weights are not included in dbl_delta_q
    3308              : !!
    3309              : !! INPUTS
    3310              : !!
    3311              : !! OUTPUT
    3312              : !!
    3313              : !! SOURCE
    3314              : 
    3315            0 : subroutine gqk_dbldelta_qpt(gqk, my_iq, gstore, eph_intmeth, eph_fsmear, qpt, weight_q, dbl_delta_q)
    3316              : 
    3317              : !Arguments ------------------------------------
    3318              :  class(gqk_t),intent(in) :: gqk
    3319              :  class(gstore_t),target,intent(inout) :: gstore
    3320              :  integer,intent(in) :: my_iq, eph_intmeth
    3321              :  real(dp),intent(in) :: eph_fsmear
    3322              :  real(dp),intent(out) :: qpt(3), weight_q, dbl_delta_q(gqk%nb_kq, gqk%nb_k, gqk%my_nk)
    3323              : 
    3324              : !Local variables ------------------------------
    3325              : !scalars
    3326              :  real(dp), parameter :: min_smear = tol9
    3327              :  integer :: nb_k, nb_kq, nkbz, spin, my_ik, ib, ib1, ib2, band1, band2, nesting
    3328              :  integer :: ik_ibz, isym_k, trev_k, tsign_k, g0_k(3)
    3329              :  integer :: ikq_ibz, isym_kq, trev_kq, tsign_kq, g0_kq(3), ii, i1, i2, i3, cnt, ik_bz, ltetra
    3330              :  real(dp) :: g1, g2, sigma !, weight_k !, cpu, wall, gflops
    3331              :  logical :: isirr_k, isirr_kq, use_adaptive
    3332              :  type(ebands_t), pointer :: ebands
    3333              :  type(crystal_t), pointer :: cryst
    3334            0 :  type(krank_t) :: my_krank
    3335              : !arrays
    3336              :  integer :: nge(3), ngw(3)
    3337            0 :  integer,allocatable :: my_kqmap(:,:), kmesh_map(:,:)
    3338            0 :  real(dp) :: kk(3), kmesh_cartvec(3,3), rlatt(3,3), klatt(3,3), vb_k(3, gqk%nb_k), vb_kq(3, gqk%nb_kq)
    3339            0 :  real(dp),allocatable :: eig_k(:,:), eig_kq(:,:), kmesh(:,:), wght_bz(:,:,:)
    3340              : !----------------------------------------------------------------------
    3341              : 
    3342            0 :  nb_k = gqk%nb_k; nb_kq = gqk%nb_kq; nkbz = gstore%nkbz; spin = gqk%spin
    3343            0 :  ebands => gstore%ebands; cryst => gstore%cryst
    3344              : 
    3345            0 :  ABI_CHECK_IEQ(nb_k, nb_kq, "gqk_dbldelta_qpt does not support nb_k != nb_kq")
    3346              : 
    3347            0 :  call gqk%myqpt(my_iq, gstore, weight_q, qpt)
    3348              : 
    3349              :  ! The double delta with tetra is ill-defined for q == 0. In this case we fall back to gaussian.
    3350            0 :  nesting = merge(1, 0, abs(eph_intmeth) == 2 .and. all(abs(qpt) < tol12))
    3351              : 
    3352            0 :  rlatt = gstore%ebands%kptrlatt; call matr3inv(rlatt, klatt)
    3353            0 :  kmesh_cartvec(:, 1) = cryst%gprimd(:,1)*klatt(1,1) + cryst%gprimd(:,2)*klatt(2,1) + cryst%gprimd(:,3)*klatt(3,1)
    3354            0 :  kmesh_cartvec(:, 2) = cryst%gprimd(:,1)*klatt(1,2) + cryst%gprimd(:,2)*klatt(2,2) + cryst%gprimd(:,3)*klatt(3,2)
    3355            0 :  kmesh_cartvec(:, 3) = cryst%gprimd(:,1)*klatt(1,3) + cryst%gprimd(:,2)*klatt(2,3) + cryst%gprimd(:,3)*klatt(3,3)
    3356              :  ! TODO: It seems that two_pi is not needed here!
    3357              : 
    3358            0 :  if (abs(eph_intmeth) == 1 .or. nesting /= 0) then
    3359            0 :    use_adaptive = eph_fsmear < zero .or. abs(eph_intmeth) == 2
    3360              :    if (use_adaptive) then
    3361            0 :      ABI_CHECK(allocated(gqk%vnk_cart_ibz), "vnk_cart_ibz should be allocated when use_adaptive is .True.")
    3362              :    end if
    3363              : 
    3364              :    ! Find k + q in the IBZ for all my k-points.
    3365            0 :    ABI_MALLOC(my_kqmap, (6, gqk%my_nk))
    3366            0 :    if (kpts_map("symrel", ebands%kptopt, cryst, gstore%krank_ibz, gqk%my_nk, gqk%my_kpts, my_kqmap, qpt=qpt) /= 0) then
    3367            0 :      ABI_ERROR(sjoin("Cannot map k+q to IBZ with qpt:", ktoa(qpt)))
    3368              :    end if
    3369              : 
    3370              :    ! Init default sigma
    3371            0 :    sigma = eph_fsmear
    3372              : 
    3373            0 :    do my_ik=1,gqk%my_nk
    3374            0 :      kk = gqk%my_kpts(:, my_ik)
    3375              : 
    3376            0 :      ik_ibz = gqk%my_k2ibz(1, my_ik); isym_k = gqk%my_k2ibz(2, my_ik)
    3377            0 :      trev_k = gqk%my_k2ibz(6, my_ik); g0_k = gqk%my_k2ibz(3:5, my_ik)
    3378            0 :      isirr_k = (isym_k == 1 .and. trev_k == 0 .and. all(g0_k == 0))
    3379            0 :      tsign_k = 1; if (trev_k == 1) tsign_k = -1
    3380              : 
    3381            0 :      ikq_ibz = my_kqmap(1, my_ik); isym_kq = my_kqmap(2, my_ik)
    3382            0 :      trev_kq = my_kqmap(6, my_ik); g0_kq = my_kqmap(3:5, my_ik)
    3383            0 :      isirr_kq = (isym_kq == 1 .and. trev_kq == 0 .and. all(g0_kq == 0))
    3384            0 :      tsign_kq = 1; if (trev_kq == 1) tsign_kq = -1
    3385              : 
    3386            0 :      if (use_adaptive) then
    3387              :        ! If k or k+q is not in the IBZ, we need to recostruct the value by symmetry using v(Sq) = S v(q).
    3388              :        ! Use transpose(R) because we are using the tables for the wavefunctions
    3389              :        ! In this case listkk has been called with symrec and use_symrec=False
    3390              :        ! so q_bz = S^T q_ibz where S is the isym_kq symmetry
    3391            0 :        vb_k = gqk%vnk_cart_ibz(:,:,ik_ibz)
    3392            0 :        vb_kq = gqk%vnk_cart_ibz(:,:,ikq_ibz)
    3393              : 
    3394            0 :        if (.not. isirr_k) then
    3395            0 :          do ib=1,nb_k
    3396            0 :            vb_k(:,ib) = tsign_k * matmul(transpose(cryst%symrel_cart(:,:,isym_k)), vb_k(:,ib))
    3397              :          end do
    3398              :        end if
    3399            0 :        if (.not. isirr_kq) then
    3400            0 :          do ib=1,nb_kq
    3401            0 :            vb_kq(:,ib) = tsign_kq * matmul(transpose(cryst%symrel_cart(:,:,isym_kq)), vb_kq(:,ib))
    3402              :          end do
    3403              :        end if
    3404              :      end if
    3405              : 
    3406            0 :      do ib2=1,nb_k
    3407            0 :        band2 = ib2 + gqk%bstart_k - 1
    3408            0 :        if (use_adaptive) then
    3409            0 :          sigma = max(maxval([(abs(dot_product(vb_k(:, ib2), kmesh_cartvec(:,ii))), ii=1,3)]), min_smear)
    3410              :          !write(std_out, *)"sigma:", sigma * Ha_eV
    3411              :        end if
    3412            0 :        g2 = gaussian(ebands%eig(band2, ik_ibz, spin) - ebands%fermie, sigma)
    3413              : 
    3414            0 :        do ib1=1,nb_kq
    3415            0 :          band1 = ib1 + gqk%bstart_kq - 1
    3416            0 :          if (use_adaptive) then
    3417            0 :            sigma = max(maxval([(abs(dot_product(vb_kq(:, ib1), kmesh_cartvec(:,ii))), ii=1,3)]), min_smear)
    3418              :          end if
    3419            0 :          g1 = gaussian(ebands%eig(band1, ikq_ibz, spin) - ebands%fermie, sigma)
    3420            0 :          dbl_delta_q(ib1, ib2, my_ik) = g1 * g2 ! / fs%nktot
    3421              :        end do
    3422              : 
    3423              :      end do
    3424              :    end do
    3425              : 
    3426            0 :    ABI_FREE(my_kqmap)
    3427              : 
    3428            0 :  else if (abs(eph_intmeth) == 2) then
    3429              : 
    3430            0 :    ABI_CHECK(isdiagmat(ebands%kptrlatt), "kptrlatt must be diagonal when tetra is used.")
    3431            0 :    ABI_CHECK(ebands%nshiftk == 1, "nshiftk must be 1 when tetra is used")
    3432            0 :    nge = get_diag(ebands%kptrlatt); ngw = nge
    3433            0 :    ABI_CHECK_IEQ(nkbz, product(nge(1:3)), "Wrong nge")
    3434              : 
    3435              :    ! Compute eig_k and eig_kq in full BZ for the relevant bands around Ef.
    3436            0 :    ABI_MALLOC(kmesh, (3, nkbz))
    3437            0 :    ABI_MALLOC(eig_k, (nb_k, nkbz))
    3438            0 :    ABI_MALLOC(eig_kq, (nb_kq, nkbz))
    3439              : 
    3440              :    ! Technical problems:
    3441              :    !
    3442              :    ! 1) libtetrabz works with the BZ and assumes a certaing ordering of the k-points (see below)
    3443              :    !    so we have to fill the array with eig_k and eig_kq from the IBZ by remapping the libtetra kk
    3444              :    !    to the Abinit IBZ
    3445              : 
    3446              :    ! 2) The dbldelta weights are given in the BZ, while the caller requires weights for k in the IBZ
    3447              :    !    and moreover only for the IBZ k-point treated by this MPI proc.
    3448              : 
    3449            0 :    ik_bz = 0
    3450            0 :    do i3=0,nge(3) - 1
    3451            0 :      do i2=0,nge(2) - 1
    3452            0 :        do i1=0,nge(1) - 1
    3453            0 :          ik_bz = ik_bz + 1
    3454            0 :          kk = ([i1, i2, i3] + ebands%shiftk(:, 1)) / nge(:)
    3455            0 :          kmesh(:, ik_bz) = kk
    3456              :        end do
    3457              :      end do
    3458              :    end do
    3459              : 
    3460              :    ! Map libtetra BZ mesh to IBZ and fill eig_k
    3461              :    !call cwtime(cpu, wall, gflops, "start")
    3462            0 :    ABI_MALLOC(kmesh_map, (6, nkbz))
    3463              : 
    3464              :    ! Find correspondence between libtetra mesh and the IBZ.
    3465            0 :    if (kpts_map("symrec", ebands%kptopt, cryst, gstore%krank_ibz, nkbz, kmesh, kmesh_map) /= 0) then
    3466            0 :      ABI_ERROR("Cannot map libtetra mesh to IBZ")
    3467              :    end if
    3468              : 
    3469            0 :    do ik_bz=1,nkbz
    3470            0 :      ik_ibz = kmesh_map(1, ik_bz)
    3471            0 :      eig_k(:, ik_bz) = ebands%eig(gqk%bstart_k:gqk%bstop_k, ik_ibz, spin) - ebands%fermie
    3472              :    end do
    3473              : 
    3474              :    ! Map libtetra BZ mesh + q to IBZ and fill eig_kq.
    3475            0 :    if (kpts_map("symrec", ebands%kptopt, cryst, gstore%krank_ibz, nkbz, kmesh, kmesh_map, qpt=qpt) /= 0) then
    3476            0 :      ABI_ERROR(sjoin("Cannot map libtetra k+q to IBZ with qpt:", ktoa(qpt)))
    3477              :    end if
    3478              : 
    3479            0 :    do ik_bz=1,nkbz
    3480            0 :      ikq_ibz = kmesh_map(1, ik_bz)
    3481            0 :      eig_kq(:, ik_bz) = ebands%eig(gqk%bstart_kq:gqk%bstop_kq, ikq_ibz, spin) - ebands%fermie
    3482              :    end do
    3483              : 
    3484            0 :    ABI_FREE(kmesh_map)
    3485              :    !call cwtime_report(" kmesh_map", cpu, wall, gflops)
    3486              : 
    3487              :    ! Call libtetra routine to compute weights for double delta integration.
    3488              :    ! Note that libtetra assumes Ef set to zero.
    3489              :    ! TODO: Average weights over degenerate states?
    3490              :    ! NB: This is a bottleneck, can pass comm_kp
    3491              : 
    3492              :    ! Select option for double delta with tetra.
    3493              :    !  2 for the optimized tetrahedron method.
    3494              :    ! -2 for the linear tetrahedron method.
    3495            0 :    ltetra = 0
    3496            0 :    if (eph_intmeth ==  2) ltetra = 2
    3497            0 :    if (eph_intmeth == -2) ltetra = 1
    3498              : 
    3499            0 :    ABI_MALLOC(wght_bz, (nb_k, nb_kq, nkbz))
    3500            0 :    call libtetrabz_dbldelta(ltetra, gstore%cryst%gprimd, nb_k, nge, eig_k, eig_kq, ngw, wght_bz) !, comm=comm)
    3501              :    !call cwtime_report(" libtetrabz_dbldelta", cpu, wall, gflops)
    3502              : 
    3503            0 :    call my_krank%init(gqk%my_nk, gqk%my_kpts)
    3504              : 
    3505              :    ! Reindex from full BZ to my set of kpoints and rescale weights.
    3506            0 :    cnt = 0
    3507            0 :    do ik_bz=1,nkbz
    3508            0 :      my_ik = my_krank%get_index(kmesh(:, ik_bz))
    3509            0 :      if (my_ik /= -1) then
    3510            0 :        dbl_delta_q(:,:,my_ik) = wght_bz(:,:,ik_bz) * gstore%nkbz
    3511            0 :        cnt = cnt + 1
    3512              :      end if
    3513              :    end do
    3514              : 
    3515              :    ! FIXME: BUG if k-point (and q-point) parallelism.
    3516            0 :    ABI_CHECK_IEQ(cnt, gqk%my_nk, sjoin("cnt != my_nk, ", itoa(cnt), itoa(gqk%my_nk)))
    3517            0 :    call my_krank%free()
    3518              :    !call cwtime_report(" transfer", cpu, wall, gflops)
    3519              : 
    3520            0 :    ABI_FREE(wght_bz)
    3521            0 :    ABI_FREE(kmesh)
    3522            0 :    ABI_FREE(eig_k)
    3523            0 :    ABI_FREE(eig_kq)
    3524              : 
    3525              :  else
    3526            0 :    ABI_ERROR(sjoin("Invalid eph_intmeth:", itoa(eph_intmeth)))
    3527              :  end if
    3528              : 
    3529            0 : end subroutine gqk_dbldelta_qpt
    3530              : !!***
    3531              : !----------------------------------------------------------------------
    3532              : 
    3533              : !!****f* m_gstore/gqk_free
    3534              : !! NAME
    3535              : !! gqk_free
    3536              : !!
    3537              : !! FUNCTION
    3538              : !!  Free dynamic memory in gqk_t instance.
    3539              : !!
    3540              : !! SOURCE
    3541              : 
    3542           24 : subroutine gqk_free(gqk)
    3543              : 
    3544              : !Arguments ------------------------------------
    3545              :  class(gqk_t),intent(inout) :: gqk
    3546              : !----------------------------------------------------------------------
    3547              : 
    3548           24 :  ABI_SFREE(gqk%my_k2ibz)
    3549           24 :  ABI_SFREE(gqk%my_kpts)
    3550           24 :  ABI_SFREE(gqk%my_wtk)
    3551           24 :  ABI_SFREE(gqk%my_q2ibz)
    3552           24 :  ABI_SFREE(gqk%my_q2bz)
    3553           24 :  ABI_SFREE(gqk%my_k2glob)
    3554           24 :  ABI_SFREE(gqk%my_q2glob)
    3555           24 :  ABI_SFREE(gqk%my_wnuq)
    3556           24 :  ABI_SFREE(gqk%my_displ_cart)
    3557           24 :  ABI_SFREE(gqk%my_iv1p_comm)
    3558           24 :  ABI_SFREE(gqk%my_pertcases)
    3559           24 :  ABI_SFREE(gqk%vnk_cart_ibz)
    3560           24 :  ABI_SFREE(gqk%vnk_mat_cart_ibz)
    3561              : 
    3562           24 :  ABI_SFREE(gqk%my_g)
    3563           24 :  ABI_SFREE(gqk%my_g2)
    3564           24 :  ABI_SFREE(gqk%my_gdw2)
    3565           24 :  if (gqk%has_both_g) then
    3566            9 :    ABI_SFREE_PTR(gqk%my_g_ks)
    3567            9 :    ABI_SFREE_PTR(gqk%my_g2_ks)
    3568            9 :    ABI_SFREE_PTR(gqk%my_gdw2_ks)
    3569              :  end if
    3570              : 
    3571           24 :  call gqk%wan%free()
    3572              : 
    3573              :  ! Free MPI communicators
    3574           24 :  call gqk%kpt_comm%free(); call gqk%qpt_comm%free(); call gqk%qpt_kpt_comm%free()
    3575           24 :  call gqk%pert_comm%free(); call gqk%band_comm%free(); call gqk%qpt_pert_comm%free()
    3576           24 :  call gqk%pert_ppsum_comm%free(); call gqk%pert_ppsum_bsum_comm%free()
    3577           24 :  call gqk%comm%free(); call gqk%bsum_comm%free(); call gqk%pp_sum_comm%free()
    3578              : 
    3579           24 : end subroutine gqk_free
    3580              : !!***
    3581              : 
    3582              : !!****f* m_gstore/gstore_get_missing_qbz_spin
    3583              : !! NAME
    3584              : !! gstore_get_missing_qbz_spin
    3585              : !!
    3586              : !! FUNCTION
    3587              : !!  Return the number of (q-points, spin) entries that have been computed.
    3588              : !!
    3589              : !! SOURCE
    3590              : 
    3591            9 : subroutine gstore_get_missing_qbz_spin(gstore, done_qbz_spin, ndone, nmiss)
    3592              : 
    3593              : !Arguments ------------------------------------
    3594              :  class(gstore_t),intent(in) :: gstore
    3595              :  integer,intent(in) :: done_qbz_spin(gstore%nqbz, gstore%nsppol)
    3596              :  integer,intent(out) :: ndone, nmiss
    3597              : 
    3598              : !Local variables ------------------------------
    3599              :  integer :: my_is, my_iq, iq_bz, spin, ierr, nscale
    3600              : !----------------------------------------------------------------------
    3601              : 
    3602            3 :  ndone = 0; nmiss = 0
    3603            6 :  do my_is=1,gstore%my_nspins
    3604            3 :    associate (gqk => gstore%gqk(my_is))
    3605            3 :    spin = gstore%my_spins(my_is)
    3606           83 :    do my_iq=1,gqk%my_nq
    3607           80 :      iq_bz = gqk%my_q2bz(my_iq)
    3608           80 :      if (done_qbz_spin(iq_bz, spin) == 0) nmiss = nmiss + 1
    3609           83 :      if (done_qbz_spin(iq_bz, spin) == 1) ndone = ndone + 1
    3610              :    end do ! my_iq
    3611              :    ! Rescale to avoid overcounting in xmpi_summ
    3612            3 :    nscale = (gqk%pert_comm%nproc * gqk%bsum_comm%nproc * gqk%pp_sum_comm%nproc)
    3613            3 :    nmiss = nmiss / nscale
    3614            6 :    ndone = ndone / nscale
    3615              :    end associate
    3616              :  end do ! my_is
    3617              : 
    3618            3 :  call xmpi_sum(ndone, gstore%comm, ierr)
    3619            3 :  call xmpi_sum(nmiss, gstore%comm, ierr)
    3620              : 
    3621            3 : end subroutine gstore_get_missing_qbz_spin
    3622              : !!***
    3623              : 
    3624              : !!****f* m_gstore/gstore_set_perts_distrib
    3625              : !! NAME
    3626              : !! gstore_set_perts_distrib
    3627              : !!
    3628              : !! FUNCTION
    3629              : !! Activate parallelism over perturbations at the level of the DVDB file.
    3630              : !!
    3631              : !! SOURCE
    3632              : 
    3633           18 : subroutine gstore_set_perts_distrib(gstore, cryst, dvdb, my_npert)
    3634              : 
    3635              : !Arguments ------------------------------------
    3636              :  class(gstore_t),intent(in) :: gstore
    3637              :  type(crystal_t),intent(in) :: cryst
    3638              :  type(dvdb_t),intent(inout) :: dvdb
    3639              :  integer,intent(out) :: my_npert
    3640              : 
    3641              : !Local variables ------------------------------
    3642              : !scalars
    3643              :  integer :: my_is, spin
    3644              : !arrays
    3645           18 :  integer,allocatable :: my_pinfo(:,:), pert_table(:,:)
    3646              : !----------------------------------------------------------------------
    3647              : 
    3648           18 :  my_npert = cryst%natom * 3
    3649           36 :  do my_is=1,gstore%my_nspins
    3650           18 :    associate (gqk => gstore%gqk(my_is))
    3651           18 :    spin = gstore%my_spins(my_is)
    3652           18 :    if (gqk%pert_comm%nproc > 1) then
    3653              :      ! Activate parallelism over perturbations
    3654              :      ! Build table with list of perturbations treated by this MPI rank inside pert_comm.
    3655              :      !ABI_WARNING("GSTORE with pert_comm%nproc > 1 not tested")
    3656            0 :      my_npert = gqk%my_npert
    3657            0 :      call ephtk_set_pertables(cryst%natom, my_npert, pert_table, my_pinfo, gqk%pert_comm%value)
    3658            0 :      call dvdb%set_pert_distrib(my_npert, cryst%natom * 3, my_pinfo, pert_table, gqk%pert_comm%value)
    3659            0 :      ABI_CHECK(all(my_pinfo(3, :) == gqk%my_pertcases), "my_pinfo(3, :) != gqk%my_pertcases")
    3660              : 
    3661            0 :      ABI_FREE(my_pinfo)
    3662            0 :      ABI_FREE(pert_table)
    3663              :    end if
    3664              :    end associate
    3665              :  end do
    3666              : 
    3667           18 : end subroutine gstore_set_perts_distrib
    3668              : !!***
    3669              : 
    3670              : !----------------------------------------------------------------------
    3671              : 
    3672              : !!****f* m_gstore/gstore_compute
    3673              : !! NAME
    3674              : !!  gstore_compute
    3675              : !!
    3676              : !! FUNCTION
    3677              : !!  Compute MPI-distributed e-ph matrix elements
    3678              : !!
    3679              : !! INPUTS
    3680              : !! wk0_path=String with the path to the GS unperturbed WFK file.
    3681              : !! ngfft(18),ngfftf(18)=Coarse and Fine FFT meshes.
    3682              : !! dtset<dataset_type>=All input variables for this dataset.
    3683              : !! ebands<ebands_t>=The GS KS band structure (energies, occupancies, k-weights...)
    3684              : !! dvdb<dbdb_type>=Database with the DFPT SCF potentials.
    3685              : !! pawfgr <type(pawfgr_type)>=fine grid parameters and related data
    3686              : !! pawang<pawang_type)>=PAW angular mesh and related data.
    3687              : !! pawrad(ntypat*usepaw)<pawrad_type>=Paw radial mesh and related data.
    3688              : !! pawtab(ntypat*usepaw)<pawtab_type>=Paw tabulated starting data.
    3689              : !! psps<pseudopotential_type>=Variables related to pseudopotentials.
    3690              : !! comm=MPI communicator.
    3691              : !!
    3692              : !! OUTPUT
    3693              : !!  GSTORE.nc file
    3694              : !!
    3695              : !! SOURCE
    3696              : 
    3697            5 : subroutine gstore_compute(gstore, wfk0_path, ngfft, ngfftf, dtset, dtfil, cryst, ebands, ifc, dvdb, &
    3698            5 :                           pawfgr, pawang, pawrad, pawtab, psps, mpi_enreg, comm)
    3699              : 
    3700              : !Arguments ------------------------------------
    3701              : !scalars
    3702              :  class(gstore_t),target,intent(inout) :: gstore
    3703              :  character(len=*),intent(in) :: wfk0_path
    3704              :  integer,intent(in) :: comm
    3705              :  type(dataset_type),intent(in) :: dtset
    3706              :  type(datafiles_type),intent(in) :: dtfil
    3707              :  type(crystal_t),intent(in) :: cryst
    3708              :  type(ebands_t),intent(in) :: ebands
    3709              :  class(ifc_type),intent(in) :: ifc
    3710              :  type(dvdb_t),intent(inout) :: dvdb
    3711              :  type(pawang_type),intent(in) :: pawang
    3712              :  type(pseudopotential_type),intent(in) :: psps
    3713              :  type(pawfgr_type),intent(in) :: pawfgr
    3714              :  type(mpi_type),intent(in) :: mpi_enreg
    3715              : !arrays
    3716              :  integer,intent(in) :: ngfft(18),ngfftf(18)
    3717              :  type(pawrad_type),intent(in) :: pawrad(psps%ntypat*psps%usepaw)
    3718              :  type(pawtab_type),intent(in) :: pawtab(psps%ntypat*psps%usepaw)
    3719              : 
    3720              : !Local variables ------------------------------
    3721              : !scalars
    3722              :  integer,parameter :: tim_getgh1c = 1, berryopt0 = 0, ider0 = 0, idir0 = 0, LOG_MODQ = 5, master = 0, ndat1 = 1
    3723              :  integer :: my_rank,nproc,nproc_lim,mband,nsppol,nkibz,idir,ipert, iq_bz
    3724              :  integer :: cplex,natom,natom3,ipc,nspinor, nskip_tetra_kq, timrev_k, timrev_q
    3725              :  integer :: band_k, in_k, ik_ibz,ikq_ibz,isym_k,isym_kq,trev_k,trev_kq, nb_k, nb_kq ! im_kq,
    3726              :  integer :: my_ik, my_is, comm_rpt, my_npert, my_ip, my_iq, spin,istwf_k,istwf_kq,npw_k,npw_kq
    3727              :  integer :: mpw, ierr, n1,n2,n3,n4,n5,n6,nspden,ndone, db_iqpt
    3728              :  integer :: sij_opt,usecprj,usevnl,optlocal,optnl,opt_gvnlx1
    3729              :  integer :: nfft,nfftf,mgfft,mgfftf, nkpg_k, nkpg_kq, qbuf_size, iqbuf_cnt, root_ncid, spin_ncid, ncerr
    3730              :  integer :: ii, iq_ibz, isym_q, trev_q
    3731              :  real(dp) :: cpu_q, wall_q, gflops_q, cpu_all, wall_all, gflops_all ! cpu, wall, gflops,
    3732              :  real(dp) :: ecut, weight_q, weight_k ! eshift,
    3733              :  logical :: gen_eigenpb, isirr_k, isirr_kq, isirr_q, print_time, need_ftinterp, qq_is_gamma, symmetrize, use_lgk
    3734            5 :  type(wfd_t) :: wfd
    3735            5 :  type(gs_hamiltonian_type) :: gs_ham_kq
    3736            5 :  type(rf_hamiltonian_type) :: rf_ham_kq
    3737              :  type(gqk_t),pointer :: gqk
    3738            5 :  type(lgroup_t) :: lg_myq
    3739              :  character(len=5000) :: msg, qq_bz_string, kk_string
    3740              : !arrays
    3741              :  integer :: g0_k(3), g0_kq(3), g0_q(3), work_ngfft(18),gmax(3),indkk_kq(6,1), units(2), qbz2dvdb(6)
    3742            5 :  integer,allocatable :: kg_k(:,:), kg_kq(:,:), nband(:,:), wfd_istwfk(:), qmap_symrec(:,:)
    3743            5 :  integer,allocatable :: iq_buf(:,:), done_qbz_spin(:,:), state_kq(:,:)
    3744              :  !integer,allocatable :: qibz2dvdb(:) !, displs(:), recvcounts(:)
    3745              :  real(dp) :: kk_bz(3),kq_bz(3),kk_ibz(3),kq_ibz(3), qq_bz(3), qq_ibz(3) !, v_nk(3)
    3746            5 :  real(dp),allocatable :: displ_cart_qibz(:,:,:,:), lambda(:)
    3747            5 :  real(dp),allocatable :: grad_berry(:,:), kinpw_k(:), kinpw_kq(:), kpg_kq(:,:), kpg_k(:,:)
    3748            5 :  real(dp),allocatable :: ffnl_k(:,:,:,:), ffnl_kq(:,:,:,:), ph3d_k(:,:,:), ph3d_kq(:,:,:)
    3749            5 :  real(dp),allocatable :: v1scf(:,:,:,:), gkq_atm(:,:,:,:), gkq_atm_ipc(:,:,:)
    3750            5 :  real(dp),allocatable :: bras_kq(:,:,:), kets_k(:,:,:), h1_kets_kq(:,:,:) !, cgwork(:,:)
    3751            5 :  real(dp),allocatable :: ph1d(:,:), vlocal(:,:,:,:), vlocal1(:,:,:,:,:)
    3752            5 :  real(dp),allocatable :: dummy_vtrial(:,:), gvnlx1(:,:,:), work(:,:,:,:)
    3753            5 :  real(dp),allocatable :: gs1c_kq(:,:) !, vnk_cart_ibz(:,:,:) !, vkq_cart_ibz(:,:,:)  !, vnk_mat_cart_ibz(:,:,:,:)
    3754            5 :  real(dp),allocatable :: my_gbuf(:,:,:,:,:,:)
    3755            5 :  logical,allocatable :: bks_mask(:,:,:),keep_ur(:,:,:)
    3756            5 :  type(pawcprj_type),allocatable  :: cwaveprj0(:,:)
    3757            5 :  type(lgroup_t),allocatable :: lg_myk(:)
    3758              : !************************************************************************
    3759              : 
    3760            5 :  my_rank = xmpi_comm_rank(comm); nproc = xmpi_comm_size(comm)
    3761           15 :  units = [std_out, ab_out]
    3762              : 
    3763            5 :  if (psps%usepaw == 1) then
    3764            0 :    ABI_ERROR("PAW not implemented")
    3765              :    ABI_UNUSED((/pawang%nsym, pawrad(1)%mesh_size/))
    3766              :  end if
    3767              : 
    3768              :  ! Check MPI distribution: abort if there are any idle processes
    3769              :  ! NOTE that we have to perform this check only at the level of gstore%compute:
    3770              :  ! if gstore object is loaded from a *GSTORE.nc file, there are no calls to individual
    3771              :  ! phonons/electrons distribution, hence k/q-iBZ is not a limiting factor anymore
    3772           10 :  do my_is=1,gstore%my_nspins
    3773            5 :    gqk => gstore%gqk(my_is)
    3774            5 :    nproc = gqk%comm%nproc
    3775            5 :    nproc_lim = min(gstore%nkibz, gstore%nqibz)
    3776           10 :    if (nproc > nproc_lim) then
    3777            0 :       write(msg, "(a,i0,a,i0,4a)") "gstore%compute: nproc=", nproc, " > min(nkibz, nqibz)=", &
    3778            0 :         nproc_lim, ch10, "This will lead to idle processes, which are not supported.", ch10, &
    3779            0 :         "Please decrease the total number of CPUs as the size of your problem is relatively small"
    3780            0 :       ABI_ERROR(msg)
    3781              :    endif
    3782              :  enddo
    3783              : 
    3784              :  ! This parameter defines the size of the q-buffer used to store the g(k, q) e-ph matrix elements
    3785              :  ! for all the k-point treated by this MPI rank.
    3786              :  ! Increasing the buffer size increases the memory requirements
    3787              :  ! but it leads to better performance as the number of IO operations is decreased.
    3788              :  ! TODO: Should compute it on the basis of my_nkpt and my_nqpt
    3789            5 :  qbuf_size = 16
    3790            5 :  call wrtout(std_out, sjoin(" Begin computation of e-ph matrix elements with qbuf_size:", itoa(qbuf_size)), pre_newlines=1)
    3791            5 :  call pstat_proc%print(_PSTAT_ARGS_)
    3792            5 :  call cwtime(cpu_all, wall_all, gflops_all, "start")
    3793              : 
    3794              :  ! If True, only k-points in the IBZ and q-points in the IBZ_k are computed.
    3795              :  ! Matrix elements in full BZs are then reconstructed by symmetry at the end of the run by calling
    3796              :  ! gstore_symmetrize.
    3797              :  symmetrize = (dtset%gstore_kzone == "bz" .and. dtset%gstore_qzone == "bz" &
    3798              :      .and. dtset%gstore_sym > 0 &
    3799            5 :      )
    3800              :  !if (symmetrize) call wrtout(units, " Computing g(k, q) with k in the IBZ and q in the BZ + final reconstruction")
    3801              : 
    3802              :  ! Copy important dimensions
    3803            5 :  natom = cryst%natom; natom3 = 3 * natom; nsppol = ebands%nsppol; nspinor = ebands%nspinor; nspden = dtset%nspden
    3804            5 :  nkibz = ebands%nkpt; mband = ebands%mband
    3805              : 
    3806              :  ! FFT meshes
    3807           20 :  nfftf = product(ngfftf(1:3)); mgfftf = maxval(ngfftf(1:3))
    3808           35 :  nfft = product(ngfft(1:3)) ; mgfft = maxval(ngfft(1:3))
    3809            5 :  n1 = ngfft(1); n2 = ngfft(2); n3 = ngfft(3); n4 = ngfft(4); n5 = ngfft(5); n6 = ngfft(6)
    3810              : 
    3811              :  ! Open the DVDB file
    3812            5 :  call dvdb%open_read(ngfftf, xmpi_comm_self)
    3813            5 :  ABI_CHECK(dvdb%has_fields("pot1", msg), msg)
    3814              : 
    3815              :  ! Activate parallelism over perturbations at the level of the DVDB
    3816            5 :  call gstore%set_perts_distrib(cryst, dvdb, my_npert)
    3817              : 
    3818              :  ! Prepare Fourier interpolation of DFPT potentials.
    3819            5 :  comm_rpt = xmpi_comm_self
    3820              :  !comm_rpt = bqs_comm%value
    3821              : 
    3822              :  ! qmap_symrec gives the mapping gstore%ibz --> dvdb%ibz
    3823            5 :  call dvdb%need_ftinterp(gstore%nqibz, gstore%qibz, gstore%qptopt, qmap_symrec, need_ftinterp)
    3824            5 :  ABI_FREE(qmap_symrec)
    3825              :  !need_ftinterp = .True.
    3826              : 
    3827            5 :  if (.not. need_ftinterp .and. dtset%eph_use_ftinterp /= 0) then
    3828            0 :    ABI_WARNING("Enforcing FT interpolation for q-points even if it's not strictly needed.")
    3829            0 :    need_ftinterp = .True.
    3830              :  end if
    3831              : 
    3832            5 :  if (need_ftinterp) then
    3833            3 :    call wrtout(units, " Cannot find all IBZ q-points in the DVDB --> Activating Fourier interpolation.")
    3834            3 :    call dvdb%ftinterp_setup(dtset%ddb_ngqpt, gstore%qptopt, 1, dtset%ddb_shiftq, nfftf, ngfftf, comm_rpt)
    3835              :  else
    3836            2 :    call wrtout(units, " DVDB file contains all q-points in the IBZ --> Reading DFPT potentials from file.")
    3837              :  end if
    3838              : 
    3839              :  ! Initialize the wave function descriptor.
    3840              :  ! Only wavefunctions for the symmetrical image of the k/k+q wavevectors treated by this MPI rank are stored.
    3841           20 :  ABI_MALLOC(nband, (nkibz, nsppol))
    3842           25 :  ABI_MALLOC(bks_mask, (mband, nkibz, nsppol))
    3843           20 :  ABI_MALLOC(keep_ur, (mband, nkibz, nsppol))
    3844         2754 :  nband = mband; bks_mask = .False.; keep_ur = .False.
    3845              : 
    3846            5 :  call gstore%fill_bks_mask(mband, nkibz, nsppol, bks_mask)
    3847              : 
    3848              :  ! Impose istwfk = 1 for all k-points. This is also done in respfn (see inkpts)
    3849              :  ! wfd_read_wfk will handle a possible conversion if WFK contains istwfk /= 1.
    3850           15 :  ABI_MALLOC(wfd_istwfk, (nkibz))
    3851          119 :  wfd_istwfk = 1
    3852            5 :  ecut = dtset%ecut
    3853              : 
    3854              :  call wfd%init(cryst, pawtab, psps, keep_ur, mband, nband, nkibz, nsppol, bks_mask,&
    3855              :                nspden, nspinor, ecut, dtset%ecutsm, dtset%dilatmx, wfd_istwfk, ebands%kptns, ngfft,&
    3856            5 :                dtset%nloalg, dtset%prtvol, dtset%pawprtvol, comm)
    3857              : 
    3858           10 :  call wfd%print([std_out], header="Wavefunctions for GSTORE calculation")
    3859              : 
    3860            5 :  ABI_FREE(nband)
    3861            5 :  ABI_FREE(keep_ur)
    3862            5 :  ABI_FREE(wfd_istwfk)
    3863            5 :  ABI_FREE(bks_mask)
    3864              : 
    3865              :  ! Read wavefunctions.
    3866            5 :  call wfd%read_wfk(wfk0_path, iomode_from_fname(wfk0_path))
    3867            5 :  call pstat_proc%print(_PSTAT_ARGS_)
    3868              : 
    3869              :  ! one-dimensional structure factor information on the coarse grid.
    3870           15 :  ABI_MALLOC(ph1d, (2, 3*(2*mgfft+1)*natom))
    3871            5 :  call getph(cryst%atindx, natom, n1, n2, n3, ph1d, cryst%xred)
    3872              : 
    3873              :  ! mpw is the maximum number of plane-waves over k and k+q where k and k+q are in the BZ.
    3874              :  ! we also need the max components of the G-spheres (k, k+q) in order to allocate the workspace array work
    3875              :  ! that will be used to symmetrize the wavefunctions in G-space.
    3876            5 :  call gstore%get_mpw_gmax(ecut, mpw, gmax)
    3877              : 
    3878              :  ! Init work_ngfft
    3879           20 :  gmax = gmax + 4 ! FIXME: this is to account for umklapp
    3880           20 :  gmax = 2*gmax + 1
    3881            5 :  call ngfft_seq(work_ngfft, gmax)
    3882              :  !write(std_out,*)"work_ngfft(1:3): ",work_ngfft(1:3)
    3883           25 :  ABI_MALLOC(work, (2, work_ngfft(4), work_ngfft(5), work_ngfft(6)))
    3884              : 
    3885              :  ! Allow PW-arrays dimensioned with mpw
    3886           15 :  ABI_MALLOC(kg_k, (3, mpw))
    3887           10 :  ABI_MALLOC(kg_kq, (3, mpw))
    3888              : 
    3889            5 :  usecprj = 0
    3890           10 :  ABI_MALLOC(cwaveprj0, (natom, nspinor*usecprj))
    3891              : 
    3892              :  ! Prepare call to getgh1c
    3893            5 :  usevnl = 0
    3894            5 :  optlocal = 1    ! local part of H^(1) is computed in gh1c=<G|H^(1)|C>
    3895            5 :  optnl = 2       ! non-local part of H^(1) is totally computed in gh1c=<G|H^(1)|C>
    3896            5 :  opt_gvnlx1 = 0  ! gvnlx1 is output
    3897            5 :  ABI_MALLOC(grad_berry, (2, nspinor*(berryopt0/4)))
    3898              : 
    3899              :  ! This part is taken from dfpt_vtorho
    3900              :  !==== Initialize most of the Hamiltonian (and derivative) ====
    3901              :  !1) Allocate all arrays and initialize quantities that do not depend on k and spin.
    3902              :  !2) Perform the setup needed for the non-local factors:
    3903              :  ! Norm-conserving: Constant kleimann-Bylander energies are copied from psps to gs_hamk.
    3904              :  ! PAW: Initialize the overlap coefficients and allocate the Dij coefficients.
    3905              : 
    3906              :  call gs_ham_kq%init(psps, pawtab, nspinor, nsppol, nspden, natom, &
    3907              :    dtset%typat, cryst%xred, nfft, mgfft, ngfft, cryst%rprimd, dtset%nloalg, &
    3908              :    comm_atom=mpi_enreg%comm_atom, mpi_atmtab=mpi_enreg%my_atmtab, mpi_spintab=mpi_enreg%my_isppoltab, &
    3909            5 :    usecprj=usecprj, ph1d=ph1d, nucdipmom=dtset%nucdipmom, gpu_option=dtset%gpu_option)
    3910              : 
    3911              :  ! Allocate vlocal. Note nvloc
    3912              :  ! I set vlocal to huge to trigger possible bugs (DFPT routines should not access the data)
    3913           30 :  ABI_MALLOC(vlocal, (n4, n5, n6, gs_ham_kq%nvloc))
    3914        26516 :  vlocal = huge(one)
    3915              : 
    3916              :  ! Allocate work space arrays.
    3917           20 :  ABI_MALLOC(displ_cart_qibz, (2, 3, cryst%natom, natom3))
    3918        22241 :  ABI_CALLOC(dummy_vtrial, (nfftf, nspden))
    3919              : 
    3920              :  ! Open GSTORE file, and read table used for restarting.
    3921              :  ! TODO: Fix problem with IO (some q-points are not written)
    3922            5 :  if (dtset%useria == 888) then
    3923              :    ! use xmpi_comm_self otherwise there will be a deadlock on lemaitre4
    3924            0 :    NCF_CHECK(nctk_open_modify(root_ncid, gstore%path, xmpi_comm_self))
    3925              :  else
    3926            5 :    NCF_CHECK(nctk_open_modify(root_ncid, gstore%path, gstore%comm))
    3927              :  end if
    3928              : 
    3929              :  ! integer scalars
    3930              :  ncerr = nctk_def_iscalars(root_ncid, [character(len=nctk_slen) :: &
    3931              :    "used_ftinterp" &
    3932           10 :  ])
    3933            5 :  NCF_CHECK(ncerr)
    3934              : 
    3935           20 :  ABI_MALLOC(done_qbz_spin, (gstore%nqbz, nsppol))
    3936            5 :  NCF_CHECK(nf90_get_var(root_ncid, nctk_idname(root_ncid, "gstore_done_qbz_spin"), done_qbz_spin))
    3937              : 
    3938            5 :  gstore%wfk0_path = wfk0_path
    3939              : 
    3940              :  !if (my_rank == master) then
    3941            5 :  ii = merge(1, 0, need_ftinterp)
    3942              :  ncerr = nctk_write_iscalars(root_ncid, [character(len=nctk_slen) :: &
    3943              :    "used_ftinterp"], &
    3944              :    [ii &
    3945           15 :  ])
    3946            5 :  NCF_CHECK(ncerr)
    3947              : 
    3948            5 :  NCF_CHECK(nf90_put_var(root_ncid, root_vid("gstore_wfk0_path"), trim(gstore%wfk0_path)))
    3949              :  !end if
    3950              : 
    3951           10 :  if (my_rank == master) call gstore%print([std_out])
    3952         2487 :  ndone = count(done_qbz_spin == 1)
    3953              : 
    3954            5 :  if (ndone == 0) then
    3955              :    ! Write phonon data here as we are not guaranteed to have all the IBZ q-points
    3956              :    ! inside the loop over my_iq if filtering has been used.
    3957              :    ! Make sure internal table with gstore_done_qbz_spin is properly filled.
    3958            5 :    call gstore%compute_and_write_ph(root_ncid)
    3959              :  else
    3960            0 :    call wrtout(units, sjoin("- Restarting GSTORE calculation from file:", gstore%path))
    3961            0 :    call wrtout(units, sjoin(" Found: ", itoa(ndone), " (qpt, spin) entries already computed"))
    3962              :  end if
    3963              : 
    3964              :  ! Create ddkop object to compute group velocities (if needed)
    3965            5 :  if (gstore%with_vk /= 0 .and. ndone == 0) then
    3966            5 :    call gstore%compute_and_write_vk(mpw, wfd, ebands, psps, pawtab, root_ncid)
    3967              :  end if
    3968              : 
    3969            5 :  if (dtset%gstore_iv1p_comm /= 0) then
    3970              :    call gstore%compute_and_write_commutator(mpw, gmax, ngfft, ngfftf, dtset, cryst, pawfgr, psps, &
    3971            0 :                                             wfd, mpi_enreg, kg_k, ebands, dvdb, gs_ham_kq, root_ncid)
    3972              :  end if
    3973              : 
    3974            5 :  call wrtout(std_out, " Begin computation of e-ph matrix elements...", pre_newlines=1)
    3975              : 
    3976              :  ! TODO: Exchange the q/k loops so that one can reduce the number of calls to _k dependente routines
    3977              :  ! and precompute u_nk(r) so that we can save one FFT every time we compute <g|v^1_{kappa,a}(r)|u_nk(r)>
    3978              :  ! The price to pay is an increase in the number of calls to get_ftqbz but for small systems this part does not dominate
    3979              :  ! Alternatively, one cah have two versions that will be invoked depending on my_nk, my_nq
    3980              : 
    3981              :  ! Here we decide if the q-points can be reduced to the IBZ(k)
    3982            5 :  use_lgk = (dtset%gstore_use_lgk /= 0 .or. dtset%gstore_sym == 2)
    3983              :  if (use_lgk) then
    3984            1 :    call wrtout(units, " Only q-points in the IBZ_k will be computed.")
    3985            4 :  else if (dtset%gstore_use_lgq /= 0) then
    3986            0 :    call wrtout(units, " Only k-points in the IBZ_q will be computed.")
    3987              :  else
    3988            4 :    call wrtout(units, " Little group operations won't be used")
    3989              :  end if
    3990              : 
    3991              :  ! if PAW, one has to solve a generalized eigenproblem
    3992            5 :  gen_eigenpb = psps%usepaw == 1; sij_opt = 0; if (gen_eigenpb) sij_opt = 1
    3993              : 
    3994              :  ! Loop over my spins.
    3995           10 :  do my_is=1,gstore%my_nspins
    3996            5 :    spin = gstore%my_spins(my_is); gqk => gstore%gqk(my_is); my_npert = gqk%my_npert
    3997              : 
    3998            5 :    NCF_CHECK(nf90_inq_ncid(root_ncid, strcat("gqk", "_spin", itoa(spin)), spin_ncid))
    3999            5 :    NCF_CHECK(nctk_prepare_mpiio(spin_ncid, "gvals"))
    4000            5 :    NCF_CHECK(nctk_prepare_mpiio(root_ncid, "gstore_done_qbz_spin"))
    4001              : 
    4002            5 :    nb_k = gqk%nb_k; nb_kq = gqk%nb_kq
    4003              : 
    4004           15 :    ABI_MALLOC(iq_buf, (2, qbuf_size))
    4005          245 :    iq_buf = 0
    4006           15 :    ABI_MALLOC(lambda, (nb_k))
    4007           25 :    ABI_MALLOC(gkq_atm, (2, nb_kq, nb_k, natom3))
    4008           20 :    ABI_MALLOC(gkq_atm_ipc, (2, nb_kq, nb_k))
    4009              : #ifdef HAVE_OPENMP_OFFLOAD
    4010              :    !$OMP TARGET ENTER DATA MAP(alloc:gkq_atm_ipc) IF (dtset%gpu_option == ABI_GPU_OPENMP)
    4011              : #endif
    4012              : 
    4013              :    ! Inside the loops we compute gkq_atm(2, nb_kq, nb_k, natom3)
    4014           40 :    ABI_MALLOC_OR_DIE(my_gbuf, (gqk%cplex, nb_kq, nb_k, natom3, gqk%my_nk, qbuf_size), ierr)
    4015            5 :    call pstat_proc%print(_PSTAT_ARGS_)
    4016              : 
    4017              :    ! Compute the little group of the k-point so that we can compute g(k,q) only for q in the IBZ_k
    4018            5 :    if (use_lgk) then
    4019            1 :      timrev_k = kpts_timrev_from_kptopt(ebands%kptopt)
    4020            4 :      ABI_MALLOC(lg_myk, (gqk%my_nk))
    4021            2 :      do my_ik=1,gqk%my_nk
    4022            4 :        kk_bz = gqk%my_kpts(:, my_ik)
    4023            2 :        call lg_myk(my_ik)%init(cryst, kk_bz, timrev_k, gstore%nqbz, gstore%qbz, gstore%nqibz, gstore%qibz, xmpi_comm_self)
    4024              :      end do
    4025              :    end if
    4026              : 
    4027           20 :    ABI_MALLOC(state_kq, (gqk%my_nk, qbuf_size))
    4028         4981 :    state_kq = GSTORE_KQ_MISSING
    4029              : 
    4030              :    ! Loop over my set of q-points
    4031          882 :    do my_iq=1,gqk%my_nq
    4032          877 :      print_time = my_rank == 0 .and. (my_iq <= LOG_MODQ .or. mod(my_iq, LOG_MODQ) == 0)
    4033          193 :      if (print_time) call cwtime(cpu_q, wall_q, gflops_q, "start")
    4034          877 :      iq_bz = gqk%my_q2bz(my_iq)
    4035              : 
    4036          877 :      call gqk%myqpt(my_iq, gstore, weight_q, qq_bz)
    4037              :      qq_is_gamma = sum(qq_bz**2) < tol14
    4038          877 :      qq_bz_string = ktoa(qq_bz)
    4039              : 
    4040              :      ! Handle possible restart.
    4041          877 :      if (done_qbz_spin(iq_bz, spin) == 1) then
    4042            0 :        call wrtout(std_out, sjoin(" iq_bz:", itoa(iq_bz), ", spin: ", itoa(spin), " already computed --> skipping iteration"))
    4043            0 :        cycle
    4044              :      end if
    4045              : 
    4046              :      ! Compute the little group of the q-point so that we can compute g(k,q) only for k in the IBZ_q
    4047          877 :      if (dtset%gstore_use_lgq /= 0) then
    4048            0 :        timrev_q = kpts_timrev_from_kptopt(gstore%qptopt)
    4049            0 :        call lg_myq%init(cryst, qq_bz, timrev_q, gstore%nkbz, gstore%kbz, gstore%nkibz, gstore%kibz, xmpi_comm_self)
    4050              :      end if
    4051              : 
    4052          877 :      iq_ibz = gqk%my_q2ibz(1, my_iq); isym_q = gqk%my_q2ibz(2, my_iq)
    4053          877 :      trev_q = gqk%my_q2ibz(6, my_iq); g0_q = gqk%my_q2ibz(3:5,my_iq)
    4054              :      ! Don't test if umklapp == 0 because we use the periodic gauge:
    4055              :      !
    4056              :      !      phfreq(q+G) = phfreq(q) and eigvec(q) = eigvec(q+G)
    4057              :      !
    4058              :      !isirr_q = (isym_q == 1 .and. trev_q == 0 .and. all(g0_q == 0))
    4059          877 :      isirr_q = (isym_q == 1 .and. trev_q == 0)
    4060         3508 :      qq_ibz = gstore%qibz(:, iq_ibz)
    4061              : 
    4062          877 :      nskip_tetra_kq = 0
    4063          877 :      iqbuf_cnt = 1 + mod(my_iq - 1, qbuf_size)
    4064         2631 :      iq_buf(:, iqbuf_cnt) = [my_iq, iq_bz]
    4065              : 
    4066          877 :      if (need_ftinterp) then
    4067              :        ! Fourier interpolation.
    4068          786 :        call dvdb%get_ftqbz(qq_bz, cplex, nfftf, ngfftf, v1scf, gqk%pert_comm%value)
    4069              :      else
    4070              :        ! Read and reconstruct the dvscf potentials for qpt and my_npert perturbations.
    4071           91 :        db_iqpt = dvdb%findq(qq_ibz)
    4072           91 :        ABI_CHECK(db_iqpt /= -1, sjoin("Could not find symmetric of q-point:", ktoa(qq_bz), "in DVDB file."))
    4073              :        ! The first entry in qbz2dvdb gives the index in dvdb%qpts.
    4074              :        ! The other entries in mapc_qq are OK as they refer to symmetries.
    4075          637 :        qbz2dvdb = gqk%my_q2ibz(:, my_iq); qbz2dvdb(1) = db_iqpt
    4076           91 :        call dvdb%readsym_qbz(cryst, qq_bz, qbz2dvdb, cplex, nfftf, ngfftf, v1scf, gqk%pert_comm%value)
    4077              :      end if
    4078              : 
    4079              :      ! Allocate vlocal1 with correct cplex. Note nvloc and my_npert.
    4080         6139 :      ABI_MALLOC(vlocal1, (cplex*n4, n5, n6, gs_ham_kq%nvloc, my_npert))
    4081              : 
    4082              :      ! Set up local potential vlocal1 with proper dimensioning from vtrial1 taking into account the spin.
    4083         6139 :      do my_ip=1,my_npert
    4084              :        call rf_transgrid_and_pack(spin, nspden, psps%usepaw, cplex, nfftf, nfft, ngfft, gs_ham_kq%nvloc,&
    4085         6139 :                                   pawfgr, mpi_enreg, dummy_vtrial, v1scf(:,:,:,my_ip), vlocal, vlocal1(:,:,:,:,my_ip))
    4086              : #ifdef HAVE_OPENMP_OFFLOAD
    4087              :        !$OMP TARGET ENTER DATA MAP(to:vlocal1(:,:,:,:,my_ip)) IF (dtset%gpu_option == ABI_GPU_OPENMP) NOWAIT
    4088              : #endif
    4089              :      end do
    4090              :      !$OMP TASKWAIT
    4091              : 
    4092              :      ! Continue to initialize the GS Hamiltonian
    4093          877 :      call gs_ham_kq%load_spin(spin, vlocal=vlocal, with_nonlocal=.true.)
    4094              : 
    4095              :      ! Loop over my k-points
    4096        74524 :      do my_ik=1,gqk%my_nk
    4097              :        ! The k-point and the symmetries relating the BZ k-point to the IBZ.
    4098       294588 :        kk_bz = gqk%my_kpts(:, my_ik)
    4099        73647 :        weight_k = gqk%my_wtk(my_ik)
    4100        73647 :        kk_string = ktoa(kk_bz)
    4101              : 
    4102        73647 :        ik_ibz = gqk%my_k2ibz(1, my_ik); isym_k = gqk%my_k2ibz(2, my_ik)
    4103       294588 :        trev_k = gqk%my_k2ibz(6, my_ik); g0_k = gqk%my_k2ibz(3:5,my_ik)
    4104       282012 :        isirr_k = (isym_k == 1 .and. trev_k == 0 .and. all(g0_k == 0))
    4105       294588 :        kk_ibz = ebands%kptns(:,ik_ibz)
    4106              : 
    4107              :        ! Set entry to zero. Important as there are cycle instructions inside these loops
    4108              :        ! and we don't want random numbers written to disk.
    4109      5565417 :        my_gbuf(:,:,:,:, my_ik, iqbuf_cnt) = zero
    4110              : 
    4111        73647 :        if (symmetrize .and. .not. isirr_k) then
    4112            0 :          state_kq(my_ik, iqbuf_cnt) = GSTORE_KQ_MISSING; cycle
    4113              :        end if
    4114              : 
    4115        73647 :        if (use_lgk) then
    4116           64 :          ii = lg_myk(my_ik)%findq_ibzk(qq_bz)
    4117           64 :          if (ii == -1) then
    4118           56 :            state_kq(my_ik, iqbuf_cnt) = GSTORE_KQ_MISSING; cycle
    4119              :          end if
    4120              :        end if
    4121              : 
    4122        73591 :        if (dtset%gstore_use_lgq /= 0) then
    4123            0 :          ii = lg_myq%findq_ibzk(kk_bz)
    4124            0 :          if (ii == -1) then
    4125            0 :            state_kq(my_ik, iqbuf_cnt) = GSTORE_KQ_MISSING; cycle
    4126              :          end if
    4127              :        end if
    4128              : 
    4129              :        ! =========================================
    4130              :        ! Find symmetrical image of k+q in the kIBZ
    4131              :        ! =========================================
    4132       294364 :        kq_bz = kk_bz + qq_bz
    4133        73591 :        if (kpts_map("symrel", ebands%kptopt, cryst, gstore%krank_ibz, 1, kq_bz, indkk_kq) /= 0) then
    4134              :          write(msg, '(3a)' ) &
    4135            0 :           "Cannot find k+q in k-mesh", ch10, 'Check your WFK file and the (k,q) point input variables.'
    4136            0 :           ABI_ERROR(msg)
    4137              :        end if
    4138              : 
    4139        73591 :        ikq_ibz = indkk_kq(1, 1); isym_kq = indkk_kq(2, 1)
    4140        73591 :        trev_kq = indkk_kq(6, 1); g0_kq = indkk_kq(3:5, 1)
    4141              :        isirr_kq = (isym_kq == 1 .and. trev_kq == 0 .and. all(g0_kq == 0))
    4142       294364 :        kq_ibz = ebands%kptns(:, ikq_ibz)
    4143              : 
    4144              :        ! If we have used the KERANGE trick, we may have k or k+q points with just one G component set to zero
    4145              :        ! so we skip this transition immediately. This should happen only if fsewin > sigma_erange.
    4146        73591 :        if (wfd%npwarr(ik_ibz) == 1 .or. wfd%npwarr(ikq_ibz) == 1) then
    4147            0 :          state_kq(my_ik, iqbuf_cnt) = GSTORE_KQ_MISSING; cycle
    4148              :        end if
    4149              : 
    4150        73591 :        if (gstore%kfilter == "fs_tetra") then
    4151              :          ! Check tetra delta(e_{k+q}) and cycle if all the weights at k+q are zero.
    4152            0 :          if (all(abs(gstore%delta_ef_kibz_spin(:, ikq_ibz, spin)) == zero)) then
    4153            0 :            nskip_tetra_kq = nskip_tetra_kq + 1
    4154            0 :            state_kq(my_ik, iqbuf_cnt) = GSTORE_KQ_MISSING; cycle
    4155              :          end if
    4156              :        end if
    4157              : 
    4158              :        ! Get npw_k, kg_k and symmetrize wavefunctions from the IBZ (if needed).
    4159              :        call wfd%sym_ug_kg_npw(ecut, kk_bz, kk_ibz, gqk%bstart_k, nb_k, spin, gqk%my_k2ibz(:, my_ik), cryst, &
    4160        73591 :                               work_ngfft, work, istwf_k, npw_k, kg_k, kets_k)
    4161              : 
    4162              : #ifdef HAVE_OPENMP_OFFLOAD
    4163              :        !$OMP TARGET ENTER DATA MAP(to:kets_k) IF (dtset%gpu_option == ABI_GPU_OPENMP) NOWAIT
    4164              : #endif
    4165              : 
    4166              :        ! Get npw_kq, kg_kq and symmetrize wavefunctions from the IBZ (if needed).
    4167              :        call wfd%sym_ug_kg_npw(ecut, kq_bz, kq_ibz, gqk%bstart_kq, nb_kq, spin, indkk_kq(:,1), cryst, &
    4168        73591 :                               work_ngfft, work, istwf_kq, npw_kq, kg_kq, bras_kq)
    4169              : 
    4170              : #ifdef HAVE_OPENMP_OFFLOAD
    4171              :        !$OMP TARGET ENTER DATA MAP(to:bras_kq) IF (dtset%gpu_option == ABI_GPU_OPENMP) NOWAIT
    4172              : #endif
    4173              : 
    4174       294364 :        ABI_MALLOC(h1_kets_kq, (2, npw_kq*nspinor, nb_k))
    4175       220773 :        ABI_MALLOC(gs1c_kq, (2, npw_kq*nspinor*nb_k*((sij_opt+1)/2)))
    4176       220773 :        ABI_MALLOC(gvnlx1, (2, npw_kq*nspinor,nb_k))
    4177              : #ifdef HAVE_OPENMP_OFFLOAD
    4178              :        !$OMP TARGET ENTER DATA MAP(alloc:h1_kets_kq, gvnlx1, kets_k, bras_kq) IF (dtset%gpu_option == ABI_GPU_OPENMP) NOWAIT
    4179              :        !$OMP TARGET ENTER DATA MAP(alloc:gs1c_kq) IF (dtset%gpu_option == ABI_GPU_OPENMP .and. sij_opt /= 0) NOWAIT
    4180              : #endif
    4181              : 
    4182              :        call gs_ham_kq%eph_setup_k("k" , kk_bz, istwf_k, npw_k, kg_k, dtset, cryst, psps, &
    4183        73591 :                                   nkpg_k, kpg_k, ffnl_k, kinpw_k, ph3d_k, gqk%pert_comm%value)
    4184              : 
    4185              : #ifdef HAVE_OPENMP_OFFLOAD
    4186              :        !$OMP TARGET ENTER DATA MAP(to:kpg_k, ffnl_k, kinpw_k, ph3d_k) IF (dtset%gpu_option == ABI_GPU_OPENMP) NOWAIT
    4187              : #endif
    4188              : 
    4189              :        call gs_ham_kq%eph_setup_k("kq", kq_bz, istwf_k, npw_kq, kg_kq, dtset, cryst, psps, &
    4190        73591 :                                   nkpg_kq, kpg_kq, ffnl_kq, kinpw_kq, ph3d_kq, gqk%pert_comm%value)
    4191              : 
    4192              : #ifdef HAVE_OPENMP_OFFLOAD
    4193              :        !$OMP TARGET ENTER DATA MAP(to:kpg_kq, ffnl_kq, kinpw_kq, ph3d_kq) IF (dtset%gpu_option == ABI_GPU_OPENMP) NOWAIT
    4194              : #endif
    4195              : 
    4196              :        !$OMP TASKWAIT
    4197              : 
    4198              :        ! Loop over my atomic perturbations and compute gkq_atm_ipc.
    4199      5483041 :        gkq_atm = zero
    4200       515137 :        do my_ip=1,my_npert
    4201       441546 :          idir = dvdb%my_pinfo(1, my_ip); ipert = dvdb%my_pinfo(2, my_ip); ipc = dvdb%my_pinfo(3, my_ip)
    4202              : 
    4203              :          ! Prepare application of the NL part.
    4204       441546 :          call rf_ham_kq%init(cplex, gs_ham_kq, ipert, has_e1kbsc=.true.)
    4205       441546 :          call rf_ham_kq%load_spin(spin, vlocal1=vlocal1(:,:,:,:,my_ip), with_nonlocal=.true.)
    4206              : 
    4207              : #if 1
    4208              :          ! Calculate dvscf * psi_k, results stored in h1_kets_kq on the k+q sphere.
    4209              :          ! Compute H(1) applied to GS wavefunction Psi(0)
    4210      1128636 :          do in_k=1,nb_k
    4211              :            ! Use scissor shift on 0-order eigenvalue
    4212       687090 :            band_k = in_k + gqk%bstart_k - 1
    4213      1128636 :            lambda(in_k) = ebands%eig(band_k, ik_ibz, spin) - dtset%dfpt_sciss
    4214              :          end do
    4215              :          !call ebands%get_dfpt_eshifted(gqk%bstart_k, nb_k, ik_ibz, spin, dtset%dfpt_sciss, lambda)
    4216              : 
    4217              :          call getgh1c(berryopt0, kets_k, cwaveprj0, h1_kets_kq, &
    4218              :                       grad_berry, gs1c_kq, gs_ham_kq, gvnlx1, idir, ipert, lambda, mpi_enreg, nb_k, optlocal, &
    4219       441546 :                       optnl, opt_gvnlx1, rf_ham_kq, sij_opt, tim_getgh1c, usevnl)
    4220              : 
    4221              : #else
    4222              :          do in_k=1,nb_k
    4223              :            ! Use scissor shift on 0-order eigenvalue
    4224              :            band_k = in_k + gqk%bstart_k - 1
    4225              :            eshift = ebands%eig(band_k, ik_ibz, spin) - dtset%dfpt_sciss
    4226              : 
    4227              :            call getgh1c(berryopt0, kets_k(:,:,in_k), cwaveprj0, h1_kets_kq(:,:,in_k), &
    4228              :                         grad_berry, gs1c_kq, gs_ham_kq, gvnlx1, idir, ipert, [eshift], mpi_enreg, ndat1, optlocal, &
    4229              :                         optnl, opt_gvnlx1, rf_ham_kq, sij_opt, tim_getgh1c, usevnl)
    4230              :          end do ! in_k
    4231              : #endif
    4232              : 
    4233       441546 :          call rf_ham_kq%free()
    4234              : 
    4235              :          ! Calculate <psi_{k+q,j}|dvscf_q*psi_{k,i}> for this perturbation. No need to handle istwf_kq because it's always 1.
    4236       441546 :          if (dtset%gpu_option == ABI_GPU_OPENMP) then
    4237              :            call abi_gpu_xgemm_d(2, 'C', 'N', nb_kq, nb_k, npw_kq*nspinor, cone, bras_kq, npw_kq*nspinor, &
    4238            0 :                                 h1_kets_kq, npw_kq*nspinor, czero, gkq_atm_ipc, nb_kq)
    4239              : #ifdef HAVE_OPENMP_OFFLOAD
    4240              :            !$OMP TARGET UPDATE FROM(gkq_atm_ipc)
    4241              : #endif
    4242              :          else
    4243              :            call ZGEMM('C', 'N', nb_kq, nb_k, npw_kq*nspinor, cone, bras_kq, npw_kq*nspinor, &
    4244       441546 :                       h1_kets_kq, npw_kq*nspinor, czero, gkq_atm_ipc, nb_kq)
    4245              :          end if
    4246              : 
    4247              :          ! Transfer data
    4248      5483041 :          gkq_atm(:,:,:,ipc) = gkq_atm_ipc
    4249              :        end do ! my_ip
    4250              : 
    4251              :        ! Collect gkq_atm inside pert_comm so that all procs can operate on the data.
    4252        73591 :        if (gqk%pert_comm%nproc > 1) call xmpi_sum(gkq_atm, gqk%pert_comm%value, ierr)
    4253              : 
    4254              :        ! Save e-ph matrix elements in the buffer.
    4255      5483041 :        my_gbuf(:,:,:,:, my_ik, iqbuf_cnt) = gkq_atm
    4256        73591 :        state_kq(my_ik, iqbuf_cnt) = GSTORE_KQ_COMPUTED
    4257              : 
    4258              : #ifdef HAVE_OPENMP_OFFLOAD
    4259              :        !$OMP TARGET EXIT DATA MAP(delete:kpg_k, ffnl_k, kinpw_k, ph3d_k) IF (dtset%gpu_option == ABI_GPU_OPENMP)
    4260              :        !$OMP TARGET EXIT DATA MAP(delete:kpg_kq, ffnl_kq, kinpw_kq, ph3d_kq) IF (dtset%gpu_option == ABI_GPU_OPENMP)
    4261              :        !$OMP TARGET EXIT DATA MAP(delete:h1_kets_kq, gvnlx1, kets_k, bras_kq) IF (dtset%gpu_option == ABI_GPU_OPENMP)
    4262              :        !$OMP TARGET EXIT DATA MAP(delete:gs1c_kq) IF (dtset%gpu_option == ABI_GPU_OPENMP .and. sij_opt /= 0)
    4263              : #endif
    4264        73591 :        ABI_FREE(ffnl_k)
    4265        73591 :        ABI_FREE(ffnl_kq)
    4266        73591 :        ABI_FREE(kpg_k)
    4267        73591 :        ABI_FREE(kpg_kq)
    4268        73591 :        ABI_FREE(ph3d_k)
    4269        73591 :        ABI_FREE(ph3d_kq)
    4270        73591 :        ABI_FREE(kinpw_k)
    4271        73591 :        ABI_FREE(kinpw_kq)
    4272        73591 :        ABI_FREE(kets_k)
    4273        73591 :        ABI_FREE(bras_kq)
    4274        73591 :        ABI_FREE(h1_kets_kq)
    4275        73591 :        ABI_FREE(gs1c_kq)
    4276        74468 :        ABI_FREE(gvnlx1)
    4277              :      end do ! my_ik
    4278              : 
    4279          877 :      ABI_FREE(v1scf)
    4280              : 
    4281              : #ifdef HAVE_OPENMP_OFFLOAD
    4282              :      do my_ip=1,my_npert
    4283              :        !$OMP TARGET EXIT DATA MAP(delete:vlocal1(:,:,:,:,my_ip)) IF (dtset%gpu_option == ABI_GPU_OPENMP)
    4284              :      end do
    4285              : #endif
    4286          877 :      ABI_FREE(vlocal1)
    4287              : 
    4288              :      ! Dump buffer
    4289          877 :      if (iqbuf_cnt == qbuf_size) call dump_my_gbuf()
    4290              : 
    4291          877 :      if (print_time) then
    4292          193 :        write(msg,'(2(a,i0),a)')" My q-point [", my_iq, "/", gqk%my_nq, "]"
    4293          193 :        call cwtime_report(msg, cpu_q, wall_q, gflops_q); if (my_iq == LOG_MODQ) call wrtout(std_out, "...", do_flush=.True.)
    4294              :      end if
    4295          882 :      call lg_myq%free()
    4296              :    end do ! my_iq
    4297              : 
    4298              :    ! Dump the remainder.
    4299            5 :    if (iqbuf_cnt /= 0) call dump_my_gbuf()
    4300              : 
    4301            5 :    ABI_FREE(state_kq)
    4302            5 :    ABI_FREE(iq_buf)
    4303            5 :    ABI_FREE(my_gbuf)
    4304            5 :    ABI_FREE(lambda)
    4305            5 :    ABI_FREE(gkq_atm)
    4306              : #ifdef HAVE_OPENMP_OFFLOAD
    4307              :    !$OMP TARGET EXIT DATA MAP(delete:gkq_atm_ipc) IF (dtset%gpu_option == ABI_GPU_OPENMP)
    4308              : #endif
    4309            5 :    ABI_FREE(gkq_atm_ipc)
    4310              : 
    4311           10 :    if (use_lgk) then
    4312            2 :      do my_ik=1,gqk%my_nk
    4313            2 :        call lg_myk(my_ik)%free()
    4314              :      end do
    4315            2 :      ABI_FREE(lg_myk)
    4316              :    end if
    4317              :  end do ! my_is
    4318              : 
    4319            5 :  call cwtime_report(" GSTORE computation done", cpu_all, wall_all, gflops_all, pre_str=ch10, end_str=ch10) !, comm=gstore%comm)
    4320              :  !call gstore%print([std_out], header="GSTORE at the end of gstore%compute")
    4321              : 
    4322              :  ! Set gstore_completed to 1 so that we can easily check if restarted is needed.
    4323              :  !if (my_rank == master) then
    4324            5 :    NCF_CHECK(nf90_put_var(root_ncid, root_vid("gstore_completed"), 1))
    4325              :  !end if
    4326              :  ! nf90_sync can deadlock on lemaitre4 for some MPI decompositions.
    4327            5 :  if (dtset%useria /= 888) then
    4328            5 :    NCF_CHECK(nf90_sync(root_ncid))
    4329              :  end if
    4330            5 :  NCF_CHECK(nf90_close(root_ncid))
    4331            5 :  call xmpi_barrier(gstore%comm)
    4332              : 
    4333              :  ! Free memory
    4334            5 :  ABI_FREE(grad_berry)
    4335            5 :  ABI_FREE(dummy_vtrial)
    4336            5 :  ABI_FREE(work)
    4337            5 :  ABI_FREE(ph1d)
    4338            5 :  ABI_FREE(vlocal)
    4339            5 :  ABI_FREE(kg_k)
    4340            5 :  ABI_FREE(kg_kq)
    4341            5 :  ABI_FREE(displ_cart_qibz)
    4342            5 :  ABI_FREE(done_qbz_spin)
    4343              : 
    4344            5 :  call gs_ham_kq%free(); call wfd%free()
    4345            5 :  call pawcprj_free(cwaveprj0)
    4346            5 :  ABI_FREE(cwaveprj0)
    4347              : 
    4348              :  ! Reconstruct g(k,q) matrix elements in the full BZ by symmetry.
    4349            5 :  if (symmetrize) then
    4350            0 :    call gstore_symmetrize(gstore%path, wfk0_path, ngfft, dtset, dtfil, cryst, psps, pawtab, ebands, ifc, comm)
    4351              :  end if
    4352              : 
    4353              :  ! Output some of the results to ab_out for testing purposes
    4354           30 :  call gstore%print_for_abitests(dtset, ebands, .True.)
    4355              : 
    4356              : contains
    4357              : 
    4358           56 : subroutine dump_my_gbuf()
    4359              : 
    4360              :  ! This function is called inside the double loop over (my_is, my_iq) or when we exit
    4361              :  ! from the my_iq loop to dump the remainder that is still in the q-buffer,
    4362              :  ! All the MPI procs in the (kpt_comm x pert_comm) grid shall call this contained routine
    4363              :  ! as we have side-effects i.e. iqbuf_cnt set to 0.
    4364              : 
    4365              :  ! On disk we have the global arrays:
    4366              :  !
    4367              :  !      nctkarr_t("gvals", "dp", "gstore_cplex, nb_kq, nb_k, natom3, glob_nk, glob_nq")
    4368              :  !
    4369              :  ! while the local MPI buffers are dimensioned as follows:
    4370              :  !
    4371              :  !      my_gbuf(2, nb_kq, nb_k, natom3, gqk%my_nk, qbuf_size)
    4372              : 
    4373              :  ! If parallelism over perturbation is activated, only the procs treating the first perturbation
    4374              :  ! i.e. the procs treating different k-points for this q are involved in IO
    4375              :  ! as all the local buffers store results for all natom3 perturbations.
    4376              : 
    4377              :  ! NOTE: A similar routine is used in m_gstore. The two implementations should be kept in synch.
    4378              : 
    4379              :  integer :: ii, iq_bz, iq_glob, my_iq
    4380              :  logical :: iscontiguous
    4381              : 
    4382           56 :  if (gqk%coords_qkpb_sumbp(3) /= 0) goto 10 ! Yes, I'm very proud of this GOTO.
    4383              : 
    4384              :  !if (dtset%prtvol > 5) then
    4385              :  !print *, "in dump_my_gbuf with start: ", [1, 1, 1, 1, gqk%my_kstart, iq_glob]
    4386              :  !print *, "                  count; ", [2, gqk%nb_kq, gqk%nb_k, gqk%natom3, gqk%my_nk, iqbuf_cnt]
    4387              :  !end if
    4388              : 
    4389              :  ! Check if the q-points in the buffer are perfectly contiguous (no cycles/holes)
    4390           56 :  iscontiguous = .True.
    4391          933 :  do ii=1, iqbuf_cnt
    4392          877 :    my_iq = iq_buf(1, ii)
    4393          877 :    if (my_iq == 0) then
    4394              :      iscontiguous = .False.; exit
    4395              :    end if
    4396          933 :    if (ii > 1) then
    4397          821 :      if (my_iq /= iq_buf(1, ii-1) + 1) then
    4398              :        iscontiguous = .False.; exit
    4399              :      end if
    4400              :    end if
    4401              :  end do
    4402              : 
    4403           56 :  if (iscontiguous) then
    4404              :    ! Fast path: Write slabs directly
    4405           56 :    my_iq = iq_buf(1, 1)
    4406           56 :    iq_glob = my_iq + gqk%my_qstart - 1
    4407              : 
    4408              :    ncerr = nf90_put_var(spin_ncid, spin_vid("gvals"), my_gbuf(:,:,:,:,:, 1:iqbuf_cnt), &
    4409              :                         start=[1, 1, 1, 1, gqk%my_kstart, iq_glob], &
    4410          728 :                         count=[2, gqk%nb_kq, gqk%nb_k, gqk%natom3, gqk%my_nk, iqbuf_cnt])
    4411           56 :    NCF_CHECK(ncerr)
    4412              : 
    4413              :    ncerr = nf90_put_var(root_ncid, root_vid("gstore_glob_state_kqs"), state_kq(:, 1:iqbuf_cnt), &
    4414              :                         start=[gqk%my_kstart, iq_glob, spin], &
    4415          392 :                         count=[gqk%my_nk, iqbuf_cnt, 1])
    4416           56 :    NCF_CHECK(ncerr)
    4417              :  else
    4418              :    ! Slow path: Q-points were filtered, write slice by slice avoiding holes
    4419            0 :    do ii=1, iqbuf_cnt
    4420            0 :      my_iq = iq_buf(1, ii)
    4421            0 :      if (my_iq == 0) cycle
    4422            0 :      iq_glob = my_iq + gqk%my_qstart - 1
    4423              : 
    4424              :      ncerr = nf90_put_var(spin_ncid, spin_vid("gvals"), my_gbuf(:,:,:,:,:, ii), &
    4425              :                           start=[1, 1, 1, 1, gqk%my_kstart, iq_glob], &
    4426            0 :                           count=[2, gqk%nb_kq, gqk%nb_k, gqk%natom3, gqk%my_nk, 1])
    4427            0 :      NCF_CHECK(ncerr)
    4428              : 
    4429              :      ncerr = nf90_put_var(root_ncid, root_vid("gstore_glob_state_kqs"), state_kq(:, ii), &
    4430              :                           start=[gqk%my_kstart, iq_glob, spin], &
    4431            0 :                           count=[gqk%my_nk, 1, 1])
    4432            0 :      NCF_CHECK(ncerr)
    4433              :    end do
    4434              :  end if
    4435              : 
    4436              :  ! Only one proc sets the entry in done_qbz_spin to 1 for all the q-points in the buffer.
    4437              :  !if (all(gqk%coords_qkpb_sumbp(2:3) == [0, 0]))  then
    4438          933 :    do ii=1,iqbuf_cnt
    4439          877 :      my_iq = iq_buf(1, ii)
    4440          877 :      if (my_iq == 0) cycle
    4441          877 :      iq_bz = iq_buf(2, ii)
    4442         2687 :      NCF_CHECK(nf90_put_var(root_ncid, root_vid("gstore_done_qbz_spin"), 1, start=[iq_bz, spin]))
    4443              :    end do
    4444              :  !end if
    4445              : 
    4446              :  ! Zero the counter before returning
    4447           56 : 10 iqbuf_cnt = 0
    4448         2744 :  iq_buf = 0
    4449        76088 :  state_kq = GSTORE_KQ_MISSING
    4450              : 
    4451              :  ! These syncs can deadlock on lemaitre4 for some MPI decompositions.
    4452           56 :  if (dtset%useria /= 888) then
    4453           56 :    NCF_CHECK(nf90_sync(spin_ncid))
    4454           56 :    NCF_CHECK(nf90_sync(root_ncid))
    4455              :  end if
    4456              : 
    4457           56 : end subroutine dump_my_gbuf
    4458              : 
    4459          943 : integer function root_vid(var_name)
    4460              :   character(len=*),intent(in) :: var_name
    4461          943 :   root_vid = nctk_idname(root_ncid, var_name)
    4462              : end function root_vid
    4463              : 
    4464           56 : integer function spin_vid(var_name)
    4465              :   character(len=*),intent(in) :: var_name
    4466           56 :   spin_vid = nctk_idname(spin_ncid, var_name)
    4467              : end function spin_vid
    4468              : 
    4469              : end subroutine gstore_compute
    4470              : !!***
    4471              : 
    4472              : !----------------------------------------------------------------------
    4473              : 
    4474              : !!****f* m_gstore/gstore_check_qkzone_gmode
    4475              : !! NAME
    4476              : !! gstore_check_cplex_qkzone_gmode
    4477              : !!
    4478              : !! FUNCTION
    4479              : !! Perform consistency checks
    4480              : !!
    4481              : !! INPUTS
    4482              : !!
    4483              : !! SOURCE
    4484              : 
    4485            9 : integer function gstore_check_cplex_qkzone_gmode(gstore, cplex, qzone, kzone, gmode, &
    4486              :                                                  kfilter, check_alloc) result(ierr)  ! optional
    4487              : 
    4488              : !Arguments ------------------------------------
    4489              :  class(gstore_t),target,intent(in) :: gstore
    4490              :  integer,intent(in) :: cplex
    4491              :  character(len=*),intent(in) :: qzone, kzone, gmode
    4492              :  character(len=*),optional,intent(in) :: kfilter
    4493              :  logical,optional,intent(in) :: check_alloc
    4494              : 
    4495              : !Local variables-------------------------------
    4496              :  integer :: my_is
    4497              :  logical :: check_alloc__
    4498              : ! *************************************************************************
    4499              : 
    4500            9 :  ierr = 0
    4501            9 :  ABI_CHECK_NOSTOP(gstore%qzone == qzone, sjoin("qzone: ", qzone, "required but got: ", gstore%qzone), ierr)
    4502            9 :  ABI_CHECK_NOSTOP(gstore%kzone == kzone, sjoin("kzone: ", kzone, "required but got: ", gstore%kzone), ierr)
    4503            9 :  ABI_CHECK_NOSTOP(gstore%gmode == gmode, sjoin("gmode: ", gmode, "required but got: ", gstore%gmode), ierr)
    4504            9 :  if (present(kfilter)) then
    4505            0 :    ABI_CHECK_NOSTOP(gstore%kfilter == kfilter, sjoin("kfilter: ", kfilter, "required but got: ", gstore%kfilter), ierr)
    4506              :  end if
    4507              : 
    4508            9 :  check_alloc__ = .True.; if (present(check_alloc)) check_alloc__ = check_alloc
    4509              : 
    4510           18 :  do my_is=1,gstore%my_nspins
    4511            9 :    associate (gqk => gstore%gqk(my_is))
    4512            0 :    ABI_CHECK_NOSTOP(gqk%cplex == cplex, sjoin("cplex:", itoa(cplex), "required but got: ", itoa(gqk%cplex)), ierr)
    4513            9 :    if (check_alloc__) then
    4514            9 :      if (cplex == 1) then
    4515            0 :        ABI_CHECK_NOSTOP(allocated(gqk%my_g2), "my_g2 array is not allocated", ierr)
    4516            9 :      else if (cplex == 2) then
    4517            9 :        ABI_CHECK_NOSTOP(allocated(gqk%my_g), "my_g array is not allocated", ierr)
    4518              :      end if
    4519              :    end if
    4520              :    end associate
    4521              :  end do
    4522              : 
    4523            9 : end function gstore_check_cplex_qkzone_gmode
    4524              : !!***
    4525              : 
    4526              : !----------------------------------------------------------------------
    4527              : 
    4528              : !!****f* m_gstore/gstore_from_ncpath
    4529              : !! NAME
    4530              : !! gstore_from_ncpath
    4531              : !!
    4532              : !! FUNCTION
    4533              : !!  Reconstruct a gstore_t instance from a netcdf file.
    4534              : !!
    4535              : !! INPUTS
    4536              : !!  path: Path to the GSTORE file.
    4537              : !!  with_cplex: 0 to read no matrix elements, 1 for |g|^2, 2 for complex g.
    4538              : !!    with_gmode defines the representation.
    4539              : !!  dtset: Input variables
    4540              : !!  cryst: crystalline structure
    4541              : !!  ebands: KS energies
    4542              : !!  ifc: interatomic force constants
    4543              : !!  with_gmode: "phonon" to have g in the phonon representation or "atom" to have them in atom representation.
    4544              : !!  gvals_name: "gvals" or "gvals_ks" to read the KS gs produced by the GWPT code.
    4545              : !!    This option is valid only for gstore files produced by the GWPT code.
    4546              : !!  with_g2dw: True if Debye-Waller g2 in the RIA should be computed and stored in memory.
    4547              : !!  comm: MPI communicator.
    4548              : !!
    4549              : !! SOURCE
    4550              : 
    4551           16 : subroutine gstore_from_ncpath(gstore, path, with_cplex, dtset, dtfil, cryst, ebands, ifc, &
    4552              :                               with_gmode, gvals_name, with_g2dw, comm)
    4553              : 
    4554              : !Arguments ------------------------------------
    4555              :  class(gstore_t),target,intent(out) :: gstore
    4556              :  character(len=*),intent(in) :: path
    4557              :  integer,intent(in) :: with_cplex
    4558              :  type(dataset_type),target,intent(in) :: dtset
    4559              :  type(datafiles_type),intent(in) :: dtfil
    4560              :  class(crystal_t),target,intent(in) :: cryst
    4561              :  class(ebands_t),target,intent(in) :: ebands
    4562              :  class(ifc_type),target,intent(in) :: ifc
    4563              :  character(len=*),intent(in) :: with_gmode, gvals_name
    4564              :  logical,intent(in) :: with_g2dw
    4565              :  integer,intent(in) :: comm
    4566              : 
    4567              : !Local variables-------------------------------
    4568              : !scalars
    4569              :  integer,parameter :: master = 0
    4570              :  integer :: my_rank, ncid, spin, spin_ncid, nproc, ierr, fform, max_nb, ib, natom, natom3, ib_m, ib_n !, varid
    4571              :  integer :: max_nq, max_nk, ncerr, my_is, my_iq, iq_glob, my_ik, ik_glob
    4572              :  integer :: nb_k, nb_kq, nb_k_file, nb_kq_file, gstore_cplex, ib_kq_start !, ip1, ip2
    4573              :  integer :: my_ip, ipert, iq_ibz, iq_bz, isym_q, trev_q, tsign_q, ii !, im_kq
    4574              :  real(dp),parameter :: G_SMALL = tol8
    4575              :  real(dp) :: cpu, wall, gflops, wqnu
    4576              :  logical :: isirr_q, from_atm_to_nu, has_iv1p_comm, read_ks, has_both_g
    4577           16 :  type(hdr_type) :: wfk0_hdr
    4578          832 :  type(crystal_t) :: gstore_cryst
    4579              :  type(gqk_t),pointer :: gqk
    4580              :  character(len=500) :: msg
    4581              : !arrays
    4582           64 :  integer :: units(2), ibuffer(9), nproc_spin(ebands%nsppol), comm_spin(ebands%nsppol)
    4583           32 :  integer :: brange_k_spin(2, ebands%nsppol), brange_kq_spin(2, ebands%nsppol), file_brange_kq_spin(2, ebands%nsppol), g0_q(3)
    4584           16 :  integer,allocatable :: qglob2bz(:,:), qbz2ibz(:,:)
    4585              :  real(dp) :: qq_ibz(3)
    4586           32 :  real(dp) :: displ_nu_red(2, 3, cryst%natom)
    4587           16 :  real(dp),allocatable :: gwork_q(:,:,:,:,:), slice_bb(:,:,:), iv1p_comm(:,:,:,:,:)
    4588           16 :  real(dp),allocatable :: ks_gwork_q(:,:,:,:,:), ks_slice_bb(:,:,:)
    4589           16 :  real(dp),allocatable :: phfreqs_ibz(:,:), pheigvec_cart_ibz(:,:,:,:,:), pheigvec_cart_qbz(:,:,:,:)
    4590           16 :  real(dp),allocatable :: displ_cart_qbz(:,:,:,:), displ_red_qbz(:,:,:,:), gmn_nu(:,:,:,:)
    4591           16 :  complex(dp),allocatable :: tpp_red(:,:), my_gq0nm_atm(:,:,:,:), ks_my_gq0nm_atm(:,:,:,:)
    4592              : ! *************************************************************************
    4593              : 
    4594           16 :  my_rank = xmpi_comm_rank(comm); nproc = xmpi_comm_size(comm)
    4595              : 
    4596           16 :  ABI_CHECK(with_cplex >= 0 .and. with_cplex <= 2, sjoin("Invalid with_cplex:", itoa(with_cplex)))
    4597              : 
    4598           48 :  units = [std_out, ab_out]
    4599           16 :  call wrtout(units, sjoin("- Reading e-ph matrix elements from: ", path), pre_newlines=1)
    4600           16 :  call wrtout(units, sjoin(" Asking for with_cplex: ", itoa(with_cplex)))
    4601           16 :  call wrtout(units, sjoin(" Asking for with_gmode: ", trim(with_gmode)))
    4602           16 :  call wrtout(units, sjoin(" Asking for gvals_name: ", trim(gvals_name)))
    4603           16 :  call wrtout(units, sjoin(" Asking for g2dw: ", yesno(with_g2dw)))
    4604              : 
    4605              :  ! Set basic parameters.
    4606           16 :  gstore%comm = comm; gstore%nsppol = dtset%nsppol; gstore%path = path
    4607              : 
    4608              :  ! Get references to other data structures.
    4609           16 :  gstore%dtset => dtset; gstore%cryst => cryst; gstore%ebands => ebands; gstore%ifc => ifc; gstore%kibz => ebands%kptns
    4610              : 
    4611           16 :  natom = cryst%natom; natom3 = cryst%natom * 3
    4612              : 
    4613           96 :  ABI_CALLOC(gstore%erange_spin, (2, gstore%nsppol))
    4614           48 :  ABI_MALLOC(gstore%glob_nk_spin, (gstore%nsppol))
    4615           48 :  ABI_MALLOC(gstore%glob_nq_spin, (gstore%nsppol))
    4616              : 
    4617              :  ! =====================================================
    4618              :  ! Master node reads basic objects and gstore dimensions
    4619              :  ! =====================================================
    4620              : 
    4621           16 :  if (my_rank == master) then
    4622           16 :    call wrtout(units, sjoin(" Initializing gstore object from:", path, ch10))
    4623           16 :    ABI_CHECK(path /= ABI_NOFILE, "Use getgstore_filepath to specify the path to GSTORE.nc")
    4624           16 :    NCF_CHECK(nctk_open_read(ncid, path, xmpi_comm_self))
    4625              : 
    4626           16 :    call wfk0_hdr%ncread(ncid, fform)
    4627           16 :    ABI_CHECK(fform /= 0, sjoin("Error while reading:", path))
    4628              : 
    4629              :    ! Read gstore dimensions
    4630           16 :    NCF_CHECK(nctk_get_dim(ncid, "gstore_cplex", gstore_cplex))
    4631           16 :    ABI_CHECK_IEQ(gstore_cplex, 2, "gstore_cplex 1 from file not supported")
    4632           16 :    NCF_CHECK(nctk_get_dim(ncid, "gstore_nkibz", gstore%nkibz))
    4633           16 :    NCF_CHECK(nctk_get_dim(ncid, "gstore_nkbz", gstore%nkbz))
    4634           16 :    NCF_CHECK(nctk_get_dim(ncid, "gstore_nqibz", gstore%nqibz))
    4635           16 :    NCF_CHECK(nctk_get_dim(ncid, "gstore_nqbz", gstore%nqbz))
    4636           16 :    NCF_CHECK(nctk_get_dim(ncid, "gstore_max_nq", max_nq))
    4637           16 :    NCF_CHECK(nctk_get_dim(ncid, "gstore_max_nk", max_nk))
    4638           16 :    NCF_CHECK(nctk_get_dim(ncid, "gstore_max_nb", max_nb))
    4639              : 
    4640              :    ! Read gstore variables
    4641           16 :    NCF_CHECK(nf90_get_var(ncid, vid("gstore_with_vk"), gstore%with_vk))
    4642           16 :    NCF_CHECK(nf90_get_var(ncid, vid("gstore_qptopt"), gstore%qptopt))
    4643              : 
    4644              :    ! little group variables were added in Abinit v10.5.6.
    4645           16 :    NCF_CHECK(nf90_get_var(ncid, vid("gstore_use_lgk"), gstore%has_used_lgk))
    4646           16 :    NCF_CHECK(nf90_get_var(ncid, vid("gstore_use_lgq"), gstore%has_used_lgq))
    4647           16 :    NCF_CHECK(nf90_get_var(ncid, vid("gstore_kzone"), gstore%kzone))
    4648           16 :    NCF_CHECK(nf90_get_var(ncid, vid("gstore_qzone"), gstore%qzone))
    4649           16 :    NCF_CHECK(nf90_get_var(ncid, vid("gstore_kfilter"), gstore%kfilter))
    4650           16 :    NCF_CHECK(nf90_get_var(ncid, vid("gstore_wfk0_path"), gstore%wfk0_path))
    4651           16 :    call replace_ch0(gstore%kzone); call replace_ch0(gstore%qzone); call replace_ch0(gstore%kfilter)
    4652           16 :    call replace_ch0(gstore%wfk0_path)
    4653              : 
    4654           16 :    NCF_CHECK(nf90_get_var(ncid, vid("gstore_gtype"), gstore%gtype))
    4655           16 :    call replace_ch0(gstore%gtype)
    4656              :    !print *, "gstore%gtype:", gstore%gtype
    4657              : 
    4658           16 :    if (gvals_name == "gvals_ks") then
    4659            2 :      call wrtout(units, " Reading KS e-ph matrix elements")
    4660           14 :    else if (gvals_name == "gvals") then
    4661           14 :      if (gstore%gtype == GSTORE_GTYPE_GWPT) then
    4662            4 :        call wrtout(units, " Reading GWPT e-ph matrix elements")
    4663              :      else
    4664           10 :        call wrtout(units, " Reading KS e-ph matrix elements")
    4665              :      end if
    4666              :    end if
    4667              : 
    4668           16 :    NCF_CHECK(nf90_get_var(ncid, vid("gstore_ngqpt"), gstore%ngqpt))
    4669              : 
    4670           48 :    ABI_MALLOC(gstore%qibz, (3, gstore%nqibz))
    4671           48 :    ABI_MALLOC(gstore%wtq, (gstore%nqibz))
    4672           48 :    ABI_MALLOC(gstore%qbz, (3, gstore%nqbz))
    4673           48 :    ABI_MALLOC(gstore%kbz, (3, gstore%nkbz))
    4674           16 :    NCF_CHECK(nf90_get_var(ncid, vid("gstore_brange_k_spin"), brange_k_spin))
    4675           16 :    NCF_CHECK(nf90_get_var(ncid, vid("gstore_brange_kq_spin"), brange_kq_spin))
    4676           16 :    NCF_CHECK(nf90_get_var(ncid, vid("gstore_erange_spin"), gstore%erange_spin))
    4677           16 :    NCF_CHECK(nf90_get_var(ncid, vid("gstore_qibz"), gstore%qibz))
    4678           16 :    NCF_CHECK(nf90_get_var(ncid, vid("gstore_wtq"), gstore%wtq))
    4679           16 :    NCF_CHECK(nf90_get_var(ncid, vid("gstore_qbz"), gstore%qbz))
    4680           16 :    NCF_CHECK(nf90_get_var(ncid, vid("gstore_kbz"), gstore%kbz))
    4681              : 
    4682           48 :    ABI_MALLOC(qbz2ibz, (6, gstore%nqbz))
    4683           48 :    ABI_MALLOC(gstore%kbz2ibz, (6, gstore%nkbz))
    4684           16 :    NCF_CHECK(nf90_get_var(ncid, vid("gstore_qbz2ibz"), qbz2ibz))
    4685           16 :    NCF_CHECK(nf90_get_var(ncid, vid("gstore_kbz2ibz"), gstore%kbz2ibz))
    4686              : 
    4687           64 :    ABI_MALLOC(qglob2bz, (max_nq, gstore%nsppol))
    4688           64 :    ABI_MALLOC(gstore%kglob2bz, (max_nk, gstore%nsppol))
    4689           16 :    NCF_CHECK(nf90_get_var(ncid, vid("gstore_qglob2bz"), qglob2bz))
    4690           16 :    NCF_CHECK(nf90_get_var(ncid, vid("gstore_kglob2bz"), gstore%kglob2bz))
    4691           16 :    NCF_CHECK(nf90_get_var(ncid, vid("gstore_glob_nq_spin"), gstore%glob_nq_spin))
    4692           16 :    NCF_CHECK(nf90_get_var(ncid, vid("gstore_glob_nk_spin"), gstore%glob_nk_spin))
    4693              : 
    4694              :    ! Read optional variables:
    4695           16 :    if (gstore%kfilter == "fs_tetra") then
    4696            0 :      ABI_MALLOC(gstore%delta_ef_kibz_spin, (max_nb, gstore%nkibz, gstore%nsppol))
    4697            0 :      NCF_CHECK(nf90_get_var(ncid, vid("gstore_delta_ef_kibz_spin"), gstore%delta_ef_kibz_spin))
    4698              :    end if
    4699              : 
    4700           16 :    NCF_CHECK(nf90_close(ncid))
    4701              : 
    4702              :    ! =================
    4703              :    ! Consistency check
    4704              :    ! =================
    4705           16 :    gstore_cryst = wfk0_hdr%get_crystal()
    4706           16 :    if (cryst%compare(gstore_cryst, header=" Comparing input crystal with the one from GSTORE file") /= 0) then
    4707            0 :      ABI_ERROR("Crystal structure from input and GSTORE do not agree! Check messages above!")
    4708              :    end if
    4709           16 :    call gstore_cryst%free()
    4710              :  end if ! master
    4711              : 
    4712           16 :  if (nproc > 1) then
    4713              :    ! Broadcast the header.
    4714            0 :    call wfk0_hdr%bcast(master, my_rank, comm)
    4715              : 
    4716              :    ! Broadcast dimensions.
    4717            0 :    if (my_rank == master) then
    4718            0 :      ibuffer = [gstore_cplex, gstore%nkibz, gstore%nkbz, gstore%nqibz, gstore%nqbz, gstore%with_vk, max_nq, max_nk, max_nb]
    4719              :    end if
    4720            0 :    call xmpi_bcast(ibuffer, master, comm, ierr)
    4721              : 
    4722            0 :    if (my_rank /= master) then
    4723              :      ! Other MPI procs need to store dims and allocate memory before the bcast.
    4724            0 :      gstore_cplex = ibuffer(1)
    4725            0 :      gstore%nkibz = ibuffer(2)
    4726            0 :      gstore%nkbz = ibuffer(3)
    4727            0 :      gstore%nqibz = ibuffer(4)
    4728            0 :      gstore%nqbz = ibuffer(5)
    4729            0 :      gstore%with_vk = ibuffer(6)
    4730            0 :      max_nq = ibuffer(7)
    4731            0 :      max_nk = ibuffer(8)
    4732            0 :      max_nb = ibuffer(9)
    4733              : 
    4734            0 :      ABI_MALLOC(gstore%qibz, (3, gstore%nqibz))
    4735            0 :      ABI_MALLOC(gstore%wtq, (gstore%nqibz))
    4736            0 :      ABI_MALLOC(gstore%qbz, (3, gstore%nqbz))
    4737            0 :      ABI_MALLOC(gstore%kbz, (3, gstore%nkbz))
    4738            0 :      ABI_MALLOC(qbz2ibz, (6, gstore%nqbz))
    4739            0 :      ABI_MALLOC(gstore%kbz2ibz, (6, gstore%nkbz))
    4740            0 :      ABI_MALLOC(qglob2bz, (max_nq, gstore%nsppol))
    4741            0 :      ABI_MALLOC(gstore%kglob2bz, (max_nk, gstore%nsppol))
    4742              :    end if
    4743              : 
    4744            0 :    call xmpi_bcast(gstore%qptopt, master, comm, ierr)
    4745            0 :    call xmpi_bcast(gstore%has_used_lgk, master, comm, ierr)
    4746            0 :    call xmpi_bcast(gstore%has_used_lgq, master, comm, ierr)
    4747            0 :    call xmpi_bcast(gstore%kzone, master, comm, ierr)
    4748            0 :    call xmpi_bcast(gstore%qzone, master, comm, ierr)
    4749            0 :    call xmpi_bcast(gstore%kfilter, master, comm, ierr)
    4750            0 :    call xmpi_bcast(gstore%gmode, master, comm, ierr)
    4751            0 :    call xmpi_bcast(gstore%gtype, master, comm, ierr)
    4752            0 :    call xmpi_bcast(gstore%ngqpt, master, comm, ierr)
    4753            0 :    call xmpi_bcast(gstore%wfk0_path, master, comm, ierr)
    4754            0 :    call xmpi_bcast(brange_k_spin, master, comm, ierr)
    4755            0 :    call xmpi_bcast(brange_kq_spin, master, comm, ierr)
    4756            0 :    call xmpi_bcast(gstore%erange_spin, master, comm, ierr)
    4757            0 :    call xmpi_bcast(gstore%qibz, master, comm, ierr)
    4758            0 :    call xmpi_bcast(gstore%wtq, master, comm, ierr)
    4759            0 :    call xmpi_bcast(gstore%qbz, master, comm, ierr)
    4760            0 :    call xmpi_bcast(gstore%kbz, master, comm, ierr)
    4761            0 :    call xmpi_bcast(qbz2ibz, master, comm, ierr)
    4762            0 :    call xmpi_bcast(gstore%kbz2ibz, master, comm, ierr)
    4763            0 :    call xmpi_bcast(qglob2bz, master, comm, ierr)
    4764            0 :    call xmpi_bcast(gstore%kglob2bz, master, comm, ierr)
    4765            0 :    call xmpi_bcast(gstore%glob_nq_spin, master, comm, ierr)
    4766            0 :    call xmpi_bcast(gstore%glob_nk_spin, master, comm, ierr)
    4767              : 
    4768            0 :    if (gstore%kfilter == "fs_tetra") then
    4769            0 :      if (my_rank /= master) then
    4770            0 :        ABI_MALLOC(gstore%delta_ef_kibz_spin, (max_nb, gstore%nkibz, gstore%nsppol))
    4771              :      end if
    4772            0 :      call xmpi_bcast(gstore%delta_ef_kibz_spin, master, comm, ierr)
    4773              :    end if
    4774              :  end if ! nproc > 1.
    4775              : 
    4776              :  ! Consistency check
    4777           16 :  call wfk0_hdr%vs_dtset(dtset); call wfk0_hdr%free()
    4778              : 
    4779              :  ! When reading an existing GSTORE file, gstore_brange selects a smaller window of
    4780              :  ! intermediate states at k+q. The external-state window at k is always the one on disk.
    4781              :  ! Keep the file range to compute the offset in the NetCDF nb_kq dimension below.
    4782           64 :  file_brange_kq_spin = brange_kq_spin
    4783           32 :  do spin=1,gstore%nsppol
    4784           62 :    if (any(dtset%gstore_brange(:, spin) /= 0)) then
    4785            3 :      ABI_CHECK(all(dtset%gstore_brange(:, spin) /= 0), "Both entries of gstore_brange must be specified")
    4786            1 :      ABI_CHECK_IEQ(dtset%gstore_brange(2, spin), dtset%mband, "gstore_brange(2, spin) must be equal to nband")
    4787            1 :      if (dtset%eph_stern /= 0) then
    4788            1 :        ABI_CHECK_IEQ(dtset%gstore_brange(1, spin), 1, "gstore_brange(1, spin) must be 1 when eph_stern is enabled")
    4789              :      end if
    4790              :      msg = sjoin("Requested gstore_brange:", ltoa(dtset%gstore_brange(:, spin)), "is not contained in the k+q band range stored in GSTORE.nc:", &
    4791            1 :        ltoa(file_brange_kq_spin(:, spin)))
    4792            1 :      ABI_CHECK(dtset%gstore_brange(1, spin) >= file_brange_kq_spin(1, spin) .and. dtset%gstore_brange(2, spin) <= file_brange_kq_spin(2, spin), msg)
    4793            3 :      brange_kq_spin(:, spin) = dtset%gstore_brange(:, spin)
    4794              :      call wrtout(units, sjoin(" Restricting k+q states for spin", itoa(spin), "to gstore_brange:", &
    4795            1 :                  ltoa(brange_kq_spin(:, spin))))
    4796              :    end if
    4797              :  end do
    4798              : 
    4799              :  ! If has_both_g is true, we allocate and read both the KS and the GWPT matrix elements.
    4800           16 :  read_ks = gstore%gtype == GSTORE_GTYPE_GWPT
    4801           16 :  has_both_g = gstore%gtype == GSTORE_GTYPE_GWPT
    4802              : 
    4803              :  ! Distribute spins, create indirect mapping to spin index and init gstore%brange_k_spin
    4804           16 :  call gstore%distribute_spins__(ebands%mband, brange_kq_spin, brange_k_spin, nproc_spin, comm_spin, comm)
    4805              : 
    4806              :  ! Compute krank
    4807           16 :  call gstore%krank_ibz%from_kptrlatt(gstore%nkibz, gstore%kibz, ebands%kptrlatt, compute_invrank=.False.)
    4808              : 
    4809           16 :  call gstore%set_mpi_grid__(dtfil, nproc_spin, comm_spin)
    4810              : 
    4811              :  ! At this point, we have the Cartesian grid (one per spin if any) and we can finally allocate and distribute other arrays.
    4812           16 :  call gstore%malloc__(with_cplex, has_both_g, max_nq, qglob2bz, max_nk, gstore%kglob2bz, qbz2ibz, gstore%kbz2ibz)
    4813              : 
    4814           16 :  call xmpi_comm_free(comm_spin)
    4815              : 
    4816              :  ! Now we read the big arrays with MPI-IO and hdf5 groups.
    4817              :  ! Note the loop over spin as each gqk has its own dimensions.
    4818              :  ! Recall the shape of the arrays:
    4819              :  !
    4820              :  ! In memory, we have allocated:
    4821              :  !
    4822              :  !    my_g(my_npert, nb_kq, my_nq, nb_k, my_nk) if with_cplex == 2 (complex array)
    4823              :  !
    4824              :  ! or
    4825              :  !
    4826              :  !    my_g2(my_npert, nb_kq, my_nq, nb_k, my_nk) if with_cplex == 1
    4827              :  !
    4828              :  ! On disk, we have:
    4829              :  !
    4830              :  !   nctkarr_t("gvals", "dp", "two, nb_kq_disk, nb_k_disk, natom3, glob_nk, glob_nq")
    4831              :  !
    4832           16 :  call cwtime(cpu, wall, gflops, "start")
    4833              : 
    4834              :  ! ===================================================
    4835              :  ! Load phonon frequencies and eigenvectors in the IBZ
    4836              :  ! ===================================================
    4837              : 
    4838              :  ! nctkarr_t("phfreqs_ibz", "dp", "natom3, gstore_nqibz")
    4839              :  ! nctkarr_t("pheigvec_cart_ibz", "dp", "two, three, natom, natom3, gstore_nqibz")
    4840           64 :  ABI_MALLOC(phfreqs_ibz, (natom3, gstore%nqibz))
    4841           80 :  ABI_MALLOC(pheigvec_cart_ibz, (2, 3, cryst%natom, cryst%natom * 3, gstore%nqibz))
    4842           64 :  ABI_MALLOC(pheigvec_cart_qbz, (2, 3, cryst%natom, cryst%natom * 3))
    4843           48 :  ABI_MALLOC(displ_cart_qbz, (2, 3, cryst%natom, cryst%natom * 3))
    4844           64 :  ABI_MALLOC(displ_red_qbz, (2, 3, cryst%natom, natom3))
    4845              : 
    4846           16 :  NCF_CHECK(nctk_open_read(ncid, gstore%path, gstore%comm))
    4847           16 :  has_iv1p_comm = gstore_nc_has_iv1p_comm(gstore, ncid)
    4848              : 
    4849           16 :  if (nproc > 1) then
    4850            0 :    NCF_CHECK(nctk_set_collective(ncid, vid("phfreqs_ibz")))
    4851            0 :    NCF_CHECK(nctk_set_collective(ncid, vid("pheigvec_cart_ibz")))
    4852              :  end if
    4853           16 :  NCF_CHECK(nf90_get_var(ncid, vid("phfreqs_ibz"), phfreqs_ibz))
    4854           16 :  NCF_CHECK(nf90_get_var(ncid, vid("pheigvec_cart_ibz"), pheigvec_cart_ibz))
    4855           16 :  NCF_CHECK(nf90_close(ncid))
    4856              : 
    4857              :  ! =========================
    4858              :  ! Load e-ph matrix elements
    4859              :  ! =========================
    4860           16 :  call pstat_proc%print(_PSTAT_ARGS_)
    4861              : 
    4862           16 :  from_atm_to_nu = .False.
    4863              :  ! Compare with_gmode with the one on disk. The only conversion I can think of is: atom --> phonon.
    4864           16 :  if (gstore%gmode /= with_gmode) then
    4865           16 :    if (gstore%gmode == GSTORE_GMODE_ATOM .and. with_gmode == GSTORE_GMODE_PHONON) then
    4866           16 :      from_atm_to_nu = .True.; gstore%gmode = GSTORE_GMODE_PHONON ! Change gstore%gmode here
    4867              :    else
    4868            0 :      ABI_ERROR(sjoin("Conversion from gstore%gmode: ", gstore%gmode, "to:", with_gmode, " is not yet supported"))
    4869              :    end if
    4870              :  end if
    4871           16 :  gstore%gmode = with_gmode
    4872              : 
    4873           16 :  if (with_g2dw) then
    4874            7 :    ABI_CHECK(with_gmode == GSTORE_GMODE_PHONON, "g2dw in the atom representation is not coded")
    4875           28 :    ABI_MALLOC(tpp_red, (natom3, natom3))
    4876              :  end if
    4877              : 
    4878           32 :  do spin=1,gstore%nsppol
    4879           16 :    my_is = gstore%spin2my_is(spin)
    4880              : 
    4881           32 :    if (my_is /= 0) then
    4882           16 :      gqk => gstore%gqk(my_is)
    4883              : 
    4884           64 :      ABI_MALLOC(gqk%my_wnuq, (gqk%my_npert, gqk%my_nq))
    4885           80 :      ABI_MALLOC(gqk%my_displ_cart, (2, 3, cryst%natom, gqk%my_npert, gqk%my_nq))
    4886              : 
    4887           16 :      NCF_CHECK(nctk_open_read(ncid, gstore%path, gqk%comm%value))
    4888           16 :      NCF_CHECK(nf90_inq_ncid(ncid, strcat("gqk", "_spin", itoa(spin)), spin_ncid))
    4889              : 
    4890           16 :      NCF_CHECK(nctk_get_dim(spin_ncid, "nb_k", nb_k_file))
    4891           16 :      NCF_CHECK(nctk_get_dim(spin_ncid, "nb_kq", nb_kq_file))
    4892              : 
    4893              :      ! Note that these dimensions should be compatible with what is stored on disk.
    4894           16 :      nb_k = gqk%nb_k; nb_kq = gqk%nb_kq
    4895           16 :      ABI_CHECK_IEQ(nb_k, nb_k_file, "nb_k !/ nb_k_file")
    4896           16 :      ABI_CHECK_ILEQ(nb_kq, nb_kq_file, "nb_kq > nb_kq_file")
    4897           16 :      ib_kq_start = gqk%bstart_kq - file_brange_kq_spin(1, spin) + 1
    4898           16 :      ABI_CHECK_IRANGE(ib_kq_start, 1, nb_kq_file, "Invalid k+q band offset in GSTORE.nc")
    4899           16 :      ABI_CHECK_ILEQ(ib_kq_start + nb_kq - 1, nb_kq_file, "Requested k+q band window exceeds GSTORE.nc")
    4900              : 
    4901              :      ! gstore_cplex defines the data on disk while cplex defines what we want to store in memory
    4902          112 :      ABI_MALLOC_OR_DIE(gwork_q, (gstore_cplex, nb_kq, nb_k, gqk%natom3, gqk%glob_nk), ierr)
    4903           80 :      ABI_MALLOC(slice_bb, (gstore_cplex, nb_kq, nb_k))
    4904           16 :      if (read_ks) then
    4905           42 :        ABI_MALLOC_OR_DIE(ks_gwork_q, (gstore_cplex, nb_kq, nb_k, gqk%natom3, gqk%glob_nk), ierr)
    4906           30 :        ABI_MALLOC(ks_slice_bb, (gstore_cplex, nb_kq, nb_k))
    4907              :      end if
    4908              : 
    4909           16 :      if (with_g2dw) then
    4910              :        ! Read my_gq0nm_atm matrix elements for DW in the RIA. Find the index of q = 0.
    4911            7 :        iq_glob = -1
    4912            7 :        do ii=1, gstore%glob_nq_spin(spin)
    4913            7 :          iq_bz = qglob2bz(ii, spin)
    4914           28 :          if (sum(gstore%qbz(:, iq_bz)**2) < tol4) then
    4915            7 :            iq_glob = ii; exit
    4916              :          end if
    4917              :        end do
    4918            7 :        ABI_CHECK_INEQ(iq_glob, -1, "Cannot finq q=0 in g(k,q)!")
    4919            7 :        call wrtout(std_out, sjoin(" Reading g_atm(k,q=0) for Debye-Waller with iq_glob:", itoa(iq_glob)))
    4920              : 
    4921              :        ! Read q-slice of the e-ph matrix elements (individual IO).
    4922              :        ! Note gvals_name so that we can read either g^KS or g^Sigma.
    4923           49 :        ncerr = nf90_get_var(spin_ncid, spin_vid(gvals_name), gwork_q, start=[1, ib_kq_start, 1, 1, 1, iq_glob])
    4924            7 :        NCF_CHECK(ncerr)
    4925              : 
    4926            7 :        if (read_ks) then
    4927           42 :          ncerr = nf90_get_var(spin_ncid, spin_vid("gvals_ks"), ks_gwork_q, start=[1, ib_kq_start, 1, 1, 1, iq_glob])
    4928            6 :          NCF_CHECK(ncerr)
    4929              :          ! Here we set g_GWPT g to g_KS if g_KS is smaller than a certain threshold as GWPT breaks symmetries.
    4930        13931 :          where (abs(ks_gwork_q) < G_SMALL)
    4931              :             gwork_q = ks_gwork_q
    4932              :          end where
    4933              :        end if
    4934              : 
    4935              :        ! Allocate gdw2
    4936           49 :        ABI_MALLOC(gqk%my_gdw2, (gqk%my_npert, nb_kq, gqk%my_nq, nb_k, gqk%my_nk))
    4937            7 :        gqk%my_gdw2_ks => gqk%my_gdw2
    4938              :        ! Allocate my_gq0nm_atm and transfer data. Note TRANSPOSITION in (m, n) indices.
    4939           42 :        ABI_MALLOC(my_gq0nm_atm, (nb_k, nb_kq, natom3, gqk%my_nk))
    4940              : 
    4941            7 :        if (gqk%has_both_g) then
    4942           36 :          ABI_MALLOC(gqk%my_gdw2_ks, (gqk%my_npert, nb_kq, gqk%my_nq, nb_k, gqk%my_nk))
    4943           30 :          ABI_MALLOC(ks_my_gq0nm_atm, (nb_k, nb_kq, natom3, gqk%my_nk))
    4944              :        end if
    4945              : 
    4946           19 :        do my_ik=1,gqk%my_nk
    4947           12 :          ik_glob = my_ik + gqk%my_kstart - 1
    4948          167 :          do ib_m=1,nb_kq
    4949          988 :            do ib_n=1,nb_k
    4950         5796 :              my_gq0nm_atm(ib_n,ib_m,:,my_ik) = gwork_q(1,ib_m,ib_n,:,ik_glob) + j_dpc * gwork_q(2,ib_m,ib_n,:,ik_glob)
    4951          976 :              if (gqk%has_both_g) then
    4952         5236 :                ks_my_gq0nm_atm(ib_n,ib_m,:,my_ik) = ks_gwork_q(1,ib_m,ib_n,:,ik_glob) + j_dpc * ks_gwork_q(2,ib_m,ib_n,:,ik_glob)
    4953              :              end if
    4954              :            end do
    4955              :          end do
    4956              :        end do
    4957              :      end if ! with_g2dw
    4958              : 
    4959           16 :      if (has_iv1p_comm) then
    4960              :        ! Read matrix elements of commutator [iv, p].
    4961            0 :        ABI_MALLOC(gqk%my_iv1p_comm, (nb_k, nb_k, 3, gqk%my_npert, gqk%my_nk))
    4962            0 :        ABI_MALLOC(iv1p_comm, (2, nb_k, nb_k, 3, natom3))
    4963              :        ! nctkarr_t("iv1p_comm", "dp", "two, nb_k, nb_k, three, natom3, glob_nk")
    4964              : 
    4965            0 :        do my_ik=1,gqk%my_nk
    4966            0 :          ik_glob = my_ik + gqk%my_kstart - 1
    4967            0 :          ncerr = nf90_get_var(spin_ncid, spin_vid("iv1p_comm"), iv1p_comm, start=[1,1,1,1,1, ik_glob])
    4968            0 :          NCF_CHECK(ncerr)
    4969              : 
    4970              :          ! Save my perturbations for this k-point.
    4971            0 :          do my_ip=1,gqk%my_npert
    4972            0 :            ipert = gqk%my_pertcases(my_ip)
    4973            0 :            gqk%my_iv1p_comm(:,:,:,my_ip, my_ik) = r2c(iv1p_comm(:,:,:,:,ipert))
    4974              :          end do
    4975              :        end do
    4976            0 :        ABI_FREE(iv1p_comm)
    4977              :      end if
    4978              : 
    4979           16 :      if (from_atm_to_nu) then
    4980           80 :        ABI_MALLOC(gmn_nu, (2, nb_kq, nb_k, 3*natom))
    4981              :      end if
    4982              : 
    4983              :      ! Read my e-ph matrix elements.
    4984         1365 :      do my_iq=1,gqk%my_nq
    4985         1349 :        iq_glob = my_iq + gqk%my_qstart - 1
    4986              : 
    4987              :        !call wrtout(std_out, " Computing and storing phonons in the full BZ by rotating the data in the IBZ...")
    4988         1349 :        iq_ibz = gqk%my_q2ibz(1, my_iq); isym_q = gqk%my_q2ibz(2, my_iq)
    4989         1349 :        trev_q = gqk%my_q2ibz(6, my_iq); g0_q = gqk%my_q2ibz(3:5, my_iq)
    4990              :        !isirr_q = (isym_q == 1 .and. trev_q == 0 .and. all(g0_q == 0))
    4991         1349 :        isirr_q = (isym_q == 1 .and. trev_q == 0)
    4992         1349 :        tsign_q = 1; if (trev_q == 1) tsign_q = -1
    4993         5396 :        qq_ibz = gstore%qibz(:, iq_ibz)
    4994              : 
    4995              :        ! Here we get the ph displacement for this q-point in the BZ from the image in the IBZ.
    4996              :        ! This is important for complex g as we have to enforce the gauge in the ph eigenvectors, including e(-q) = e(q)^*.
    4997              :        call pheigvec_rotate(cryst, qq_ibz, isym_q, trev_q, pheigvec_cart_ibz(:,:,:,:,iq_ibz), pheigvec_cart_qbz, displ_cart_qbz, &
    4998         1349 :                             displ_red_qbz=displ_red_qbz)
    4999              : 
    5000              :        ! Save my frequencies and my phonon displacements.
    5001        17537 :        gqk%my_wnuq(:, my_iq) = phfreqs_ibz(gqk%my_pertcases(:), iq_ibz)
    5002       179417 :        gqk%my_displ_cart(:,:,:,:,my_iq) = displ_cart_qbz(:,:,:,gqk%my_pertcases(:))
    5003              : 
    5004         1349 :        if (with_g2dw) then
    5005         1176 :          do my_ip=1,gqk%my_npert
    5006              :            ! Compute T_pp'(q,nu) matrix in reduced coordinates for DW.
    5007         1008 :            call phdispl_cart2red_nmodes(natom, 1, cryst%gprimd, gqk%my_displ_cart(:,:,:,my_ip,my_iq), displ_nu_red)
    5008         1008 :            call sigtk_dw_tpp_red(natom, displ_nu_red, tpp_red)
    5009         1008 :            wqnu = gqk%my_wnuq(my_ip, my_iq)
    5010              : 
    5011         2424 :            do my_ik=1,gqk%my_nk
    5012         2256 :              if (.not. gqk%has_both_g .or. dtset%gwpt_g2mode == 1) then
    5013              :                call calc_and_store_gdw2(gqk, my_ik, my_iq, my_ip, wqnu, tpp_red, &
    5014          864 :                                         my_gq0nm_atm(:,:,:,my_ik), my_gq0nm_atm(:,:,:,my_ik))
    5015              :              else
    5016              :                !print *, "Computing g2dw with both g^KS g_GWPT"
    5017              :                call calc_and_store_gdw2(gqk, my_ik, my_iq, my_ip, wqnu, tpp_red, &
    5018          384 :                                         ks_my_gq0nm_atm(:,:,:,my_ik), my_gq0nm_atm(:,:,:,my_ik))
    5019              :              end if
    5020              :            end do ! my_ik
    5021              : 
    5022              :          end do ! my_ip
    5023              :        end if
    5024              : 
    5025              :        ! Read q-slice of g(k,q) in the atom representation. (individual IO).
    5026         9443 :        ncerr = nf90_get_var(spin_ncid, spin_vid(gvals_name), gwork_q, start=[1, ib_kq_start, 1, 1, 1, iq_glob])
    5027         1349 :        NCF_CHECK(ncerr)
    5028              : 
    5029         1349 :        if (read_ks) then
    5030          728 :          ncerr = nf90_get_var(spin_ncid, spin_vid("gvals_ks"), ks_gwork_q, start=[1, ib_kq_start, 1, 1, 1, iq_glob])
    5031          104 :          NCF_CHECK(ncerr)
    5032              :          ! Here we set g_GWPT g to g_KS if g_KS is smaller than a certain threshold as GWPT breaks symmetries.
    5033       153560 :          where (abs(ks_gwork_q) < G_SMALL)
    5034              :             gwork_q = ks_gwork_q
    5035              :          end where
    5036              :        end if
    5037              : 
    5038       111960 :        do my_ik=1,gqk%my_nk
    5039       110595 :          ik_glob = my_ik + gqk%my_kstart - 1
    5040       110595 :          if (from_atm_to_nu) then
    5041              :            ! Here we convert from g(k,q)_atom to g(k,q)_phonon and replace data in gwork_q at ik_glob
    5042              :            call ephtk_gkknu_from_atm(nb_kq, nb_k, 1, natom, gwork_q(:,:,:,:, ik_glob), &
    5043       110595 :                                      phfreqs_ibz(:, iq_ibz), displ_red_qbz, gmn_nu)
    5044     12601221 :            gwork_q(:,:,:,:, ik_glob) = gmn_nu
    5045              : 
    5046       110595 :            if (gqk%has_both_g) then
    5047              :              call ephtk_gkknu_from_atm(nb_kq, nb_k, 1, natom, ks_gwork_q(:,:,:,:, ik_glob), &
    5048          144 :                                        phfreqs_ibz(:, iq_ibz), displ_red_qbz, gmn_nu)
    5049       153456 :              ks_gwork_q(:,:,:,:, ik_glob) = gmn_nu
    5050              :            end if
    5051              :          end if
    5052              : 
    5053       775514 :          do my_ip=1,gqk%my_npert
    5054       663570 :            ipert = gqk%my_pertcases(my_ip)
    5055     13154196 :            slice_bb = gwork_q(:,:,:, ipert, ik_glob)
    5056       663570 :            if (read_ks) then
    5057       154176 :              ks_slice_bb = ks_gwork_q(:,:,:, ipert, ik_glob)
    5058              :            end if
    5059              : 
    5060              :            ! Put data in the right place and handle conversion g --> |g|^2.
    5061       774165 :            if (with_cplex == gstore_cplex) then
    5062       662706 :              if (with_cplex == 1) then
    5063            0 :                gqk%my_g2(my_ip,:,my_iq,:,my_ik) = slice_bb(1,:,:)
    5064            0 :                if (read_ks .and. gqk%has_both_g) then
    5065            0 :                  gqk%my_g2_ks(my_ip,:,my_iq,:,my_ik) = ks_slice_bb(1,:,:)
    5066              :                end if
    5067              :              end if
    5068       662706 :              if (with_cplex == 2) then
    5069      5439486 :                gqk%my_g(my_ip,:,my_iq,:,my_ik) = slice_bb(1,:,:) + j_dpc * slice_bb(2,:,:)
    5070       662706 :                if (read_ks .and. gqk%has_both_g) then
    5071        17280 :                  gqk%my_g_ks(my_ip,:,my_iq,:,my_ik) = ks_slice_bb(1,:,:) + j_dpc * ks_slice_bb(2,:,:)
    5072              :                end if
    5073              :              end if
    5074              : 
    5075              :            else
    5076          864 :              if (with_cplex == 1 .and. gstore_cplex == 2) then
    5077        69984 :                gqk%my_g2(my_ip, :, my_iq, :, my_ik) = slice_bb(1,:,:) ** 2 + slice_bb(2,:,:) ** 2
    5078          864 :                if (read_ks .and. gqk%has_both_g) then
    5079        37344 :                  gqk%my_g2_ks(my_ip, :, my_iq, :, my_ik) = ks_slice_bb(1,:,:) ** 2 + ks_slice_bb(2,:,:) ** 2
    5080              :                end if
    5081            0 :              else if (with_cplex == 0) then
    5082              :                 continue
    5083              :              else
    5084            0 :                ABI_ERROR("Conversion from g2 on file to g_complex in memory is not possible!")
    5085              :              end if
    5086              :            end if
    5087              :          end do ! my_ip
    5088              :        end do ! my_ik
    5089              : 
    5090              :      end do ! my_iq
    5091              : 
    5092           16 :      ABI_FREE(gwork_q)
    5093           16 :      ABI_FREE(slice_bb)
    5094           16 :      if (read_ks) then
    5095            6 :        ABI_FREE(ks_gwork_q)
    5096            6 :        ABI_FREE(ks_slice_bb)
    5097              :      end if
    5098              : 
    5099           16 :      ABI_SFREE(gmn_nu)
    5100           16 :      ABI_SFREE(my_gq0nm_atm)
    5101           16 :      ABI_SFREE(ks_my_gq0nm_atm)
    5102              : 
    5103              :      ! =========================================
    5104              :      ! Read matrix elements of velocity operator
    5105              :      ! =========================================
    5106           16 :      if (gstore%with_vk == 1) then
    5107           16 :        if (gqk%comm%nproc > 1) then
    5108            0 :          NCF_CHECK(nctk_set_collective(spin_ncid, spin_vid("vk_cart_ibz")))
    5109              :        end if
    5110           16 :        NCF_CHECK(nf90_get_var(spin_ncid, spin_vid("vk_cart_ibz"), gqk%vnk_cart_ibz))
    5111              : 
    5112            0 :      else if (gstore%with_vk == 2) then
    5113            0 :        if (gqk%comm%nproc > 1) then
    5114            0 :          NCF_CHECK(nctk_set_collective(spin_ncid, spin_vid("vnk_mat_cart_ibz")))
    5115              :        end if
    5116            0 :        NCF_CHECK(nf90_get_var(spin_ncid, spin_vid("vnk_mat_cart_ibz"), gqk%vnk_mat_cart_ibz))
    5117              : 
    5118              :        ! Transfer diagonal terms to vnk_cart_ibz.
    5119            0 :        do ib=1,gqk%nb_k
    5120            0 :          gqk%vnk_cart_ibz(:, ib, :) = gqk%vnk_mat_cart_ibz(1, :, ib, ib, :)
    5121              :        end do
    5122              :      end if
    5123              : 
    5124           16 :      NCF_CHECK(nf90_close(ncid))
    5125              :    end if
    5126              :  end do ! spin
    5127              : 
    5128           16 :  ABI_FREE(qglob2bz)
    5129           16 :  ABI_FREE(qbz2ibz)
    5130           16 :  ABI_FREE(phfreqs_ibz)
    5131           16 :  ABI_FREE(pheigvec_cart_ibz)
    5132           16 :  ABI_FREE(displ_cart_qbz)
    5133           16 :  ABI_FREE(displ_red_qbz)
    5134           16 :  ABI_FREE(pheigvec_cart_qbz)
    5135           16 :  ABI_SFREE(tpp_red)
    5136              : 
    5137           16 :  call pstat_proc%print(_PSTAT_ARGS_)
    5138           16 :  call xmpi_barrier(gstore%comm)
    5139           48 :  call cwtime_report(" gstore_from_ncpath", cpu, wall, gflops)
    5140              : 
    5141              :  !stop
    5142              : 
    5143              : contains
    5144          400 : integer function vid(var_name)
    5145              :   character(len=*),intent(in) :: var_name
    5146          400 :   vid = nctk_idname(ncid, var_name)
    5147              : end function vid
    5148              : 
    5149         1482 : integer function spin_vid(var_name)
    5150              :   character(len=*),intent(in) :: var_name
    5151         1482 :   spin_vid = nctk_idname(spin_ncid, var_name)
    5152              : end function spin_vid
    5153              : 
    5154              : end subroutine gstore_from_ncpath
    5155              : !!***
    5156              : 
    5157         1248 : subroutine calc_and_store_gdw2(gqk, my_ik, my_iq, my_ip, wqnu, tpp_red, gq0l_atm, gq0r_atm)
    5158              : 
    5159              :  type(gqk_t), intent(inout) :: gqk
    5160              :  integer,intent(in) :: my_ik, my_iq, my_ip
    5161              :  real(dp),intent(in) :: wqnu
    5162              :  complex(dp),intent(in) :: tpp_red(gqk%natom3, gqk%natom3)
    5163              :  complex(dp),intent(in) :: gq0l_atm(gqk%nb_k, gqk%nb_kq, gqk%natom3)
    5164              :  complex(dp),intent(in) :: gq0r_atm(gqk%nb_k, gqk%nb_kq, gqk%natom3)
    5165              : 
    5166              : !Local variables-------------------------------
    5167              : !scalars
    5168              :  integer :: im_kq, in_k, ip2, ip1
    5169              :  real(dp) :: gdw2
    5170              :  complex(dp) :: cfact
    5171              : ! *************************************************************************
    5172              : 
    5173              :  ! Loop over bands in |m,k+q>
    5174        18432 :  do im_kq=1,gqk%nb_kq
    5175              :    ! Loop over the n index in |n,k>.
    5176        98496 :    do in_k=1,gqk%nb_k
    5177              :      ! Compute DW term following XG paper. Check prefactor.
    5178              :      gdw2 = zero
    5179       560448 :      do ip2=1,gqk%natom3
    5180      3442752 :        do ip1=1,gqk%natom3
    5181              :          cfact = ( &
    5182              :            + real(gq0l_atm(in_k, im_kq, ip1)) * real(gq0r_atm(in_k, im_kq, ip2)) &
    5183              :            + aimag(gq0l_atm(in_k, im_kq, ip1)) * aimag(gq0r_atm(in_k, im_kq, ip2)) &
    5184              :            + real(gq0l_atm(in_k, im_kq, ip2)) * real(gq0r_atm(in_k, im_kq, ip1)) &
    5185              :            + aimag(gq0l_atm(in_k, im_kq, ip2)) * aimag(gq0r_atm(in_k, im_kq, ip1)) &
    5186      2882304 :          )
    5187      3362688 :          gdw2 = gdw2 + real(tpp_red(ip1,ip2) * cfact)
    5188              :        end do
    5189              :      end do
    5190              : 
    5191        80064 :      if (wqnu < EPHTK_WTOL) then
    5192              :        gdw2 = zero
    5193              :      else
    5194        77580 :        gdw2 = gdw2 / (four * two * wqnu)
    5195              :      end if
    5196              : 
    5197              :      !print *, "gdw2", gdw2
    5198        97248 :      gqk%my_gdw2(my_ip, im_kq, my_iq, in_k, my_ik) = gdw2
    5199              :    end do ! in_k
    5200              :  end do ! im_kq
    5201              : 
    5202         1248 : end subroutine calc_and_store_gdw2
    5203              : 
    5204              : !----------------------------------------------------------------------
    5205              : 
    5206              : !!****f* m_gstore/gstore_check_restart
    5207              : !! NAME
    5208              : !! gstore_check_restart
    5209              : !!
    5210              : !! FUNCTION
    5211              : !!  Check whether restart from a previous GSTORE.nc is possible.
    5212              : !!
    5213              : !! INPUTS
    5214              : !!
    5215              : !! SOURCE
    5216              : 
    5217            3 : subroutine gstore_check_restart(filepath, dtset, nqbz, done_qbz_spin, restart, comm)
    5218              : 
    5219              : !Arguments ------------------------------------
    5220              :  character(len=*),intent(in) :: filepath
    5221              :  type(dataset_type),intent(in) :: dtset
    5222              :  integer,intent(out) :: nqbz, restart
    5223              :  integer,allocatable,intent(out) :: done_qbz_spin(:,:)
    5224              :  integer,intent(in) :: comm
    5225              : 
    5226              : !Local variables-------------------------------
    5227              : !scalars
    5228              :  integer,parameter :: master = 0
    5229              :  integer :: my_rank, root_ncid, ierr, gstore_completed, gstore_fform, units(2) ! fform
    5230              :  character(len=500) :: msg
    5231            3 :  type(hdr_type) :: gstore_hdr
    5232              : ! *************************************************************************
    5233              : 
    5234            9 :  my_rank = xmpi_comm_rank(comm); units = [std_out, ab_out]
    5235              : 
    5236              :  !print *, "eph_restart:", dtset%eph_restart
    5237              : 
    5238            3 :  restart = 0; nqbz = 0
    5239            3 :  if (my_rank == master .and. dtset%eph_restart == 1) then
    5240            3 :     if (file_exists(filepath)) then
    5241            0 :       call wrtout(units, sjoin("- Found pre-existent GSTORE file:", trim(filepath)))
    5242            0 :       call wrtout(units, " Testing if all e-ph terms have been computed...")
    5243              :       ! Use gstore_completed to understand if the previous GSTORE run completed else we need to restart.
    5244            0 :       NCF_CHECK(nctk_open_read(root_ncid, filepath, xmpi_comm_self))
    5245            0 :       NCF_CHECK(nf90_get_var(root_ncid, root_vid("gstore_completed"), gstore_completed))
    5246            0 :       call gstore_hdr%ncread(root_ncid, gstore_fform)
    5247            0 :       ABI_CHECK_INEQ(gstore_fform, 0, "Wrong gstore_fform")
    5248            0 :       call gstore_hdr%vs_dtset(dtset); call gstore_hdr%free()
    5249              : 
    5250            0 :       NCF_CHECK(nctk_get_dim(root_ncid, "gstore_nqbz", nqbz))
    5251            0 :       ABI_MALLOC(done_qbz_spin, (nqbz, dtset%nsppol))
    5252            0 :       NCF_CHECK(nf90_get_var(root_ncid, root_vid("gstore_done_qbz_spin"), done_qbz_spin))
    5253            0 :       NCF_CHECK(nf90_close(root_ncid))
    5254              :       !print *, "done_qbz_spin:", done_qbz_spin
    5255              : 
    5256              :       ! FIXME: done_qbz_spin is dimensioned with the q-points in the BZ but we
    5257              :       ! should set to 1 the q-points in the BZ else we never restart
    5258              :       ! Perhaps can can set to -1 if q = TS q_ibz if q_ibz is done.
    5259            0 :       if (gstore_completed /= 0) then
    5260              :         ! Previous computation completed, keep a backup of the file and start from scratch.
    5261            0 :         restart = 0; done_qbz_spin = 0
    5262              :         msg = sjoin("- WARNING: Found GSTORE.nc file with all entries already computed.", ch10, &
    5263            0 :                     "- Will overwrite:", trim(filepath), ch10, "Keeping backup copy in:", strcat(filepath, ".bkp"))
    5264            0 :         call wrtout(units, msg)
    5265            0 :         ABI_CHECK(clib_rename(trim(filepath), strcat(filepath, ".bkp")) == 0, "Failed to rename GSTORE file.")
    5266              :       else
    5267            0 :         restart = 1
    5268            0 :         call wrtout(units, "- Restarting from a previous GSTORE.nc file")
    5269              :       end if
    5270              :     else
    5271            3 :       call wrtout(units, sjoin("- Cannot find pre-existent GSTORE file:", trim(filepath)))
    5272              :     end if
    5273              :  end if
    5274              : 
    5275            3 :  call xmpi_bcast(restart, master, comm, ierr)
    5276            3 :  call xmpi_bcast(nqbz, master, comm, ierr)
    5277              : 
    5278            3 :  if (my_rank /= master) then
    5279            0 :    ABI_MALLOC(done_qbz_spin, (nqbz, dtset%nsppol))
    5280              :  end if
    5281            3 :  if (nqbz /= 0) call xmpi_bcast(done_qbz_spin, master, comm, ierr)
    5282              :  !stop
    5283              : 
    5284              : contains
    5285            0 : integer function root_vid(var_name)
    5286              :   character(len=*),intent(in) :: var_name
    5287            0 :   root_vid = nctk_idname(root_ncid, var_name)
    5288              : end function root_vid
    5289              : 
    5290              : end subroutine gstore_check_restart
    5291              : !!***
    5292              : 
    5293              : !----------------------------------------------------------------------
    5294              : 
    5295              : !!****f* m_gstore/gstore_print_for_abitests
    5296              : !! NAME
    5297              : !! gstore_print_for_abitests
    5298              : !!
    5299              : !! FUNCTION
    5300              : !!  Print subset of results to ab_out for testing purposes.
    5301              : !!  This routine should be called when the output of the GSTORE.nc file is completed
    5302              : !!
    5303              : !! INPUTS
    5304              : !!  dtset<type(dataset_type)>=all input variables for this dataset
    5305              : !!  [with_ks]: if True, read "gvals" as well as "gvals_ks". This options is used in GWPT
    5306              : !!   in which "gvals" are the GWPT matrix elements and ""gvals_ks" are the KS ones.
    5307              : !!
    5308              : !! SOURCE
    5309              : 
    5310            8 : subroutine gstore_print_for_abitests(gstore, dtset, ebands, do_avg, with_ks)
    5311              : 
    5312              : !Arguments ------------------------------------
    5313              :  class(gstore_t),intent(inout) :: gstore
    5314              :  type(dataset_type),intent(in) :: dtset
    5315              :  type(ebands_t),intent(in) :: ebands
    5316              :  logical,intent(in) :: do_avg
    5317              :  logical,optional,intent(in) :: with_ks
    5318              : 
    5319              : !Local variables-------------------------------
    5320              : !scalars
    5321              :  integer,parameter :: master = 0
    5322              :  integer :: root_ncid, spin_ncid, gstore_completed, spin, ik_glob, iq_glob, ipc, ncerr, natom3
    5323              :  integer :: glob_nq, glob_nk, im_kq, in_k, m_kq, n_k, nb_k, nb_kq, ii ! ib_k,
    5324              :  integer :: bstart_k, bstop_k, bstart_kq, bstop_kq, max_nk, max_nq, idir
    5325              :  integer :: ik_bz, ik_ibz, ib_min_k, ib_max_k, iq_bz, ikq_ibz, ib_min_kq, ib_max_kq, nn
    5326              :  logical :: with_ks__, changed_k, changed_kq, all_gs, has_iv1p_comm
    5327              :  real(dp) :: gg, gg_ks, g_ratio, min_g_ratio, max_g_ratio, mean_g_ratio, stdev_g_ratio !, vnk
    5328              :  character(len=abi_slen) :: gstore_gmode
    5329              :  character(len=500) :: msg
    5330              : !arrays
    5331              :  integer :: mapl_kq(6)
    5332            8 :  integer,allocatable :: done_qbz_spin(:,:), qglob2bz(:,:), degblock_k(:,:), degblock_kq(:,:)
    5333              :  real(dp) :: kk(3), qq(3), kq(3), rtmp(2)
    5334            8 :  real(dp),allocatable :: gslice_mn(:,:,:), gslice_ks_mn(:,:,:), g2_mn(:,:), g2ks_mn(:,:), iv1p_comm(:,:,:,:,:)
    5335              :  !real(dp),allocatable :: vnk_cart_ibz(:,:) !, vnk_mat_cart_ibz(:,:,:,:)
    5336              : ! *************************************************************************
    5337              : 
    5338              :  ! Only master prints to ab_out
    5339            8 :  if (xmpi_comm_rank(gstore%comm) /= master) return
    5340              : 
    5341            8 :  with_ks__ = .False.; if (present(with_ks)) with_ks__ = with_ks
    5342            8 :  all_gs = .False. ; if (dtset%prtvol >= 10) all_gs = .True.
    5343              : 
    5344            8 :  natom3 = dtset%natom * 3
    5345           16 :  max_nq = maxval(gstore%glob_nq_spin) ! Max dim over spin
    5346              :  max_nk = maxval(gstore%glob_nk_spin)
    5347              : 
    5348            8 :  NCF_CHECK(nctk_open_read(root_ncid, gstore%path, xmpi_comm_self))
    5349              : 
    5350            8 :  NCF_CHECK(nf90_get_var(root_ncid, root_vid("gstore_completed"), gstore_completed))
    5351            8 :  write(ab_out, *)""
    5352            8 :  write(ab_out, "(a,i0)")" gstore_completed: ", gstore_completed
    5353              : 
    5354           32 :  ABI_MALLOC(done_qbz_spin, (gstore%nqbz, dtset%nsppol))
    5355            8 :  NCF_CHECK(nf90_get_var(root_ncid, root_vid("gstore_done_qbz_spin"), done_qbz_spin))
    5356         2573 :  write(ab_out, "(a,*(i0,1x))")" gstore_done_qbz_spin: ", count(done_qbz_spin == 1)
    5357            8 :  ABI_FREE(done_qbz_spin)
    5358              : 
    5359          997 :  ABI_CALLOC(qglob2bz, (max_nq, dtset%nsppol))
    5360            8 :  NCF_CHECK(nf90_get_var(root_ncid, root_vid("gstore_qglob2bz"), qglob2bz))
    5361              : 
    5362              :  gstore_gmode = GSTORE_GMODE_ATOM
    5363              : 
    5364           16 :  do spin=1,gstore%nsppol
    5365            8 :    NCF_CHECK(nf90_inq_ncid(root_ncid, strcat("gqk", "_spin", itoa(spin)), spin_ncid))
    5366            8 :    NCF_CHECK(nctk_get_dim(spin_ncid, "glob_nq", glob_nq))
    5367            8 :    NCF_CHECK(nctk_get_dim(spin_ncid, "glob_nk", glob_nk))
    5368            8 :    NCF_CHECK(nctk_get_dim(spin_ncid, "nb_k", nb_k))
    5369            8 :    NCF_CHECK(nctk_get_dim(spin_ncid, "nb_kq", nb_kq))
    5370              : 
    5371            8 :    bstart_k = gstore%brange_k_spin(1, spin)
    5372            8 :    bstop_k = gstore%brange_k_spin(2, spin)
    5373            8 :    bstart_kq = gstore%brange_kq_spin(1, spin)
    5374            8 :    bstop_kq = gstore%brange_kq_spin(2, spin)
    5375              : 
    5376            8 :    write(ab_out, "(a,i0)")" nb_k: ", nb_k
    5377            8 :    write(ab_out, "(a,i0)")" bstart_k: ", bstart_k
    5378            8 :    write(ab_out, "(a,i0)")" nb_kq: ", nb_kq
    5379            8 :    write(ab_out, "(a,i0)")" bstart_kq: ", bstart_kq
    5380            8 :    write(ab_out, "(a,i0)")" glob_nq: ", glob_nq
    5381            8 :    write(ab_out, "(a,i0)")" glob_nk: ", glob_nk
    5382              : 
    5383              :    ! Handle the output of group velocities. On disk, we have:
    5384              :    !
    5385              :    !    nctkarr_t("vk_cart_ibz", "dp", "three, nb_k, gstore_nkibz"))
    5386              :    ! or
    5387              :    !    nctkarr_t("vnk_mat_cart_ibz", "dp", "two, three, nb_k, nb_k, gstore_nkibz")))
    5388              : 
    5389            8 :    select case (gstore%with_vk)
    5390              :    case (0)
    5391              :      continue
    5392              : 
    5393              :    case (1)
    5394            0 :      continue
    5395              :      !write(ab_out,"(2a)") ch10," Group velocities |v_nk| in atomic units:"
    5396              : 
    5397              :      !ABI_MALLOC(vnk_cart_ibz, (3, nb_k))
    5398              :      !do ik_ibz=1,gstore%nkibz
    5399              :      !  ! Only a subset of k-points are written to ab_out.
    5400              :      !  if (all(ik_ibz /= [1, 2, gstore%nkibz - 1, gstore%nkibz])) cycle
    5401              :      !  NCF_CHECK(nf90_get_var(spin_ncid, spin_vid("vk_cart_ibz"), vnk_cart_ibz, start=[1,1,ik_ibz], count=[3,nb_k,1]))
    5402              : 
    5403              :      !  write(ab_out, "(a)")sjoin(" For k-point:", ktoa(gstore%kibz(:,ik_ibz)), ", spin", itoa(spin))
    5404              :      !  do ib_k=1,min(nb_k, 10)
    5405              :      !    vnk = sqrt(norm2(vnk_cart_ibz(:,ib_k)))
    5406              :      !    write(ab_out, "(a,i0,1x,es16.6)")" ib_k: ", ib_k, vnk
    5407              :      !  end do
    5408              :      !end do
    5409              :      !ABI_FREE(vnk_cart_ibz)
    5410              :      !write(ab_out, "(a)")" "
    5411              : 
    5412              :    case (2)
    5413            8 :      ABI_ERROR(" TEXT output of vkmat is not coded yet!")
    5414              :    end select
    5415              : 
    5416              :    ! Handle the output of the e-ph matrix elements. On disk we have the global array:
    5417              :    !
    5418              :    !    nctkarr_t("gvals", "dp", "gstore_cplex, nb_kq, nb_k, natom3, glob_nk, glob_nq")
    5419              : 
    5420              :    ! These e-ph matrix elements are ALWAYS in the atom representation.
    5421           32 :    ABI_MALLOC(gslice_mn, (2, nb_kq, nb_k))
    5422           24 :    ABI_MALLOC(gslice_ks_mn, (2, nb_kq, nb_k))
    5423           32 :    ABI_MALLOC(g2_mn, (nb_kq, nb_k))
    5424           24 :    ABI_MALLOC(g2ks_mn, (nb_kq, nb_k))
    5425              : 
    5426            8 :    write(ab_out,"(a)") " E-PH matrix elements in the atom representation: pcase = (idir, iatom)"
    5427            8 :    if (do_avg) then
    5428            8 :      write(ab_out,"(a)") " NB: Values are averaged over e_mk+q, and e_nk degenerate states."
    5429              :    else
    5430            0 :      write(ab_out,"(a)") " NB: Values are NOT averaged over e_mk+q, and e_nk degenerate states."
    5431              :    end if
    5432              : 
    5433            8 :    if (with_ks__) then
    5434            3 :      write(ab_out, "(1x,5(a5,1x),2(a16))") "iq", "ik", "pcase", "m_kq", "n_k", "|g^GW| in Ha", "|g^KS| in Ha"
    5435              :    else
    5436            5 :      write(ab_out, "(1x,5(a5,1x),a16)") "iq", "ik", "pcase", "m_kq", "n_k", "|g| in Ha"
    5437              :    end if
    5438              : 
    5439          319 :    do ik_glob=1,glob_nk
    5440              :      ! Write the first and the last k-point.
    5441          311 :      if ((ik_glob /= 1 .and. ik_glob /= glob_nk) .and. .not. all_gs) cycle
    5442              : 
    5443           14 :      ik_bz = gstore%kglob2bz(ik_glob, spin)
    5444           14 :      ik_ibz = gstore%kbz2ibz(1, ik_bz)
    5445              :      !ik_ibz = gstore%bz2ibz(1, ik_bz); isym_k = gstore%bz2ibz(2, ik_bz)
    5446              :      !trev_k = gstore%bz2ibz(6, ik_bz); g0_k = gstore%bz2ibz(3:5, ik_bz)
    5447              :      !isirr_k = (isym_k == 1 .and. trev_k == 0 .and. all(g0_k == 0))
    5448              : 
    5449           56 :      kk = ebands%kptns(:,ik_ibz)
    5450           14 :      ib_min_k = bstart_k; ib_max_k = bstop_k
    5451              : 
    5452              :      call ebands%enclose_degbands(ik_ibz, spin, ib_min_k, ib_max_k, changed_k, dtset%symsigma_de, &
    5453           14 :                                   degblock=degblock_k)
    5454           14 :      if (changed_k) then
    5455              :        !write(ab_out, "(a)")" Non all the degenerate bands at k were included. This should not happen!"
    5456           10 :        do ii=1,size(degblock_k, dim=2)
    5457            8 :          degblock_k(1, ii) = max(degblock_k(1, ii), bstart_k)
    5458           10 :          degblock_k(2, ii) = min(degblock_k(2, ii), bstop_k)
    5459              :        end do
    5460              :      end if
    5461              : 
    5462         1800 :      do iq_glob=1,glob_nq
    5463              :        ! Write the first and the last q-point.
    5464         1786 :        if ((iq_glob /= 1 .and. iq_glob /= glob_nq) .and. .not. all_gs) cycle
    5465              : 
    5466              :        ! Find k+q image in the IBZ.
    5467           28 :        iq_bz = qglob2bz(iq_glob, spin)
    5468          112 :        qq = gstore%qbz(:, iq_bz)
    5469          112 :        kq = kk + qq
    5470           28 :        if (kpts_map("symrel", ebands%kptopt, gstore%cryst, gstore%krank_ibz, 1, kq, mapl_kq) /= 0) then
    5471            0 :          write(msg, '(4a)' )"k-mesh is not closed!",ch10, "k+q could not be generated from a symmetrical one.",trim(ltoa(kq))
    5472            0 :          ABI_ERROR(msg)
    5473              :        end if
    5474           28 :        ikq_ibz = mapl_kq(1)
    5475           28 :        ib_min_kq = bstart_kq; ib_max_kq = bstop_kq
    5476              : 
    5477              :        call ebands%enclose_degbands(ikq_ibz, spin, ib_min_kq, ib_max_kq, changed_kq, dtset%symsigma_de, &
    5478           28 :                                     degblock=degblock_kq)
    5479              : 
    5480           28 :        if (changed_kq) then
    5481              :          !write(ab_out, "(a)")" Non all the degenerate bands at k+q were included. This should not happen!"
    5482           34 :          do ii=1,size(degblock_kq, dim=2)
    5483           30 :            degblock_kq(1, ii) = max(degblock_kq(1, ii), bstart_kq)
    5484           34 :            degblock_kq(2, ii) = min(degblock_kq(2, ii), bstop_kq)
    5485              :          end do
    5486              :        end if
    5487              : 
    5488          196 :        do ipc=1,natom3
    5489              :          ! Write the 4th and the last perturbation.
    5490          168 :          if ((ipc /= 4 .and. ipc /= natom3) .and. .not. all_gs) cycle
    5491              :          ! TODO: Write that pcase is filtered
    5492              :          ncerr = nf90_get_var(spin_ncid, spin_vid("gvals"), gslice_mn, &
    5493          728 :                               start=[1,1,1,ipc,ik_glob,iq_glob], count=[2,nb_kq,nb_k,1,1,1])
    5494           56 :          NCF_CHECK(ncerr)
    5495           56 :          call average_g2_mn(do_avg, nb_kq, nb_k, bstart_kq, bstart_k, degblock_kq, degblock_k, gslice_mn, g2_mn)
    5496              : 
    5497           56 :          write(ab_out, "(3(a,1x,i0,1x))")" |g(k,q)| in Ha for iq:", iq_glob, "ik:", ik_glob, "pcase:", ipc
    5498              : 
    5499           84 :          if (.not. with_ks__) then
    5500              :           ! gvals only.
    5501           36 :            write(ab_out, "(1x,5(a5,1x),a16)")"iq", "ik", "pcase", "m_kq", "n_k", "|g|"
    5502          196 :            do im_kq=1,nb_kq
    5503          160 :              m_kq = im_kq + bstart_kq - 1
    5504          740 :              do in_k=1,nb_k
    5505          544 :                n_k = in_k + bstart_k - 1
    5506          544 :                gg = sqrt(g2_mn(im_kq, in_k))
    5507          704 :                write(ab_out, "(a1,5(i5,1x),es16.6)")"-", iq_glob, ik_glob, ipc, m_kq, n_k, gg
    5508              :              end do
    5509              :            end do
    5510              :         else
    5511              :           ! GW/KS ratio, g^GW, g^KS
    5512              :           ncerr = nf90_get_var(spin_ncid, spin_vid("gvals_ks"), gslice_ks_mn, &
    5513          260 :                                start=[1,1,1,ipc,ik_glob,iq_glob], count=[2,nb_kq,nb_k,1,1,1])
    5514           20 :           NCF_CHECK(ncerr)
    5515           20 :           call average_g2_mn(do_avg, nb_kq, nb_k, bstart_kq, bstart_k, degblock_kq, degblock_k, gslice_ks_mn, g2ks_mn)
    5516              : 
    5517           20 :           write(ab_out, "(1x,5(a5,1x),3a16)")"iq", "ik", "pcase", "m_kq", "n_k", "GW/KS", "|g^GW|", "|g^KS|"
    5518           20 :           min_g_ratio = +huge(one); max_g_ratio = -huge(one); mean_g_ratio = zero; stdev_g_ratio = zero; nn = 0
    5519              : 
    5520          252 :           do im_kq=1,nb_kq
    5521          232 :             m_kq = im_kq + bstart_kq - 1
    5522         1564 :             do in_k=1,nb_k
    5523         1312 :               n_k = in_k + bstart_k - 1
    5524         1312 :               gg = sqrt(g2_mn(im_kq, in_k))
    5525         1312 :               gg_ks = sqrt(g2ks_mn(im_kq, in_k))
    5526         1312 :               call safe_div(gg, gg_ks, -one, g_ratio)
    5527         1312 :               if (g_ratio /= -one) then
    5528          944 :                 nn = nn + 1
    5529          944 :                 min_g_ratio = min(g_ratio, min_g_ratio)
    5530          944 :                 max_g_ratio = max(g_ratio, max_g_ratio)
    5531          944 :                 mean_g_ratio = mean_g_ratio + g_ratio
    5532          944 :                 stdev_g_ratio = stdev_g_ratio + g_ratio ** 2
    5533              :               end if
    5534         1544 :               write(ab_out, "(a1,5(i5,1x),3(es16.6))")"-", iq_glob, ik_glob, ipc, m_kq, n_k, g_ratio, gg, gg_ks
    5535              :             end do
    5536              :           end do
    5537              : 
    5538           20 :           if (nn /= 0) then
    5539           14 :             mean_g_ratio = mean_g_ratio / nn
    5540           14 :             write(ab_out, "(a,es16.6)")"- mean_g_ratio:", mean_g_ratio
    5541              :             ! \sigma^{2} = \langle x^{2} \rangle - \langle x \rangle^{2}
    5542           14 :             write(ab_out, "(a,es16.6)")"- stdev_g_ratio:", sqrt((stdev_g_ratio / nn) - (mean_g_ratio ** 2))
    5543           14 :             write(ab_out, "(a,es16.6)")"- min_g_ratio:", min_g_ratio
    5544           14 :             write(ab_out, "(a,es16.6)")"- max_g_ratio:", max_g_ratio
    5545              :           end if
    5546              :         end if
    5547              : 
    5548              :        end do ! ipc
    5549              : 
    5550         1800 :        ABI_FREE(degblock_kq)
    5551              :      end do ! iq_glob
    5552          319 :      ABI_FREE(degblock_k)
    5553              :    end do ! ik_glob
    5554              : 
    5555            8 :    ABI_FREE(gslice_mn)
    5556            8 :    ABI_FREE(gslice_ks_mn)
    5557            8 :    ABI_FREE(g2_mn)
    5558           16 :    ABI_FREE(g2ks_mn)
    5559              :  end do ! spin
    5560              : 
    5561            8 :  ABI_FREE(qglob2bz)
    5562              : 
    5563              :  ! Here we read the matrix elements of i[V1, p] if present on disk.
    5564            8 :  has_iv1p_comm = gstore_nc_has_iv1p_comm(gstore, root_ncid)
    5565              : 
    5566            8 :  if (has_iv1p_comm) then
    5567            0 :    do spin=1,gstore%nsppol
    5568            0 :      NCF_CHECK(nf90_inq_ncid(root_ncid, strcat("gqk", "_spin", itoa(spin)), spin_ncid))
    5569            0 :      NCF_CHECK(nctk_get_dim(spin_ncid, "glob_nk", glob_nk))
    5570            0 :      NCF_CHECK(nctk_get_dim(spin_ncid, "nb_k", nb_k))
    5571              : 
    5572            0 :      bstart_k = gstore%brange_k_spin(1, spin)
    5573            0 :      bstop_k = gstore%brange_k_spin(2, spin)
    5574              : 
    5575            0 :      ABI_CALLOC(iv1p_comm, (2, nb_k, nb_k, 3, natom3))
    5576              : 
    5577            0 :      do ik_glob=1,glob_nk
    5578              :        ! Write the first and the last k-point.
    5579            0 :        if ((ik_glob /= 1 .and. ik_glob /= glob_nk) .and. .not. all_gs) cycle
    5580              : 
    5581              :        !ik_bz = gstore%kglob2bz(ik_glob, spin)
    5582              :        !ik_ibz = gstore%kbz2ibz(1, ik_bz)
    5583              :        !kk_ibz = ebands%kptns(:,ik_ibz)
    5584              : 
    5585              :        ! nctkarr_t("iv1p_comm", "dp", "two, nb_k, nb_k, three, natom3, glob_nk")
    5586              :        ncerr = nf90_get_var(spin_ncid, spin_vid("iv1p_comm"), iv1p_comm, &
    5587            0 :                             start=[1,1,1,1,1,ik_glob], count=[2,nb_k,nb_k,3,natom3,1])
    5588            0 :        NCF_CHECK(ncerr)
    5589              : 
    5590              :        ! Only n_nk states are included in the matrix.
    5591            0 :        write(ab_out, "(1x,5(a5,1x),a16)")"ik", "pcase", "m_k", "n_k", "idir", "i[V1,p]"
    5592            0 :        do im_kq=1,nb_k
    5593            0 :          m_kq = im_kq + bstart_k - 1
    5594            0 :          do in_k=1,nb_k
    5595            0 :            n_k = in_k + bstart_k - 1
    5596            0 :            do ipc=1,natom3
    5597            0 :              if ((ipc /= 4 .and. ipc /= natom3) .and. .not. all_gs) cycle
    5598            0 :              do idir=1,3
    5599            0 :                rtmp = iv1p_comm(:, im_kq, in_k, idir, ipc)
    5600            0 :                write(ab_out, "(a1,5(i5,1x),2es16.6)") "-", ik_glob, ipc, m_kq, n_k, idir, rtmp(1), rtmp(2)
    5601              :              end do ! idir
    5602              :            end do ! ipc
    5603              :          end do ! in_k
    5604              :        end do ! im_kq
    5605              : 
    5606              :      end do ! ik_glob
    5607              : 
    5608            0 :      ABI_FREE(iv1p_comm)
    5609              :    end do ! spin
    5610              :  end if
    5611              : 
    5612           16 :  NCF_CHECK(nf90_close(root_ncid))
    5613              : 
    5614              : contains
    5615           24 : integer function root_vid(var_name)
    5616              :   character(len=*),intent(in) :: var_name
    5617           24 :   root_vid = nctk_idname(root_ncid, var_name)
    5618              : end function root_vid
    5619              : 
    5620           76 : integer function spin_vid(var_name)
    5621              :   character(len=*),intent(in) :: var_name
    5622           76 :   spin_vid = nctk_idname(spin_ncid, var_name)
    5623              : end function spin_vid
    5624              : 
    5625              : end subroutine gstore_print_for_abitests
    5626              : !!***
    5627              : 
    5628           76 : subroutine average_g2_mn(do_avg, nb_kq, nb_k, bstart_kq, bstart_k, degblock_kq, degblock_k, g_mn, g2_mn)
    5629              : 
    5630              : !Arguments ------------------------------------
    5631              :  logical,intent(in) :: do_avg
    5632              :  integer,intent(in) :: nb_kq, nb_k, bstart_kq, bstart_k
    5633              :  integer,intent(in) :: degblock_kq(:,:), degblock_k(:,:)
    5634              :  real(dp),intent(in) :: g_mn(2, nb_kq, nb_k)
    5635              :  real(dp),intent(out) :: g2_mn(nb_kq, nb_k)
    5636              : 
    5637              : !Local variables-------------------------------
    5638              :  integer :: im_group, in_group, count, m_kq, im_kq, n_k, in_k
    5639              :  real(dp) :: g2_avg
    5640              : !----------------------------------------------------------------------
    5641              : 
    5642           76 :  if (do_avg) then
    5643              :    ! Average over electronic degenerate states at k and k+q
    5644         3564 :    g2_mn = -one
    5645          460 :    do im_group = 1, size(degblock_kq, dim=2)
    5646         1414 :      do in_group = 1, size(degblock_k, dim=2)
    5647          954 :        g2_avg = zero; count = 0
    5648         2542 :        do m_kq = degblock_kq(1, im_group), degblock_kq(2, im_group)
    5649         1588 :          im_kq = m_kq - bstart_kq + 1
    5650         5710 :          do n_k = degblock_k(1, in_group), degblock_k(2, in_group)
    5651         3168 :            in_k = n_k - bstart_k + 1
    5652         3168 :            g2_avg = g2_avg + g_mn(1, im_kq, in_k)**2 + g_mn(2, im_kq, in_k)**2
    5653         4756 :            count = count + 1
    5654              :          end do
    5655              :        end do
    5656          954 :        g2_avg = g2_avg / count
    5657              : 
    5658              :        ! Loop again over degenerate bands and copy average.
    5659         2926 :        do m_kq = degblock_kq(1, im_group), degblock_kq(2, im_group)
    5660         1588 :          im_kq = m_kq - bstart_kq + 1
    5661         5710 :          do n_k = degblock_k(1, in_group), degblock_k(2, in_group)
    5662         3168 :            in_k = n_k - bstart_k + 1
    5663         4756 :            g2_mn(im_kq, in_k) = g2_avg
    5664              :          end do
    5665              :        end do
    5666              : 
    5667              :      end do ! in_group
    5668              :    end do ! im_group
    5669              : 
    5670              :  else
    5671              :    ! No average here.
    5672            0 :    do im_kq=1, nb_kq
    5673            0 :      do in_k=1, nb_k
    5674            0 :        g2_mn(im_kq, in_k) = g_mn(1, im_kq, in_k)**2 + g_mn(2, im_kq, in_k)**2
    5675              :      end do
    5676              :    end do
    5677              :  end if
    5678              : 
    5679           76 : end subroutine average_g2_mn
    5680              : !!***
    5681              : 
    5682              : !----------------------------------------------------------------------
    5683              : 
    5684              : !!****f* m_gstore/gqk_gather
    5685              : !! NAME
    5686              : !!  gqk_gather
    5687              : !!
    5688              : !! FUNCTION
    5689              : !!  Gather the MPI-distributed matrix elements for a given k/q-point index.
    5690              : !!  Once one reciprocal dimension is fixed, the gathering is performed across the other one.
    5691              : !!
    5692              : !! INPUTS
    5693              : !!  mode = String controlling the choice of the fixed dimension ("k" or "q")
    5694              : !!  fixed_pt = Index of the fixed k/q-point
    5695              : !!
    5696              : !! OUTPUT
    5697              : !!  g_gathered(:,:,:,:) = Matrix elements for the given k/q-point, ordered as
    5698              : !!      (my_npert, nb, nb, glob_nq) - k-point is fixed
    5699              : !!      (my_npert, nb, nb, glob_nk) - q-point is fixed
    5700              : !!
    5701              : !! SOURCE
    5702              : 
    5703       555656 : subroutine gqk_gather(gqk, mode, fixed_pt, g_gathered)
    5704              : 
    5705              : !Arguments ------------------------------------
    5706              : !scalars
    5707              :  class(gqk_t), target, intent(in) :: gqk
    5708              :  character(len=*),intent(in) :: mode
    5709              :  integer,intent(in) :: fixed_pt
    5710              : !arrays
    5711              :  complex(dp), allocatable, intent(out) :: g_gathered(:,:,:,:)
    5712              : 
    5713              : !Local variables-------------------------------
    5714              : !scalars
    5715              :  integer :: comm, ierr, ipt_glob, ngather, my_ipt, my_ngather, my_ptstart, my_pert, ib, jb
    5716              : !arrays
    5717       277828 :  complex(dp), pointer :: my_g(:,:,:,:)
    5718              : !----------------------------------------------------------------------
    5719              : 
    5720            0 :  ABI_CHECK_IEQ(gqk%nb_kq, gqk%nb_k, "nb_kq != nb_k not tested")
    5721              : 
    5722            0 :  select case (mode)
    5723              :  case ("k")
    5724            0 :    comm = gqk%qpt_comm%value
    5725            0 :    ngather = gqk%glob_nq
    5726            0 :    my_ngather = gqk%my_nq
    5727            0 :    my_ptstart = gqk%my_qstart
    5728            0 :    my_g => gqk%my_g(:,:,:,:,fixed_pt)
    5729            0 :    ABI_CALLOC(g_gathered, (gqk%my_npert, gqk%nb_kq, gqk%nb_k, ngather))
    5730              : 
    5731              :  case ("q")
    5732       277828 :    comm = gqk%kpt_comm%value
    5733       277828 :    ngather = gqk%glob_nk
    5734       277828 :    my_ngather = gqk%my_nk
    5735       277828 :    my_ptstart = gqk%my_kstart
    5736       277828 :    my_g => gqk%my_g(:,:,fixed_pt,:,:)
    5737   2150164396 :    ABI_CALLOC(g_gathered, (gqk%my_npert, gqk%nb_k, gqk%nb_kq, ngather))
    5738              : 
    5739              :  case default
    5740       277828 :    ABI_ERROR(sjoin("Gathering MPI-distributed matrix elements, unsupported mode: ", mode))
    5741              :  end select
    5742              : 
    5743     33678830 :  do my_ipt=1,my_ngather
    5744     33401002 :    ipt_glob = my_ipt + my_ptstart - 1
    5745              : 
    5746              :    ! FIXME: can the rearrangement be done in the select case statement?
    5747    130800122 :    do ib=1,gqk%nb_k
    5748    418804456 :      do jb=1,gqk%nb_kq
    5749   2115096426 :        do my_pert=1,gqk%my_npert
    5750   2017975134 :          if (mode == "k") then
    5751            0 :            g_gathered(my_pert, jb, ib, ipt_glob) = my_g(my_pert, jb, my_ipt, ib)
    5752              :          else
    5753   1729692972 :            g_gathered(my_pert, jb, ib, ipt_glob) = my_g(my_pert, jb, ib, my_ipt)
    5754              :          endif
    5755              :        enddo
    5756              :      enddo
    5757              :    enddo
    5758              :  enddo
    5759              : 
    5760       277828 :  call xmpi_sum(g_gathered, comm, ierr)
    5761              : 
    5762       277828 : end subroutine gqk_gather
    5763              : !!***
    5764              : 
    5765              : !----------------------------------------------------------------------
    5766              : 
    5767              : !!****f* m_gstore/gstore_wannierize_and_write_gwan
    5768              : !! NAME
    5769              : !! gstore_wannierize_and_write_gwan
    5770              : !!
    5771              : !! FUNCTION
    5772              : !!  Compute g(R_e,R_ph) from g(k,q). Save results to GWAN.nc file
    5773              : !!
    5774              : !! INPUTS
    5775              : !!
    5776              : !! SOURCE
    5777              : 
    5778            0 : subroutine gstore_wannierize_and_write_gwan(gstore, dvdb, dtfil)
    5779              : 
    5780              : !Arguments ------------------------------------
    5781              :  class(gstore_t),target, intent(in) :: gstore
    5782              :  type(dvdb_t),intent(in) :: dvdb
    5783              :  type(datafiles_type),intent(in) :: dtfil
    5784              : 
    5785              : !Local variables-------------------------------
    5786              : !scalars
    5787              :  integer,parameter :: master = 0
    5788              :  integer,parameter :: wan_ntest = 4
    5789              :  integer,parameter :: wan_nperiod = 3
    5790              :  real(dp),parameter :: WAN_CLOSURE_TOL = tol8
    5791              :  real(dp),parameter :: WAN_VELOCITY_FD_STEP = 1.0d-5
    5792              :  real(dp),parameter :: WAN_VELOCITY_DEGEN_TOL = 1.0d-5
    5793              :  real(dp),parameter :: WAN_VELOCITY_TOL = tol6
    5794              :  integer :: nr_e, nr_p, nwan, iwan, jwan, spin, my_is, my_ip, ir, irp, my_ik, my_iq, nb_k, nb_kq
    5795              :  integer :: my_nk, my_nq, ierr, ik, ikq, my_npert, nwin_k, nwin_kq, ii, jj, band_kq, band_k, ib_k, ib_kq
    5796              :  integer :: itest, ip_loc, ik_glob, iq_glob, ntest_found, iperiod, idir, ib, nvelocity_tested
    5797              :  real(dp) :: max_err, ref_scale, max_period_eig_err, period_eig_scale, max_period_g2_err, period_g2_scale
    5798              :  real(dp) :: max_velocity_err, velocity_scale, band_gap, velocity_fd
    5799              :  character(len=500) :: msg
    5800              :  logical :: keep_umats, test_found(wan_ntest)
    5801              :  type(wan_t),pointer :: wan
    5802              :  type(gqk_t),pointer :: gqk
    5803              : !arrays
    5804              :  integer :: qptrlatt_(3,3), units(2)
    5805              :  integer :: test_ik(wan_ntest), test_iq(wan_ntest)
    5806              :  integer :: period_gk(3,wan_nperiod), period_gq(3,wan_nperiod)
    5807              :  real(dp) :: weight_qq, qpt(3), kpt(3), kq(3), dkred(3), cpu, wall, gflops
    5808            0 :  real(dp),allocatable :: eigens_k_test(:), eigens_kq_test(:), eigens_k_period(:), eigens_kq_period(:)
    5809            0 :  real(dp),allocatable :: eigens_k_plus(:), eigens_k_minus(:), vcart_test(:,:)
    5810            0 :  complex(dp),allocatable :: emikr(:), emiqr(:), u_k(:,:), u_kq(:,:), gww_epq(:,:,:,:,:), gww_pk(:,:,:,:), g_bb(:,:), tmp_mat(:,:)
    5811            0 :  complex(dp),allocatable :: test_gref(:,:,:,:), u_k_test(:,:), u_kq_test(:,:), cmat_test(:,:), g_expected(:,:)
    5812            0 :  complex(dp),allocatable :: g_atm_test(:,:,:,:), g_atm_period(:,:,:,:)
    5813              : ! *************************************************************************
    5814              : 
    5815            0 :  units = [std_out, ab_out]
    5816            0 :  period_gk = reshape([1,0,0,  0,0,0, -1,1,0], shape(period_gk))
    5817            0 :  period_gq = reshape([0,0,0,  0,1,0,  0,0,1], shape(period_gq))
    5818            0 :  call wrtout(units, " Computing g(R_e,R_ph) in the Wannier representation...", pre_newlines=1)
    5819            0 :  call cwtime(cpu, wall, gflops, "start")
    5820              : 
    5821            0 :  if (gstore%check_cplex_qkzone_gmode(2, "bz", "bz", "atom", kfilter="none") /= 0) then
    5822            0 :    ABI_ERROR("The gstore object is inconsistent with gstore_wannierize_and_write_gwan. See messages above.")
    5823              :  end if
    5824              : 
    5825              :  ! TODO: Handle long-range part.
    5826            0 :  if (dvdb%has_zeff .or. dvdb%has_quadrupoles) then
    5827            0 :    ABI_WARNING("Treatment of long-range part not yet coded in gstore_wannierize_and_write_gwan!")
    5828              :  end if
    5829              : 
    5830            0 :  do my_is=1,gstore%my_nspins
    5831            0 :    spin = gstore%my_spins(my_is); gqk => gstore%gqk(my_is); my_nq = gqk%my_nq; my_nk = gqk%my_nk; my_npert = gqk%my_npert
    5832            0 :    nb_k = gqk%nb_k; nb_kq = gqk%nb_kq
    5833              : 
    5834              :    ! Initialize gkq%wan from ABIWAN.nc for this spin.
    5835            0 :    keep_umats = .False.
    5836            0 :    call gqk%wan%from_abiwan(dtfil%filabiwanin, spin, gstore%nsppol, keep_umats, dtfil%filnam_ds(4), gqk%comm%value)
    5837            0 :    wan => gqk%wan
    5838              : 
    5839              :    ! Compute Wigner-Seitz lattice vectors and llocate grpe_wwp with shape: (nr_p, nr_e, nwan, nwan, my_npert).
    5840            0 :    call kptrlatt_from_ngkpt(gstore%ngqpt, qptrlatt_)
    5841              :    call wan%setup_eph_ws_kq(gstore%cryst, gstore%ebands%shiftk(:,1), gstore%ebands%kptrlatt, qptrlatt_, &
    5842            0 :                             gqk%my_pert_start, my_npert, gqk%pert_comm)
    5843              : 
    5844            0 :    nr_p = wan%nr_p; nr_e = wan%nr_e; nwan = wan%nwan
    5845              :    !if (gqk%comm%me == master) call wan%print(units)
    5846              : 
    5847              :    ! Cache the pre-FT ground truth at four fixed GLOBAL coarse-mesh points.  Using
    5848              :    ! local first/last indices would make the test points depend on the MPI grid.
    5849            0 :    test_ik = [1, gqk%glob_nk, 1, gqk%glob_nk]
    5850            0 :    test_iq = [1, 1, gqk%glob_nq, gqk%glob_nq]
    5851            0 :    test_found = .False.
    5852            0 :    ABI_CALLOC(test_gref, (nwan, nwan, my_npert, wan_ntest))
    5853              : 
    5854            0 :    ABI_MALLOC(emikr, (nr_e))
    5855            0 :    ABI_MALLOC(emiqr, (nr_p))
    5856            0 :    ABI_MALLOC(gww_pk, (nwan, nwan, my_npert, my_nk))
    5857              :    ! Intermediate buffer to store the sum over k-points. Note my_nq.
    5858            0 :    ABI_CALLOC(gww_epq, (nwan, nwan, nr_e, my_npert, my_nq))
    5859              : 
    5860              :    ! Loop over my q-points (partial sum over q).
    5861            0 :    do my_iq=1,my_nq
    5862            0 :      call gqk%myqpt(my_iq, gstore, weight_qq, qpt)
    5863              : 
    5864              :      !call get_kg(qpt, 1, ecut_lr, gstore%cryst%gmet, ng_q, gvec_q)
    5865              :      !ABI_FREE(gvec_q)
    5866              : 
    5867              :      ! Loop over my k-points (partial sum over k).
    5868            0 :      do my_ik=1,my_nk
    5869            0 :        kpt = gqk%my_kpts(:,my_ik); kq = kpt + qpt
    5870            0 :        ik = wan%krank%get_index(kpt); ikq = wan%krank%get_index(kq)
    5871            0 :        ABI_CHECK(ik  /= -1, sjoin("Cannot find kpt: ", ktoa(kpt)))
    5872            0 :        ABI_CHECK(ikq /= -1, sjoin("Cannot find k+q: ", ktoa(kq)))
    5873              : 
    5874              :        ! Get rotation matrices at k and k+q.
    5875            0 :        nwin_k = wan%dimwin(ik); nwin_kq = wan%dimwin(ikq)
    5876            0 :        ABI_MALLOC(g_bb, (nwin_kq, nwin_k))
    5877            0 :        ABI_MALLOC(u_k, (1:nwin_k, 1:nwan))
    5878            0 :        ABI_MALLOC(u_kq, (1:nwin_kq, 1:nwan))
    5879            0 :        ABI_MALLOC(tmp_mat, (nwin_kq, nwan))
    5880              : 
    5881            0 :        u_k = wan%u_k(1:nwin_k, 1:nwan, ik)
    5882            0 :        u_kq = wan%u_k(1:nwin_kq, 1:nwan, ikq)
    5883              : 
    5884            0 :        do my_ip=1,gqk%my_npert
    5885              :          !----------------------------------------------------------
    5886              :          !  STEP 1: rotation to optimally smooth Bloch states
    5887              :          !----------------------------------------------------------
    5888              :          ! [Eqn. 24 of PRB 76, 165108 (2007)]
    5889              :          ! g~(k,q) = U(k+q)^\dagger * g(k,q) * U(k)
    5890              : 
    5891              :          ! gqk%nb = wan%bmax - wan%bmin + 1
    5892              :          ! (my_npert, nb, my_nq, nb, my_nk)
    5893              :          ! (       p, b1_kq,     q, b2_k, k)  -->  <k+q, b1| D_{q,p}H |k, b2>
    5894              : 
    5895              :          ! Extract e-ph matrix elements from my_g buffer to align bands with the U matrices at k and k+q.
    5896              :          jj = 0
    5897            0 :          do ib_k=1,nb_k
    5898            0 :            band_k = ib_k - wan%bmin + 1; if (.not. wan%lwindow(band_k, ik)) cycle
    5899            0 :            jj = jj + 1; ii = 0
    5900            0 :            do ib_kq=1,nb_kq
    5901            0 :              band_kq = ib_kq - wan%bmin + 1; if (.not. wan%lwindow(band_kq, ikq)) cycle
    5902            0 :              ii = ii + 1
    5903            0 :              g_bb(ii, jj) = gqk%my_g(my_ip, ib_kq, my_iq, ib_k, my_ik)
    5904              :            end do
    5905              :          end do
    5906              : 
    5907              :          ! TODO: Remove LR part.
    5908              :          !call handle_lr_term(cryst, qpt, ng_q, gvec_q, nwin_kq, nwin_k, nwan, u_kq, u_k, dvdb%zeff, dvdb%qstar, -1, g_bb)
    5909              : 
    5910              :          ! the two zgemm calls perform: epmats  = [ cu(ikq)^\dagger * epmatk ] * cu(ikk)
    5911              :          ! [here we have a size-reduction from nbnd*nbnd to nwan*nwan]
    5912              :          ! output stored in gww_pk(:,:, my_ip, my_ik)
    5913              : 
    5914              :          ! gww_pk(:,:, my_ip, my_ik) = MATMUL(CONJG(TRANSPOSE(u_kq)), MATMUL(g_bb, u_k))
    5915              :          ! tmp_mat (nwin_kq x nwan) = g_bb (nwin_kq x nwin_k) . u_k (nwin_k x nwan)
    5916            0 :          call ZGEMM('N', 'N', nwin_kq, nwan, nwin_k, cone, g_bb, nwin_kq, u_k, nwin_k, czero, tmp_mat, nwin_kq)
    5917              :          ! gww_pk (nwan x nwan) = u_kq^dagger (nwan x nwin_kq) . tmp_mat (nwin_kq x nwan)
    5918            0 :          call ZGEMM('C', 'N', nwan, nwan, nwin_kq, cone, u_kq, nwin_kq, tmp_mat, nwin_kq, czero, gww_pk(:,:, my_ip, my_ik), nwan)
    5919              : 
    5920              :          !call ZGEMM('C', 'N', nwan, nbnd, nbnd, cone, u_kq, nbnd, epmatk(:, :, ik, imode), nbnd, czero, eptmp, nwan)
    5921              :          !call ZGEMM('N', 'N', nwan, nwan, nbnd, cone, eptmp, nwan, u_k, nbnd, czero, epmats(:, :, ik, imode), nwan)
    5922              :        end do ! my_ip
    5923              : 
    5924              :        ! Cache gww_pk(:,:,:,my_ik) for the on-mesh closure self-check below, while it is still
    5925              :        ! valid for THIS my_iq (it gets overwritten by the next my_iq iteration).
    5926            0 :        ik_glob = my_ik + gqk%my_kstart - 1
    5927            0 :        iq_glob = my_iq + gqk%my_qstart - 1
    5928            0 :        do itest=1,wan_ntest
    5929            0 :          if (test_ik(itest) == ik_glob .and. test_iq(itest) == iq_glob) then
    5930            0 :            test_gref(:,:,:,itest) = gww_pk(:,:,:,my_ik)
    5931            0 :            test_found(itest) = .True.
    5932              :          end if
    5933              :        end do
    5934              : 
    5935            0 :        ABI_FREE(g_bb)
    5936            0 :        ABI_FREE(tmp_mat)
    5937              : 
    5938              :        !----------------------------------------------------------------------
    5939              :        !  STEP 3: Fourier transform to obtain matrix elements in electron wannier basis
    5940              :        !----------------------------------------------------------------------
    5941              :        ! [Eqn. 24 of PRB 76, 165108 (2007)]
    5942              :        ! g(R_e,q) = (1/nkc) sum_k e^{-ikR_e} g~(k,q)
    5943              :        ! g(R_e,q) is epmatw (nwan,nwan,ir)
    5944              : 
    5945            0 :        do ir=1,nr_e
    5946            0 :          emikr(ir) = exp(-j_dpc * two_pi * dot_product(kpt, wan%r_e(:, ir))) / dble(gstore%nkbz)
    5947              :        end do
    5948              :        ! gww_pk(nwan, nwan, my_npert,my_nk)
    5949            0 :        do my_ip=1,gqk%my_npert
    5950            0 :          do ir=1,nr_e
    5951            0 :            gww_epq(:,:,ir, my_ip, my_iq) = gww_epq(:,:,ir, my_ip, my_iq) + emikr(ir) * gww_pk(:,:,my_ip, my_ik)
    5952              :          end do
    5953              :        end do
    5954              : 
    5955            0 :        ABI_FREE(u_k)
    5956            0 :        ABI_FREE(u_kq)
    5957              :      end do ! my_ik
    5958              :    end do ! my_iq
    5959              : 
    5960            0 :    call xmpi_sum(gww_epq, gqk%kpt_comm%value, ierr)
    5961              : 
    5962              :    !------------------------------------------
    5963              :    !  Fourier transform to go to Wannier basis
    5964              :    !------------------------------------------
    5965              :    ! [Eqn. 24 of PRB 76, 165108 (2007)]
    5966              :    ! g(R_e,R_p) = (1/nq) sum_q e^{-iqR_p} g(R_e,q)
    5967              : 
    5968              :    ! Loop over my q-points (partial sum over q).
    5969            0 :    do my_iq=1,my_nq
    5970            0 :      call gqk%myqpt(my_iq, gstore, weight_qq, qpt)
    5971            0 :      do irp=1,nr_p
    5972            0 :        emiqr(irp) = exp(-j_dpc * two_pi * dot_product(qpt, wan%r_p(:, irp))) / dble(gstore%nqbz)
    5973              :      end do
    5974              : 
    5975            0 :       do my_ip=1,my_npert
    5976            0 :         do jwan=1,nwan
    5977            0 :           do iwan=1,nwan
    5978            0 :             do ir=1,nr_e
    5979              :                ! Fixed R_e (index ir), all R_p (colon): g(R_e,R_p) = g(R_e,R_p) + g(R_e,q) * e^{-iq.R_p}
    5980              :                wan%grpe_wwp(:, ir, iwan, jwan, my_ip) = wan%grpe_wwp(:, ir, iwan, jwan, my_ip) + &
    5981            0 :                  gww_epq(iwan, jwan, ir, my_ip, my_iq) * emiqr(:)
    5982              :             end do
    5983              :           end do
    5984              :         end do
    5985              :       end do ! my_ip
    5986              :    end do ! my_iq
    5987              : 
    5988            0 :    call xmpi_sum(wan%grpe_wwp, gqk%qpt_kpt_comm%value, ierr)
    5989              : 
    5990            0 :    if (gqk%comm%me == master) then
    5991            0 :      write(std_out, '(a)') '#   R_e [Bohr]    max_{m,n,nu} |g(m,n,nu R_e,:)|  min_{m,n,nu} |g(m,n,nu R_e,:)|[Ha/Bohr] '
    5992            0 :      do ir=1,nr_e
    5993            0 :        write(std_out, *) wan%rmod_e(ir), maxval(abs(wan%grpe_wwp(:,ir,:,:,:))), sum(abs(wan%grpe_wwp(:,ir,:,:,:))) / size(wan%grpe_wwp(:,ir,:,:,:))
    5994              :      end do
    5995              :    end if
    5996              : 
    5997              :    !--------------------------------------------------------------------------------
    5998              :    ! Wannier on-mesh closure self-check: interpolating g(k,q) back at a handful of
    5999              :    ! the SAME coarse (k,q) points used to build wan%grpe_wwp must reproduce the pre-FT
    6000              :    ! gww_pk cached above, once rotated by the SAME wan%interp_ham-derived u_k/u_kq
    6001              :    ! (interp_ham's gauge is generically different from the ABIWAN gauge used for gww_pk,
    6002              :    ! even on-mesh, so we apply the identical rotation to both sides rather than comparing
    6003              :    ! against raw gww_pk). This isolates the WS/ndegen bookkeeping and forward/backward FT
    6004              :    ! consistency. Cheap (wan_ntest points only) and deterministic: a hard ABI_CHECK, not a
    6005              :    ! Refs-compared print, since it is a precision-only mathematical identity.
    6006              :    !--------------------------------------------------------------------------------
    6007            0 :    ABI_MALLOC(u_k_test, (nwan,nwan))
    6008            0 :    ABI_MALLOC(u_kq_test, (nwan,nwan))
    6009            0 :    ABI_MALLOC(eigens_k_test, (nwan))
    6010            0 :    ABI_MALLOC(eigens_kq_test, (nwan))
    6011            0 :    ABI_MALLOC(eigens_k_period, (nwan))
    6012            0 :    ABI_MALLOC(eigens_kq_period, (nwan))
    6013            0 :    ABI_MALLOC(eigens_k_plus, (nwan))
    6014            0 :    ABI_MALLOC(eigens_k_minus, (nwan))
    6015            0 :    ABI_MALLOC(vcart_test, (3,nwan))
    6016            0 :    ABI_MALLOC(cmat_test, (nwan,nwan))
    6017            0 :    ABI_MALLOC(g_expected, (nwan,nwan))
    6018            0 :    ABI_MALLOC(g_atm_test, (nwan, nwan, my_npert, 1))
    6019            0 :    ABI_MALLOC(g_atm_period, (nwan, nwan, my_npert, 1))
    6020              : 
    6021            0 :    max_err = zero; ref_scale = zero
    6022            0 :    max_period_eig_err = zero; period_eig_scale = zero
    6023            0 :    max_period_g2_err = zero; period_g2_scale = zero
    6024            0 :    max_velocity_err = zero; velocity_scale = zero; nvelocity_tested = 0
    6025            0 :    do itest=1,wan_ntest
    6026            0 :      if (.not. test_found(itest)) cycle
    6027            0 :      my_ik = test_ik(itest) - gqk%my_kstart + 1
    6028            0 :      my_iq = test_iq(itest) - gqk%my_qstart + 1
    6029            0 :      kpt = gqk%my_kpts(:,my_ik)
    6030            0 :      call gqk%myqpt(my_iq, gstore, weight_qq, qpt)
    6031            0 :      call wan%interp_ham(gstore%cryst, kpt, u_k_test, eigens_k_test, vcart_test)
    6032            0 :      call wan%interp_ham(gstore%cryst, kpt + qpt, u_kq_test, eigens_kq_test)
    6033            0 :      call wan%interp_eph_manyq(gstore%cryst, 1, qpt, kpt, g_atm_test)
    6034            0 :      ref_scale = max(ref_scale, maxval(abs(test_gref(:,:,:,itest))))
    6035            0 :      do ip_loc=1,my_npert
    6036              :        ! Same order/dagger convention as wan_interp_eph_manyq (m_mlwfovlp.F90).
    6037            0 :        call ZGEMM('N', 'N', nwan, nwan, nwan, cone, u_kq_test, nwan, test_gref(:,:,ip_loc,itest), nwan, czero, cmat_test, nwan)
    6038            0 :        call ZGEMM('N', 'C', nwan, nwan, nwan, cone, cmat_test, nwan, u_k_test, nwan, czero, g_expected, nwan)
    6039            0 :        max_err = max(max_err, maxval(abs(g_expected - g_atm_test(:,:,ip_loc,1))))
    6040              :      end do
    6041              : 
    6042              :      ! Validate analytic Cartesian group velocities against centered finite
    6043              :      ! differences of the interpolated eigenvalues. Skip degenerate bands,
    6044              :      ! whose individual diagonal velocities depend on the chosen subspace basis.
    6045              :      ! These calls intentionally follow the closure comparison because the
    6046              :      ! finite-difference diagonalizations reuse the u_kq_test work buffer.
    6047            0 :      do idir=1,3
    6048            0 :        dkred = WAN_VELOCITY_FD_STEP * gstore%cryst%rprimd(idir,:) / two_pi
    6049            0 :        call wan%interp_ham(gstore%cryst, kpt + dkred, u_kq_test, eigens_k_plus)
    6050            0 :        call wan%interp_ham(gstore%cryst, kpt - dkred, u_kq_test, eigens_k_minus)
    6051            0 :        do ib=1,nwan
    6052            0 :          band_gap = huge(one)
    6053            0 :          if (ib > 1) band_gap = min(band_gap, abs(eigens_k_test(ib) - eigens_k_test(ib-1)))
    6054            0 :          if (ib < nwan) band_gap = min(band_gap, abs(eigens_k_test(ib+1) - eigens_k_test(ib)))
    6055            0 :          if (band_gap < WAN_VELOCITY_DEGEN_TOL) cycle
    6056            0 :          velocity_fd = (eigens_k_plus(ib) - eigens_k_minus(ib)) / (two * WAN_VELOCITY_FD_STEP)
    6057            0 :          max_velocity_err = max(max_velocity_err, abs(vcart_test(idir,ib) - velocity_fd))
    6058            0 :          velocity_scale = max(velocity_scale, abs(vcart_test(idir,ib)), abs(velocity_fd))
    6059            0 :          nvelocity_tested = nvelocity_tested + 1
    6060              :        end do
    6061              :      end do
    6062              : 
    6063              :      ! Reciprocal-periodicity self-check. Integer shifts leave the real-space
    6064              :      ! Fourier sums invariant. Compare eigenvalues and per-perturbation
    6065              :      ! Frobenius norms, which remain well defined even if a tiny roundoff
    6066              :      ! difference rotates eigenvectors inside a degenerate subspace.
    6067            0 :      period_eig_scale = max(period_eig_scale, maxval(abs(eigens_k_test)), maxval(abs(eigens_kq_test)))
    6068            0 :      do ip_loc=1,my_npert
    6069            0 :        period_g2_scale = max(period_g2_scale, sum(abs(g_atm_test(:,:,ip_loc,1))**2))
    6070              :      end do
    6071            0 :      do iperiod=1,wan_nperiod
    6072            0 :        call wan%interp_ham(gstore%cryst, kpt + period_gk(:,iperiod), u_k_test, eigens_k_period)
    6073              :        call wan%interp_ham(gstore%cryst, kpt + qpt + period_gk(:,iperiod) + period_gq(:,iperiod), &
    6074            0 :                            u_kq_test, eigens_kq_period)
    6075              :        call wan%interp_eph_manyq(gstore%cryst, 1, qpt + period_gq(:,iperiod), &
    6076            0 :                                  kpt + period_gk(:,iperiod), g_atm_period)
    6077              :        max_period_eig_err = max(max_period_eig_err, maxval(abs(eigens_k_period - eigens_k_test)), &
    6078            0 :                                maxval(abs(eigens_kq_period - eigens_kq_test)))
    6079            0 :        do ip_loc=1,my_npert
    6080              :          max_period_g2_err = max(max_period_g2_err, abs( &
    6081            0 :            sum(abs(g_atm_period(:,:,ip_loc,1))**2) - sum(abs(g_atm_test(:,:,ip_loc,1))**2)))
    6082              :        end do
    6083              :      end do
    6084              :    end do
    6085              : 
    6086              :    ! Each fixed (k,q) pair must be owned exactly once within each perturbation
    6087              :    ! slice. Reduce diagnostics over the complete spin communicator so every rank
    6088              :    ! applies the same check and the printed result is MPI-decomposition invariant.
    6089            0 :    ntest_found = count(test_found)
    6090            0 :    call xmpi_sum(ntest_found, gqk%qpt_kpt_comm%value, ierr)
    6091            0 :    ABI_CHECK_IEQ(ntest_found, wan_ntest, "Wannier closure test did not find each fixed global (k,q) point exactly once")
    6092            0 :    call xmpi_max(max_err, gqk%comm%value, ierr)
    6093            0 :    call xmpi_max(ref_scale, gqk%comm%value, ierr)
    6094            0 :    call xmpi_max(max_period_eig_err, gqk%comm%value, ierr)
    6095            0 :    call xmpi_max(period_eig_scale, gqk%comm%value, ierr)
    6096            0 :    call xmpi_max(max_period_g2_err, gqk%comm%value, ierr)
    6097            0 :    call xmpi_max(period_g2_scale, gqk%comm%value, ierr)
    6098            0 :    call xmpi_max(max_velocity_err, gqk%comm%value, ierr)
    6099            0 :    call xmpi_max(velocity_scale, gqk%comm%value, ierr)
    6100            0 :    call xmpi_sum(nvelocity_tested, gqk%qpt_kpt_comm%value, ierr)
    6101            0 :    ref_scale = max(ref_scale, tol12)
    6102            0 :    period_eig_scale = max(period_eig_scale, tol12)
    6103            0 :    period_g2_scale = max(period_g2_scale, tol12)
    6104            0 :    velocity_scale = max(velocity_scale, one)
    6105              : 
    6106            0 :    if (gqk%comm%me == master) then
    6107            0 :      write(std_out,'(a,es10.2,a,es10.2)') " Wannier on-mesh closure self-check: max_err=", max_err, "  ref_scale=", ref_scale
    6108            0 :      write(std_out,'(a,es10.2,a,es10.2)') " Wannier reciprocal-periodicity self-check: max_eig_err=", &
    6109            0 :        max_period_eig_err, "  max_g2_err=", max_period_g2_err
    6110            0 :      write(std_out,'(a,i0,a,es10.2)') " Wannier group-velocity self-check: nvalues=", &
    6111            0 :        nvelocity_tested, "  max_err=", max_velocity_err
    6112              :    end if
    6113              : 
    6114            0 :    ABI_CHECK(max_err < WAN_CLOSURE_TOL * ref_scale, "Wannier on-mesh closure self-check failed")
    6115            0 :    msg = "Wannier reciprocal-periodicity self-check failed for interpolated electronic eigenvalues."
    6116            0 :    ABI_CHECK(max_period_eig_err < WAN_CLOSURE_TOL * period_eig_scale, msg)
    6117            0 :    msg = "Wannier reciprocal-periodicity self-check failed for gauge-invariant e-ph Frobenius norms."
    6118            0 :    ABI_CHECK(max_period_g2_err < WAN_CLOSURE_TOL * period_g2_scale, msg)
    6119            0 :    ABI_CHECK(nvelocity_tested > 0, "Wannier group-velocity self-check did not find a nondegenerate band")
    6120            0 :    msg = "Analytic Wannier group velocities do not agree with finite differences of the interpolated eigenvalues."
    6121            0 :    ABI_CHECK(max_velocity_err < WAN_VELOCITY_TOL * velocity_scale, msg)
    6122              : 
    6123            0 :    ABI_FREE(u_k_test)
    6124            0 :    ABI_FREE(u_kq_test)
    6125            0 :    ABI_FREE(eigens_k_test)
    6126            0 :    ABI_FREE(eigens_kq_test)
    6127            0 :    ABI_FREE(eigens_k_period)
    6128            0 :    ABI_FREE(eigens_kq_period)
    6129            0 :    ABI_FREE(eigens_k_plus)
    6130            0 :    ABI_FREE(eigens_k_minus)
    6131            0 :    ABI_FREE(vcart_test)
    6132            0 :    ABI_FREE(cmat_test)
    6133            0 :    ABI_FREE(g_expected)
    6134            0 :    ABI_FREE(g_atm_test)
    6135            0 :    ABI_FREE(g_atm_period)
    6136            0 :    ABI_FREE(test_gref)
    6137              : 
    6138              :    ! Free memory for this spin.
    6139            0 :    ABI_FREE(emikr)
    6140            0 :    ABI_FREE(emiqr)
    6141            0 :    ABI_FREE(gww_pk)
    6142            0 :    ABI_FREE(gww_epq)
    6143              :  end do ! my_is
    6144              : 
    6145              :  ! =====================
    6146              :  ! Write data to GWAN.nc
    6147              :  ! =====================
    6148            0 :  do spin=1,gstore%nsppol
    6149            0 :    my_is = gstore%spin2my_is(spin)
    6150            0 :    if (my_is /= 0) then
    6151            0 :      gqk => gstore%gqk(my_is)
    6152              :      ! grpe_wwp has already been reduced over qpt_kpt_comm and is replicated
    6153              :      ! across the q/k (and auxiliary sum/band) grid. Exactly one such slice
    6154              :      ! must enter the writer; all ranks along its perturbation axis participate
    6155              :      ! collectively because grpe_wwp remains distributed over perturbations.
    6156            0 :      if (all(gqk%coords_qkpb_sumbp([1,2,4,5,6]) == 0)) then
    6157            0 :        call gqk%wan%ncwrite_gwan(dtfil, gstore%cryst, gstore%ebands, gqk%pert_comm)
    6158              :      end if
    6159              :    end if
    6160            0 :    call xmpi_barrier(gstore%comm)
    6161              :  end do ! spin
    6162              : 
    6163            0 :  call cwtime_report(" gstore_wannierize_and_write_gwan:", cpu, wall, gflops)
    6164              : 
    6165            0 : end subroutine gstore_wannierize_and_write_gwan
    6166              : !!***
    6167              : 
    6168              : !!****f* m_gstore/handle_lr_term
    6169              : !! NAME
    6170              : !! handle_lr_term
    6171              : !!
    6172              : !! FUNCTION
    6173              : !!  Add/Remove the long range term to/from the e-ph matrix elements.
    6174              : !!
    6175              : !! INPUTS
    6176              : !!
    6177              : !! SOURCE
    6178              : 
    6179              : !subroutine handle_lr_term(cryst, qpt, ng, gvec, nwin_kq, nwin_k, nwan, u_kq, u_k, zeff, qstar, isgn, g_bb)
    6180              : !
    6181              : !!Arguments ------------------------------------
    6182              : ! type(crystal_t),intent(in) :: cryst
    6183              : ! real(dp),intent(in) :: qpt(3)
    6184              : ! integer,intent(in) :: ng, nwin_kq, nwin_k, nwan, isgn, gvec(3,ng)
    6185              : ! complex(dp),intent(in) :: u_kq(nwin_kq, nwan), u_k(nwin_k,nwan)
    6186              : ! real(dp),intent(in) :: zeff(3,3,cryst%natom), qstar(3,3,3,cryst%natom)
    6187              : ! complex(dp),intent(inout) :: g_bb(nwin_kq, nwin_k)
    6188              : !
    6189              : !!Local variables-------------------------------
    6190              : !!scalars
    6191              : ! !integer :: ig
    6192              : ! !character(len=500) :: msg
    6193              : !!arrays
    6194              : !! *************************************************************************
    6195              : !
    6196              : !end subroutine handle_lr_term
    6197              : !!***
    6198              : 
    6199              : !----------------------------------------------------------------------
    6200              : 
    6201              : !!****f* m_gstore/gqk_get_erange_mask
    6202              : !! NAME
    6203              : !!  gqk_get_erange_mask
    6204              : !!
    6205              : !! FUNCTION
    6206              : !!  Compute MPI-distributed and global masks for electronic states |n,k> allowed by erange.
    6207              : !!
    6208              : !! INPUTS
    6209              : !!  gstore<gstore_t>=Electron-phonon object containing dimensions and related quantities.
    6210              : !!  erange=Energy range:
    6211              : !!    -- if both entries are negative, assume metal and include states within the
    6212              : !! [efermi-abs(erange(1)), efermi+abs(erange(2))] window;
    6213              : !!    -- otherwise, erange(1) & erange(2) select window wrt VBM & CBM, respectively.
    6214              : !!
    6215              : !! OUTPUT
    6216              : !!  my_states(gqk%nb_k, gqk%my_nk)=Mask for selected states at this MPI proc.
    6217              : !!  glob_states(gqk%nb_k, gqk%my_nk)=Global mask for selected states.
    6218              : !!
    6219              : !! SOURCE
    6220              : 
    6221            0 : subroutine gqk_get_erange_mask(gqk, gstore, erange, my_states, glob_states)
    6222              : 
    6223              : !Arguments ------------------------------------
    6224              : !scalars
    6225              :  class(gqk_t), target, intent(inout) :: gqk
    6226              :  class(gstore_t), target, intent(in) :: gstore
    6227              : !arrays
    6228              :  real(dp), intent(in) :: erange(2)
    6229              :  integer, intent(out) :: my_states(gqk%nb_k, gqk%my_nk), glob_states(gqk%nb_k, gqk%glob_nk)
    6230              : 
    6231              : !Local variables-------------------------------
    6232              : !scalars
    6233              :  class(ebands_t), pointer :: ebands
    6234              :  type(gaps_t) :: gaps
    6235              :  integer :: my_ik, ik_ibz, ik_glob, ib_k, bstart_k, gap_err, ierr
    6236              :  real(dp) :: vmax, cmin, eig
    6237              :  logical :: assume_gap
    6238              : !----------------------------------------------------------------------
    6239              : 
    6240            0 :  ebands => gstore%ebands
    6241              : 
    6242            0 :  assume_gap = .not. all(erange < tol12)
    6243            0 :  gaps = ebands%get_gaps(gap_err)
    6244              : 
    6245            0 :  if (assume_gap) then
    6246            0 :    call gaps%print([std_out])
    6247            0 :    vmax = gaps%vb_max(gqk%spin) + tol2 * eV_Ha
    6248            0 :    cmin = gaps%cb_min(gqk%spin) - tol2 * eV_Ha
    6249              :  else
    6250            0 :    vmax = ebands%fermie
    6251            0 :    cmin = ebands%fermie
    6252              :  end if
    6253              : 
    6254              :  ! Fill the mask for allowed states
    6255            0 :  my_states(:,:) = 0
    6256            0 :  glob_states(:,:) = 0
    6257            0 :  bstart_k = gstore%brange_k_spin(1, gqk%spin)
    6258              : 
    6259            0 :  do my_ik=1,gqk%my_nk
    6260            0 :    ik_ibz = gqk%my_k2ibz(1, my_ik)
    6261            0 :    ik_glob = my_ik + gqk%my_kstart - 1
    6262              : 
    6263            0 :    do ib_k=1,gqk%nb_k
    6264            0 :      eig = ebands%eig(bstart_k + ib_k - 1, ik_ibz, gqk%spin)
    6265              : 
    6266            0 :      if (abs(erange(1)) > tol12) then
    6267              :        ! Filter valence states.
    6268            0 :        if (eig <= vmax .and. vmax - eig <= abs(erange(1))) then
    6269            0 :          my_states(ib_k, my_ik) = 1; glob_states(ib_k, ik_glob) = 1
    6270              :        end if
    6271              :      end if
    6272              : 
    6273            0 :      if (abs(erange(2)) > tol12) then
    6274              :        ! Filter conduction states.
    6275            0 :        if (eig >= cmin .and. eig - cmin <= abs(erange(2))) then
    6276            0 :          my_states(ib_k, my_ik) = 1; glob_states(ib_k, ik_glob) = 1
    6277              :        end if
    6278              :      end if
    6279              : 
    6280              :    enddo
    6281              :  enddo
    6282              : 
    6283            0 :  call xmpi_sum(glob_states, gqk%kpt_comm%value, ierr)
    6284            0 :  call gaps%free()
    6285              : 
    6286            0 : end subroutine gqk_get_erange_mask
    6287              : !!***
    6288              : 
    6289              : !----------------------------------------------------------------------
    6290              : 
    6291              : !!****f* m_gstore/gqk_filter_erange
    6292              : !! NAME
    6293              : !!  gqk_filter_erange
    6294              : !!
    6295              : !! FUNCTION
    6296              : !!  Nullify all matrix elements connecting electronic states excluded by energy range.
    6297              : !!
    6298              : !! INPUTS
    6299              : !!  gstore<gstore_t>=Electron-phonon object containing dimensions and related quantities.
    6300              : !!  erange=Energy range:
    6301              : !!    -- if both entries are negative, assume metal and include states within the
    6302              : !! [efermi-abs(erange(1)), efermi+abs(erange(2))] window;
    6303              : !!    -- otherwise, erange(1) & erange(2) select window wrt VBM & CBM, respectively.
    6304              : !!
    6305              : !! OUTPUT
    6306              : !!
    6307              : !! SOURCE
    6308              : 
    6309            0 : subroutine gqk_filter_erange(gqk, gstore, erange)
    6310              : 
    6311              : !Arguments ------------------------------------
    6312              : !scalars
    6313              :  class(gqk_t), target, intent(inout) :: gqk
    6314              :  class(gstore_t), target, intent(in) :: gstore
    6315              : !arrays
    6316              :  real(dp), intent(in) :: erange(2)
    6317              : 
    6318              : !Local variables-------------------------------
    6319              : !scalars
    6320              :  integer :: my_ik, ik_glob, my_iq, ikq, ipert, ierr, ib_k, jb_kq
    6321              :  real(dp) :: wtq
    6322              :  logical :: skip_nk, skip_mkq, skip_q
    6323            0 :  type(krank_t) :: krank_kpts
    6324              :  type(ebands_t), pointer :: ebands
    6325              : !arrays
    6326            0 :  integer :: my_states(gqk%nb_k, gqk%my_nk), glob_states(gqk%nb_k, gqk%glob_nk)
    6327            0 :  real(dp) :: kpt(3), qpt(3), kpq(3), kpts(3, gqk%glob_nk), my_qpts(3, gqk%my_nq)
    6328              : !----------------------------------------------------------------------
    6329              : 
    6330            0 :  ABI_CHECK_IEQ(gqk%nb_kq, gqk%nb_k, "nb_kq /= nk_k not tested")
    6331              : 
    6332            0 :  ebands => gstore%ebands
    6333              : 
    6334              :  ! Compute masks
    6335            0 :  call gqk%get_erange_mask(gstore, erange, my_states, glob_states)
    6336              : 
    6337              :  ! Get global krank for k+q transitions
    6338            0 :  kpts(:, :) = zero
    6339            0 :  do my_ik=1,gqk%my_nk
    6340            0 :    ik_glob = my_ik + gqk%my_kstart - 1
    6341            0 :    kpts(:, ik_glob) = gqk%my_kpts(:, my_ik)
    6342              :  enddo
    6343            0 :  call xmpi_sum(kpts, gqk%kpt_comm%value, ierr)
    6344              : 
    6345            0 :  call krank_kpts%from_kptrlatt(gqk%glob_nk, kpts, ebands%kptrlatt, compute_invrank=.True.)
    6346              : 
    6347              :  ! Get all q-points for this proc
    6348            0 :  do my_iq=1,gqk%my_nq
    6349            0 :    call gqk%myqpt(my_iq, gstore, wtq, my_qpts(:, my_iq))
    6350              :  enddo
    6351              : 
    6352              :  ! Nullify matrix elements connecting the excluded states
    6353            0 :  do my_ik=1,gqk%my_nk
    6354            0 :    kpt(:) = gqk%my_kpts(:, my_ik)
    6355              : 
    6356            0 :    do ib_k=1,gqk%nb_k
    6357              :      ! |nk> is forbidden
    6358            0 :      skip_nk = .false.
    6359            0 :      if (my_states(ib_k, my_ik) == 0) skip_nk = .true.
    6360              : 
    6361            0 :      do my_iq=1,gqk%my_nq
    6362            0 :        qpt(:) = my_qpts(:, my_iq)
    6363              : 
    6364              :        ! Find k+q --> k' index in krank_kpts
    6365            0 :        kpq(:) = kpt(:) + qpt(:)
    6366            0 :        ikq = krank_kpts%get_index(kpq)
    6367              : 
    6368              :        ! k+q falls outside the filtered kpts pool
    6369            0 :        skip_q = .false.
    6370            0 :        if (ikq == -1) skip_q = .true.
    6371              : 
    6372            0 :        do jb_kq=1,gqk%nb_kq
    6373              :          ! |mk+q> is forbidden
    6374            0 :          skip_mkq = .false.
    6375            0 :          if (glob_states(jb_kq, ikq) == 0) skip_mkq = .true.
    6376              : 
    6377            0 :          do ipert=1,gqk%my_npert
    6378              : 
    6379            0 :            if (skip_nk .or. skip_q .or. skip_mkq) then
    6380            0 :              select case (gqk%cplex)
    6381              :              case (1)
    6382            0 :                gqk%my_g2(ipert, jb_kq, my_iq, ib_k, my_ik) = zero
    6383              :              case (2)
    6384            0 :                gqk%my_g(ipert, jb_kq, my_iq, ib_k, my_ik) = czero
    6385              :              case default
    6386            0 :                ABI_ERROR(sjoin("Invalid gqk%cplex:", itoa(gqk%cplex)))
    6387              :              end select
    6388              :            end if
    6389              : 
    6390              :          enddo
    6391              :        enddo
    6392              :      enddo
    6393              :    enddo
    6394              :  enddo
    6395              : 
    6396            0 :  call krank_kpts%free()
    6397              : 
    6398            0 : end subroutine gqk_filter_erange
    6399              : !!***
    6400              : 
    6401              : !----------------------------------------------------------------------
    6402              : 
    6403              : !!****f* m_gstore/gstore_compute_and_write_ph
    6404              : !! NAME
    6405              : !!  gstore_compute_and_write_ph
    6406              : !!
    6407              : !! FUNCTION
    6408              : !!  Compute phonon frequencies and eigenvectors in the IBZ. Write results to disk
    6409              : !!
    6410              : !! SOURCE
    6411              : 
    6412            8 : subroutine gstore_compute_and_write_ph(gstore, root_ncid)
    6413              : 
    6414              : !Arguments ------------------------------------
    6415              : !scalars
    6416              :  class(gstore_t), intent(in) :: gstore
    6417              :  integer,intent(in) :: root_ncid
    6418              : 
    6419              : !Local variables-------------------------------
    6420              : !scalars
    6421              :  integer :: natom, natom3, nproc, ii, iq_ibz, my_nqibz, iq_start, ncerr
    6422              :  real(dp) :: cpu, wall, gflops
    6423              : !arrays
    6424            8 :  integer,allocatable :: my_iqibz_inds(:)
    6425            8 :  real(dp),allocatable :: buf_wqnu(:,:), buf_eigvec_cart(:,:,:,:,:), displ_cart_qibz(:,:,:,:)
    6426              : !----------------------------------------------------------------------
    6427              : 
    6428            8 :  nproc = xmpi_comm_size(gstore%comm)
    6429            8 :  natom = gstore%cryst%natom; natom3 = 3 * natom
    6430              : 
    6431            8 :  call wrtout(std_out, " Computing phonon frequencies and displacements in the IBZ ...", pre_newlines=1, do_flush=.True.)
    6432            8 :  call cwtime(cpu, wall, gflops, "start")
    6433              : 
    6434            8 :  call xmpi_split_block(gstore%nqibz, gstore%comm, my_nqibz, my_iqibz_inds)
    6435           32 :  ABI_MALLOC(buf_wqnu, (natom3, my_nqibz))
    6436           40 :  ABI_MALLOC(buf_eigvec_cart, (2, 3, natom, natom3, my_nqibz))
    6437           32 :  ABI_MALLOC(displ_cart_qibz, (2, 3, natom, natom3))
    6438              : 
    6439            8 :  NCF_CHECK(nctk_prepare_mpiio(root_ncid, "phfreqs_ibz"))
    6440            8 :  NCF_CHECK(nctk_prepare_mpiio(root_ncid, "pheigvec_cart_ibz"))
    6441              : 
    6442          141 :  do ii=1,my_nqibz
    6443          133 :    iq_ibz = my_iqibz_inds(ii)
    6444              :    call gstore%ifc%fourq(gstore%cryst, gstore%qibz(:, iq_ibz), buf_wqnu(:,ii), displ_cart_qibz, &
    6445          141 :                          out_eigvec=buf_eigvec_cart(:,:,:,:,ii))
    6446              :  end do
    6447              : 
    6448            8 :  if (nproc > 1 .and. gstore%nqibz >= nproc) then
    6449            0 :    NCF_CHECK(nctk_set_collective(root_ncid, root_vid("phfreqs_ibz")))
    6450            0 :    NCF_CHECK(nctk_set_collective(root_ncid, root_vid("pheigvec_cart_ibz")))
    6451              :  end if
    6452            8 :  call xmpi_barrier(gstore%comm)
    6453              : 
    6454            8 :  if (my_nqibz > 0) then
    6455            8 :    iq_start = my_iqibz_inds(1)
    6456              :    ncerr = nf90_put_var(root_ncid, root_vid("phfreqs_ibz"), buf_wqnu, &
    6457           40 :                         start=[1, iq_start], count=[natom3, my_nqibz])
    6458            8 :    NCF_CHECK(ncerr)
    6459              :    ncerr = nf90_put_var(root_ncid, root_vid("pheigvec_cart_ibz"), buf_eigvec_cart, &
    6460           88 :                         start=[1,1,1,1,iq_start], count=[2, 3, natom, natom3, my_nqibz])
    6461            8 :    NCF_CHECK(ncerr)
    6462              :  end if
    6463              : 
    6464            8 :  ABI_FREE(displ_cart_qibz)
    6465            8 :  ABI_FREE(my_iqibz_inds)
    6466            8 :  ABI_FREE(buf_wqnu)
    6467            8 :  ABI_FREE(buf_eigvec_cart)
    6468           16 :  call cwtime_report(" Phonon computation + output", cpu, wall, gflops)
    6469              : 
    6470              : contains
    6471              : 
    6472           16 : integer function root_vid(var_name)
    6473              :   character(len=*),intent(in) :: var_name
    6474           16 :   root_vid = nctk_idname(root_ncid, var_name)
    6475              : end function root_vid
    6476              : 
    6477              : end subroutine gstore_compute_and_write_ph
    6478              : !!***
    6479              : 
    6480              : !!****f* m_gstore/gstore_compute_and_write_vk
    6481              : !! NAME
    6482              : !!  gstore_compute_and_write_vk
    6483              : !!
    6484              : !! FUNCTION
    6485              : !!  Compute electronic group velocities in the IBZ.
    6486              : !!  Write results to disk
    6487              : !!
    6488              : !! SOURCE
    6489              : 
    6490            8 : subroutine gstore_compute_and_write_vk(gstore, mpw, wfd, ebands, psps, pawtab, root_ncid)
    6491              : 
    6492              : !Arguments ------------------------------------
    6493              :  class(gstore_t), intent(in) :: gstore
    6494              :  integer,intent(in) :: mpw
    6495              :  type(wfd_t),intent(in) :: wfd
    6496              :  type(ebands_t),target,intent(in) :: ebands
    6497              :  type(pseudopotential_type),intent(in) :: psps
    6498              :  type(pawtab_type),intent(in) :: pawtab(psps%ntypat*psps%usepaw)
    6499              :  integer,intent(in) :: root_ncid
    6500              : 
    6501              : !Local variables-------------------------------
    6502              : !scalars
    6503              :  integer :: my_is, spin, nb_k, nb_kq, spin_ncid, band, in_k, my_ik, usecprj, ierr, ii, ik_ibz, isym_k, trev_k, npw_k, istwf_k
    6504              :  real(dp) :: cpu_kk, wall_kk, gflops_kk, eig0nk
    6505              :  logical :: isirr_k
    6506           80 :  type(ddkop_t) :: ddkop
    6507              : !arrays
    6508              :  integer :: g0_k(3)
    6509            8 :  integer,allocatable :: count_bk(:,:)
    6510              :  real(dp) :: kk(3) !, kk_ibz(3)
    6511           16 :  real(dp),allocatable :: vnk_cart_ibz(:,:,:), cg_work(:,:)
    6512            8 :  type(pawcprj_type),allocatable :: cwaveprj0(:,:)
    6513              : !----------------------------------------------------------------------
    6514              : 
    6515            8 :  call wrtout(std_out, " computing and writing velocity operator matrix elements in the ibz")
    6516            8 :  call wrtout(std_out, " note that not all the k-points in the ibz are computed when kfilter is activated!")
    6517            8 :  call cwtime(cpu_kk, wall_kk, gflops_kk, "start")
    6518              : 
    6519              :  ! On disk, we have:
    6520              :  !    nctkarr_t("vk_cart_ibz", "dp", "three, nb_k, gstore_nkibz"))
    6521              :  !    nctkarr_t("vkmat_cart_ibz", "dp", "two, three, nb, nb, gstore_nkibz")))
    6522              : 
    6523            8 :  call ddkop%init(gstore%dtset, gstore%cryst, pawtab, psps, wfd%mpi_enreg, mpw, wfd%ngfft)
    6524           24 :  ABI_MALLOC(cg_work, (2, mpw*wfd%nspinor))
    6525              : 
    6526            8 :  usecprj = gstore%dtset%usepaw
    6527           32 :  ABI_MALLOC(cwaveprj0, (gstore%cryst%natom, wfd%nspinor*usecprj))
    6528              : 
    6529           16 :  do my_is=1,gstore%my_nspins
    6530            8 :    associate (gqk => gstore%gqk(my_is))
    6531            8 :    spin = gstore%my_spins(my_is); nb_k = gqk%nb_k; nb_kq = gqk%nb_kq
    6532              : 
    6533              :    ! Be careful as wavefunctions might be replicated.
    6534              :    ! Use count_bk to count how many states have been computed in parallel in order to rescale the results.
    6535            8 :    if (gstore%with_vk == 1) then
    6536         1285 :      ABI_CALLOC(vnk_cart_ibz, (3, nb_k, gstore%nkibz))
    6537          445 :      ABI_ICALLOC(count_bk, (nb_k, gstore%nkibz))
    6538              :    else
    6539            0 :      ABI_ERROR("gstore%with_vk 2 not implemented")
    6540              :    end if
    6541              : 
    6542            8 :    NCF_CHECK(nf90_inq_ncid(root_ncid, strcat("gqk", "_spin", itoa(spin)), spin_ncid))
    6543            8 :    NCF_CHECK(nctk_prepare_mpiio(spin_ncid, "vk_cart_ibz"))
    6544              : 
    6545          319 :    do my_ik=1,gqk%my_nk
    6546              :      ! The k-point and the symmetries relating the BZ k-point to the IBZ.
    6547         1244 :      kk = gqk%my_kpts(:, my_ik)
    6548          311 :      ik_ibz = gqk%my_k2ibz(1, my_ik) ; isym_k = gqk%my_k2ibz(2, my_ik)
    6549         1244 :      trev_k = gqk%my_k2ibz(6, my_ik); g0_k = gqk%my_k2ibz(3:5,my_ik)
    6550         1149 :      isirr_k = (isym_k == 1 .and. trev_k == 0 .and. all(g0_k == 0))
    6551              :      if (.not. isirr_k) cycle
    6552              : 
    6553              :      ! parallelize inside (q, pert) so that only one proc in the 3D grid
    6554              :      ! computes v_nk for this kpt in the BZ and we can use xmpi_sum_master.
    6555              :      !cnt = cnt + 1
    6556              :      !if (gqk%qpt_pert_comm%skip(cnt)) cycle
    6557              : 
    6558           36 :      npw_k = wfd%npwarr(ik_ibz); istwf_k = wfd%istwfk(ik_ibz)
    6559           36 :      call ddkop%setup_spin_kpoint(gstore%dtset, gstore%cryst, psps, spin, kk, istwf_k, npw_k, wfd%kdata(ik_ibz)%kg_k)
    6560              : 
    6561          150 :      do band=gqk%bstart_k, gqk%bstop_k
    6562          106 :        call wfd%copy_cg(band, ik_ibz, spin, cg_work)
    6563          106 :        eig0nk = ebands%eig(band, ik_ibz, spin)
    6564          106 :        in_k = band - gqk%bstart_k + 1
    6565          106 :        vnk_cart_ibz(:, in_k, ik_ibz) = ddkop%get_vdiag(eig0nk, istwf_k, npw_k, wfd%nspinor, cg_work, cwaveprj0)
    6566          142 :        count_bk(in_k, ik_ibz) = count_bk(in_k, ik_ibz) + 1
    6567              :      end do
    6568              :    end do ! my_ik
    6569              : 
    6570            8 :    call xmpi_sum(count_bk, gqk%comm%value, ierr)
    6571            8 :    call xmpi_sum(vnk_cart_ibz, gqk%comm%value, ierr)
    6572              : 
    6573          141 :    do ik_ibz=1, gstore%nkibz
    6574          421 :      do band=gqk%bstart_k, gqk%bstop_k
    6575          280 :        in_k = band - gqk%bstart_k + 1
    6576          280 :        if (count_bk(in_k, ik_ibz) == 0) cycle
    6577          557 :        do ii=1,3
    6578          598 :          vnk_cart_ibz(ii,in_k,ik_ibz) = vnk_cart_ibz(ii,in_k,ik_ibz) / count_bk(in_k, ik_ibz)
    6579              :        end do
    6580              :      end do
    6581              :    end do
    6582              : 
    6583              :    ! Write v_nk to disk.
    6584              :    !if (gqk%comm%me == master) then
    6585            8 :      NCF_CHECK(nf90_put_var(spin_ncid, spin_vid("vk_cart_ibz"), vnk_cart_ibz))
    6586              :    !end if
    6587              : 
    6588            8 :    ABI_FREE(vnk_cart_ibz)
    6589           16 :    ABI_FREE(count_bk)
    6590              :    end associate
    6591              :  end do ! my_is
    6592              : 
    6593            8 :  ABI_FREE(cg_work)
    6594            8 :  call ddkop%free()
    6595              : 
    6596            8 :  call pawcprj_free(cwaveprj0)
    6597            8 :  ABI_FREE(cwaveprj0)
    6598              : 
    6599           96 :  call cwtime_report(sjoin(" Computation of v_k group velocities with with_vk:", itoa(gstore%with_vk)), cpu_kk, wall_kk, gflops_kk)
    6600              : 
    6601              : contains
    6602              : 
    6603            8 : integer function spin_vid(var_name)
    6604              :   character(len=*),intent(in) :: var_name
    6605            8 :   spin_vid = nctk_idname(spin_ncid, var_name)
    6606              : end function spin_vid
    6607              : 
    6608              : end subroutine gstore_compute_and_write_vk
    6609              : !!***
    6610              : 
    6611              : !!****f* m_gstore/gstore_compute_and_write_commutator
    6612              : !! NAME
    6613              : !!  gstore_compute_and_write_commutator
    6614              : !!
    6615              : !! FUNCTION
    6616              : !!  Compute matrix elements i <psi_mk|[V1_q0ka, p]|psi_nk> in the full BZ in reduced coordinates.
    6617              : !!  Write results to disk.
    6618              : !!  See [[cite:Lihm2020]], PhysRevB.101.121102
    6619              : !!
    6620              : !! SOURCE
    6621              : 
    6622            0 : subroutine gstore_compute_and_write_commutator(gstore, mpw, gmax, ngfft, ngfftf, dtset, cryst, pawfgr, psps, &
    6623            0 :                                                wfd, mpi_enreg, kg_k, ebands, dvdb, gs_ham_kq, root_ncid)
    6624              : 
    6625              : !Arguments ------------------------------------
    6626              :  class(gstore_t), intent(in) :: gstore
    6627              :  integer,intent(in) :: gmax(3), mpw
    6628              :  integer,intent(in) :: ngfft(18),ngfftf(18)
    6629              :  type(dvdb_t),intent(inout) :: dvdb
    6630              :  type(gs_hamiltonian_type),intent(inout) :: gs_ham_kq
    6631              :  type(dataset_type),intent(in) :: dtset
    6632              :  type(crystal_t),intent(in) :: cryst
    6633              :  type(wfd_t),intent(in) :: wfd
    6634              :  type(mpi_type),intent(in) :: mpi_enreg
    6635              :  type(ebands_t),intent(in) :: ebands
    6636              :  type(pawfgr_type),intent(in) :: pawfgr
    6637              :  type(pseudopotential_type),intent(in) :: psps
    6638              :  integer,intent(in) :: root_ncid
    6639              : !arrays
    6640              :  integer,intent(inout) :: kg_k(3,mpw)
    6641              : 
    6642              : !Local variables-------------------------------
    6643              : !scalars
    6644              :  integer,parameter :: tim_getgh1c = 1, berryopt0 = 0, master = 0
    6645              :  integer :: my_is, spin, nb_k, nb_kq, spin_ncid, in_k, my_ik, ii, ik_ibz, npw_k, npwsp_k, istwf_k ! ik_bz,
    6646              :  integer :: cplex, db_iqpt, idir, ipert, ipc, my_ip, natom, natom3, n1, n2, n3, n4, n5, n6, nsppol, nspinor, nspden
    6647              :  integer :: nfft, nfftf, mgfftf, my_npert, nkpg_k, band_k !, glob_nk mgfft,
    6648              :  integer :: sij_opt,usecprj,usevnl,optlocal,optnl,opt_gvnlx1, ncerr, ik_glob, ierr
    6649              :  real(dp) :: cpu_kk, wall_kk, gflops_kk
    6650              :  logical :: gen_eigenpb
    6651            0 :  type(rf_hamiltonian_type) :: rf_ham_kq
    6652              : !arrays
    6653              :  integer :: units(2), work_ngfft(18) ! g0_k(3)
    6654              :  !integer,allocatable :: count_bk(:,:)
    6655              :  real(dp) :: kk_ibz(3), kk_bz(3), gamma_point(3)
    6656            0 :  real(dp),allocatable :: v1scf(:,:,:,:), work(:,:,:,:), p_kets_k(:,:,:,:), gs1c_kq(:,:), dmat(:,:,:,:)
    6657            0 :  real(dp),allocatable :: kets_k(:,:,:), h1_kets_kq(:,:,:), iv1p_comm(:,:,:,:,:)
    6658            0 :  real(dp),allocatable :: ffnl_k(:,:,:,:), ph3d_k(:,:,:), grad_berry(:,:), kinpw_k(:), kpg_k(:,:)
    6659            0 :  real(dp),allocatable :: vlocal(:,:,:,:), vlocal1(:,:,:,:,:), dummy_vtrial(:,:), gvnlx1(:,:,:), lambda(:)
    6660            0 :  type(pawcprj_type),allocatable :: cwaveprj0(:,:)
    6661              : !----------------------------------------------------------------------
    6662              : 
    6663            0 :  units = [std_out, ab_out]
    6664            0 :  call wrtout(units, " Computing and writing i <psi_mk| [V1, p]| psi_nk> ...")
    6665            0 :  call cwtime(cpu_kk, wall_kk, gflops_kk, "start")
    6666              : 
    6667              :  ! Copy important dimensions
    6668            0 :  natom = cryst%natom; natom3 = 3 * natom; nsppol = ebands%nsppol; nspinor = ebands%nspinor; nspden = dtset%nspden
    6669              : 
    6670            0 :  n1 = ngfftf(1); n2 = ngfftf(2); n3 = ngfftf(3); n4 = ngfftf(4); n5 = ngfftf(5); n6 = ngfftf(6)
    6671            0 :  nfftf = product(ngfftf(1:3)); mgfftf = maxval(ngfftf(1:3))
    6672              : 
    6673            0 :  call ngfft_seq(work_ngfft, gmax)
    6674            0 :  ABI_MALLOC(work, (2, work_ngfft(4), work_ngfft(5), work_ngfft(6)))
    6675              : 
    6676              :  ! Read the dvscf potentials at qq=Gamma for all 3*natom perturbations.
    6677              :  ! This call allocates v1scf(cplex, nfftf, nspden, 3*natom)
    6678            0 :  gamma_point(:) = zero; db_iqpt = dvdb%findq(gamma_point)
    6679            0 :  call dvdb%readsym_allv1(db_iqpt, cplex, nfftf, ngfftf, v1scf, gstore%comm)
    6680            0 :  ABI_CHECK_IEQ(cplex, 1, "cplex should be zero when q == 0")
    6681              : 
    6682              :  ! Allocate vlocal. Note nvloc
    6683              :  ! I set vlocal to huge to trigger possible bugs (DFPT routines should not access the data)
    6684            0 :  usecprj = gstore%dtset%usepaw
    6685            0 :  ABI_MALLOC(vlocal, (n4, n5, n6, gs_ham_kq%nvloc))
    6686            0 :  vlocal = huge(one)
    6687            0 :  ABI_CALLOC(dummy_vtrial, (nfftf, nspden))
    6688            0 :  ABI_MALLOC(cwaveprj0, (gstore%cryst%natom, wfd%nspinor*usecprj))
    6689              : 
    6690              :  ! Prepare call to getgh1c
    6691            0 :  usevnl = 0
    6692            0 :  optlocal = 1    ! local part of H^(1) is computed in gh1c=<G|H^(1)|C>
    6693            0 :  optnl = 2       ! non-local part of H^(1) is totally computed in gh1c=<G|H^(1)|C>
    6694            0 :  opt_gvnlx1 = 0  ! gvnlx1 is output
    6695              : 
    6696            0 :  ABI_MALLOC(grad_berry, (2, nspinor*(berryopt0/4)))
    6697              : 
    6698              :  ! Since v1(q=0) and p are Hermitian operators, we have:
    6699              :  !
    6700              :  !  i <psi_mk| [v1, p] |psi_nk> = i <v1 psi_mk | p psi_nk> -i <p psi_mk | v1 psi_nk>
    6701              :  !
    6702              :  ! Note that in the present implementation both m and n indices run from bstart_k to bstop_k.
    6703              : 
    6704              :  ! if PAW, one has to solve a generalized eigenproblem
    6705            0 :  gen_eigenpb = psps%usepaw == 1; sij_opt = 0; if (gen_eigenpb) sij_opt = 1
    6706              : 
    6707              :  ! Define netcdf arrays inside the spin group.
    6708            0 :  do spin=1, nsppol
    6709            0 :    NCF_CHECK(nf90_inq_ncid(root_ncid, strcat("gqk", "_spin", itoa(spin)), spin_ncid))
    6710              :    ncerr = nctk_def_arrays(spin_ncid, [ &
    6711              :      nctkarr_t("iv1p_comm", "dp", "two, nb_k, nb_k, three, natom3, glob_nk") &
    6712            0 :    ], defmode=.True.)
    6713            0 :    NCF_CHECK(ncerr)
    6714              : 
    6715            0 :    NCF_CHECK(nf90_def_var_fill(spin_ncid, spin_vid("iv1p_comm"), NF90_FILL, -huge(one)))
    6716            0 :    NCF_CHECK(nctk_set_datamode(spin_ncid))
    6717              :  end do
    6718              :  !NCF_CHECK(nctk_set_datamode(root_ncid))
    6719              : 
    6720            0 :  do my_is=1,gstore%my_nspins
    6721            0 :    associate (gqk => gstore%gqk(my_is))
    6722            0 :    spin = gstore%my_spins(my_is); nb_k = gqk%nb_k; nb_kq = gqk%nb_kq; my_npert = gqk%my_npert
    6723              : 
    6724              :    ! Be careful as wavefunctions might be replicated.
    6725              :    ! Use count_bk to count how many states have been computed in parallel in order to rescale the results.
    6726              :    !ABI_ICALLOC(count_bk, (nb_k, gstore%nkibz))
    6727            0 :    NCF_CHECK(nf90_inq_ncid(root_ncid, strcat("gqk", "_spin", itoa(spin)), spin_ncid))
    6728            0 :    NCF_CHECK(nctk_prepare_mpiio(spin_ncid, "iv1p_comm"))
    6729              : 
    6730              :    ! Allocate vlocal1 with correct cplex. Note nvloc and my_npert.
    6731            0 :    ABI_MALLOC(vlocal1, (cplex*n4, n5, n6, gs_ham_kq%nvloc, my_npert))
    6732            0 :    ABI_MALLOC(lambda, (nb_k))
    6733              : 
    6734            0 :    ABI_CALLOC(iv1p_comm, (2, nb_k, nb_k, 3, natom3))
    6735            0 :    ABI_MALLOC(dmat, (2, nb_k, nb_k, 3))
    6736              : 
    6737              :    ! Set up local potential vlocal1 with proper dimensioning from vtrial1 taking into account the spin.
    6738              :    ! Note that here v1scf contains all 3 natom perturbations as we called dvdb%readsym_allv1.
    6739            0 :    do my_ip=1,my_npert
    6740            0 :      idir = dvdb%my_pinfo(1, my_ip); ipert = dvdb%my_pinfo(2, my_ip); ipc = dvdb%my_pinfo(3, my_ip)
    6741              :      call rf_transgrid_and_pack(spin, nspden, psps%usepaw, cplex, nfftf, nfft, ngfft, gs_ham_kq%nvloc,&
    6742            0 :                                 pawfgr, mpi_enreg, dummy_vtrial, v1scf(:,:,:,ipc), vlocal, vlocal1(:,:,:,:,my_ip))
    6743              :    end do
    6744              : 
    6745              :    ! Continue to initialize the GS Hamiltonian
    6746            0 :    call gs_ham_kq%load_spin(spin, vlocal=vlocal, with_nonlocal=.true.)
    6747              : 
    6748            0 :    do my_ik=1,gqk%my_nk
    6749              :      ! Parallelism inside q-point communicator.
    6750            0 :      if (gqk%qpt_comm%skip(my_ik)) cycle
    6751              : 
    6752              :      ! The k-point and the symmetries relating the BZ k-point to the IBZ.
    6753            0 :      kk_bz = gqk%my_kpts(:, my_ik)
    6754            0 :      ik_ibz = gqk%my_k2ibz(1, my_ik)
    6755            0 :      kk_ibz = ebands%kptns(:,ik_ibz)
    6756            0 :      ik_glob = my_ik + gqk%my_kstart - 1
    6757              : 
    6758              :      ! Get npw_k, kg_k and symmetrize wavefunctions from the IBZ (if needed).
    6759              :      call wfd%sym_ug_kg_npw(dtset%ecut, kk_bz, kk_ibz, gqk%bstart_k, nb_k, spin, gqk%my_k2ibz(:, my_ik), cryst, &
    6760            0 :                             work_ngfft, work, istwf_k, npw_k, kg_k, kets_k)
    6761              : 
    6762              :      call gs_ham_kq%eph_setup_k("k", kk_bz, istwf_k, npw_k, kg_k, dtset, cryst, psps, &       ! in
    6763            0 :                                 nkpg_k, kpg_k, ffnl_k, kinpw_k, ph3d_k, gqk%pert_comm%value)  ! out
    6764              : 
    6765            0 :      npwsp_k = npw_k * nspinor
    6766            0 :      ABI_MALLOC(h1_kets_kq, (2, npwsp_k, nb_k))
    6767            0 :      ABI_MALLOC(gs1c_kq, (2, npwsp_k*nb_k*((sij_opt+1)/2)))
    6768            0 :      ABI_MALLOC(gvnlx1, (2, npwsp_k,nb_k))
    6769              : 
    6770              :      ! Compute <g|-i\Nabla |psi_nk>.
    6771            0 :      ABI_MALLOC(p_kets_k, (2, npwsp_k, nb_k, 3))
    6772            0 :      call cg_p_psi(npw_k, nspinor, nb_k, kk_bz, kg_k, kets_k, p_kets_k)
    6773              : 
    6774            0 :      iv1p_comm = zero
    6775            0 :      do my_ip=1,my_npert
    6776            0 :        idir = dvdb%my_pinfo(1, my_ip); ipert = dvdb%my_pinfo(2, my_ip); ipc = dvdb%my_pinfo(3, my_ip)
    6777              : 
    6778              :        ! Prepare application of the NL part.
    6779            0 :        call rf_ham_kq%init(cplex, gs_ham_kq, ipert, has_e1kbsc=.true.)
    6780            0 :        call rf_ham_kq%load_spin(spin, vlocal1=vlocal1(:,:,:,:,my_ip), with_nonlocal=.true.)
    6781              : 
    6782            0 :        do in_k=1,nb_k
    6783              :          ! Use scissor shift on 0-order eigenvalue
    6784            0 :          band_k = in_k + gqk%bstart_k - 1
    6785            0 :          lambda(in_k) = ebands%eig(band_k, ik_ibz, spin) - dtset%dfpt_sciss
    6786              :        end do
    6787              :        !call ebands%get_dfpt_eshifted(gqk%bstart_k, nb_k, ik_ibz, spin, dtset%dfpt_sciss, lambda)
    6788              : 
    6789              :        ! Calculate dvscf * psi_k, results stored in h1_kets_kq on the k+q sphere.
    6790              :        ! Compute H(1) applied to GS wavefunction Psi(0).
    6791              :        call getgh1c(berryopt0, kets_k, cwaveprj0, h1_kets_kq, &
    6792              :                     grad_berry, gs1c_kq, gs_ham_kq, gvnlx1, idir, ipert, lambda, mpi_enreg, nb_k, optlocal, &
    6793            0 :                     optnl, opt_gvnlx1, rf_ham_kq, sij_opt, tim_getgh1c, usevnl)
    6794              : 
    6795            0 :        call rf_ham_kq%free()
    6796              : 
    6797              :        ! Here we compute: i <u_mk| [v1, p] u_nk> = i <v1 u_mk | p u_nk> -i <p u_mk | v1 u_nk>
    6798              :        !    p_kets_k(:, npwsp_k, nb_k, 3)
    6799              :        !    h1_kets_kq, (2, npw_k*nspinor, nb_k))
    6800            0 :        dmat = zero
    6801            0 :        do ii=1,3
    6802              :          call ZGEMM('C', 'N', nb_k, nb_k, npwsp_k, j_dpc, h1_kets_kq, npwsp_k, &
    6803            0 :                     p_kets_k(:,:,:,ii), npwsp_k, cone, dmat(:,:,:,ii), nb_k)
    6804              : 
    6805              :          call ZGEMM('C', 'N', nb_k, nb_k, npwsp_k, -j_dpc, p_kets_k(:,:,:,ii), npwsp_k, &
    6806            0 :                     h1_kets_kq, npwsp_k, cone, dmat(:,:,:,ii), nb_k)
    6807              :        end do
    6808              : 
    6809            0 :        iv1p_comm(:,:,:,:,ipc) = dmat
    6810              :      end do ! my_ip
    6811              : 
    6812            0 :      call xmpi_sum(iv1p_comm, gqk%pert_comm%value, ierr)
    6813            0 :      if (gqk%pert_comm%me == 0) then
    6814            0 :        NCF_CHECK(nf90_put_var(spin_ncid, spin_vid("iv1p_comm"), iv1p_comm, start=[1,1,1,1,1,ik_glob]))
    6815              :      end if
    6816              : 
    6817            0 :      ABI_FREE(ffnl_k)
    6818            0 :      ABI_FREE(kinpw_k)
    6819            0 :      ABI_FREE(ph3d_k)
    6820            0 :      ABI_FREE(kpg_k)
    6821            0 :      ABI_FREE(kets_k)
    6822            0 :      ABI_FREE(p_kets_k)
    6823            0 :      ABI_FREE(gs1c_kq)
    6824            0 :      ABI_FREE(h1_kets_kq)
    6825            0 :      ABI_FREE(gvnlx1)
    6826              :    end do ! my_ik
    6827              : 
    6828            0 :    ABI_FREE(vlocal1)
    6829            0 :    ABI_FREE(lambda)
    6830            0 :    ABI_FREE(dmat)
    6831              : 
    6832              :    !call xmpi_sum(count_bk, gqk%comm%value, ierr)
    6833              : 
    6834              :    !do ik_ibz=1, gstore%nkibz
    6835              :    !  do band=gqk%bstart_k, gqk%bstop_k
    6836              :    !    in_k = band - gqk%bstart_k + 1
    6837              :    !    if (count_bk(in_k, ik_ibz) == 0) cycle
    6838              :    !    do ii=1,3
    6839              :    !      vnk_cart_ibz(ii,in_k,ik_ibz) = vnk_cart_ibz(ii,in_k,ik_ibz) / count_bk(in_k, ik_ibz)
    6840              :    !    end do
    6841              :    !  end do
    6842              :    !end do
    6843              :    !ABI_FREE(count_bk)
    6844              : 
    6845            0 :    ABI_FREE(iv1p_comm)
    6846              :    end associate
    6847              :  end do ! my_is
    6848              : 
    6849            0 :  ABI_FREE(vlocal)
    6850            0 :  ABI_FREE(dummy_vtrial)
    6851            0 :  ABI_FREE(v1scf)
    6852            0 :  ABI_FREE(work)
    6853            0 :  ABI_FREE(grad_berry)
    6854              : 
    6855            0 :  call pawcprj_free(cwaveprj0)
    6856            0 :  ABI_FREE(cwaveprj0)
    6857              : 
    6858            0 :  call xmpi_barrier(gstore%comm)
    6859            0 :  call cwtime_report(" Computation of commutator:", cpu_kk, wall_kk, gflops_kk)
    6860              : 
    6861              : contains
    6862              : 
    6863            0 : integer function spin_vid(var_name)
    6864              :   character(len=*),intent(in) :: var_name
    6865            0 :   spin_vid = nctk_idname(spin_ncid, var_name)
    6866              : end function spin_vid
    6867              : 
    6868              : end subroutine gstore_compute_and_write_commutator
    6869              : !!***
    6870              : 
    6871              : !!****f* m_gstore/gstore_nc_has_iv1p_comm
    6872              : !! NAME
    6873              : !! gstore_nc_has_iv1p_comm
    6874              : !!
    6875              : !! FUNCTION
    6876              : !! Return True if GSTORE.nc contains commutator matrix elements.
    6877              : !!
    6878              : !! SOURCE
    6879              : 
    6880           24 : logical function gstore_nc_has_iv1p_comm(gstore, root_ncid) result (has_iv1p_comm)
    6881              : 
    6882              : !Arguments ------------------------------------
    6883              :  class(gstore_t),target, intent(in) :: gstore
    6884              :  integer,intent(in) :: root_ncid
    6885              : 
    6886              : !Local variables-------------------------------
    6887              :  integer :: spin, ncerr, spin_ncid, varid
    6888              : ! *************************************************************************
    6889              : 
    6890           24 :  has_iv1p_comm = .True.
    6891           24 :  do spin=1,gstore%nsppol
    6892           24 :    NCF_CHECK(nf90_inq_ncid(root_ncid, strcat("gqk", "_spin", itoa(spin)), spin_ncid))
    6893           24 :    ncerr = nf90_inq_varid(spin_ncid, "iv1p_comm", varid)
    6894           24 :    if (ncerr /= nf90_noerr) then
    6895              :      has_iv1p_comm = .False.; exit
    6896              :    end if
    6897              :  end do
    6898              : 
    6899           24 : end function gstore_nc_has_iv1p_comm
    6900              : !!***
    6901              : 
    6902              : !!****f* m_gstore/gstore_read_gtype
    6903              : !! NAME
    6904              : !! gstore_read_gtype
    6905              : !!
    6906              : !! FUNCTION
    6907              : !!  Read the value of "gstore_gtype" from the NetCDF file.
    6908              : !!  Only the master process reads the value and broadcasts it to all processes in comm.
    6909              : !!
    6910              : !! INPUTS
    6911              : !!  ncid: NetCDF file ID (open for reading).
    6912              : !!  comm: MPI communicator.
    6913              : !!
    6914              : !! OUTPUTS
    6915              : !!  gtype: The value of gstore_gtype read from the file.
    6916              : !!
    6917              : !! SOURCE
    6918              : 
    6919            7 : subroutine gstore_read_gtype(path, gtype, comm, &
    6920            7 :                              brange_k_spin, brange_kq_spin) ! optional
    6921              : 
    6922              : !Arguments ------------------------------------
    6923              :  character(len=*), intent(in) :: path
    6924              :  character(len=abi_slen), intent(out) :: gtype
    6925              :  integer, intent(in) :: comm
    6926              :  integer,optional,intent(out) :: brange_k_spin(:,:)
    6927              :  integer,optional,intent(out) :: brange_kq_spin(:,:)
    6928              : 
    6929              : !Local variables-------------------------------
    6930              :  integer, parameter :: master = 0
    6931              :  integer :: my_rank, nproc, ierr, varid, ncerr, ncid
    6932              : ! *************************************************************************
    6933              : 
    6934            7 :  my_rank = xmpi_comm_rank(comm); nproc = xmpi_comm_size(comm)
    6935              : 
    6936            7 :  if (my_rank == master) then
    6937            7 :    NCF_CHECK(nf90_open(path, nf90_nowrite, ncid))
    6938            7 :    gtype = GSTORE_GTYPE_KS
    6939            7 :    ncerr = nf90_inq_varid(ncid, "gstore_gtype", varid)
    6940            7 :    if (ncerr == nf90_noerr) then
    6941            7 :      NCF_CHECK(nf90_get_var(ncid, varid, gtype))
    6942            7 :      call replace_ch0(gtype)
    6943              :    end if
    6944            7 :    if (present(brange_k_spin)) then
    6945            0 :      NCF_CHECK(nf90_get_var(ncid, vid("gstore_brange_k_spin"), brange_k_spin))
    6946              :    end if
    6947            7 :    if (present(brange_kq_spin)) then
    6948            0 :      NCF_CHECK(nf90_get_var(ncid, vid("gstore_brange_kq_spin"), brange_kq_spin))
    6949              :    end if
    6950            7 :    NCF_CHECK(nf90_close(ncid))
    6951              :  end if
    6952              : 
    6953            7 :  if (nproc > 1) then
    6954            0 :    call xmpi_bcast(gtype, master, comm, ierr)
    6955            0 :    if (present(brange_k_spin)) call xmpi_bcast(brange_k_spin, master, comm, ierr)
    6956            0 :    if (present(brange_kq_spin)) call xmpi_bcast(brange_kq_spin, master, comm, ierr)
    6957              :  end if
    6958              : 
    6959              :  contains
    6960              : 
    6961            0 : integer function vid(var_name)
    6962              :   character(len=*),intent(in) :: var_name
    6963            0 :   vid = nctk_idname(ncid, var_name)
    6964              : end function vid
    6965              : 
    6966              : end subroutine gstore_read_gtype
    6967              : !!***
    6968              : 
    6969              : !----------------------------------------------------------------------
    6970              : 
    6971              : !!****f* m_gstore/gstore_symmetrize
    6972              : !! NAME
    6973              : !! gstore_symmetrize
    6974              : !!
    6975              : !! FUNCTION
    6976              : !! Reconstruct the electron-phonon matrix elements g(k,q) in the full
    6977              : !! Brillouin Zone (BZ) using the values stored in the IBZ for k and the IBZ_k for q.
    6978              : !! Uses the NetCDF API for in-place modification of the GSTORE file
    6979              : !! and wfd_t to fetch wavefunctions and compute unitary matrices.
    6980              : !!
    6981              : !! SOURCE
    6982              : 
    6983            0 : subroutine gstore_symmetrize(gstore_path, wfk_path, ngfft, dtset, dtfil, cryst, psps, pawtab, ebands, ifc, comm)
    6984              : 
    6985              : !Arguments ------------------------------------
    6986              : !scalars
    6987              :  character(len=*),intent(in) :: gstore_path
    6988              :  character(len=*),intent(in) :: wfk_path
    6989              :  integer,intent(in) :: ngfft(18)
    6990              :  type(dataset_type),intent(in) :: dtset
    6991              :  type(datafiles_type),intent(in) :: dtfil
    6992              :  class(crystal_t),target,intent(in) :: cryst
    6993              :  class(ebands_t),target,intent(in) :: ebands
    6994              :  class(ifc_type),target,intent(in) :: ifc
    6995              :  type(pseudopotential_type),intent(in) :: psps
    6996              :  type(pawtab_type),intent(in) :: pawtab(psps%ntypat*psps%usepaw)
    6997              :  integer,intent(in) :: comm
    6998              : 
    6999              : !Local variables-------------------------------
    7000              : !scalars
    7001              :  integer :: with_cplex, my_is, spin, my_ik, my_iq, ik_glob, iq_glob, units(2)
    7002              :  integer :: ncid, spin_ncid, nprocs, my_rank, ncerr, this_state, ierr
    7003              :  integer :: nb, nkbz, nkibz, nqbz, nqibz, nsym, itime_k
    7004              :  integer :: ik_ibz, isym_k, trev_k, tsign_k, g0_k(3), g0_q(3)
    7005              :  integer :: ik_ibz_file, isym_lg, itime_lg, isym_combined, c1_gs, n_gv, igv
    7006              :  integer :: n_lg, ii_lg, tsign_lg !, isym_lg, itime_lg,
    7007              :  integer :: idir, iat, idir_eq, iat_eq, mu, mu_eq, iq_sym
    7008              :  integer :: symrec_eq(3,3), symrec_eq_kspace(3,3), l0(3), mat_tmp(3,3)
    7009              :  real(dp) :: weight_qq, phase
    7010              :  complex(dp) :: cphase
    7011              :  logical :: with_g2dw, isirr_k, found_lg
    7012              :  character(len=abi_slen) :: with_gmode, gtype, gvals_name, gv_names(2)
    7013              :  character(len=5000) :: msg
    7014            0 :  type(gstore_t) :: gstore
    7015            0 :  type(dmats_t) :: dmats
    7016              :  integer :: isym_kqS, isym_kqT, ikq_ibz_s, ikq_ibz_t, h_isym, itime_h, h_isym_inv, trev_kqS, trev_kqT
    7017              :  integer :: indkk_s(6,1), indkk_t(6,1)
    7018              :  real(dp) :: L_h_gs(3), kq_ibz_pt(3)
    7019              :  complex(dp) :: phase_h_gs, phase_ket_gs
    7020              :  logical,parameter :: DEBUG_DUMP_DH = .False.
    7021              :  real(dp) :: kk_lg_test(3)
    7022              : !!arrays
    7023            0 :  integer :: brange_kq_spin(2, dtset%nsppol)
    7024            0 :  integer,allocatable :: state_kq(:,:), kibz2bz(:) !, qibz2bz(:), qglob2bz(:,:), ! kmesh_map(:,:), my_kqmap(:,:),
    7025            0 :  integer,allocatable :: lg_isym(:), lg_itime(:)
    7026              :  real(dp) :: kk_bz(3), kk_ibz(3), qpt(3), qpt_tmp(3), kq_bz_source(3), kq_bz_target(3)
    7027            0 :  real(dp),allocatable :: qbz(:,:)
    7028            0 :  real(dp),contiguous,pointer :: gkq_rot_ptr(:,:,:,:,:), gkq_base_ptr(:,:,:,:,:)
    7029            0 :  complex(dp),target,allocatable :: gkq_rot(:,:,:,:,:), gkq_base(:,:,:,:,:)
    7030            0 :  complex(dp),allocatable :: gtmp(:,:), dh_mat(:,:), ket_mat(:,:)
    7031              : !----------------------------------------------------------------------
    7032              : 
    7033            0 :  nprocs = xmpi_comm_size(comm); my_rank = xmpi_comm_rank(comm)
    7034              : 
    7035            0 :  units = [std_out, ab_out]
    7036            0 :  call wrtout(units, " Entering gstore_symmetrize...")
    7037            0 :  call wrtout(units, sjoin(" GSTORE file: ", gstore_path))
    7038              : 
    7039            0 :  call gstore_read_gtype(gstore_path, gtype, comm, brange_kq_spin=brange_kq_spin)
    7040              : 
    7041              :  ! Compute the D-matrices D_mn(S) = <psi_m,S kq_ibz|S|psi_n,kq_ibz>.
    7042              :  ! These are used below (as dh_mat) to correct the extra rotation the bra (electron state
    7043              :  ! at k+q) picks up when its own already-computed BZ representative differs from the one
    7044              :  ! obtained by applying isym_k directly. dh_mat is applied to the (k+q)/bra band index only
    7045              :  ! (gvals' first band dimension, nb_kq) -- never to the k/ket index (nb_k) -- so dmats must be
    7046              :  ! built with brange_kq_spin (bstart_kq:bstop_kq), NOT brange_k_spin: the two band windows are
    7047              :  ! only required to have the SAME COUNT (gstore%same_nbands, checked below) but may start at a
    7048              :  ! different absolute band (bstart_k need not equal bstart_kq, and neither needs to start at 1).
    7049              :  ! All MPI ranks participate here since dmats%init distributes the work internally over comm.
    7050              :  !
    7051              :  ! NOTE: dmats_init also computes genuine (WFK-derived) D-matrices for symmetries S that do
    7052              :  ! NOT stabilize a given IBZ k-point (S.k /= k+G), not just little-group elements -- this
    7053              :  ! routine (gstore_symmetrize) is UNAFFECTED by that generalization and needs no changes
    7054              :  ! because it never reads a non-little-group slot: every dmats%for_spin(...) lookup below
    7055              :  ! uses either h_isym/h_isym_inv (searched for specifically as a stabilizer of ikq_ibz_t --
    7056              :  ! see "Cannot find little-group element h for the k+q leg" below) or isym_k (drawn directly
    7057              :  ! from lg_isym, the explicitly-enumerated little group of kk_ibz in Pass A). Both are
    7058              :  ! guaranteed, by construction, to land on the little-group branch of dmats_init, which is
    7059              :  ! untouched by the generalization -- confirmed by byte-identical validation numbers on
    7060              :  ! diamond/AlAs before and after. See gstore_symmetrize_status memory for the full story.
    7061            0 :  call dmats%init(wfk_path, dtset, cryst, brange_kq_spin, ngfft, pawtab, psps, comm)
    7062              : 
    7063              :  ! Only master processor performs the symmetrization of the e-ph matrix elements.
    7064              :  ! Performance is not crucial and the algorithm is IO-bound.
    7065            0 :  if (my_rank /= 0) goto 100
    7066              : 
    7067              :  ! GWPT files store two sets of e-ph matrix elements: "gvals" (g^Sigma) and "gvals_ks" (g^KS),
    7068              :  ! written at the same (k,q) grid positions (see m_gwpt.F90's dump_my_gbuf). Symmetrize both.
    7069            0 :  n_gv = 1; gv_names(1) = "gvals"
    7070            0 :  if (gtype == GSTORE_GTYPE_GWPT) then
    7071            0 :    n_gv = 2; gv_names(2) = "gvals_ks"
    7072              :  end if
    7073              : 
    7074              :  ! Read GSTORE.nc dimensions and metadata from file, without allocating gvals buffer.
    7075            0 :  with_cplex = 0; with_gmode = GSTORE_GMODE_ATOM; with_g2dw = .False.; gvals_name = "gvals"
    7076              :  call gstore%from_ncpath(gstore_path, with_cplex, dtset, dtfil, cryst, ebands, ifc, &
    7077            0 :                          with_gmode, gvals_name, with_g2dw, xmpi_comm_self)
    7078              : 
    7079              :  ! We need the same number of bands for m and n. Also, k and q must be in the BZ without any filter.
    7080            0 :  ABI_CHECK(gstore%same_nbands(msg), msg)
    7081            0 :  if (gstore%check_cplex_qkzone_gmode(2, "bz", "bz", "atom", kfilter="none", check_alloc=.False.) /= 0) then
    7082            0 :    ABI_ERROR("GSTORE.nc should have both k and q in the full BZ. See messages above.")
    7083              :  end if
    7084              : 
    7085              :  ! has_used_lgk is supported via the gstore_sym == 2 "Pass A" reconstruction below.
    7086              :  ! has_used_lgq remains unsupported: it is a structurally different restriction
    7087              :  ! (k filtered by the little group of q), out of scope for gstore_sym.
    7088            0 :  ABI_CHECK_IEQ(gstore%has_used_lgq, 0, "Symmetrization of g(k,q) with use_lgq /= 0 is not coded")
    7089              : 
    7090              :  ! Useful dimensions.
    7091            0 :  nkbz = gstore%nkbz; nkibz = gstore%nkibz
    7092            0 :  nqbz = gstore%nqbz; nqibz = gstore%nqibz
    7093            0 :  nsym = cryst%nsym
    7094              : 
    7095              :  ! Need to know the position of the IBZ k-points in the netcdf array..
    7096            0 :  call get_ibz2bz(gstore%nkibz, gstore%nkbz, gstore%kbz2ibz, kibz2bz, msg, ierr)
    7097            0 :  ABI_CHECK(ierr == 0, sjoin("Something wrong in symmetry tables for k-points", ch10, msg))
    7098              : 
    7099            0 :  NCF_CHECK(nctk_open_modify(ncid, gstore_path, xmpi_comm_self))
    7100              : 
    7101              :  if (DEBUG_DUMP_DH) open(unit=789, file="dh_debug.csv", status="replace", action="write")
    7102              :  if (DEBUG_DUMP_DH) open(unit=790, file="dh_mat_full_debug.csv", status="replace", action="write")
    7103              :  if (DEBUG_DUMP_DH) open(unit=791, file="gtmp_debug.csv", status="replace", action="write")
    7104              :  if (DEBUG_DUMP_DH) open(unit=792, file="mu_debug.csv", status="replace", action="write")
    7105              : 
    7106              :  ! Loop over collinear spins.
    7107            0 :  do my_is=1,gstore%my_nspins
    7108            0 :    spin = gstore%my_spins(my_is)
    7109              :    associate (gqk => gstore%gqk(my_is))
    7110              :    ! nb_k == nb_kq is enforced by gstore%same_nbands above, so either count can be used here for
    7111              :    ! sizing; the absolute band offsets (bstart_k vs bstart_kq, handled via brange_kq_spin passed
    7112              :    ! to dmats%init above) are what actually differ and matter for correctness.
    7113            0 :    nb = gqk%nb_k
    7114            0 :    ABI_CHECK_IEQ(gqk%bstart_kq, brange_kq_spin(1, spin), "gqk%bstart_kq != brange_kq_spin(1, spin)")
    7115            0 :    ABI_CHECK_IEQ(gqk%bstop_kq, brange_kq_spin(2, spin), "gqk%bstop_kq != brange_kq_spin(2, spin)")
    7116              : 
    7117              :    ! Get the group id for this spin.
    7118            0 :    NCF_CHECK(nf90_inq_ncid(ncid, strcat("gqk", "_spin", itoa(spin)), spin_ncid))
    7119              : 
    7120              :    ! Read table with status of the (k, q) entry.
    7121            0 :    ABI_MALLOC(state_kq, (gqk%glob_nk, gqk%glob_nq))
    7122            0 :    ncerr = nf90_get_var(ncid, nctk_idname(ncid, "gstore_glob_state_kqs"), state_kq, start=[1,1,spin])
    7123            0 :    NCF_CHECK(ncerr)
    7124              : 
    7125            0 :    ABI_MALLOC(gkq_base, (nb, nb, gqk%natom3, gqk%my_nq, n_gv))
    7126            0 :    ABI_MALLOC(gkq_rot, (nb, nb, gqk%natom3, gqk%my_nq, n_gv))
    7127            0 :    ABI_MALLOC(gtmp, (nb, nb))
    7128            0 :    ABI_MALLOC(dh_mat, (nb, nb))
    7129            0 :    ABI_MALLOC(ket_mat, (nb, nb))
    7130              : 
    7131              :    ! Build q-points in the BZ.
    7132            0 :    ABI_MALLOC(qbz, (3, gqk%my_nq))
    7133            0 :    do my_iq=1, gqk%my_nq
    7134            0 :      call gqk%myqpt(my_iq, gstore, weight_qq, qbz(:,my_iq))
    7135              :    end do
    7136              : 
    7137              :    ! =====================================================================
    7138              :    ! Pass A (gstore_sym == 2 only): if gstore_use_lgk restricted the q's
    7139              :    ! actually computed directly for k in the IBZ, an IBZ row may have some
    7140              :    ! q entries GSTORE_KQ_COMPUTED (q in IBZ_k) and others GSTORE_KQ_MISSING
    7141              :    ! (q outside IBZ_k). Fill the MISSING ones here, using ONLY the little
    7142              :    ! group of kk_ibz itself (k never moves in this pass -- the degenerate
    7143              :    ! case of the k-star formula below, kk_bz := kk_ibz). Once every IBZ row
    7144              :    ! is fully populated, the k-star loop below runs completely unchanged
    7145              :    ! for the non-IBZ rows, exactly as it always has when gstore_use_lgk == 0.
    7146              :    ! =====================================================================
    7147            0 :    if (dtset%gstore_sym == 2) then
    7148            0 :      do ik_ibz=1,nkibz
    7149            0 :        ik_glob = kibz2bz(ik_ibz)
    7150            0 :        if (all(state_kq(ik_glob, :) /= GSTORE_KQ_MISSING)) cycle
    7151              : 
    7152            0 :        kk_ibz = ebands%kptns(:, ik_ibz)
    7153            0 :        ik_ibz_file = ik_glob
    7154            0 :        kk_bz = kk_ibz   ! degenerate case: k never moves in Pass A
    7155              : 
    7156              :        ! Enumerate the little group of kk_ibz once per row: symrel^T membership
    7157              :        ! test, mirroring dmats_get_star_dmats (m_classify_bands.F90:2048-2061).
    7158              :        ! Deliberately NOT lgroup_t/littlegroup_q here: those use the symrec
    7159              :        ! convention, which can disagree with the symrel^T convention used
    7160              :        ! throughout dmats/gstore_symmetrize for non-orthogonal symrel.
    7161            0 :        ABI_MALLOC(lg_isym, (2*nsym))
    7162            0 :        ABI_MALLOC(lg_itime, (2*nsym))
    7163            0 :        n_lg = 0
    7164            0 :        do itime_lg=1,2
    7165            0 :          do isym_lg=1,nsym
    7166            0 :            tsign_lg = 1; if (itime_lg == 2) tsign_lg = -1
    7167            0 :            kk_lg_test = tsign_lg * matmul(transpose(cryst%symrel(:,:,isym_lg)), kk_ibz)
    7168            0 :            if (isamek(kk_ibz, kk_lg_test, g0_q)) then
    7169            0 :              n_lg = n_lg + 1
    7170            0 :              lg_isym(n_lg) = isym_lg; lg_itime(n_lg) = itime_lg
    7171              :            end if
    7172              :          end do
    7173              :        end do
    7174            0 :        ABI_CHECK(n_lg > 0, "Little group of kk_ibz is empty (should at least contain the identity)")
    7175              : 
    7176              :        ! Read g(k_ibz, q) for all q already available (same read pattern as below).
    7177            0 :        do igv=1,n_gv
    7178            0 :          call c_f_pointer(c_loc(gkq_base(1,1,1,1,igv)), gkq_base_ptr, [2, nb, nb, gqk%natom3, gqk%my_nq])
    7179              :          ncerr = nf90_get_var(spin_ncid, spin_vid(gv_names(igv)), gkq_base_ptr, &
    7180              :                               start=[1, 1, 1, 1, ik_ibz_file, 1], &
    7181            0 :                               count=[2, nb, nb, gqk%natom3, 1, gqk%my_nq])
    7182            0 :          NCF_CHECK(ncerr)
    7183              :        end do
    7184              : 
    7185            0 :        do my_iq=1, gqk%my_nq
    7186            0 :          iq_glob = my_iq + gqk%my_qstart - 1
    7187              : 
    7188            0 :          if (state_kq(ik_glob, iq_glob) /= GSTORE_KQ_MISSING) then
    7189              :            ! Already GSTORE_KQ_COMPUTED (q in IBZ_k): keep the on-disk value unchanged.
    7190            0 :            gkq_rot(:,:,:,iq_glob,:) = gkq_base(:,:,:,iq_glob,:)
    7191            0 :            cycle
    7192              :          end if
    7193              : 
    7194            0 :          qpt = qbz(:, my_iq)
    7195              : 
    7196              :          ! Search the little group x the row's own COMPUTED q entries for a source match.
    7197              :          found_lg = .False.
    7198            0 :          do ii_lg=1,n_lg
    7199            0 :            isym_k = lg_isym(ii_lg); trev_k = lg_itime(ii_lg) - 1
    7200            0 :            tsign_k = 1; if (trev_k == 1) tsign_k = -1
    7201            0 :            symrec_eq = transpose(cryst%symrel(:,:,isym_k))
    7202            0 :            symrec_eq_kspace = tsign_k * symrec_eq
    7203            0 :            do iq_sym=1, gqk%my_nq
    7204            0 :              if (state_kq(ik_glob, iq_sym + gqk%my_qstart - 1) /= GSTORE_KQ_COMPUTED) cycle
    7205            0 :              qpt_tmp = matmul(symrec_eq_kspace, qbz(:, iq_sym))
    7206            0 :              if (isamek(qpt, qpt_tmp, g0_q)) then
    7207            0 :                found_lg = .True.; exit
    7208              :              end if
    7209              :            end do
    7210            0 :            if (found_lg) exit
    7211              :          end do
    7212              : 
    7213              :          msg = sjoin("Pass A: no little-group image of q found among GSTORE_KQ_COMPUTED", &
    7214            0 :            " entries for ik_ibz=", itoa(ik_ibz), " -- IBZ_k does not cover this q's star")
    7215            0 :          ABI_CHECK(found_lg, msg)
    7216              : 
    7217            0 :          do isym_combined=1,nsym
    7218            0 :            if (all(cryst%symrec(:,:,isym_combined) == symrec_eq)) exit
    7219              :          end do
    7220            0 :          ABI_CHECK(isym_combined /= nsym + 1, "Cannot find symrec_eq")
    7221              : 
    7222              :          ! Note on non-uniqueness of (isym_k, iq_sym): when kk_ibz has a non-trivial little group
    7223              :          ! (the typical case, not a rare corner case -- measured on the reference test systems
    7224              :          ! below, EVERY Pass-A point in diamond and most in AlAs have more than one valid
    7225              :          ! candidate, up to ~96 at Gamma), the found_lg search above can match several different
    7226              :          ! (isym,itime,iq_sym) triples for the same target q; "first found" is taken arbitrarily.
    7227              :          ! Verified this does NOT introduce a gauge/correctness bug: a dedicated diagnostic
    7228              :          ! (temporarily instrumented, then removed) recomputed the full reconstruction using EVERY
    7229              :          ! valid candidate for a set of known-redundant points on both diamond (4 points, 2-4
    7230              :          ! candidates each) and AlAs (2 points), and all candidates agreed with each other to
    7231              :          ! numerical noise (~1e-7 to 1e-10) in every case -- i.e. the formula is empirically
    7232              :          ! gauge-invariant to this choice, the same way the bra leg's h_isym/phase_h_gs/L_h_gs
    7233              :          ! machinery is already known (and was originally designed) to be invariant to which
    7234              :          ! (isym_kqS,isym_kqT) kpts_map happens to return. See gstore_symmetrize_status memory for
    7235              :          ! the full data. Contrast with dmats_get_star_dmats_at_kpt (m_classify_bands.F90), a
    7236              :          ! DIAGNOSTIC-only routine with a structurally identical first-match-wins search that its
    7237              :          ! own authors flag as an unverified risk -- that routine has NOT been checked this way and
    7238              :          ! is a separate, lower-priority open item (never reached by production gstore_symmetrize).
    7239              : 
    7240              :          ! -----------------------------------------------------------------
    7241              :          ! From here on, reused VERBATIM from the k-star loop below (Bug A /
    7242              :          ! h_isym / phase_h_gs / phase_ket_gs / itime_h / dh_mat / mu-rotation
    7243              :          ! -- kk_bz == kk_ibz here, the degenerate case, so the formula
    7244              :          ! derived for the general k-star case applies unchanged). See the
    7245              :          ! k-star loop's own comments for the full derivation.
    7246            0 :          kq_bz_source = kk_ibz + qbz(:, iq_sym)
    7247            0 :          kq_bz_target = kk_bz + qpt
    7248            0 :          ierr = kpts_map("symrel", ebands%kptopt, cryst, gstore%krank_ibz, 1, kq_bz_source, indkk_s)
    7249            0 :          ABI_CHECK(ierr == 0, "Cannot find symmetric image of k+q (source)")
    7250            0 :          ierr = kpts_map("symrel", ebands%kptopt, cryst, gstore%krank_ibz, 1, kq_bz_target, indkk_t)
    7251            0 :          ABI_CHECK(ierr == 0, "Cannot find symmetric image of k+q (target)")
    7252            0 :          ikq_ibz_s = indkk_s(1,1); isym_kqS = indkk_s(2,1)
    7253            0 :          ikq_ibz_t = indkk_t(1,1); isym_kqT = indkk_t(2,1)
    7254            0 :          trev_kqS = indkk_s(6,1); trev_kqT = indkk_t(6,1)
    7255            0 :          ABI_CHECK(ikq_ibz_s == ikq_ibz_t, "Source and target k+q map to different IBZ points!")
    7256              : 
    7257            0 :          mat_tmp = matmul(transpose(cryst%symrel(:,:,dmats%toinv(1,isym_kqT))), &
    7258            0 :                           matmul(symrec_eq, transpose(cryst%symrel(:,:,isym_kqS))))
    7259            0 :          do h_isym=1,nsym
    7260            0 :            if (all(transpose(cryst%symrel(:,:,h_isym)) == mat_tmp)) exit
    7261              :          end do
    7262            0 :          ABI_CHECK(h_isym /= nsym + 1, "Cannot find little-group element h for the k+q leg")
    7263              : 
    7264            0 :          c1_gs = dmats%multable(1, isym_kqS, isym_k)
    7265              :          L_h_gs = real(dmats%multable(2:4, isym_kqS, isym_k), dp) &
    7266              :                 + real(dmats%multable(2:4, c1_gs, dmats%toinv(1,isym_kqT)), dp) &
    7267            0 :                 - matmul(real(cryst%symrel(:,:,h_isym), dp), real(dmats%toinv(2:4,isym_kqT), dp))
    7268            0 :          kq_ibz_pt = ebands%kptns(:, ikq_ibz_t)
    7269            0 :          phase_h_gs = exp(cmplx(zero, two_pi * sum(kq_ibz_pt * L_h_gs), dp))
    7270              : 
    7271              :          ! Pass-A-only companion to phase_ket_gs. The k-star formula below (kk_bz generally
    7272              :          ! != kk_ibz) was validated to 100% exact match WITHOUT this extra term. In Pass A,
    7273              :          ! kk_bz == kk_ibz identically (the degenerate case), and an extra residual survived
    7274              :          ! even after the ket_mat fix: isolated (h_isym==1, scalar-only residual, i.e. exactly
    7275              :          ! reproducible by a single global phase -- see gstore_symmetrize_status memory) to be
    7276              :          ! a clean function of isym_k and kk_ibz alone: exp(-i*2pi*kk_ibz.w(isym_k)) for an
    7277              :          ! integer vector w. Empirically fit w(isym_k) exactly (32/32 points, zero exceptions,
    7278              :          ! all 3 distinct ik_ibz/isym_k combinations in the reference test) to
    7279              :          ! toinv(2:4,isym_k) -- the SAME single-inverse convention used for L_h_gs's own
    7280              :          ! toinv(1,isym_kqT) term, and notably NOT the double-inverse toinv(2:4,toinv(1,isym_k))
    7281              :          ! used by the qpt term just above. Plausible reading: the qpt-term's
    7282              :          ! toinv(2:4,toinv(1,isym_k)) is the companion to kk_bz = symrec_eq.kk_ibz (the k-star's
    7283              :          ! moved k), which in Pass A degenerates to kk_ibz itself, making this term newly
    7284              :          ! separate and nonzero instead of staying absorbed into the k-star's single term.
    7285              :          phase_ket_gs = exp(cmplx(zero, -two_pi * sum(qpt * real(dmats%toinv(2:4, dmats%toinv(1,isym_k)), dp)), dp)) &
    7286            0 :                       * exp(cmplx(zero, -two_pi * sum(kk_ibz * real(dmats%toinv(2:4, isym_k), dp)), dp))
    7287              : 
    7288            0 :          itime_h = 1 + mod(trev_k + trev_kqS + trev_kqT, 2)
    7289              : 
    7290            0 :          h_isym_inv = dmats%toinv(1, h_isym)
    7291            0 :          if (itime_h == 2) then
    7292            0 :            dh_mat = conjg(phase_h_gs) * phase_ket_gs * dmats%for_spin(spin)%value(:,:,h_isym_inv,itime_h,ikq_ibz_t)
    7293              :          else
    7294            0 :            dh_mat = phase_h_gs * phase_ket_gs * dmats%for_spin(spin)%value(:,:,h_isym_inv,itime_h,ikq_ibz_t)
    7295              :          end if
    7296              : 
    7297            0 :          if (trev_kqT == 1) dh_mat = conjg(dh_mat)
    7298              : 
    7299              :          ! Ket-leg correction (Pass A only -- k-star never needs this, see below). Unlike k-star
    7300              :          ! reconstruction, whose ket is always *derived* via cgtk_rotate from the IBZ wavefunction
    7301              :          ! (so ground truth and reconstruction structurally share the same gauge for any degenerate
    7302              :          ! ket subspace), Pass A's ket lives AT kk_ibz itself and is read directly from the WFK for
    7303              :          ! every q processed there. Ground truth's own independent direct e-ph calculations at
    7304              :          ! different q (same k) do not share a common internal gauge for a degenerate ket subspace.
    7305              :          ! isym_k stabilizes kk_ibz (drawn from its own little group, by construction), so
    7306              :          ! dmats%for_spin(...)(isym_k,...) is a genuine, tabulated (non-placeholder) D-matrix here
    7307              :          ! -- unlike the general k-star case, where isym_k need not stabilize anything.
    7308              :          !
    7309              :          ! Convention: read dmats%for_spin(...)(isym_k,...) DIRECTLY, not the toinv(1,isym_k) slot.
    7310              :          ! isym_k here is found purely via the symrel^T convention (little-group membership test),
    7311              :          ! and dmats's own array is indexed the same way (symrel^T, per dmats_init's own little-group
    7312              :          ! check), so isym_k already names the exact tabulated operation that rotates the ket -- no
    7313              :          ! inversion is needed or correct. (Contrast with the BRA correction above, dh_mat: h_isym
    7314              :          ! there is defined as a genuine COMPOSITE/residual little-group element of kq_ibz whose
    7315              :          ! natural tabulated slot -- per dmats_init's own toinv/multable bookkeeping around
    7316              :          ! cgtk_rotate's isym_inv=toinv(isym) workaround -- is toinv(1,h_isym), not h_isym itself;
    7317              :          ! that is a property of how h_isym's OWN definition composes with dmats_init's internal
    7318              :          ! convention, not a general rule that every dmats lookup needs a toinv step.) The original
    7319              :          ! implementation used toinv(1,isym_k) "by analogy" with dh_mat and was validated only on an
    7320              :          ! involutory isym_k (toinv(1,isym_k)==isym_k), which cannot distinguish the two conventions.
    7321              :          ! Diagnosed by finding a 100%/0% clean split: EVERY point with non-involutory isym_k was
    7322              :          ! wrong (needing a genuine unitary matrix fix, not a scalar) while every involutory-isym_k
    7323              :          ! point was already exact -- direct, decisive evidence the toinv(1,.) step was the bug.
    7324            0 :          itime_k = trev_k + 1
    7325            0 :          ket_mat = dmats%for_spin(spin)%value(:,:,isym_k,itime_k,ik_ibz)
    7326            0 :          if (trev_k == 1) ket_mat = conjg(ket_mat)
    7327              :          ! -----------------------------------------------------------------
    7328              : 
    7329              :          ! Perform symmetrization.
    7330            0 :          do mu=1,gqk%natom3
    7331            0 :            idir = mod(mu-1, 3) + 1; iat = (mu - idir) / 3 + 1
    7332              : 
    7333            0 :            iat_eq = cryst%indsym(4, isym_combined, iat)
    7334            0 :            l0 = cryst%indsym(1:3, isym_combined, iat)
    7335            0 :            phase = -two_pi * dot_product(qbz(:, iq_sym), l0)
    7336            0 :            cphase = cmplx(cos(phase), sin(phase), dp)
    7337              : 
    7338            0 :            do igv=1,n_gv
    7339            0 :              gtmp = zero
    7340            0 :              do idir_eq=1,3
    7341            0 :                mu_eq = idir_eq + (iat_eq - 1) * 3
    7342            0 :                gtmp = gtmp + cphase * symrec_eq(idir, idir_eq) * gkq_base(:,:,mu_eq,iq_sym,igv)
    7343              :              end do
    7344            0 :              if (trev_k == 1) gtmp = conjg(gtmp)
    7345            0 :              gkq_rot(:,:,mu,iq_glob,igv) = matmul(matmul(dh_mat, gtmp), ket_mat)
    7346              :            end do
    7347              :          end do
    7348              : 
    7349              :        end do ! my_iq
    7350              : 
    7351              :        ! Write the newly reconstructed + copied-through rows back to the netcdf file.
    7352            0 :        do igv=1,n_gv
    7353            0 :          call c_f_pointer(c_loc(gkq_rot(1,1,1,1,igv)), gkq_rot_ptr, [2, nb, nb, gqk%natom3, gqk%my_nq])
    7354              :          ncerr = nf90_put_var(spin_ncid, spin_vid(gv_names(igv)), gkq_rot_ptr, &
    7355              :                               start=[1, 1, 1, 1, ik_glob, 1], &
    7356            0 :                               count=[2, nb, nb, gqk%natom3, 1, gqk%my_nq])
    7357            0 :          NCF_CHECK(ncerr)
    7358              :        end do
    7359            0 :        where (state_kq(ik_glob, :) == GSTORE_KQ_MISSING) state_kq(ik_glob, :) = GSTORE_KQ_SYMMETRIZED
    7360              : 
    7361            0 :        ABI_FREE(lg_isym)
    7362            0 :        ABI_FREE(lg_itime)
    7363              :      end do ! ik_ibz
    7364              :    end if ! gstore_sym == 2
    7365              : 
    7366            0 :    NCF_CHECK(nf90_sync(spin_ncid))
    7367              : 
    7368              :    ! Loop over k-points in the IBZ.
    7369            0 :    do my_ik=1,gqk%my_nk
    7370            0 :      ik_glob = my_ik + gqk%my_kstart - 1
    7371            0 :      kk_bz = gqk%my_kpts(:, my_ik)
    7372              : 
    7373            0 :      if (state_kq(ik_glob, 1) /= GSTORE_KQ_MISSING) then
    7374              :        ! Row already fully resolved: either directly COMPUTED (gstore_use_lgk == 0), or
    7375              :        ! filled by Pass A above (gstore_sym == 2, mix of COMPUTED and SYMMETRIZED).
    7376            0 :        ABI_CHECK(all(state_kq(ik_glob, :) /= GSTORE_KQ_MISSING), "all state")
    7377            0 :        cycle
    7378              :      end if
    7379              : 
    7380              :      ! Symmetry tables for k-point. Using symrel^T convention for k..
    7381            0 :      ik_ibz = gqk%my_k2ibz(1, my_ik); isym_k = gqk%my_k2ibz(2, my_ik)
    7382            0 :      trev_k = gqk%my_k2ibz(6, my_ik); g0_k = gqk%my_k2ibz(3:5, my_ik)
    7383              :      isirr_k = (isym_k == 1 .and. trev_k == 0 .and. all(g0_k == 0))
    7384            0 :      tsign_k = 1; if (trev_k == 1) tsign_k = -1
    7385            0 :      itime_k = trev_k + 1
    7386            0 :      kk_ibz = ebands%kptns(:,ik_ibz)
    7387              : 
    7388              :      ! Index of the IBZ k-point on disk.
    7389            0 :      ik_ibz_file = kibz2bz(ik_ibz)
    7390              : 
    7391              :      ! symrec_eq is the SPATIAL rotation (used for atomic-perturbation-direction
    7392              :      ! bookkeeping below, which is TR-blind: time reversal does not move atoms.
    7393              :      ! symrec_eq_kspace additionally carries the TR sign and is the one that actually relates k-space
    7394              :      ! vectors (kk_bz, q) to their IBZ images
    7395            0 :      symrec_eq = transpose(cryst%symrel(:,:,isym_k))
    7396            0 :      symrec_eq_kspace = tsign_k * symrec_eq
    7397            0 :      ABI_CHECK(isamek(kk_bz, matmul(symrec_eq_kspace, kk_ibz), g0_q), "kk_bz != symrec_eq_kspace kk_ibz")
    7398              : 
    7399            0 :      do isym_combined=1,nsym
    7400            0 :        if (all(cryst%symrec(:,:,isym_combined) == symrec_eq)) exit
    7401              :      end do
    7402            0 :      ABI_CHECK(isym_combined /= nsym + 1, "Cannot find symrec_eq")
    7403              : 
    7404              :      ! Read g(k_ibz, q) for all q-point in the BZ, for each gvals stream ("gvals", and "gvals_ks" too when gtype == "gwpt").
    7405            0 :      do igv=1,n_gv
    7406            0 :        call c_f_pointer(c_loc(gkq_base(1,1,1,1,igv)), gkq_base_ptr, [2, nb, nb, gqk%natom3, gqk%my_nq])
    7407              :        ncerr = nf90_get_var(spin_ncid, spin_vid(gv_names(igv)), gkq_base_ptr, &
    7408              :                             start=[1, 1, 1, 1, ik_ibz_file, 1], &
    7409            0 :                             count=[2, nb, nb, gqk%natom3, 1, gqk%my_nq])
    7410            0 :        NCF_CHECK(ncerr)
    7411              :      end do
    7412              : 
    7413              :      ! Loop over q-points in the BZ.
    7414            0 :      do my_iq=1, gqk%my_nq
    7415            0 :        iq_glob = my_iq + gqk%my_qstart - 1
    7416            0 :        this_state = state_kq(ik_glob, iq_glob)
    7417            0 :        if (this_state /= GSTORE_KQ_MISSING) cycle
    7418              : 
    7419              :        ! Symmetry tables for q-point. NB: Using symrec convention for q.
    7420              :        !iq_ibz = gqk%my_q2ibz(1, my_iq); isym_q = gqk%my_q2ibz(2, my_iq)
    7421              :        !trev_q = gqk%my_q2ibz(6, my_iq); g0_q = gqk%my_q2ibz(3:5, my_iq)
    7422              :        !isirr_q = (isym_q == 1 .and. trev_q == 0 .and. all(g0_q == 0))
    7423              :        !tsign_q = 1; if (trev_q == 1) tsign_q = -1
    7424              :        !qq_ibz = gstore%qibz(:, iq_ibz)
    7425            0 :        qpt = qbz(:, my_iq)
    7426              : 
    7427              :        ! Find q. Uses symrec_eq_kspace (not symrec_eq): q, like k, is a genuine k-space vector
    7428              :        ! that picks up the TR sign under the same combined operation mapping kk_ibz -> kk_bz.
    7429            0 :        do iq_sym=1, gqk%my_nq
    7430              :          ! qpt = qpt_tmp + G0_q
    7431            0 :          qpt_tmp = matmul(symrec_eq_kspace, qbz(:, iq_sym)); if (isamek(qpt, qpt_tmp, g0_q)) exit
    7432              :        end do
    7433            0 :        ABI_CHECK(iq_sym /= gqk%my_nq + 1, sjoin("Cannot find:", ktoa(qpt)))
    7434              : 
    7435              :        ! -----------------------------------------------------------------
    7436              :        ! Bug A fix: the bra (electron state at k+q) reaches its target BZ
    7437              :        ! point via two composed rotations (isym_k applied to the SOURCE
    7438              :        ! bra's own rotation from kq_ibz), while the "true" bra is obtained
    7439              :        ! by a single direct rotation from kq_ibz. The two differ by U(h),
    7440              :        ! h being the residual element of the little group (stabilizer) of
    7441              :        ! kq_ibz. h always stabilizes kq_ibz by construction (never an
    7442              :        ! out-of-domain little-group lookup), so the D-matrices already
    7443              :        ! tabulated by dmats are valid here. See gstore_symmetrize_status
    7444              :        ! memory (session 10) for the full derivation.
    7445            0 :        kq_bz_source = kk_ibz + qbz(:, iq_sym)
    7446            0 :        kq_bz_target = kk_bz + qpt
    7447            0 :        ierr = kpts_map("symrel", ebands%kptopt, cryst, gstore%krank_ibz, 1, kq_bz_source, indkk_s)
    7448            0 :        ABI_CHECK(ierr == 0, "Cannot find symmetric image of k+q (source)")
    7449            0 :        ierr = kpts_map("symrel", ebands%kptopt, cryst, gstore%krank_ibz, 1, kq_bz_target, indkk_t)
    7450            0 :        ABI_CHECK(ierr == 0, "Cannot find symmetric image of k+q (target)")
    7451            0 :        ikq_ibz_s = indkk_s(1,1); isym_kqS = indkk_s(2,1)
    7452            0 :        ikq_ibz_t = indkk_t(1,1); isym_kqT = indkk_t(2,1)
    7453            0 :        trev_kqS = indkk_s(6,1); trev_kqT = indkk_t(6,1)
    7454            0 :        ABI_CHECK(ikq_ibz_s == ikq_ibz_t, "Source and target k+q map to different IBZ points!")
    7455              : 
    7456              :        ! mat_tmp = Srel(toinv(isym_kqT)) . Srel(isym_k) . Srel(isym_kqS), with Srel(S) := symrel(S)^T
    7457              :        ! (same k/kq convention as symrec_eq above, i.e. NOT cryst%symrec). h_isym is the isym s.t.
    7458              :        ! Srel(h_isym) == mat_tmp.
    7459            0 :        mat_tmp = matmul(transpose(cryst%symrel(:,:,dmats%toinv(1,isym_kqT))), &
    7460            0 :                         matmul(symrec_eq, transpose(cryst%symrel(:,:,isym_kqS))))
    7461            0 :        do h_isym=1,nsym
    7462            0 :          if (all(transpose(cryst%symrel(:,:,h_isym)) == mat_tmp)) exit
    7463              :        end do
    7464            0 :        ABI_CHECK(h_isym /= nsym + 1, "Cannot find little-group element h for the k+q leg")
    7465              : 
    7466              :        ! Lattice-vector-phase companion to h_isym (bra leg). The rotation-only h_isym search above
    7467              :        ! finds the correct isym s.t. Srel(h_isym) matches the literal 3-way rotation product, but
    7468              :        ! (analogous to dmats_get_star_dmats's validated S0.g.S0^{-1} + L_h construction) the literal
    7469              :        ! Seitz composition Tab(isym_kqS).Tab(isym_k).Tab(isym_kqT)^{-1} generally differs from
    7470              :        ! Tab(h_isym) by a residual lattice vector L_h_gs whenever any of isym_kqS/isym_k/isym_kqT is
    7471              :        ! non-symmorphic, even when h_isym is the identity rotation. Derived by substituting
    7472              :        ! Tab(c1)=T_{-L1}.Tab(isym_kqS).Tab(isym_k) [c1=multable(1,isym_kqS,isym_k), the SAME rotation
    7473              :        ! recipe already validated for h_isym itself] into Tab(c1).Tab(toinv(isym_kqT))=T_{L2}.Tab(h_isym),
    7474              :        ! then Tab(toinv(isym_kqT)) = Tab(isym_kqT)^{-1}.T_{L0} (L0=toinv(2:4,isym_kqT)), and pushing
    7475              :        ! T_{-L0} through Tab(h_isym) (Tab(h).T_v = T_{R(h).v}.Tab(h)). Verified EXACTLY (3000/3000
    7476              :        ! random (isym_k,isym_kqS,isym_kqT) triples, zero umklapp) against the literal 3-operator
    7477              :        ! Seitz composition computed independently with the EXACT (non-tabulated) group inverse. The
    7478              :        ! overall sign was pinned down against a hand-verified counterexample (h_isym=1, needing a
    7479              :        ! missing factor of exactly +i).
    7480            0 :        c1_gs = dmats%multable(1, isym_kqS, isym_k)
    7481              :        L_h_gs = real(dmats%multable(2:4, isym_kqS, isym_k), dp) &
    7482              :               + real(dmats%multable(2:4, c1_gs, dmats%toinv(1,isym_kqT)), dp) &
    7483            0 :               - matmul(real(cryst%symrel(:,:,h_isym), dp), real(dmats%toinv(2:4,isym_kqT), dp))
    7484            0 :        kq_ibz_pt = ebands%kptns(:, ikq_ibz_t)
    7485            0 :        phase_h_gs = exp(cmplx(zero, two_pi * sum(kq_ibz_pt * L_h_gs), dp))
    7486              : 
    7487              :        ! Companion phase on the KET leg. Even with phase_h_gs above, a residual remained, isolated
    7488              :        ! (via h_isym==1 points, where dh_mat=I so phase_h_gs is the only other active correction) to
    7489              :        ! be a clean function of isym_k and the TARGET q alone: exp(-i*2pi*qpt.v(isym_k)) for an
    7490              :        ! integer vector v. Empirically fit v(isym_k) exactly (100% across all isym_k appearing in
    7491              :        ! the reference test, zero exceptions) to toinv(2:4, toinv(1,isym_k)) -- i.e. the
    7492              :        ! lattice-vector residual of composing isym_k with its OWN inverse in the OTHER order from
    7493              :        ! toinv's own convention (toinv(2:4,isym_k) is for S(isym_k).S(isym_k^{-1}); this needs
    7494              :        ! S(isym_k^{-1}).S(isym_k) instead, which only coincides with the former when isym_k is
    7495              :        ! self-inverse -- the same class of composition-order mixup fixed in dmats_check_one_k and in
    7496              :        ! deriving L_h_gs above). Physical origin not fully pinned down: isym_k plays a role in BOTH
    7497              :        ! the ket rotation (kk_bz = symrec_eq.kk_ibz) AND the atomic-perturbation-direction rotation
    7498              :        ! via the SAME symrec_eq in the mu-loop below (whose existing cphase/l0 term is dotted with
    7499              :        ! the SOURCE q, not the target) -- plausibly this is the missing lattice-vector companion to
    7500              :        ! THAT term, evaluated at the target q instead, but this is a plausible reading of the
    7501              :        ! empirical formula, not an independently re-derived physical proof (unlike L_h_gs above,
    7502              :        ! which was verified against the literal Seitz composition directly). Trust the formula
    7503              :        ! (exhaustively validated below); treat the physical narrative as informed conjecture only.
    7504              :        !
    7505              :        ! Effect of phase_h_gs+phase_ket_gs alone on the gstore_brange 1 4 reference test: raw
    7506              :        ! exact-match rate 60.4% -> 91.7%, gauge-invariant unchanged at 100%. NOTE: the remaining 8.3%
    7507              :        ! was INITIALLY (wrongly) attributed entirely to expected degenerate-band gauge freedom per
    7508              :        ! AGENTS.md -- this was corrected later (see the THIRD correction right below): a Procrustes
    7509              :        ! best-fit-unitary check proved EXACT reconstruction is achievable for within-range-degenerate
    7510              :        ! bra multiplets, so that mismatch was a real, fixable bug, not gauge freedom. Do not repeat
    7511              :        ! that mistake: eigenvalue-degeneracy alone never proves a mismatch is harmless -- check
    7512              :        ! whether a single matrix can exactly relate reconstruction to truth first.
    7513            0 :        phase_ket_gs = exp(cmplx(zero, -two_pi * sum(qpt * real(dmats%toinv(2:4, dmats%toinv(1,isym_k)), dp)), dp))
    7514              : 
    7515              :        ! THIRD correction: dmats%for_spin(h_isym) is the WRONG tabulated matrix for the bra whenever
    7516              :        ! h_isym is a non-self-inverse symmetry. Root cause: dmats_init computes D(isym) by calling
    7517              :        ! cgtk_rotate with isym_inv=toinv(isym) and a separately-recomputed umklapp g0_inv (a
    7518              :        ! documented workaround for cgtk_rotate silently returning D_true(S)^{-1} for non-involutions).
    7519              :        ! D(h) and D(toinv(h)) are unitary inverses of each other only up to an EXTRA phase that
    7520              :        ! dmats_init's own toinv/multable bookkeeping already knows about (this is exactly what
    7521              :        ! dmats_check_one_k's "inv_phase"/"phase_analytic" diagnostic measures and validates) --
    7522              :        ! reconstructing D(toinv(h)) from D(h) via a bare conjugate-transpose silently drops that
    7523              :        ! phase. Looking up dmats%for_spin(toinv(h_isym)) directly sidesteps this entirely, since
    7524              :        ! dmats_init already computed that matrix independently and self-consistently under its own
    7525              :        ! label: there is nothing to reconstruct.
    7526              :        !
    7527              :        ! Earlier sessions gated this substitution behind an empirical "is a correction needed at
    7528              :        ! all" heuristic (g0-mismatch OR non-self-inverse-and-degenerate-bra), applying toinv(h_isym)
    7529              :        ! only when it fired and h_isym unmodified otherwise. That heuristic is UNNECESSARY: applying
    7530              :        ! dmats%for_spin(toinv(h_isym)) unconditionally (i.e. always, regardless of degeneracy or g0)
    7531              :        ! reproduces the exact same result on every point where the heuristic previously used
    7532              :        ! h_isym directly -- because on the reference test system, no such point exists: every
    7533              :        ! non-self-inverse h_isym already satisfied the heuristic's trigger condition. (For
    7534              :        ! self-inverse h_isym, toinv(1,h_isym)==h_isym, so the two forms are trivially identical
    7535              :        ! regardless.) Verified end-to-end against check_symm.py: byte-for-byte identical results to
    7536              :        ! the old conditional form -- 3584/3584 (100.0%) raw+gauge-invariant exact matches on
    7537              :        ! gstore_brange 1 4 (max diff 3.66e-7, noise level), 3533/3584 (98.6%) raw==gauge-invariant on
    7538              :        ! gstore_brange 1 2 (the residual there is the known, inherent out-of-range-degeneracy
    7539              :        ! limitation of truncating the band range, not a bug). See gstore_symmetrize_status memory
    7540              :        ! (sessions 14-15) for the full derivation history and this final unconditional-formula
    7541              :        ! confirmation.
    7542              :        ! TIME-REVERSAL generalization of itime_h (was hardcoded to 1, i.e. always the pure-spatial
    7543              :        ! D-matrix slice). The unitary/antiunitary character of a composed operator is a Z2
    7544              :        ! homomorphism (same rule dmats_check_one_k's group-multiplication test uses:
    7545              :        ! itime3 = 1 + mod((itime1-1)+(itime2-1), 2), Bradley & Cracknell sec. 7.3), extended here
    7546              :        ! by associativity to h's three-fold composition toinv(isym_kqT).isym_k.isym_kqS
    7547              :        ! (itime(A^{-1}) = itime(A), so toinv(isym_kqT) contributes trev_kqT unchanged). High
    7548              :        ! confidence, not yet empirically validated on a TR-nonzero system.
    7549            0 :        itime_h = 1 + mod(trev_k + trev_kqS + trev_kqT, 2)
    7550              : 
    7551              :        ! HYPOTHESIS (open question, validate empirically -- see gstore_symmetrize_status memory):
    7552              :        ! phase_h_gs's lattice-vector phase is built from dmats%multable/toinv, which are
    7553              :        ! itime-independent by construction, so its formula should carry over unchanged. But the
    7554              :        ! closest validated analogue, dmats_get_star_dmats (m_classify_bands.F90), needs an EXTRA
    7555              :        ! conjugation on its own analogous phase whenever itime==2. Applying the same pattern here
    7556              :        ! as a first hypothesis; h's composition shape differs from that routine's, so this is not
    7557              :        ! a proof, only a well-motivated starting point.
    7558            0 :        h_isym_inv = dmats%toinv(1, h_isym)
    7559            0 :        if (itime_h == 2) then
    7560            0 :          dh_mat = conjg(phase_h_gs) * phase_ket_gs * dmats%for_spin(spin)%value(:,:,h_isym_inv,itime_h,ikq_ibz_t)
    7561              :        else
    7562            0 :          dh_mat = phase_h_gs * phase_ket_gs * dmats%for_spin(spin)%value(:,:,h_isym_inv,itime_h,ikq_ibz_t)
    7563              :        end if
    7564              : 
    7565              :        ! HYPOTHESIS (open question, validate empirically): pulling D(h) through the outer operator
    7566              :        ! that maps ikq_ibz -> kq_bz_target picks up a conjugate exactly when that operator
    7567              :        ! (governed by isym_kqT/trev_kqT) is antiunitary -- a flag logically independent of trev_k
    7568              :        ! (see 2.4's gtmp conjugation below) and of itime_h (which only selects WHICH tabulated
    7569              :        ! matrix to read, not whether the whole assembled dh_mat needs conjugating on top).
    7570            0 :        if (trev_kqT == 1) dh_mat = conjg(dh_mat)
    7571              : 
    7572              :        if (DEBUG_DUMP_DH) then
    7573              :          write(789,'(7(i0,1x),2(es16.8,1x),9(i0,1x),6(es16.8,1x))') ik_glob, iq_glob, isym_k, h_isym, ikq_ibz_t, &
    7574              :            isym_kqS, isym_kqT, real(dh_mat(1,1)), aimag(dh_mat(1,1)), indkk_s(3:5,1), indkk_t(3:5,1), g0_k, &
    7575              :            qpt, kk_ibz
    7576              :          write(790,*) ik_glob, iq_glob, nb, isym_k, h_isym, ikq_ibz_t, isym_kqS, isym_kqT, g0_q, &
    7577              :            trev_k, trev_kqS, trev_kqT, itime_h, &
    7578              :            real(phase_h_gs), aimag(phase_h_gs), real(phase_ket_gs), aimag(phase_ket_gs), &
    7579              :            dmats%for_spin(spin)%value(:,:,h_isym,itime_h,ikq_ibz_t)
    7580              :        end if
    7581              :        ! -----------------------------------------------------------------
    7582              : 
    7583              :        ! Perform symmetrization.
    7584            0 :        do mu=1,gqk%natom3
    7585            0 :          idir = mod(mu-1, 3) + 1; iat = (mu - idir) / 3 + 1
    7586              : 
    7587            0 :          iat_eq = cryst%indsym(4, isym_combined, iat)
    7588            0 :          l0 = cryst%indsym(1:3, isym_combined, iat)
    7589            0 :          phase = -two_pi * dot_product(qbz(:, iq_sym), l0)
    7590            0 :          cphase = cmplx(cos(phase), sin(phase), dp)
    7591              : 
    7592              :          ! Per-mu atomic-mapping/phase diagnostic (iat_eq, l0, symrec_eq row, cphase, iq_sym):
    7593              :          ! reusable general-purpose dump, not tied to any specific (ik_glob,iq_glob) -- add a
    7594              :          ! filter here (e.g. "if (ik_glob==... .and. iq_glob==...)") when tracing one point on a
    7595              :          ! large system, to keep mu_debug.csv a manageable size.
    7596              :          if (DEBUG_DUMP_DH) then
    7597              :            write(792,*) ik_glob, iq_glob, mu, iat, iat_eq, isym_combined, isym_k, ik_ibz, iq_sym, &
    7598              :              l0, symrec_eq(idir,1), symrec_eq(idir,2), symrec_eq(idir,3), idir, ik_ibz_file, cphase
    7599              :          end if
    7600              : 
    7601              :          ! Apply the same geometric rotation (cphase/symrec_eq/dh_mat, all independent of which
    7602              :          ! gvals stream is being processed) to each stream separately, since gtmp's accumulation
    7603              :          ! reads actual matrix-element values from gkq_base.
    7604            0 :          do igv=1,n_gv
    7605            0 :            gtmp = zero
    7606            0 :            do idir_eq=1,3
    7607            0 :              mu_eq = idir_eq + (iat_eq - 1) * 3
    7608            0 :              gtmp = gtmp + cphase * symrec_eq(idir, idir_eq) * gkq_base(:,:,mu_eq,iq_sym,igv)
    7609              :            end do
    7610              :            ! HYPOTHESIS (open question, validate empirically): conjugate gtmp before the dh_mat
    7611              :            ! multiply whenever the ket leg's own operation (isym_k, trev_k) is antiunitary. Matches
    7612              :            ! the "rotate spatially first, conjugate as the last step" pattern used identically by
    7613              :            ! cgtk_rotate, pheigvec_rotate, rotate_fqg and dmats_init elsewhere in this codebase.
    7614              :            ! Order matters: conjugate gtmp itself, not matmul(dh_mat,gtmp), since dh_mat is complex.
    7615            0 :            if (trev_k == 1) gtmp = conjg(gtmp)
    7616              :            ! Apply the Bug A correction: left-multiply by D(h) on the bra (m) index.
    7617            0 :            gkq_rot(:,:,mu,iq_glob,igv) = matmul(dh_mat, gtmp)
    7618            0 :            if (DEBUG_DUMP_DH) write(791,*) ik_glob, iq_glob, mu, nb, trev_k, trim(gv_names(igv)), gtmp
    7619              :          end do
    7620              :        end do
    7621              : 
    7622              :      end do ! my_iq
    7623              : 
    7624              :      ! Write the newly computed g_{mn, nu} back to the netcdf file (in-place modification),
    7625              :      ! for each gvals stream, and update the entry in state_kq.
    7626            0 :      do igv=1,n_gv
    7627            0 :        call c_f_pointer(c_loc(gkq_rot(1,1,1,1,igv)), gkq_rot_ptr, [2, nb, nb, gqk%natom3, gqk%my_nq])
    7628              :        ncerr = nf90_put_var(spin_ncid, spin_vid(gv_names(igv)), gkq_rot_ptr, &
    7629              :                             start=[1, 1, 1, 1, ik_glob, 1], &
    7630            0 :                             count=[2, nb, nb, gqk%natom3, 1, gqk%my_nq])
    7631            0 :        NCF_CHECK(ncerr)
    7632              :      end do
    7633            0 :      state_kq(ik_glob, :) = GSTORE_KQ_SYMMETRIZED
    7634              :    end do ! my_ik
    7635              :    end associate
    7636              : 
    7637              :    ! Update state_kq for this spin.
    7638            0 :    ncerr = nf90_put_var(ncid, vid("gstore_glob_state_kqs"), state_kq, start=[1,1,spin])
    7639            0 :    NCF_CHECK(ncerr)
    7640              : 
    7641            0 :    ABI_FREE(qbz)
    7642            0 :    ABI_FREE(gkq_base)
    7643            0 :    ABI_FREE(gkq_rot)
    7644            0 :    ABI_FREE(state_kq)
    7645            0 :    ABI_FREE(gtmp)
    7646            0 :    ABI_FREE(dh_mat)
    7647            0 :    ABI_FREE(ket_mat)
    7648              :  end do ! my_is
    7649              : 
    7650            0 :  NCF_CHECK(nf90_close(ncid))
    7651              :  if (DEBUG_DUMP_DH) close(789)
    7652              :  if (DEBUG_DUMP_DH) close(790)
    7653              :  if (DEBUG_DUMP_DH) close(791)
    7654              :  if (DEBUG_DUMP_DH) close(792)
    7655              : 
    7656            0 :  ABI_FREE(kibz2bz)
    7657            0 :  call gstore%free()
    7658              : 
    7659            0 :  100 call dmats%free()
    7660            0 :  call xmpi_barrier(comm)
    7661            0 :  call wrtout(units, " Symmetrization completed successfully.")
    7662              : 
    7663              : contains
    7664            0 : integer function vid(var_name)
    7665              :   character(len=*),intent(in) :: var_name
    7666            0 :   vid = nctk_idname(ncid, var_name)
    7667              : end function vid
    7668              : 
    7669            0 : integer function spin_vid(var_name)
    7670              :   character(len=*),intent(in) :: var_name
    7671            0 :   spin_vid = nctk_idname(spin_ncid, var_name)
    7672              : end function spin_vid
    7673              : 
    7674              : end subroutine gstore_symmetrize
    7675              : !!***
    7676              : 
    7677        78498 : end module m_gstore
    7678              : !!***
        

Generated by: LCOV version 2.3-1