LCOV - code coverage report
Current view: top level - src/56_recipspace - m_gsphere.F90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 77.4 % 695 538
Test Date: 2026-09-21 13:49:52 Functions: 85.7 % 21 18

            Line data    Source code
       1              : !!****m* ABINIT/m_gsphere
       2              : !! NAME
       3              : !!  m_gsphere
       4              : !!
       5              : !! FUNCTION
       6              : !!  The Gsphere data type defines the set of G-vectors
       7              : !!  centered on Gamma used to describe (chi0|epsilon|W) in the GW code.
       8              : !!  Note that, unlike the kg_k arrays used for wavefunctions, here the
       9              : !!  G-vectors are ordered in shells (increasing length). Moreover
      10              : !!  the sphere can be enlarged to take into account umklapps for which
      11              : !!  one need the knowledge of several quantities at G-G0.
      12              : !!
      13              : !! COPYRIGHT
      14              : !! Copyright (C) 1999-2026 ABINIT group (MG, GMR, VO, LR, RWG, MT, XG)
      15              : !! This file is distributed under the terms of the
      16              : !! GNU General Public License, see ~abinit/COPYING
      17              : !! or http://www.gnu.org/copyleft/gpl.txt .
      18              : !!
      19              : !! SOURCE
      20              : 
      21              : #if defined HAVE_CONFIG_H
      22              : #include "config.h"
      23              : #endif
      24              : 
      25              : #include "abi_common.h"
      26              : 
      27              : module m_gsphere
      28              : 
      29              :  use defs_basis
      30              :  use m_abicore
      31              :  use m_errors
      32              :  use m_sort
      33              : 
      34              :  use defs_abitypes,   only : MPI_type
      35              :  use m_fstrings,      only : sjoin, itoa
      36              :  use m_numeric_tools, only : bisect
      37              :  use m_geometry,      only : normv
      38              :  use m_crystal,       only : crystal_t
      39              :  use m_fftcore,       only : kpgsph, kgindex, sphereboundary
      40              :  use m_mpinfo,        only : destroy_mpi_enreg, initmpi_seq
      41              : 
      42              :  implicit none
      43              : 
      44              :  private
      45              : 
      46              : ! Low-level procedures.
      47              :  public :: merge_and_sort_kg   ! Merges a set of k-centered G-spheres of cutoff ecut. Return a Gamma-centered G-spheres.
      48              :  public :: table_gbig2kg       ! Associate the kg_k set of G-vectors with Gamma-centered G-sphere.
      49              :  public :: get_irredg          ! Given a set of G vectors, find the set of G"s generating the others by symmetry.
      50              :  public :: merge_kgirr         ! Merge a list of irreducible G vectors (see routine for more info)
      51              :  public :: setshells           ! Set consistently the number of shells, the number of plane-waves, and the energy cut-off
      52              :  public :: kg_map              ! Compute the mapping between two lists of g-vectors.
      53              :  public :: make_istwfk_table
      54              :  public :: getkpgnorm          ! Compute the norms of the k+G vectors
      55              :  public :: symg
      56              : !!***
      57              : 
      58              : !----------------------------------------------------------------------
      59              : 
      60              : !!****t* m_gsphere/gsphere_t
      61              : !! NAME
      62              : !! gsphere_t
      63              : !!
      64              : !! FUNCTION
      65              : !! The gsphere_t data type contains information related to the set of G vectors
      66              : !! used during a screening or a GW calculation, as well as symmetry tables relating
      67              : !! these vectors. Presently the following quantities are stored
      68              : !!
      69              : !! 1) The reduced coordinates of the G vectors (arrays gvec)
      70              : !! 2) Tables giving the correspondence between a G-vector and its rotated image
      71              : !!    through a symmetry operation in reciprocal space.
      72              : !! 3) List of the irreducible G pairs
      73              : !! 4) Tables giving, for each pair in the full reciprocal space, the corresponding
      74              : !!    irreducible pair as well as the symmetry operation in reciprocal space
      75              : !!
      76              : !! Note that, unlike the GS part, the basis set does not depend on the k-point.
      77              : !!
      78              : !! NOTES
      79              : !!
      80              : !! To indicate the indices in the arrays grottb, grottbm1 we use the following notation:
      81              : !!
      82              : !!  g defines the index of the reciprocal lattice vector in the array gvec
      83              : !!  s  indicates the index of the symmetry operation in reciprocal space
      84              : !!  i  can  be one or two. 1 is used to indicate the identity operator
      85              : !!
      86              : !! SOURCE
      87              : 
      88              :  type,public :: gsphere_t
      89              : 
      90              :   integer :: ng
      91              :   ! Total number of G vectors in the sphere taking into account umklapps
      92              :   ! it defines the size of the array gvec and it accounts for possible umklapps for which
      93              :   ! one has to shift the sphere.
      94              : 
      95              :   ! TODO: The sphere should be enlarged in gpairs_init using mg0 and (ecut|ng) as input.
      96              :   ! For the time being we keep the old implementation.
      97              :   !%integer :: ng_eff
      98              :   ! Effective number of G vectors, i.e. the number of G in the smaller sphere without umklapps.
      99              :   ! ng_eff<=ng and should be used to loop over the elements of (chi0|epsilon|W).
     100              :   !
     101              :   ! TODO: Add info on FFT including zero-padding algorithm.
     102              :   ! table must be recalculated for each G0 and rho_tw_g should accept gpshere in input.
     103              : 
     104              :   integer :: nsh                   ! Number of shells
     105              :   integer :: nsym                  ! The number of symmetry operations
     106              :   integer :: timrev                ! 2 if time-reversal is used, 1 otherwise
     107              :   integer :: istwfk=1              ! Storage mode. At present time-reversal is not used.
     108              : 
     109              :   !integer :: mg0(3)=0
     110              :   ! For each reduced direction gives the max G0 component to account for umklapp processes.
     111              : 
     112              :   real(dp) :: ecut
     113              :   ! Cutoff energy of the sphere.
     114              : 
     115              :   real(dp) :: gmet(3,3)
     116              :   ! Reciprocal space metric ($\textrm{bohr}^{-2}$).
     117              : 
     118              :   real(dp) :: gprimd(3,3)
     119              :   ! Dimensional reciprocal space primitive translations (bohr^{-1})
     120              : 
     121              :   integer,allocatable :: g2sh(:)
     122              :   ! g2sh(ng)
     123              :   ! For each G, it gives the index of the shell to which it belongs.
     124              : 
     125              :   integer,allocatable :: gvec(:,:)
     126              :   ! gvec(3,ng)
     127              :   ! Reduced coordinates of G vectors.
     128              : 
     129              :   integer,allocatable :: g2mg(:)
     130              :   ! g2mg(ng)
     131              :   ! Correspondence G --> -G
     132              : 
     133              :   integer,allocatable :: rottb(:,:,:)
     134              :   ! rottb(ng,timrev,nsym)
     135              :   ! rottb(G,I,S) is the index of (SI) G in the array gvec
     136              :   ! where I is either the identity or the inversion.
     137              : 
     138              :   integer,allocatable :: rottbm1(:,:,:)
     139              :   ! rottb(ng,timrev,nsym)
     140              :   ! rottbm1(G,I,S) is the index of IS{^-1} G in the array gvec
     141              : 
     142              :   integer,allocatable :: shlim(:)
     143              :   ! shlim(nsh+1)
     144              :   ! Index of the first G vector in each shell, =ng+1 for nsh+1
     145              : 
     146              :   real(dp),allocatable :: shlen(:)
     147              :   ! shlen(nsh)
     148              :   ! Radius of each shell.
     149              : 
     150              :   !TODO switch to dpc
     151              :   complex(gwp),allocatable :: phmGt(:,:)
     152              :   ! phmGt(ng,nsym)
     153              :   ! Phase factor e^{-i2\pi(G.\tau)} where $\tau$ is the fractional translation associated to isym.
     154              : 
     155              :   complex(gwp),allocatable :: phmSGt(:,:)
     156              :   ! phmSGt(ng,nsym)
     157              :   ! Phase factor e^{-i2\pi(SG.\tau)} where S is one of the symmetry properties in reciprocal space.
     158              : 
     159              :   contains
     160              : 
     161              :    procedure  :: init        => gsph_init           ! Initialize the G-sphere.
     162              :    procedure  :: fft_tabs    => gsph_fft_tabs       ! Returns useful tables for FFT (with or without padding).
     163              :    procedure  :: in_fftbox   => gsph_in_fftbox      ! Initialize the largest Gsphere contained in the FFT box.
     164              :    procedure  :: print       => gsph_print          ! Printout of basic dimensions.
     165              :    procedure  :: free        => gsph_free           ! Free memory allocated in the object.
     166              :    procedure  :: g_idx       => gsph_g_idx          ! Returns the index of G from its reduced coordinates.
     167              :    procedure  :: gmg_idx     => gsph_gmg_idx        ! Returns the index of G1-G2 from their indices
     168              :    procedure  :: gmg_fftidx  => gsph_gmg_fftidx     ! Returns the index of G1-G2 in the FFT mesh defined by ngfft.
     169              :    procedure  :: extend      => gsph_extend         ! Construct a new gsphere_t with a larger cutoff energy
     170              : 
     171              :  end type gsphere_t
     172              : !!***
     173              : 
     174              : CONTAINS  !=================================================================================
     175              : !!***
     176              : 
     177              : !!****f* m_gsphere/setup_G_rotation
     178              : !! NAME
     179              : !! setup_G_rotation
     180              : !!
     181              : !! FUNCTION
     182              : !! Set up tables indicating rotation of G-vectors.
     183              : !!
     184              : !! INPUTS
     185              : !! nsym=Number of symmetry operations.
     186              : !! symrec(3,3,nsym)=Symmetry operations in reciprocal space.
     187              : !! timrev=2 if time reversal can be used, 1 otherwise.
     188              : !! npw=Number of planewaves in the sphere.
     189              : !! gvec(3,npw)=Coordinates of plane waves, supposed to be ordered in increasing modulus
     190              : !! g2sh(npw)=For each G, it gives the index of the shell to which it belongs.
     191              : !! nsh=Number of shells
     192              : !! shlim(nsh+1)=Index of the first G vector in each shell, =npw+1 for nsh+1
     193              : !!
     194              : !! OUTPUT
     195              : !!  grottb  (npw,2,nsym)= grottb(G,I,S) is the index of (SI) G in the array gvec.
     196              : !!  grottbm1(npw,2,nsym)= index of IS^{-1} G.
     197              : !!
     198              : !! NOTES:
     199              : !!  I is either the identity or the inversion (time reversal in reciprocal space).
     200              : !!  S is one of the symmetry operation in reciprocal space belonging to the Space group.
     201              : !!
     202              : !! SOURCE
     203              : 
     204         1066 : subroutine setup_G_rotation(nsym,symrec,timrev,npw,gvec,g2sh,nsh,shlim,grottb,grottbm1)
     205              : 
     206              : !Arguments ------------------------------------
     207              : !scalars
     208              :  integer,intent(in) :: npw,nsh,nsym,timrev
     209              : !arrays
     210              :  integer,intent(in) :: g2sh(npw),gvec(3,npw),shlim(nsh+1),symrec(3,3,nsym)
     211              :  integer,intent(inout) :: grottb  (npw,timrev,nsym)
     212              :  integer,intent(inout) :: grottbm1(npw,timrev,nsym)
     213              : 
     214              : !Local variables ------------------------------
     215              : !scalars
     216              :  integer :: ee,ig1,ig2,ish1,isym,itim,ss
     217              :  logical :: found
     218              :  character(len=500) :: msg
     219              : !arrays
     220              :  integer :: gbase(3),grot(3)
     221              : !************************************************************************
     222              : 
     223              :  ! === Set up G-rotation table ===
     224       716498 :  do ig1=1,npw
     225       715432 :    ish1=g2sh(ig1) ; ss=shlim(ish1) ; ee=shlim(ish1+1)-1
     226      2861728 :    gbase(:)=gvec(:,ig1)
     227              : 
     228      2141747 :    do itim=1,timrev
     229     35359841 :      do isym=1,nsym
     230    531506560 :        grot=(3-2*itim)*MATMUL(symrec(:,:,isym),gbase)
     231              :        found=.FALSE.
     232              :        ! * Loop on the shell of ig1 to speed up the search.
     233   2033871256 :        do ig2=ss,ee
     234   2296357632 :          if (ALL(ABS(grot(:)-gvec(:,ig2))==0)) then
     235     33219160 :            found=.TRUE.
     236     33219160 :            grottb  (ig1,itim,isym)=ig2
     237     33219160 :            grottbm1(ig2,itim,isym)=ig1
     238              :          end if
     239              :        end do
     240     34644409 :        if (.not.found) then
     241              :          write(msg,'(3a,i5,a,i5,1x,2(3i5,a),a,i3,a,i3)')&
     242            0 :           'G-shell not closed',ch10,&
     243            0 :           '  Initial G vector ',ig1,'/',npw,gbase(:),' Rotated G vector ',grot(:),ch10,&
     244            0 :           '  Through sym ',isym,' and itim ',itim
     245            0 :          ABI_ERROR(msg)
     246              :        end if
     247              :      end do
     248              :    end do
     249              : 
     250              :  end do !ig1
     251              : 
     252         1066 : end subroutine setup_G_rotation
     253              : !!***
     254              : 
     255              : !----------------------------------------------------------------------
     256              : 
     257              : !!****f* m_gsphere/gsph_init
     258              : !! NAME
     259              : !! gsph_init
     260              : !!
     261              : !! FUNCTION
     262              : !!  Main creation method for the Gvectors data type
     263              : !!
     264              : !! INPUTS
     265              : !!  Cryst<crystal_t> = Info on unit cell and its symmetries
     266              : !!  ng=number of G vectors, needed only if gvec is passed.
     267              : !!  [gvec(3,ng)]=coordinates of G vectors
     268              : !!  [ecut]=Cutoff energy for G-sphere. gvec and ecut are mutually exclusive.
     269              : !!
     270              : !! OUTPUT
     271              : !!  Gsph<gsphere_t>=Data type containing information related to the set of G vectors
     272              : !!   completely initialized in output.
     273              : !!
     274              : !! NOTES
     275              : !!  gvec are supposed to be ordered with increasing norm.
     276              : !!
     277              : !! SOURCE
     278              : 
     279         2026 : subroutine gsph_init(Gsph, Cryst, ng, gvec, ecut)
     280              : 
     281              : !Arguments ------------------------------------
     282              : !scalars
     283              :  class(gsphere_t),intent(out) :: Gsph
     284              :  integer,intent(in) :: ng
     285              :  real(dp),optional,intent(in) :: ecut
     286              :  type(crystal_t),target,intent(in) :: Cryst
     287              : 
     288              : !arrays
     289              :  integer,optional,intent(in) :: gvec(3,ng)
     290              : !Local variables-------------------------------
     291              : !scalars
     292              :  integer,parameter :: nkpt1=1
     293              :  integer :: ig,isearch,img,ish,isym,nsh,nsym,timrev,pinv,g1,g2,g3,ss,ee
     294              :  real(dp) :: eps,norm,norm_old,max_ecut,gsq
     295              : !arrays
     296              :  real(dp),parameter :: k_gamma(3)=(/zero,zero,zero/)
     297              :  integer :: sg(3),gsearch(3)
     298         1066 :  integer,allocatable :: shlim(:)
     299         1066 :  integer,pointer :: symrec(:,:,:),gvec_ptr(:,:)
     300              :  real(dp) :: kptns1(3,nkpt1)
     301         1066 :  real(dp),allocatable :: shlen(:)
     302         1066 :  real(dp),pointer :: tnons(:,:)
     303              : !************************************************************************
     304              : 
     305              :  DBG_ENTER("COLL")
     306              : 
     307              :  ! Copy info on symmetries
     308         1066 :  nsym   =  Cryst%nsym
     309         1066 :  timrev =  Cryst%timrev
     310         1066 :  symrec => Cryst%symrec
     311         1066 :  tnons  => Cryst%tnons
     312              : 
     313              :  ! Initialize the object
     314         1066 :  Gsph%istwfk = 1           ! Time reversal is not used here.
     315         1066 :  Gsph%nsym   = nsym
     316         1066 :  Gsph%timrev = timrev
     317              : 
     318        13858 :  Gsph%gmet   = Cryst%gmet
     319        13858 :  Gsph%gprimd = Cryst%gprimd
     320              : 
     321         1066 :  if (PRESENT(gvec)) then
     322          960 :    if (PRESENT(ecut)) then
     323            0 :      ABI_BUG("ecut cannot be present when gvec is used")
     324              :    end if
     325          960 :    Gsph%ng= ng
     326         2880 :    ABI_MALLOC(Gsph%gvec,(3,ng))
     327      1931848 :    Gsph%gvec=gvec
     328              :    !
     329              :    ! Calculate cutoff energy of the sphere.
     330              :    max_ecut=-one
     331       483442 :    do ig=1,ng
     332       482482 :      g1=gvec(1,ig)
     333       482482 :      g2=gvec(2,ig)
     334       482482 :      g3=gvec(3,ig)
     335              :      gsq=       Cryst%gmet(1,1)*g1**2+Cryst%gmet(2,2)*g2**2+Cryst%gmet(3,3)*g3**2+ &
     336       482482 :            two*(Cryst%gmet(1,2)*g1*g2+Cryst%gmet(1,3)*g1*g3+Cryst%gmet(2,3)*g2*g3)
     337       483442 :      max_ecut=MAX(max_ecut,gsq)
     338              :    end do
     339          960 :    max_ecut=two*max_ecut*pi**2
     340          960 :    Gsph%ecut= max_ecut
     341              : 
     342              :  else
     343              :    ! To be consistent with the previous implementation.
     344              :    !ABI_WARNING("Init from ecut has to be tested")
     345              :    !call setshells(ecut,npw,nsh,nsym,Cryst%gmet,Cryst%gprimd,Cryst%symrel,tag,Cryst%ucvol)
     346          106 :    Gsph%ecut = ecut
     347          106 :    pinv=+1; kptns1(:,1)=k_gamma
     348          106 :    call merge_and_sort_kg(nkpt1,kptns1,ecut,Cryst%nsym,pinv,Cryst%symrel,Cryst%gprimd,gvec_ptr,0)
     349          106 :    Gsph%ng = SIZE(gvec_ptr,DIM=2)
     350          318 :    ABI_MALLOC(Gsph%gvec, (3,Gsph%ng))
     351       932012 :    Gsph%gvec = gvec_ptr
     352          106 :    ABI_FREE(gvec_ptr)
     353              :  end if
     354              : 
     355              :  ! Calculate phase exp{-i2\pi G.\tau}
     356         4264 :  ABI_MALLOC(Gsph%phmGt, (Gsph%ng, nsym))
     357        43674 :  do isym=1,nsym
     358     16763342 :    do ig=1,Gsph%ng
     359     66921280 :     Gsph%phmGt(ig, isym) = EXP(-j_dpc*two_pi*DOT_PRODUCT(Gsph%gvec(:,ig), tnons(:,isym)))
     360              :    end do
     361              :  end do
     362              :  !
     363              :  ! === Calculate phase phsgt= exp{-i2\pi SG\cdot t} ===
     364              :  ! TODO Here we can store only one of this arrays but I have to rewrite screeening!
     365         3198 :  ABI_MALLOC(Gsph%phmSGt,(Gsph%ng,nsym))
     366       716498 :  do ig=1,Gsph%ng
     367     17436166 :    do isym=1,nsym
     368    518309708 :      sg=MATMUL(symrec(:,:,isym),Gsph%gvec(:,ig))
     369     67594104 :      Gsph%phmSGt(ig,isym)=EXP(-j_dpc*two_pi*DOT_PRODUCT(sg,tnons(:,isym)))
     370              :    end do
     371              :  end do
     372              :  !
     373              :  ! === Calculate number of shells and corresponding starting index ===
     374              :  ! * Shells are useful to speed up search algorithms see e.g setup_G_rotation.
     375              :  ! * The last shell ends at ng+1, thus gvec is supposed to be closed.
     376              : 
     377         4264 :  ABI_CHECK(ALL(Gsph%gvec(1:3,1)==0), 'First G must be 0')
     378              : 
     379         3198 :  ABI_MALLOC(Gsph%g2sh,(Gsph%ng))
     380         1066 :  Gsph%g2sh(1)=1 ! This table is useful if we dont loop over shell
     381              : 
     382              :  ! For each shell, gives the index of the initial G-vector.
     383         3198 :  ABI_MALLOC(shlim,(Gsph%ng+1))
     384         1066 :  shlim(1)=1
     385              : 
     386              :  ! For each shell, gives the radius of the shell.
     387         3198 :  ABI_MALLOC(shlen,(Gsph%ng))
     388         1066 :  shlen(1)=zero
     389              : 
     390         1066 :  nsh=1; norm_old=zero
     391       715432 :  do ig=2,Gsph%ng
     392     13572954 :    norm=two_pi*SQRT(DOT_PRODUCT(Gsph%gvec(:,ig),MATMUL(Cryst%gmet,Gsph%gvec(:,ig))))
     393       714366 :    eps=norm*tol8
     394       714366 :    if (ABS(norm-norm_old)>eps) then
     395        19085 :      norm_old = norm; nsh = nsh + 1
     396        19085 :      shlim(nsh)=ig
     397        19085 :      shlen(nsh)=norm
     398              :    end if
     399       715432 :    Gsph%g2sh(ig)=nsh
     400              :  end do
     401         1066 :  shlim(nsh+1)=Gsph%ng+1
     402              : 
     403              :  ! Save info on the shells
     404         1066 :  Gsph%nsh = nsh
     405         3198 :  ABI_MALLOC(Gsph%shlim, (nsh+1))
     406        23349 :  Gsph%shlim = shlim(1:nsh+1)
     407         3198 :  ABI_MALLOC(Gsph%shlen, (nsh  ))
     408        22283 :  Gsph%shlen = shlen(1:nsh)
     409         1066 :  ABI_FREE(shlim)
     410         1066 :  ABI_FREE(shlen)
     411              : 
     412              :  ! Calculate tables for rotated G"s
     413         5330 :  ABI_MALLOC(Gsph%rottb  , (Gsph%ng,timrev,nsym))
     414         4264 :  ABI_MALLOC(Gsph%rottbm1, (Gsph%ng,timrev,nsym))
     415              : 
     416              :  call setup_G_rotation(nsym, symrec, timrev, Gsph%ng, Gsph%gvec,&
     417         1066 :    Gsph%g2sh, Gsph%nsh, Gsph%shlim, Gsph%rottb, Gsph%rottbm1)
     418              : 
     419              :  ! Store Mapping G --> -G
     420              :  ! (we use a specialized table instead of rootb since rottb assumes time-reversal symmetry.
     421         3198 :  ABI_MALLOC(gsph%g2mg, (gsph%ng))
     422              : 
     423       716498 :  do ig=1,gsph%ng
     424       715432 :    ish=gsph%g2sh(ig)
     425       715432 :    ss=gsph%shlim(ish); ee=gsph%shlim(ish+1)-1
     426      2861728 :    gsearch = -gsph%gvec(:,ig)
     427     25258959 :    img = 0
     428              :    ! Loop on shells to speed up the search.
     429     25258959 :    do isearch=ss,ee
     430     29266560 :      if (all(gsph%gvec(:,isearch) == gsearch)) then
     431              :        img = isearch; exit
     432              :      end if
     433              :    end do
     434       715432 :    if (img==0) ABI_ERROR("Cannot find -G in G-sphere!")
     435       716498 :    gsph%g2mg(ig) = img
     436              :  end do
     437              : 
     438              :  !call Gsph%print(unit=std_out,prtvol=1)
     439              :  DBG_EXIT("COLL")
     440              : 
     441         2026 : end subroutine gsph_init
     442              : !!***
     443              : 
     444              : !----------------------------------------------------------------------
     445              : 
     446              : !!****f* m_gsphere/gsph_fft_tabs
     447              : !! NAME
     448              : !! gsph_fft_tabs
     449              : !!
     450              : !! FUNCTION
     451              : !!
     452              : !! INPUTS
     453              : !!  Gsph<gsphere_t>=Info on the G-sphere
     454              : !!  g0(3)
     455              : !!  mgfft=MAXVAL(ngfft(1:3))
     456              : !!  ngfftf(18)=Info on the FFT mesh.
     457              : !!
     458              : !! OUTPUT
     459              : !!  use_padfft=1 if padded FFT can be used, 0 otherwise.
     460              : !!  gmg0_gbound(2*mgfft+8,2)=Tables for improved zero-padded FFTS. Calculated only if use_padfft==1
     461              : !!  gmg0_ifft(Gsph%ng)=Index of G-G0 in the FFT mesh defined by ngfft.
     462              : !!
     463              : !! NOTES
     464              : !!  The routine will stop if any G-G0 happens to be outside the FFT box.
     465              : !!
     466              : !! SOURCE
     467              : 
     468       104432 : subroutine gsph_fft_tabs(Gsph, g0, mgfft, ngfft, use_padfft, gmg0_gbound, gmg0_ifft)
     469              : 
     470              : !Arguments ------------------------------------
     471              : !scalars
     472              :  class(gsphere_t),intent(in) :: Gsph
     473              :  integer,intent(in) :: mgfft
     474              :  integer,intent(out) :: use_padfft
     475              : !arrays
     476              :  integer,intent(in) :: g0(3),ngfft(18)
     477              :  integer,intent(out) :: gmg0_gbound(2*mgfft+8,2),gmg0_ifft(Gsph%ng)
     478              : 
     479              : !Local variables-------------------------------
     480              : !scalars
     481              :  integer :: ig,ng,ierr
     482              :  character(len=500) :: msg
     483       104432 :  type(MPI_type) :: MPI_enreg_seq
     484              : !arrays
     485       104432 :  integer,allocatable :: gmg0(:,:)
     486       104432 :  logical,allocatable :: kg_mask(:)
     487              : ! *************************************************************************
     488              : 
     489       417728 :  if (mgfft/=MAXVAL(ngfft(1:3))) then
     490            0 :    ABI_ERROR("mgfft/-MAXVAL(ngfft(1:3)")
     491              :  end if
     492              : 
     493       104432 :  ng = Gsph%ng
     494              : 
     495       104432 :  ierr=0; use_padfft=0
     496       313296 :  ABI_MALLOC(gmg0,(3,ng))
     497      6084642 :  do ig=1,ng
     498     23920840 :    gmg0(:,ig) = Gsph%gvec(:,ig)-g0
     499              :    ! Consider possible wrap around errors.
     500     47841680 :    if ( ANY(gmg0(:,ig)>ngfft(1:3)/2) .or. ANY(gmg0(:,ig)<-(ngfft(1:3)-1)/2) ) then
     501              :      !gmg0_ifft(ig,ig01+mg0(1)+1,ig02+mg0(2)+1,ig03+mg0(3)+1) = 0
     502            0 :      write(std_out,*)" outside FFT box ",gmg0(:,ig)
     503            0 :      ierr=ierr+1
     504              :    end if
     505      8066604 :    if (ALL(gmg0(:,ig) == 0)) use_padfft=1
     506              :  end do
     507              : 
     508       104432 :  if (ierr/=0) then
     509            0 :    write(msg,'(a,i0,a)')'Found ',ierr,' G-G0 vectors falling outside the FFT box. This is not allowed '
     510            0 :    ABI_ERROR(msg)
     511              :  end if
     512              :  !
     513              :  ! Evaluate the tables needed for the padded FFT performed in rhotwg. Note that we have
     514              :  ! to pass G-G0 to sphereboundary instead of G as we need FFT results on the shifted G-sphere,
     515              :  ! If Gamma is not inside G-G0 one has to disable FFT padding as sphereboundary will give wrong tables.
     516       104432 :  if (use_padfft == 1) call sphereboundary(gmg0_gbound,1,gmg0,mgfft,ng)
     517              : 
     518       104432 :  call initmpi_seq(MPI_enreg_seq) ! No FFT parallelism.
     519       104432 :  call MPI_enreg_seq%distribfft%init_seq('c',ngfft(2),ngfft(3),'all')
     520              : 
     521       313296 :  ABI_MALLOC(kg_mask, (ng))
     522       104432 :  call kgindex(gmg0_ifft, gmg0, kg_mask, MPI_enreg_seq, ngfft, ng)
     523              : 
     524      6084642 :  ABI_CHECK(ALL(kg_mask),"FFT para not yet implemented")
     525       104432 :  ABI_FREE(kg_mask)
     526              : 
     527       104432 :  ABI_FREE(gmg0)
     528       104432 :  call destroy_mpi_enreg(MPI_enreg_seq)
     529              : 
     530       104432 : end subroutine gsph_fft_tabs
     531              : !!***
     532              : 
     533              : !----------------------------------------------------------------------
     534              : 
     535              : !!****f* m_gsphere/gsph_in_fftbox
     536              : !! NAME
     537              : !! gsph_in_fftbox
     538              : !!
     539              : !! FUNCTION
     540              : !!  Initialize the largest Gsphere contained in the FFT box.
     541              : !!
     542              : !! INPUTS
     543              : !!  Cryst<crystal_t> = Info on unit cell and its symmetries.
     544              : !!  ngfft(18)=Info on the FFT box.
     545              : !!
     546              : !! OUTPUT
     547              : !!  Gsph<gsphere_t>=Data type containing information related to the set of G vectors
     548              : !!   completely initialized in output.
     549              : !!
     550              : !! SOURCE
     551              : 
     552           39 : subroutine gsph_in_fftbox(Gsph, Cryst, ngfft)
     553              : 
     554              : !Arguments ------------------------------------
     555              : !scalars
     556              :  class(gsphere_t),intent(out) :: Gsph
     557              :  type(crystal_t),intent(in) :: Cryst
     558              : !arrays
     559              :  integer,intent(in) :: ngfft(18)
     560              : 
     561              : !Local variables-------------------------------
     562              : !scalars
     563              :  integer :: dir1,dir2,dir3,npw,ig,i_st
     564              :  real(dp) :: ecut,trial_ene
     565              : !arrays
     566              :  integer :: n1_max(3),n2_max(3),n3_max(3),vec(3)
     567           39 :  integer,allocatable :: gvec(:,:)
     568              : !************************************************************************
     569              : 
     570              :  ! Find ecut for the largest G-sphere contained in the FFT box.
     571           39 :  n1_max(1) = -(ngfft(1)-1)/2
     572           39 :  n2_max(1) = -(ngfft(2)-1)/2
     573           39 :  n3_max(1) = -(ngfft(3)-1)/2
     574              : 
     575           39 :  n1_max(2) = 0
     576           39 :  n2_max(2) = 0
     577           39 :  n3_max(2) = 0
     578              : 
     579           39 :  n1_max(3) = ngfft(1)/2
     580           39 :  n2_max(3) = ngfft(2)/2
     581           39 :  n3_max(3) = ngfft(3)/2
     582              : 
     583           39 :  ecut = HUGE(one)
     584          156 :  do dir3=1,3
     585          117 :    vec(3) = n1_max(dir3)
     586          507 :    do dir2=1,3
     587          351 :      vec(2) = n2_max(dir2)
     588         1521 :      do dir1=1,3
     589         1053 :        vec(1) = n1_max(dir1)
     590         1911 :        if (ANY(vec/=0)) then
     591         1014 :          trial_ene = half * normv(vec,Cryst%gmet,"G")**2
     592         1014 :          ecut = MIN(ecut,trial_ene)
     593              :          !write(std_out,*)vec(:),trial_ene
     594              :        end if
     595              :      end do
     596              :    end do
     597              :  end do
     598              :  !
     599              :  ! Init sphere from ecut.
     600           39 :  call Gsph%init(Cryst, 0, ecut=ecut)
     601              :  !
     602              :  ! Make sure that Gsph does not contain G vectors outside the FFT box.
     603              :  ! kpgsph might return G whose energy is larger than the input ecut.
     604           39 :  npw = Gsph%ng
     605         3013 :  star_loop: do i_st=1,Gsph%nsh-1
     606       159018 :    do ig=Gsph%shlim(i_st),Gsph%shlim(i_st+1)
     607      1251266 :      if ( ANY(Gsph%gvec(:,ig)>ngfft(1:3)/2) .or. ANY(Gsph%gvec(:,ig)<-(ngfft(1:3)-1)/2) ) then
     608           36 :        npw = Gsph%shlim(i_st)-1  ! Gsph exceeds the FFT box. Only the shells up to npw will be used.
     609           36 :        EXIT star_loop
     610              :      end if
     611              :    end do
     612              :  end do star_loop
     613              : 
     614           39 :  if (npw<Gsph%ng) then
     615           36 :    ABI_COMMENT("Have to reinit Gpshere")
     616          108 :    ABI_MALLOC(gvec,(3,npw))
     617       610328 :    gvec = Gsph%gvec(:,1:npw)
     618           36 :    call Gsph%free()
     619           36 :    call Gsph%init(Cryst, npw, gvec=gvec)
     620           36 :    ABI_FREE(gvec)
     621              :  end if
     622              : 
     623           39 : end subroutine gsph_in_fftbox
     624              : !!***
     625              : 
     626              : !----------------------------------------------------------------------
     627              : 
     628              : !!****f* m_gsphere/gsph_print
     629              : !! NAME
     630              : !! gsph_print
     631              : !!
     632              : !! FUNCTION
     633              : !!  Print info on object.
     634              : !!
     635              : !! INPUTS
     636              : !!  unit=the unit number for output
     637              : !!  prtvol = verbosity level
     638              : !!
     639              : !! SOURCE
     640              : 
     641          144 : subroutine gsph_print(Gsph, units, prtvol, header)
     642              : 
     643              : !Arguments ------------------------------------
     644              : !scalars
     645              :  class(gsphere_t),intent(in) :: Gsph
     646              :  integer,intent(in) :: units(:), prtvol
     647              :  character(len=*),optional,intent(in) :: header
     648              : 
     649              : !Local variables-------------------------------
     650              : !scalars
     651              :  integer :: ish, nsc
     652              :  real(dp) :: fact, kin
     653              :  character(len=500) :: msg
     654              : ! *************************************************************************
     655              : 
     656           72 :  msg = ch10 // ' ==== Info on the G-sphere ==== ' // ch10
     657           72 :  if (present(header)) msg = ' ==== '//trim(adjustl(header))//' ==== '
     658           72 :  call wrtout(units, msg)
     659              : 
     660              :  write(msg,'(2(a,i8,a))')&
     661           72 :    '  Number of G vectors ... ',Gsph%ng,ch10,&
     662          144 :    '  Number of shells ...... ',Gsph%nsh,ch10
     663           72 :  call wrtout(units, msg)
     664              : 
     665           80 :  select case (Gsph%timrev)
     666              :  case (1)
     667            8 :    call wrtout(units, ' Time reversal symmetry cannot be used')
     668              :  case (2)
     669           64 :    call wrtout(units, ' Time reversal symmetry is used')
     670              :  case default
     671           72 :    ABI_BUG("Wrong timrev")
     672              :  end select
     673              : 
     674           72 :  if (prtvol /= 0) then
     675            2 :    fact = half*two_pi**2
     676            2 :    write(msg,'(a)')
     677            2 :    call wrtout(units, ' Shell   Tot no. of Gs   Cutoff [Ha]')
     678           88 :    do ish=1,Gsph%nsh
     679           86 :      nsc=Gsph%shlim(ish+1)-1
     680           86 :      kin=half*Gsph%shlen(ish)**2
     681           86 :      write(msg, '(2x,i4,10x,i6,5x,f8.3)')ish,nsc,kin
     682           88 :      call wrtout(units, msg)
     683              :    end do
     684            2 :    call wrtout(units, ch10)
     685              :  end if
     686              : 
     687           72 : end subroutine gsph_print
     688              : !!***
     689              : 
     690              : !----------------------------------------------------------------------
     691              : 
     692              : !!****f* m_gsphere/gsph_free
     693              : !! NAME
     694              : !! gsph_free
     695              : !!
     696              : !! FUNCTION
     697              : !!  Deallocate the memory in a gsphere_t data type.
     698              : !!
     699              : !! SOURCE
     700              : 
     701         1949 : subroutine gsph_free(Gsph)
     702              : 
     703              : !Arguments ------------------------------------
     704              :  class(gsphere_t),intent(inout) :: Gsph
     705              : ! *************************************************************************
     706              : 
     707              :  DBG_ENTER("COLL")
     708              : 
     709              :  !@gsphere_t
     710              : 
     711              : ! integer arrays.
     712         1949 :  ABI_SFREE(Gsph%g2sh)
     713         1949 :  ABI_SFREE(Gsph%gvec)
     714         1949 :  ABI_SFREE(Gsph%g2mg)
     715         1949 :  ABI_SFREE(Gsph%rottb)
     716         1949 :  ABI_SFREE(Gsph%rottbm1)
     717         1949 :  ABI_SFREE(Gsph%shlim)
     718              : 
     719         1949 :  ABI_SFREE(Gsph%shlen)
     720              : 
     721              : ! complex arrays
     722         1949 :  ABI_SFREE(Gsph%phmGt)
     723         1949 :  ABI_SFREE(Gsph%phmSGt)
     724              : 
     725              :  DBG_EXIT("COLL")
     726              : 
     727         1949 : end subroutine gsph_free
     728              : !!***
     729              : 
     730              : !----------------------------------------------------------------------
     731              : 
     732              : !!****f* m_gsphere/gsph_g_idx
     733              : !! NAME
     734              : !! gsph_g_idx
     735              : !!
     736              : !! FUNCTION
     737              : !! Return the index of G in the sphere. zero if not in the sphere
     738              : !!
     739              : !! INPUTS
     740              : !!  Gsph<gsphere_t>=Info on the G-sphere
     741              : !!  gg(3)=Reduced coordinates of the G-vector.
     742              : !!
     743              : !! NOTES
     744              : !!  The function assumes that the G-vectors are ordered with increasing length.
     745              : !!
     746              : !! SOURCE
     747              : 
     748            0 : pure function gsph_g_idx(Gsph, gg) result(g_idx)
     749              : 
     750              : !Arguments ------------------------------------
     751              : !scalars
     752              :  class(gsphere_t),intent(in) :: Gsph
     753              :  integer :: g_idx
     754              : !arrays
     755              :  integer,intent(in) :: gg(3)
     756              : 
     757              : !Local variables-------------------------------
     758              : !scalars
     759              :  integer :: ishbsc,igs,ige
     760              :  real(dp) :: glen
     761              :  logical :: found
     762              : ! *************************************************************************
     763              : 
     764              :  ! Use shells and bisection to find the star and stop index thus avoiding the storage of a table (ig1,ig2)
     765            0 :  glen = two_pi*SQRT(DOT_PRODUCT(gg,MATMUL(Gsph%gmet,gg)))
     766              : 
     767            0 :  ishbsc = bisect(Gsph%shlen,glen)
     768            0 :  if ( ANY(ishbsc==(/0,Gsph%nsh/)) ) then ! glen out of range.
     769            0 :    g_idx=0; RETURN
     770              :  end if
     771              : 
     772            0 :  igs = Gsph%shlim(ishbsc)
     773            0 :  ige = Gsph%shlim(MIN(ishbsc+2,Gsph%nsh+1))-1
     774              : 
     775            0 :  g_idx=igs-1; found=.FALSE.
     776            0 :  do while (.not.found .and. g_idx<ige)
     777            0 :    g_idx=g_idx+1
     778            0 :    found=(ALL(Gsph%gvec(:,g_idx)==gg(:)))
     779              :  end do
     780            0 :  if (.not.found) g_idx=0
     781              : 
     782            0 : end function gsph_g_idx
     783              : !!***
     784              : 
     785              : !----------------------------------------------------------------------
     786              : 
     787              : !!****f* m_gsphere/gsph_gmg_idx
     788              : !! NAME
     789              : !! gsph_gmg_idx
     790              : !!
     791              : !! FUNCTION
     792              : !! Return the index of G1-G2 in the sphere. zero if not in the sphere
     793              : !!
     794              : !! INPUTS
     795              : !!  Gsph<gsphere_t>=Info on the G-sphere
     796              : !!  ig1,ig2 index of g1 and g2 in the G-sphere.
     797              : !!
     798              : !! NOTES
     799              : !!  The function assumes that the G-vectors are ordered with increasing length.
     800              : !!
     801              : !! SOURCE
     802              : 
     803      6422840 : pure function gsph_gmg_idx(Gsph, ig1, ig2) result(ig1mg2)
     804              : 
     805              : !Arguments ------------------------------------
     806              : !scalars
     807              :  class(gsphere_t),intent(in) :: Gsph
     808              :  integer,intent(in) :: ig1,ig2
     809              :  integer :: ig1mg2
     810              : 
     811              : !Local variables-------------------------------
     812              : !scalars
     813              :  integer :: ishbsc,igs,ige
     814              :  real(dp) :: difflen
     815              :  logical :: found
     816              : !arrays
     817              :  integer :: g1mg2(3)
     818              : ! *************************************************************************
     819              : 
     820     25691360 :  g1mg2 = Gsph%gvec(:,ig1)-Gsph%gvec(:,ig2)
     821              : 
     822              :  ! Use shells and bisect to find the star and stop index thus avoiding the storage of a table (ig1,ig2)
     823    122033960 :  difflen = two_pi*SQRT(DOT_PRODUCT(g1mg2,MATMUL(Gsph%gmet,g1mg2)))
     824              : 
     825              :  ! FIXME It seems bisect is not portable, on my laptop test v5/t72 the number of skipped G-vectors is > 0
     826      6422840 :  ishbsc = bisect(Gsph%shlen,difflen)
     827      6422840 :  if ( ANY(ishbsc==(/0,Gsph%nsh/)) ) then ! difflen out of range.
     828            0 :    ig1mg2=0; RETURN
     829              :  end if
     830              : 
     831      6422840 :  igs = Gsph%shlim(ishbsc)
     832      6422840 :  ige = Gsph%shlim(MIN(ishbsc+2,Gsph%nsh+1))-1
     833              : 
     834      6422840 :  ig1mg2=igs-1; found=.FALSE.
     835     78583046 :  do while (.not.found .and. ig1mg2<ige)
     836     72160206 :    ig1mg2=ig1mg2+1
     837    108457970 :    found=(ALL(Gsph%gvec(:,ig1mg2)==g1mg2(:)))
     838              :  end do
     839      6422840 :  if (.not.found) ig1mg2=0
     840              : 
     841      6422840 : end function gsph_gmg_idx
     842              : !!***
     843              : 
     844              : !----------------------------------------------------------------------
     845              : 
     846              : !!****f* m_gsphere/gsph_gmg_fftidx
     847              : !! NAME
     848              : !! gsph_gmg_fftidx
     849              : !!
     850              : !! FUNCTION
     851              : !! Return the index of G1-G2 in the FFT mesh defined by ngfft. zero if not found.
     852              : !!
     853              : !! INPUTS
     854              : !!  Gsph<gsphere_t>=Info on the G-sphere
     855              : !!  ig1,ig2 index of g1 and g2 in the G-sphere.
     856              : !!  ngfft(18)=Info on the FFT mesh.
     857              : !!
     858              : !! SOURCE
     859              : 
     860      3586176 : pure function gsph_gmg_fftidx(Gsph, ig1, ig2, ngfft) result(fft_idx)
     861              : 
     862              : !Arguments ------------------------------------
     863              : !scalars
     864              :  class(gsphere_t),intent(in) :: Gsph
     865              :  integer,intent(in) :: ig1,ig2
     866              :  integer :: fft_idx
     867              : !arrays
     868              :  integer,intent(in) :: ngfft(18)
     869              : 
     870              : !Local variables-------------------------------
     871              : !scalars
     872              :  integer :: id1,id2,id3
     873              : !arrays
     874              :  integer :: g1mg2(3)
     875              : ! *************************************************************************
     876              : 
     877     14344704 :  g1mg2(:)=Gsph%gvec(:,ig1)-Gsph%gvec(:,ig2)
     878              : 
     879              :  ! Make sure G1-G2 is still in the FFT mesh.
     880              :  ! MODULO wraps G1-G2 in the FFT box but the Fourier components are not periodic!
     881     28689408 :  if (ANY(g1mg2(:)>ngfft(1:3)/2) .or. ANY(g1mg2(:)<-(ngfft(1:3)-1)/2)) then
     882      3586176 :    fft_idx=0; RETURN
     883              :  end if
     884              : 
     885      3586176 :  id1=MODULO(g1mg2(1),ngfft(1))
     886      3586176 :  id2=MODULO(g1mg2(2),ngfft(2))
     887      3586176 :  id3=MODULO(g1mg2(3),ngfft(3))
     888      3586176 :  fft_idx= 1 + id1 + id2*ngfft(1) + id3*ngfft(1)*ngfft(2)
     889              : 
     890      3586176 : end function gsph_gmg_fftidx
     891              : !!***
     892              : 
     893              : !----------------------------------------------------------------------
     894              : 
     895              : !!****f* m_gsphere/merge_and_sort_kg
     896              : !! NAME
     897              : !!  merge_and_sort_kg
     898              : !!
     899              : !! FUNCTION
     900              : !!  This routine merges a set of k-centered G-spheres of cutoff energy ecut and
     901              : !!  returns a Gamma-centered G-spheres. The elements in the final G-spheres are packed with increasing module.
     902              : !!
     903              : !! INPUTS
     904              : !!  nkpt=Number of k-points
     905              : !!  kptns(3,nkpt)=The k-points in reduced coordinates defining the k-centered G-spheres.
     906              : !!  ecut=Cutoff energy for the k-centered G-spheres.
     907              : !!  nsym2=Number of symmetry operations.
     908              : !!  pinv=-1 if time-reversal can be used, 1 otherwise
     909              : !!  symrel2(3,3,nsym2)=symmetry operations in real space.
     910              : !!  gprimd(3,3)=dimensional primitive translations for reciprocal space ($\textrm{bohr}^{-1}$)
     911              : !!  prtvol=Flag defining the verbosity level.
     912              : !!
     913              : !! SIDE EFFECTS
     914              : !!  gbig(:,:)
     915              : !!    in input : pointer to NULL
     916              : !!    in output: gbig(3,1:npw) contains the set of G-vectors ordered by shell obtained by
     917              : !!               merging the k-centered sphere.
     918              : !!  shlim_p(:)
     919              : !!    in input : pointer to NULL
     920              : !!    in output: shlim_p(nbase)=Cumulative number of G-vectors for each shell.
     921              : !!               where nbase is the number of irreducible G"s found.
     922              : !!
     923              : !! SOURCE
     924              : 
     925          469 : subroutine merge_and_sort_kg(nkpt,kptns,ecut,nsym2,pinv,symrel2,gprimd,gbig,prtvol,shlim_p)
     926              : 
     927              : !Arguments ------------------------------------
     928              : !scalars
     929              :  integer,intent(in) :: nkpt,nsym2,pinv,prtvol
     930              :  real(dp),intent(in) :: ecut
     931              : !arrays
     932              :  integer,intent(in) :: symrel2(3,3,nsym2)
     933              :  real(dp),intent(in) :: kptns(3,nkpt),gprimd(3,3)
     934              :  integer,pointer :: gbig(:,:)
     935              :  integer,optional,pointer :: shlim_p(:)
     936              : 
     937              : !Local variables-------------------------------
     938              : !scalars
     939              :  integer,parameter :: mkmem_=1
     940              :  integer :: ikg,ig,ikpt,nbase,sizepw,in,maxpw,is,iinv,ish,ilim,mpw
     941              :  integer :: exchn2n3d,istwf_k,onpw_k,ierr,npw_k,ii,isym,sizeold
     942              :  logical :: found
     943              :  character(len=500) :: msg
     944          469 :  type(MPI_type) :: MPI_enreg_seq
     945              : !arrays
     946          938 :  integer :: gcur(3),geq(3),dum_kg(3,0),symrec2t(3,3,nsym2)
     947          469 :  integer,allocatable :: gbase(:,:),gbasek(:,:,:)
     948          469 :  integer,allocatable :: gcurr(:,:),gshell(:,:),insort(:),gtmp(:,:)
     949          469 :  integer,allocatable :: nbasek(:),nshell(:),shlim(:), npwarr(:)
     950              :  real(dp) :: kpoint(3),gmet(3,3)
     951          469 :  real(dp),allocatable :: cnorm(:),cnormk(:,:),ctmp(:)
     952              : ! *********************************************************************
     953              : 
     954              :  ! Fake MPI_type for the sequential part.
     955              :  ! This routine should not be parallelized as communicating gbig and other
     956              :  ! tables takes more time than recalculating them in sequential.
     957          469 :  call initmpi_seq(MPI_enreg_seq)
     958              : 
     959              : !Compute reciprocal space metrics
     960         1876 :  do ii=1,3
     961              :    gmet(ii,:)=gprimd(1,ii)*gprimd(1,:)+&
     962              : &   gprimd(2,ii)*gprimd(2,:)+&
     963         6097 : &   gprimd(3,ii)*gprimd(3,:)
     964              :  end do
     965              : 
     966              :  ! * Here we use TRANSPOSE(symrel2) instead of the more intuitive symrel2^{-1t} for historical reasons
     967              :  ! It does not affect the results since in the code below we only check the module of G
     968        19207 :  do isym=1,nsym2
     969       244063 :    symrec2t(:,:,isym)=TRANSPOSE(symrel2(:,:,isym))
     970              :  end do
     971              :  !
     972              :  ! ==============================================
     973              :  ! ==== Find irreducible G-vectors at each k ====
     974              :  ! ==============================================
     975              : 
     976         1407 :  ABI_MALLOC(npwarr,(nkpt))
     977          469 :  exchn2n3d=0; ikg=0
     978         2722 :  do ikpt=1,nkpt
     979         9012 :    kpoint=kptns(:,ikpt); istwf_k=1
     980         2722 :    call kpgsph(ecut,exchn2n3d,gmet,ikg,0,istwf_k,dum_kg,kpoint,0,MPI_enreg_seq,0,npwarr(ikpt))
     981              :  end do
     982         2722 :  mpw = MAXVAL(npwarr)
     983              : 
     984          938 :  ABI_MALLOC(nbasek,(nkpt))
     985         1876 :  ABI_MALLOC(gbasek,(3,mpw,nkpt))
     986         1876 :  ABI_MALLOC(cnormk,(mpw,nkpt))
     987         2722 :  nbasek=0     ! # of irreducible G at each k.
     988       904022 :  cnormk=zero  ! Norm of each irreducible G.
     989      3607922 :  gbasek=0     ! The set of irreducible G"s at each k.
     990              : 
     991         2722 :  do ikpt=1,nkpt
     992              : 
     993         9012 :    kpoint = kptns(:,ikpt)
     994         2253 :    npw_k  = npwarr(ikpt)
     995              : 
     996         2253 :    exchn2n3d=0; ikg=0; istwf_k=1
     997         6759 :    ABI_MALLOC(gcurr,(3,npw_k))
     998         2253 :    call kpgsph(ecut,exchn2n3d,gmet,ikg,0,istwf_k,gcurr,kpoint,mkmem_,MPI_enreg_seq,npw_k,onpw_k)
     999              : 
    1000         9012 :    if (ANY(gcurr(:,1)/=0)) then
    1001            0 :      ABI_BUG("gcurr(:,1)/=0")
    1002              :    end if
    1003              :    !
    1004              :    ! * Search for the G"s generating the others by symmetry.
    1005              :    !  NB: Here we use symrec2t=TRANSPOSE(symrel2) for historical reasons, see note above
    1006         2253 :    call get_irredg(npw_k,nsym2,pinv,gprimd,symrec2t,gcurr,nbasek(ikpt),gbasek(:,:,ikpt),cnormk(:,ikpt))
    1007              : 
    1008         2722 :    ABI_FREE(gcurr)
    1009              :  end do
    1010              :  !
    1011              :  ! === Reduce info over k-points ===
    1012              :  ! * Here symrec2t=TRANSPOSE(symrel2) for historical reasons, see note above
    1013          469 :  sizepw=2*mpw
    1014         1407 :  ABI_MALLOC(gbase,(3,sizepw))
    1015         1407 :  ABI_MALLOC(cnorm,(sizepw))
    1016              :  nbase=0                    ! # of irred G found.
    1017              : 
    1018          469 :  call merge_kgirr(nsym2,pinv,nkpt,mpw,sizepw,symrec2t,nbasek,cnormk,gbasek,nbase,gbase,cnorm,ierr)
    1019          469 :  if (ierr/=0) then
    1020            0 :    ABI_ERROR('merge_kgirr returned a non-zero status error')
    1021              :  end if
    1022              : 
    1023          469 :  ABI_FREE(nbasek)
    1024          469 :  ABI_FREE(cnormk)
    1025          469 :  ABI_FREE(gbasek)
    1026              :  !
    1027              :  !=== Reorder base G-vectors in order of increasing module ===
    1028              :  !
    1029              :  !Generate all shells of G-vectors: star of a g==set of all symmetrics of this g
    1030         1407 :  ABI_MALLOC(gshell,(3,2*nsym2))
    1031         1407 :  ABI_MALLOC(shlim,(nbase))
    1032              : 
    1033          938 :  ABI_MALLOC(gbig,(3,sizepw))
    1034              : !
    1035              : !TODO
    1036              : #if 0
    1037              : !* Here symrec2t=TRANSPOSE(symrel2) for historical reasons, see note above
    1038              :  call getfullg(nbase,nsym2,pinv,sizepw,gbase,symrec2t,cnorm,maxpw,gbig,shlim,ierr)
    1039              :  if (ierr/0) RETURN
    1040              : 
    1041              : #else
    1042          938 :  ABI_MALLOC(insort,(nbase))
    1043          938 :  ABI_MALLOC(nshell,(nbase))
    1044        37400 :  do in=1,nbase
    1045        37400 :    insort(in)=in
    1046              :  end do
    1047          469 :  call sort_dp(nbase,cnorm,insort,tol14)
    1048              : !
    1049              : !Loop over all different modules of g''s (=shells):
    1050          469 :  maxpw=0
    1051        37400 :  do in=1,nbase
    1052        36931 :    nshell(in)=0
    1053       147724 :    gcur(:)=gbase(:,insort(in))
    1054              : 
    1055       853453 :    do is=1,nsym2 !  Loop over all symmetries:
    1056      1669975 :      do iinv=pinv,1,2
    1057      3266088 :        geq(:)=iinv*(symrel2(1,:,is)*gcur(1)+symrel2(2,:,is)*gcur(2)+symrel2(3,:,is)*gcur(3))
    1058              : 
    1059              :        found=.FALSE.; ish=1
    1060      7050483 :        do while ((.not.found) .and. (ish<=nshell(in))) ! Search for symmetric of g and eventually add it:
    1061      8227704 :          found=ALL(geq(:)==gshell(:,ish))
    1062      6730442 :          ish=ish+1
    1063              :        end do
    1064      1633044 :        if (.not.found) then
    1065       496481 :          nshell(in)=nshell(in)+1
    1066      1985924 :          gshell(:,nshell(in))=geq(:)
    1067              :        end if
    1068              :      end do
    1069              :    end do
    1070              : 
    1071        36931 :    if ((maxpw+nshell(in)) > sizepw) then
    1072              :      ! We need to increase the size of the gbase, gbig and cnorm arrays while still keeping their content.
    1073              :      ! This is done using two temporary arrays gtmp and ctmp
    1074            0 :      ABI_WARNING("Had to reallocate gbase, gbig, cnorm. Perhaps geometry too inaccurate. Possible fix: correct your input file.")
    1075            0 :      ABI_MALLOC(ctmp,(sizepw))
    1076            0 :      ABI_MALLOC(gtmp,(3,sizepw))
    1077            0 :      sizeold=sizepw
    1078            0 :      sizepw=maxpw+nshell(in)
    1079              : 
    1080            0 :      ctmp(:)=cnorm(:)
    1081            0 :      gtmp(:,:)=gbase(:,:)
    1082              : 
    1083            0 :      ABI_FREE(cnorm)
    1084            0 :      ABI_MALLOC(cnorm,(sizepw))
    1085            0 :      cnorm(1:sizeold)=ctmp(1:sizeold)
    1086            0 :      cnorm(sizeold+1:sizepw)=zero
    1087            0 :      ABI_FREE(ctmp)
    1088              : 
    1089              : !    MG why this? gbase should not be changed!
    1090            0 :      ABI_FREE(gbase)
    1091            0 :      ABI_MALLOC(gbase,(3,sizepw))
    1092            0 :      gbase(:,:sizeold)=gtmp(:,:sizeold)
    1093            0 :      gbase(:,sizeold+1:sizepw)=0
    1094            0 :      gtmp(:,:)=gbig(:,:)
    1095              : 
    1096            0 :      ABI_FREE(gbig)
    1097            0 :      ABI_MALLOC(gbig,(3,sizepw))
    1098            0 :      gbig(:,:sizeold)=gtmp(:,:sizeold)
    1099            0 :      gbig(:,sizeold+1:sizepw)=0
    1100            0 :      ABI_FREE(gtmp)
    1101              :    end if
    1102              :    !
    1103              :    ! Store this shell of g''s in a big array of g (gbig):
    1104       533412 :    do ig=1,nshell(in)
    1105      2022855 :      gbig(:,ig+maxpw)=gshell(:,ig)
    1106              :    end do
    1107        37400 :    maxpw=maxpw+nshell(in)
    1108              : 
    1109              :  end do ! End loop over shells
    1110              :  !
    1111              :  ! * Compute shell limits
    1112          469 :  ilim=0
    1113        37400 :  do in=1,nbase
    1114        36931 :    ilim=ilim+nshell(in)
    1115        37400 :    shlim(in)=ilim
    1116              :  end do
    1117              : 
    1118          469 :  if (PRESENT(shlim_p)) then ! Return shlim_p
    1119          726 :   ABI_MALLOC(shlim_p,(nbase))
    1120        20880 :   shlim_p = shlim
    1121              :  end if
    1122              : 
    1123              :  ! Re-allocate gbig with correct sizes so that caller can inquire the size
    1124         1407 :  ABI_MALLOC(gtmp,(3,ilim))
    1125      1986862 :  gtmp = gbig(:,1:ilim)
    1126          469 :  ABI_FREE(gbig)
    1127          938 :  ABI_MALLOC(gbig,(3,ilim))
    1128      1986393 :  gbig=gtmp
    1129          469 :  ABI_FREE(gtmp)
    1130              : 
    1131          469 :  if (prtvol>10) then ! Print out shell limits
    1132              :    write(msg,'(3a)')&
    1133            0 : &    ' Shells found:',ch10,&
    1134            0 : &    ' number of shell    number of G vectors      cut-off energy [Ha} '
    1135            0 :    call wrtout(std_out,msg)
    1136            0 :    do in=1,nbase
    1137            0 :      write(msg,'(12x,i4,17x,i6,12x,f8.3)')in,shlim(in),2*pi**2*cnorm(in)
    1138            0 :      call wrtout(std_out,msg)
    1139              :    end do
    1140            0 :    call wrtout(std_out,ch10)
    1141              :  end if
    1142              : 
    1143          469 :  ABI_FREE(gshell)
    1144          469 :  ABI_FREE(insort)
    1145          469 :  ABI_FREE(nshell)
    1146              : #endif
    1147              : 
    1148          469 :  call destroy_mpi_enreg(MPI_enreg_seq)
    1149          469 :  ABI_FREE(gbase)
    1150          469 :  ABI_FREE(shlim)
    1151          469 :  ABI_FREE(cnorm)
    1152          469 :  ABI_FREE(npwarr)
    1153              : 
    1154          938 : end subroutine merge_and_sort_kg
    1155              : !!***
    1156              : 
    1157              : !----------------------------------------------------------------------
    1158              : 
    1159              : !!****f* m_gsphere/getfullg
    1160              : !! NAME
    1161              : !! getfullg
    1162              : !!
    1163              : !! FUNCTION
    1164              : !!  Reconstruct a G-sphere starting from a set of irreducible lattice vectors
    1165              : !!
    1166              : !! INPUTS
    1167              : !!  pinv=-1 if time-reversal can be used, 1 otherwise
    1168              : !!  nsym=number of symmetry operations
    1169              : !!  sizepw=Max expected number of G vectors in the shere
    1170              : !!  symrec(3,3,nsym)=symmetry operation in reciprocal space
    1171              : !!  nbase=number of irreducible G vectors
    1172              : !!  gbase(3,nbase)=irreducible G-vectors
    1173              : !!  cnorm(nbase)=norm of the irreducible G vectors (supposed not yet sorted)
    1174              : !!
    1175              : !! OUTPUT
    1176              : !!  maxpw=Number of G vectors found
    1177              : !!  gbig(3,sizepw)=G vectors in the sphere packed in the first maxpw columns
    1178              : !!  shlim(nbase)=number of G vectors within each shell
    1179              : !!  ierr= Exit status, if /=0 the number of G vectors found exceeds sizepw
    1180              : !!
    1181              : !! SIDE EFFECTS
    1182              : !!
    1183              : !! NOTES
    1184              : !!  cnorm is a bit redundant since it can be calculated from gbase. However this procedure
    1185              : !!  is called by outkss in which cnorm is already calculated and we dont want to do it twice
    1186              : !!
    1187              : !! SOURCE
    1188              : 
    1189              : subroutine getfullg(nbase,nsym,pinv,sizepw,gbase,symrec,cnorm,maxpw,gbig,shlim,ierr)
    1190              : 
    1191              : !Arguments ------------------------------------
    1192              : !scalars
    1193              :  integer,intent(in) :: nbase,nsym,pinv,sizepw
    1194              :  integer,intent(out) :: ierr,maxpw
    1195              : !arrays
    1196              :  integer,intent(in) :: gbase(3,nbase),symrec(3,3,nsym)
    1197              :  integer,intent(out) :: gbig(3,sizepw),shlim(nbase)
    1198              :  real(dp),intent(inout) :: cnorm(nbase) !sort_dp can change cnorm
    1199              : 
    1200              : !Local variables-------------------------------
    1201              : !scalars
    1202              :  integer :: ibase,ig,ilim,ish,isym,itim
    1203              :  logical :: found
    1204              :  character(len=500) :: msg
    1205              : !arrays
    1206              :  integer :: gcur(3),geq(3)
    1207              :  integer,allocatable :: gshell(:,:),insort(:),nshell(:)
    1208              : ! *************************************************************************
    1209              : 
    1210              :  if (pinv/=1.and.pinv/=-1) then
    1211              :    write(msg,'(a,i6)')&
    1212              : &   ' The argument pinv should be -1 or 1, however, pinv =',pinv
    1213              :    ABI_BUG(msg)
    1214              :  end if
    1215              :  !
    1216              :  ! === Reorder base g-vectors in order of increasing module ===
    1217              :  ABI_MALLOC(insort,(nbase))
    1218              :  do ibase=1,nbase
    1219              :    insort(ibase)=ibase
    1220              :  end do
    1221              :  call sort_dp(nbase,cnorm,insort,tol14)
    1222              :  !
    1223              :  ! === Generate all stars of G-vectors ===
    1224              :  ! Star of G is the set of all symmetrical images of the vector
    1225              :  ! gshell contains the symmetrical G at fixed gbase. No need to add an additional dimension
    1226              :  ! or initialize to zero the array inside the loop over nbase as we loop over (ish<=nshell(ibase))
    1227              :  ABI_MALLOC(nshell,(nbase))
    1228              :  ABI_MALLOC(gshell,(3,2*nsym))
    1229              :  !
    1230              :  ! === Start with zero number of G vectors found ===
    1231              :  maxpw=0 ; ierr=0
    1232              :  do ibase=1,nbase
    1233              :    !
    1234              :    ! === Loop over all different modules of G ===
    1235              :    ! * Start with zero G vectors found in this star
    1236              :    nshell(ibase)=0
    1237              :    gcur(:)=gbase(:,insort(ibase))
    1238              :    !
    1239              :    !  === Loop over symmetries ===
    1240              :    do isym=1,nsym
    1241              :      do itim=pinv,1,2
    1242              :        geq(:)=itim*MATMUL(symrec(:,:,isym),gcur)
    1243              :        !
    1244              :        ! * Search for symmetric of g and eventually add it:
    1245              :        found=.FALSE. ; ish=1
    1246              :        do while ((.not.found).and. (ish<=nshell(ibase)))
    1247              :          found=ALL(geq(:)==gshell(:,ish))
    1248              :          ish=ish+1
    1249              :        end do
    1250              :        if (.not.found) then
    1251              :          nshell(ibase)=nshell(ibase)+1
    1252              :          gshell(:,nshell(ibase))=geq(:)
    1253              :        end if
    1254              :      end do
    1255              :    end do
    1256              :    !
    1257              :    ! * Was sizepw large enough?
    1258              :    if ((maxpw+nshell(ibase))>sizepw) then
    1259              :      write(msg,'(a,i6,2a)')&
    1260              : &     ' Number of G in sphere exceeds maximum allowed value =',sizepw,ch10,&
    1261              : &     ' check the value of sizepw in calling routine '
    1262              :      ABI_WARNING(msg)
    1263              :      ierr=1; RETURN
    1264              :    end if
    1265              :    !
    1266              :    ! === Store this shell of Gs in a big array (gbig) ===
    1267              :    do ig=1,nshell(ibase)
    1268              :      gbig(:,ig+maxpw)=gshell(:,ig)
    1269              :    end do
    1270              :    maxpw=maxpw+nshell(ibase)
    1271              :  end do ! ibase
    1272              :  !
    1273              :  ! === Compute number of G"s within each shell ===
    1274              :  ilim=0
    1275              :  do ibase=1,nbase
    1276              :    ilim=ilim+nshell(ibase)
    1277              :    shlim(ibase)=ilim
    1278              :  end do
    1279              :  !
    1280              :  ! === Print out shell limits ===
    1281              :  write(msg,'(3a)')&
    1282              : & ' Shells found:',ch10,&
    1283              : & ' number of shell    number of G vectors      cut-off energy [Ha] '
    1284              :  call wrtout(std_out,msg)
    1285              : 
    1286              :  do ibase=1,nbase
    1287              :    write(msg,'(12x,i4,17x,i6,12x,f8.3)')ibase,shlim(ibase),two*pi**2*cnorm(ibase)
    1288              :    call wrtout(std_out,msg)
    1289              :  end do
    1290              :  write(msg,'(a)')ch10
    1291              :  call wrtout(std_out,msg)
    1292              :  ABI_FREE(gshell)
    1293              :  ABI_FREE(insort)
    1294              :  ABI_FREE(nshell)
    1295              : 
    1296              : end subroutine getfullg
    1297              : !!***
    1298              : 
    1299              : !----------------------------------------------------------------------
    1300              : 
    1301              : !!****f* m_gsphere/get_irredg
    1302              : !! NAME
    1303              : !! get_irredg
    1304              : !!
    1305              : !! FUNCTION
    1306              : !!  Given a set of reciprocal lattice vectors, find the set of G"s generating the others by symmetry.
    1307              : !!
    1308              : !! INPUTS
    1309              : !!  nsym=number of symmetry operations
    1310              : !!  pinv=-1 if time-reversal can be used, 1 otherwise
    1311              : !!  npw_k=number of G vectors (for this k-point, as the set of G is k-centered)
    1312              : !!  gcurr(3,npw_k)=the list of G vectors
    1313              : !!  gprimd(3,3)=dimensional primitive translations for reciprocal space ($\textrm{bohr}^{-1}$)
    1314              : !!  symrec(3,3,nsym)=symmetry operations in terms of reciprocal space primitive translations.
    1315              : !!
    1316              : !! OUTPUT
    1317              : !!  nbasek=number of irreducible G vectors found
    1318              : !!  cnormk(npw_k)=first nbasek elements are the norm of each irreducible G-vector
    1319              : !!  gbasek(3,npw_k)=first nbasek elements are the irreducible G vectors
    1320              : !!
    1321              : !! NOTES
    1322              : !!  The search can be optimized by looping over shells. See m_skw for a faster algo
    1323              : !!
    1324              : !! SOURCE
    1325              : 
    1326         3526 : subroutine get_irredg(npw_k,nsym,pinv,gprimd,symrec,gcurr,nbasek,gbasek,cnormk)
    1327              : 
    1328              : !Arguments ------------------------------------
    1329              : !scalars
    1330              :  integer,intent(in) :: npw_k,nsym,pinv
    1331              :  integer,intent(out) :: nbasek
    1332              : !arrays
    1333              :  integer,intent(in) :: gcurr(3,npw_k),symrec(3,3,nsym)
    1334              :  integer,intent(out) :: gbasek(3,npw_k)
    1335              :  real(dp),intent(in) :: gprimd(3,3)
    1336              :  real(dp),intent(out) :: cnormk(npw_k)
    1337              : 
    1338              : !Local variables-------------------------------
    1339              : !scalars
    1340              :  integer :: ig,irr,isym,jj
    1341              :  real(dp) :: eps,norm
    1342              :  logical :: found
    1343              : !arrays
    1344              :  integer :: gbas(3),gcur(3),geq(3)
    1345              :  real(dp) :: gcar(3)
    1346              : ! *************************************************************************
    1347              : 
    1348              :  DBG_ENTER("COLL")
    1349              : 
    1350         3526 :  if (pinv/=1.and.pinv/=-1) then
    1351            0 :    ABI_BUG(sjoin('pinv should be -1 or 1, however, pinv =', itoa(pinv)))
    1352              :  end if
    1353              : 
    1354              :  ! Zero irred G vectors found, zeroing output arrays.
    1355      4569461 :  nbasek = 0; cnormk(:) = zero; gbasek(:,:) = 0
    1356              : 
    1357       916713 :  do ig=1,npw_k
    1358      3652748 :    gcur(:) = gcurr(:,ig); norm = zero
    1359      3652748 :    do jj=1,3
    1360      2739561 :      gcar(jj)=gcur(1)*gprimd(jj,1)+gcur(2)*gprimd(jj,2)+gcur(3)*gprimd(jj,3)
    1361      3652748 :      norm=norm+gcar(jj)**2
    1362              :    end do
    1363       913187 :    eps = tol8 * norm; found = .False.; irr = 1
    1364    113280552 :    do while (.not.found .and. irr <= nbasek)  ! This loop can be optimized by looping inside the shell.
    1365    112367365 :      if (abs(norm - cnormk(irr)) <= eps) then
    1366      7264036 :        gbas(:) = gbasek(:,irr); isym = 1
    1367     31324101 :        do while (.not.found .and. isym <= nsym)
    1368    383605196 :          geq(:) = matmul(symrec(:,:,isym),gcur)
    1369     34650661 :          found = all(geq(:) == gbas(:))
    1370     29508092 :          if (pinv == -1) found = (found .or. all(geq == -gbas)) ! For time-reversal
    1371     31324101 :          isym = isym + 1
    1372              :        end do
    1373              :      end if
    1374    112445004 :      irr = irr + 1
    1375              :    end do
    1376       916713 :    if (.not. found) then
    1377       310556 :      nbasek = nbasek + 1; cnormk(nbasek) = norm; gbasek(:,nbasek) = gcur(:)
    1378              :    end if
    1379              :  end do
    1380              : 
    1381              :  DBG_EXIT("COLL")
    1382              : 
    1383         3526 : end subroutine get_irredg
    1384              : !!***
    1385              : 
    1386              : !----------------------------------------------------------------------
    1387              : 
    1388              : !!****f* m_gsphere/merge_kgirr
    1389              : !! NAME
    1390              : !! merge_kgirr
    1391              : !!
    1392              : !! FUNCTION
    1393              : !!  Given a list of irreducible reciprocal vectors associated to different k-centered spheres,
    1394              : !!  this subroutine finds the minimal set of G vectors needed to reconstruct the union of the spheres
    1395              : !!  through symmetry operations.
    1396              : !!
    1397              : !! INPUTS
    1398              : !! nsym=number of symmetry operations
    1399              : !! pinv=-1 if time-reversal can be used, 0 otherwise
    1400              : !! nkpt=number of k-points for k-centered spheres
    1401              : !! mpw=Max number of G vectors for each k-point
    1402              : !! sizepw=Max expected number of G vectors found
    1403              : !! symrec(3,3,nsym)=symmetries in reciprocal space given in reduced coordinates
    1404              : !! nbasek(nkpt)=number of irred G for each k-point
    1405              : !! cnormk(mpw,nkpt)=the norm of each k-centered G (only 1:nbase(ik)) is used
    1406              : !! gbasek(3,mpw,nkpt)
    1407              : !!
    1408              : !! OUTPUT
    1409              : !! nbase=number of irreducible G needed to reconstruct the initial set of spheres
    1410              : !! gbase(3,sizepw)=irreducible G found in reciprocal coordinates
    1411              : !! cnorm(sizepw)=Norm of each irred G vector
    1412              : !! ierr= Exit status, if /=0 the number of G vectors found exceeds sizepw
    1413              : !!
    1414              : !! SOURCE
    1415              : 
    1416          469 : subroutine merge_kgirr(nsym,pinv,nkpt,mpw,sizepw,symrec,nbasek,cnormk,gbasek,nbase,gbase,cnorm,ierr)
    1417              : 
    1418              : !Arguments ------------------------------------
    1419              : !scalars
    1420              :  integer,intent(in) :: mpw,nkpt,nsym,pinv,sizepw
    1421              :  integer,intent(out) :: ierr,nbase
    1422              : !arrays
    1423              :  integer,intent(in) :: gbasek(3,mpw,nkpt),nbasek(nkpt),symrec(3,3,nsym)
    1424              :  integer,intent(inout) :: gbase(3,sizepw) !vz_i
    1425              :  real(dp),intent(in) :: cnormk(mpw,nkpt)
    1426              :  real(dp),intent(inout) :: cnorm(sizepw) !vz_i
    1427              : 
    1428              : !Local variables-------------------------------
    1429              : !scalars
    1430              :  integer :: ikpt,inb,irgk,isym
    1431              :  real(dp) :: eps,norm
    1432              :  logical :: found
    1433              :  character(len=500) :: msg
    1434              : !arrays
    1435              :  integer :: gbas(3),gcur(3),geq(3)
    1436              : ! *************************************************************************
    1437              : 
    1438              :  DBG_ENTER("COLL")
    1439              : 
    1440          469 :  if (pinv/=1.and.pinv/=-1) then
    1441            0 :    write(msg,'(a,i6)')' The argument pinv should be -1 or 1, however, pinv =',pinv
    1442            0 :    ABI_BUG(msg)
    1443              :  end if
    1444              :  !
    1445              :  ! === Start with zero number of G found ===
    1446          469 :  nbase=0 ; ierr=0
    1447         2722 :  do ikpt=1,nkpt
    1448        78198 :    do irgk=1,nbasek(ikpt)
    1449       301904 :      gcur(:)=gbasek(:,irgk,ikpt)
    1450        75476 :      norm=cnormk(irgk,ikpt) ; eps=tol8*norm
    1451        75476 :      found=.FALSE. ; inb=1
    1452      9601384 :      do while ((.not.found).and.(inb<=nbase))
    1453      9525908 :        if (ABS(norm-cnorm(inb))<=eps) then
    1454       510904 :          gbas(:)=gbase(:,inb)
    1455              :          isym=1
    1456      1615525 :          do while ((.not.found).and.(isym<=nsym))
    1457     19341387 :            geq(:)=MATMUL(symrec(:,:,isym),gcur)
    1458      1720250 :            found=ALL(geq(:)==gbas(:))
    1459      1487799 :            if (pinv==-1) found= (found.or.ALL(geq(:)==-gbas(:)) ) ! For time-reversal
    1460      1615525 :            isym=isym+1
    1461              :          end do
    1462              :        end if
    1463      9562839 :        inb=inb+1
    1464              :      end do
    1465        77729 :      if (.not.found) then
    1466              :        ! === Add to the list ===
    1467        36931 :        nbase=nbase+1
    1468        36931 :        if (nbase>sizepw) then
    1469              :          write(msg,'(2(a,i5),a)')&
    1470            0 : &         ' nbase (',nbase,') became greater than sizepw = ',sizepw,' returning ierr=1 '
    1471            0 :          ABI_WARNING(msg)
    1472            0 :          ierr=1; RETURN
    1473              :        end if
    1474        36931 :        cnorm(nbase)=cnormk(irgk,ikpt)
    1475       147724 :        gbase(:,nbase)=gcur(:)
    1476              :      end if
    1477              :    end do
    1478              :  end do
    1479              : 
    1480              :  DBG_EXIT("COLL")
    1481              : 
    1482              : end subroutine merge_kgirr
    1483              : !!***
    1484              : 
    1485              : !----------------------------------------------------------------------
    1486              : 
    1487              : !!****f* m_gpshere/setshells
    1488              : !! NAME
    1489              : !! setshells
    1490              : !!
    1491              : !! FUNCTION
    1492              : !! Set consistently the number of shells, the number of plane-waves, and the energy cut-off
    1493              : !!
    1494              : !! INPUTS
    1495              : !!  nsym=number of symmetry operations
    1496              : !!  gmet(3,3)=metric tensor in reciprocal space
    1497              : !!  gprimd(3,3)=dimensional primitive vectors in reciprocal space
    1498              : !!  symrel(3,3,nsym)=symmetry operations in real space
    1499              : !!  tag=suffix to account for the different possibilities for these variables (npw, ecut or nsh ..)
    1500              : !!  ucvol=unit cell volume
    1501              : !!
    1502              : !! OUTPUT
    1503              : !!  (see side effects)
    1504              : !!
    1505              : !! SIDE EFFECTS
    1506              : !!  ecut,npw,nsh=one of them is an input, the two others are output
    1507              : !!  ecut=cut-off energy for plane wave basis sphere (Ha)
    1508              : !!  npw=number of plane waves
    1509              : !!  nsh=number of shells
    1510              : !!
    1511              : !! SOURCE
    1512              : 
    1513         1396 : subroutine setshells(ecut,npw,nsh,nsym,gmet,gprimd,symrel,tag,ucvol)
    1514              : 
    1515              : !Arguments ------------------------------------
    1516              : !scalars
    1517              :  integer,intent(in) :: nsym
    1518              :  integer,intent(inout) :: npw,nsh
    1519              :  real(dp),intent(in) :: ucvol
    1520              :  real(dp),intent(inout) :: ecut
    1521              :  character(len=*),intent(in) :: tag
    1522              : !arrays
    1523              :  integer,intent(in) :: symrel(3,3,nsym)
    1524              :  real(dp),intent(in) :: gmet(3,3),gprimd(3,3)
    1525              : 
    1526              : !Local variables-------------------------------
    1527              : !scalars
    1528              :  integer :: exchn2n3d,ifound,ig,ii,ish,isym,npw_found,npwave
    1529              :  integer :: npwwrk,nsh_found,pad=50
    1530              :  real(dp) :: ecut_found,ecut_trial,eps,scale=1.3_dp
    1531              :  logical :: found
    1532              :  character(len=500) :: msg
    1533         1396 :  type(MPI_type) :: MPI_enreg_seq
    1534              : !arrays
    1535              :  integer :: geq(3)
    1536         1396 :  integer,allocatable :: gvec(:,:),gvec_sh(:,:),insort(:),npw_sh(:)
    1537              :  real(dp) :: gctr(3)
    1538         1396 :  real(dp),allocatable :: gnorm(:),gnorm_sh(:)
    1539              : 
    1540              : !******************************************************************
    1541              : 
    1542              :  ! Check coherence of input variables ecut, npw, and nsh.
    1543              :  ! 1-> one at least should be non-null
    1544         1396 :  if (npw==0.and.nsh==0.and.ecut<=tol6) then
    1545              :    write(msg,'(8a)')&
    1546          176 :     'One of the three variables ecut',TRIM(tag),', npw',TRIM(tag),', or nsh',TRIM(tag),ch10,&
    1547          352 :     'must be non-null. Returning.'
    1548          176 :    ABI_COMMENT(msg)
    1549          176 :    RETURN
    1550              :  end if
    1551              :  ! 2-> one and only one should be non-null
    1552         1220 :  if (npw/=0.and.nsh/=0) then
    1553              :    write(msg,'(6a)')&
    1554            0 :     'Only one of the two variables npw',TRIM(tag),' and nsh',TRIM(tag),ch10,&
    1555            0 :     'can be non-null. Modify the value of one of these in input file.'
    1556            0 :    ABI_ERROR(msg)
    1557              :  end if
    1558         1220 :  if (ecut>tol6.and.npw/=0) then
    1559              :    write(msg,'(6a)')&
    1560            0 :     'Only one of the two variables ecut',TRIM(tag),' and npw',TRIM(tag),ch10,&
    1561            0 :     'can be non-null. Modify the value of one of these in input file.'
    1562            0 :    ABI_ERROR(msg)
    1563              :  end if
    1564         1220 :  if (ecut>tol6.and.nsh/=0) then
    1565              :    write(msg,'(6a)')&
    1566            0 :     'Only one of the two variables ecut',TRIM(tag),' and nsh',TRIM(tag),ch10,&
    1567            0 :     'can be non-null Action : modify the value of one of these in input file.'
    1568            0 :    ABI_ERROR(msg)
    1569              :  end if
    1570              : 
    1571              :  ! Calculate an upper bound for npw.
    1572              :  ! gctr is center of the g-vector sphere
    1573         1220 :  gctr(:)= [zero,zero,zero]
    1574         1220 :  if (ecut>tol6) then
    1575              :    ! The average number of plane-waves in the cutoff sphere is given by:
    1576              :    ! npwave = (2*ecut)**(3/2)*ucvol/(6*pi**2)
    1577              :    ! The upper bound is calculated as npwwrk=int(scale * npwave) + pad
    1578         1092 :    npwave=NINT(ucvol*(two*ecut)**1.5_dp/(six*pi**2))
    1579         1092 :    npwwrk=NINT(DBLE(npwave)*scale)+pad
    1580         1092 :    ecut_trial=ecut
    1581          128 :  else if (npw/=0) then
    1582              :    ! npw is given in the input
    1583          128 :    npwwrk=NINT(DBLE(npw)*scale)+pad
    1584          128 :    ecut_trial=(six*pi**2*npw/ucvol)**two_thirds/two
    1585              :  else
    1586              :    ! If nsh is given in the input
    1587            0 :    npwwrk=nsh*18+2*pad
    1588            0 :    ecut_trial=(six*pi**2*nsh*18/ucvol)**two_thirds/two
    1589              :  end if
    1590              : 
    1591         1220 :  call initmpi_seq(MPI_enreg_seq)
    1592              : 
    1593         3660 :  ABI_MALLOC(gvec,(3,npwwrk))
    1594         2440 :  ifound=0
    1595         2440 :  do while (ifound==0)
    1596              :    !write(msg,'(a,f8.2)')' setshells : ecut_trial = ',ecut_trial
    1597              :    !call wrtout(std_out,msg,'COLL')
    1598         1220 :    exchn2n3d=0 ! For the time being, no exchange of n2 and n3
    1599              : 
    1600         1220 :    call kpgsph(ecut_trial,exchn2n3d,gmet,0,1,1,gvec,gctr,1,MPI_enreg_seq,npwwrk,npw_found)
    1601              : 
    1602         3660 :    ABI_MALLOC(gnorm,(npw_found))
    1603         3660 :    ABI_MALLOC(insort,(npw_found))
    1604              : 
    1605       359454 :    do ig=1,npw_found
    1606       358234 :      insort(ig)=ig
    1607       358234 :      gnorm(ig)=zero
    1608      1434156 :      do ii=1,3
    1609              :        gnorm(ig)=gnorm(ig)+(gvec(1,ig)*gprimd(ii,1)+&
    1610              :                             gvec(2,ig)*gprimd(ii,2)+&
    1611      1432936 :                             gvec(3,ig)*gprimd(ii,3))**2
    1612              :      end do
    1613              :    end do
    1614         1220 :    call sort_dp(npw_found,gnorm,insort,tol14)
    1615              : 
    1616         2440 :    ABI_MALLOC(npw_sh,(npw_found))
    1617         2440 :    ABI_MALLOC(gnorm_sh,(npw_found))
    1618         3660 :    ABI_MALLOC(gvec_sh,(3,npw_found))
    1619       359454 :    npw_sh(:)=0
    1620       359454 :    gnorm_sh(:)=zero
    1621      1434156 :    gvec_sh(:,:)=0
    1622              :    ! Count the number of shells:
    1623              :    ! (search for the G-vectors generating the others by symmetry)
    1624         1220 :    nsh_found=0
    1625              : 
    1626       359454 :    do ig=1,npw_found
    1627       358234 :      eps=1.d-8*gnorm(ig)
    1628       358234 :      found=.FALSE.
    1629       358234 :      ish=1
    1630     43087727 :      do while ((.not.found).and.(ish<=nsh_found))
    1631     42729493 :        if (ABS(gnorm(ig)-gnorm_sh(ish))<=eps) then
    1632              :          isym=1
    1633     11871425 :          do while ((.not.found).and.(isym<=nsym))
    1634              :            geq(:)=(symrel(1,:,isym)*gvec(1,insort(ig))+&
    1635              :                   symrel(2,:,isym)*gvec(2,insort(ig))+&
    1636     44360616 :                   symrel(3,:,isym)*gvec(3,insort(ig)))
    1637              : 
    1638              :            found=((geq(1)==gvec_sh(1,ish)).and.&
    1639              :                   (geq(2)==gvec_sh(2,ish)).and.&
    1640     11090154 :                   (geq(3)==gvec_sh(3,ish)))
    1641     11417526 :            isym=isym+1
    1642              :          end do
    1643              :        end if
    1644     42729493 :        ish=ish+1
    1645              :      end do
    1646       359454 :      if (.not.found) then
    1647        30862 :        nsh_found=nsh_found+1
    1648        30862 :        gnorm_sh(nsh_found)=gnorm(ig)
    1649       123448 :        gvec_sh(:,nsh_found)=gvec(:,insort(ig))
    1650        30862 :        npw_sh(nsh_found)=1
    1651              :      else
    1652       327372 :        ish=ish-1
    1653       327372 :        npw_sh(ish)=npw_sh(ish)+1
    1654              :      end if
    1655              :    end do
    1656              : 
    1657         1220 :    ecut_found=two*pi**2*gnorm(npw_found)
    1658              : 
    1659         1220 :    if(ecut>tol6) then
    1660              :      ! ecut is given in the input
    1661              :      !if (ecut_found<ecut-0.1) then
    1662              :      !  write(msg,'(3a,e14.6,9a,e14.6,3a)')&
    1663              :      !   'The value ecut',TRIM(tag),'=',ecut,' given in the input file leads to',ch10,&
    1664              :      !   'the same values for nsh',TRIM(tag),' and npw',TRIM(tag),' as ecut',TRIM(tag),'=',ecut_found,ch10
    1665              :      !  ABI_COMMENT(msg)
    1666              :      !end if
    1667              :      ifound=1
    1668          128 :    else if (npw/=0) then
    1669              :      ! If npw is given in the input
    1670          128 :      if (npw_found==npw) then
    1671              :        ecut_found=two*pi**2*gnorm(npw_found)
    1672              :        ifound=1
    1673           11 :      else if (npw_found>npw) then
    1674           11 :        npw_found=0
    1675           11 :        nsh_found=0
    1676           60 :        do while (npw_found<npw)
    1677           49 :          nsh_found=nsh_found+1
    1678           49 :          npw_found=npw_found+npw_sh(nsh_found)
    1679              :        end do
    1680              :        ! check that the shell is closed
    1681           11 :        if(npw_found>npw) then
    1682              :          ! shell not closed
    1683            0 :          npw_found=npw_found-npw_sh(nsh_found)
    1684            0 :          nsh_found=nsh_found-1
    1685            0 :          do while (ABS(gnorm_sh(nsh_found)-gnorm_sh(nsh_found+1))<0.000001)
    1686            0 :            npw_found=npw_found-npw_sh(nsh_found)
    1687            0 :            nsh_found=nsh_found-1
    1688              :          end do
    1689              :          write(msg,'(3a,i6,5a,i6,3a)')&
    1690            0 :           'The value npw',TRIM(tag),'=',npw,' given in the input file does not close the shell',ch10,&
    1691            0 :           'The lower closed-shell is obtained for a value npw',TRIM(tag),'=',npw_found,ch10,&
    1692            0 :           'This value will be adopted for the calculation.',ch10
    1693            0 :          ABI_WARNING(msg)
    1694              :        end if
    1695           11 :        ecut_found=two*pi**2*gnorm(npw_found)
    1696              :        ifound=1
    1697              :      end if
    1698            0 :    else if (nsh/=0) then
    1699              :      ! If nsh is given in the input
    1700            0 :      if (nsh_found==nsh) then
    1701              :        ecut_found=two*pi**2*gnorm(npw_found)
    1702              :        ifound=1
    1703            0 :      else if (nsh_found>nsh) then
    1704            0 :        npw_found=0
    1705            0 :        nsh_found=0
    1706            0 :        do ish=1,nsh
    1707            0 :          npw_found=npw_found+npw_sh(ish)
    1708            0 :          nsh_found=nsh_found+1
    1709              :        end do
    1710            0 :        if (ABS(gnorm_sh(nsh_found)-gnorm_sh(nsh_found+1))<0.000001) then
    1711            0 :          do while (ABS(gnorm_sh(nsh_found)-gnorm_sh(nsh_found+1))<0.000001)
    1712            0 :            nsh_found=nsh_found+1
    1713            0 :            npw_found=npw_found+npw_sh(nsh_found)
    1714              :          end do
    1715              :          write(msg,'(3a,i6,5a,i6,3a)')&
    1716            0 :           'The value nsh',TRIM(tag),'=',nsh,' given in the input file corresponds to the same',ch10,&
    1717            0 :           'cut-off energy as for closed-shell upto nsh',TRIM(tag),'=',nsh_found,ch10,&
    1718            0 :           'This value will be adopted for the calculation.',ch10
    1719            0 :          ABI_WARNING(msg)
    1720              :        end if
    1721            0 :        ecut_found=two*pi**2*gnorm(npw_found)
    1722              :        ifound=1
    1723              :      end if
    1724              :    end if
    1725              : 
    1726         1220 :    if (ifound==0) then
    1727            0 :      ecut_trial=1.1*ecut_trial
    1728            0 :      ABI_FREE(gnorm)
    1729            0 :      ABI_FREE(gnorm_sh)
    1730            0 :      ABI_FREE(gvec_sh)
    1731            0 :      ABI_FREE(insort)
    1732            0 :      ABI_FREE(npw_sh)
    1733              :    else
    1734              :      ! ecut was not provided as an input, then set it now!
    1735         1220 :      if (ecut<tol6) then
    1736          128 :        ecut=ecut_found
    1737              :      end if
    1738         1220 :      npw=npw_found
    1739         1220 :      nsh=nsh_found
    1740              :    end if
    1741              : 
    1742              :  end do ! while(ifound==0)
    1743              : 
    1744         1220 :  call destroy_mpi_enreg(MPI_enreg_seq)
    1745              : 
    1746         1220 :  ABI_FREE(gnorm)
    1747         1220 :  ABI_FREE(gnorm_sh)
    1748         1220 :  ABI_FREE(gvec)
    1749         1220 :  ABI_FREE(gvec_sh)
    1750         1220 :  ABI_FREE(insort)
    1751         1220 :  ABI_FREE(npw_sh)
    1752              : 
    1753         1396 : end subroutine setshells
    1754              : !!***
    1755              : 
    1756              : !----------------------------------------------------------------------
    1757              : 
    1758              : !!****f* m_gsphere/kg_map
    1759              : !! NAME
    1760              : !!  kg_map
    1761              : !!
    1762              : !! FUNCTION
    1763              : !!  Compute the mapping between two lists of g-vectors.
    1764              : !!
    1765              : !! INPUTS
    1766              : !!   npw1, kg1(3,npw1)=First list of G-vectors
    1767              : !!   npw2, kg2(3,npw2)=Second list of G-vectors
    1768              : !!
    1769              : !! OUTPUT
    1770              : !!   g2g1(npw2) = Mapping kg2 index --> kg1 index.
    1771              : !!                Set to 0 if kg2(:,ig) not in kg1
    1772              : !!   nmiss = Number of G-vectors in kg2 not found in kg1
    1773              : !!
    1774              : !! SOURCE
    1775              : 
    1776         4252 : subroutine kg_map(npw1, kg1, npw2, kg2, g2g1, nmiss)
    1777              : 
    1778              : !Arguments ------------------------------------
    1779              : !scalars
    1780              :  integer,intent(in) :: npw1,npw2
    1781              :  integer,intent(out) :: nmiss
    1782              : !arrays
    1783              :  integer,intent(in) :: kg1(3,npw1),kg2(3,npw2)
    1784              :  integer,intent(out) :: g2g1(npw2)
    1785              : 
    1786              : !Local variables ------------------------------
    1787              : !scalars
    1788              :  integer :: ii,ipw,i1,i2,i3,n1,n2,n3
    1789              : !arrays
    1790              :  integer :: gmax(3),g1_max(3),g2_max(3)
    1791         4252 :  integer,allocatable :: iwork(:,:,:)
    1792              : !************************************************************************
    1793              : 
    1794      7443324 :  g1_max = maxval(abs(kg1))
    1795      7011176 :  g2_max = maxval(abs(kg2))
    1796        17008 :  do ii=1,3
    1797        17008 :    gmax(ii) = max(g1_max(ii), g2_max(ii))
    1798              :  end do
    1799        17008 :  gmax = 2*gmax + 1
    1800         4252 :  n1 = gmax(1); n2 = gmax(2); n3 = gmax(3)
    1801              : 
    1802              :  !print *, "n1, n2, n3", n1, n2, n3; print *, "kg1:", kg1; print *, "kg2:", kg2
    1803        21260 :  ABI_MALLOC(iwork, (n1, n2, n3))
    1804              : 
    1805              :  ! Insert kg1 into work with extra 0 s around outside:
    1806      6627552 :  iwork = 0
    1807      1859768 :  do ipw=1,npw1
    1808      1855516 :    i1 = kg1(1,ipw); if (i1<0) i1=i1+n1; i1=i1+1
    1809      1855516 :    i2 = kg1(2,ipw); if (i2<0) i2=i2+n2; i2=i2+1
    1810      1855516 :    i3 = kg1(3,ipw); if (i3<0) i3=i3+n3; i3=i3+1
    1811      1859768 :    iwork(i1,i2,i3) = ipw
    1812              :  end do
    1813              : 
    1814      1751731 :  g2g1 = 0; nmiss = 0
    1815      1751731 :  do ipw=1,npw2
    1816      1747479 :    i1 = kg2(1,ipw); if (i1<0) i1=i1+n1; i1=i1+1
    1817      1747479 :    i2 = kg2(2,ipw); if (i2<0) i2=i2+n2; i2=i2+1
    1818      1747479 :    i3 = kg2(3,ipw); if (i3<0) i3=i3+n3; i3=i3+1
    1819              : !#if defined FC_NVHPC
    1820              : !   !if (n1 == -1) write(std_out, *)"NVHPC raises SIGSEGV"
    1821              : !   print *, "ipw, i1, i2, i3, n1, n2, n3", ipw, i1, i2, i3, n1, n2, n3
    1822              : !#endif
    1823      1747479 :    g2g1(ipw) = iwork(i1,i2,i3)
    1824      1751731 :    if (g2g1(ipw) == 0) nmiss = nmiss + 1
    1825              :  end do
    1826              : 
    1827         4252 :  ABI_FREE(iwork)
    1828              : 
    1829         4252 : end subroutine kg_map
    1830              : !!***
    1831              : 
    1832              : !----------------------------------------------------------------------
    1833              : 
    1834              : !!****f* m_gsphere/make_istwk_table
    1835              : !! NAME
    1836              : !! make_istwfk_table
    1837              : !!
    1838              : !! FUNCTION
    1839              : !!
    1840              : !! INPUTS
    1841              : !!  ng1,ng2,ng3
    1842              : !!
    1843              : !! OUTPUT
    1844              : !!
    1845              : !! NOTES
    1846              : !!   Useful relations:
    1847              : !!     u_k(G) = u_{k+G0}(G-G0); u_{-k}(G) = u_k(G)^*
    1848              : !!   and therefore:
    1849              : !!     u_{G0/2}(G) = u_{G0/2}(-G-G0)^*.
    1850              : !!
    1851              : !! SOURCE
    1852              : 
    1853            0 : subroutine make_istwfk_table(istwf_k,ng1,ng2,ng3,ig1_inver,ig2_inver,ig3_inver)
    1854              : 
    1855              : !Arguments ------------------------------------
    1856              : !scalars
    1857              :  integer,intent(in) :: ng1,ng2,ng3,istwf_k
    1858              : !arrays
    1859              :  integer,intent(out) :: ig1_inver(ng1),ig2_inver(ng2),ig3_inver(ng3)
    1860              : 
    1861              : !Local variables ------------------------------
    1862              : !scalars
    1863              :  integer :: i1,i2,i3
    1864              :  character(len=500) :: msg
    1865              : !************************************************************************
    1866              : 
    1867              : ! Initialize the inverse coordinates
    1868            0 :  select case (istwf_k)
    1869              : 
    1870              :  case (1)
    1871            0 :    ig1_inver(1)=1
    1872            0 :    do i1=2,ng1
    1873            0 :      ig1_inver(i1)=ng1+2-i1
    1874              :    end do
    1875            0 :    ig2_inver(1)=1
    1876            0 :    do i2=2,ng2
    1877            0 :      ig2_inver(i2)=ng2+2-i2
    1878              :    end do
    1879            0 :    ig3_inver(1)=1
    1880            0 :    do i3=2,ng3
    1881            0 :      ig3_inver(i3)=ng3+2-i3
    1882              :    end do
    1883              : 
    1884              :  case (2:8)
    1885            0 :    if (istwf_k==2 .or. istwf_k==4 .or. istwf_k==6 .or. istwf_k==8) then
    1886            0 :      ig1_inver(1)=1
    1887            0 :      do i1=2,ng1
    1888            0 :        ig1_inver(i1)=ng1+2-i1
    1889              :      end do
    1890              :    else
    1891            0 :      do i1=1,ng1
    1892            0 :        ig1_inver(i1)=ng1+1-i1
    1893              :      end do
    1894              :    end if
    1895            0 :    if (istwf_k>=2 .and. istwf_k<=5) then
    1896            0 :      ig2_inver(1)=1
    1897            0 :      do i2=2,ng2
    1898            0 :        ig2_inver(i2)=ng2+2-i2
    1899              :      end do
    1900              :    else
    1901            0 :      do i2=1,ng2
    1902            0 :        ig2_inver(i2)=ng2+1-i2
    1903              :      end do
    1904              :    end if
    1905            0 :    if (istwf_k==2 .or. istwf_k==3 .or. istwf_k==6 .or. istwf_k==7) then
    1906            0 :      ig3_inver(1)=1
    1907            0 :      do i3=2,ng3
    1908            0 :        ig3_inver(i3)=ng3+2-i3
    1909              :      end do
    1910              :    else
    1911            0 :      do i3=1,ng3
    1912            0 :        ig3_inver(i3)=ng3+1-i3
    1913              :      end do
    1914              :    end if
    1915              : 
    1916              :  case default
    1917            0 :    write(msg,'(a,i0)')" Wrong value for istwf_k: ",istwf_k
    1918            0 :    ABI_ERROR(msg)
    1919              :  end select
    1920              : 
    1921            0 : end subroutine make_istwfk_table
    1922              : !!***
    1923              : 
    1924              : !----------------------------------------------------------------------
    1925              : 
    1926              : !!****f* m_gsphere/table_gbig2kg
    1927              : !! NAME
    1928              : !!  table_gbig2kg
    1929              : !!
    1930              : !! FUNCTION
    1931              : !!  Associate the kg_k set of g-vectors with the big array of gbig
    1932              : !!  The array gbig(3,maxpw) contains all g-vectors used for all k-points, in order of
    1933              : !!  increasing shells. For a each k-point, the wave-functions are defined only on a particular set
    1934              : !!  of g-vectors kg_k (included in gbig). This set is defined by array gamma2k:
    1935              : !!  The array gamma2k(ig=1,maxpw) translates the index of the gbig (from 1 to maxpw) into the corresponding
    1936              : !!  index in array kg_k. If gbig(ig) does not exist in kg_k, gamma2k(ig) contains npw_k+1.
    1937              : !!
    1938              : !! INPUTS
    1939              : !!  npw_k=Number of planewaves in the k-centered basis set
    1940              : !!  kg_k(3,npw_k)=The k-centered basis set
    1941              : !!  maxpw=Number of G in gbig
    1942              : !!  gbig(3,maxpw)=The union of the G-spheres at different k-points.
    1943              : !!
    1944              : !! OUTPUT
    1945              : !!  ierr=Status error. It gives the number of G of kg_k not contained in gbig.
    1946              : !!  gamma2k(maxpw)=Mapping gbig -> kg_k
    1947              : !!
    1948              : !! SOURCE
    1949              : 
    1950           31 : pure subroutine table_gbig2kg(npw_k,kg_k,maxpw,gbig,gamma2k,ierr)
    1951              : 
    1952              : !Arguments ------------------------------------
    1953              : !scalars
    1954              :  integer,intent(in) :: npw_k,maxpw
    1955              :  integer,intent(out) :: ierr
    1956              : !arrays
    1957              :  integer,intent(in) :: kg_k(3,npw_k)
    1958              :  integer,intent(in) :: gbig(3,maxpw)
    1959              :  integer,intent(out) :: gamma2k(maxpw)
    1960              : 
    1961              : !Local variables-------------------------------
    1962              : !scalars
    1963              :  integer :: ig,igp
    1964              :  logical :: found
    1965              : !arrays
    1966              :  integer :: gcur(3)
    1967              : ! *********************************************************************
    1968              : 
    1969           31 :  ierr=0
    1970        30608 :  gamma2k(:)=npw_k+1  ! Initialize array gamma2k
    1971              : 
    1972        21877 :  do ig=1,npw_k       ! Loop over g-vectors, for this k point.
    1973        87384 :    gcur(:)=kg_k(:,ig)
    1974              :    igp=0; found=.FALSE.
    1975     11381569 :    do while ((.not.found) .and. igp<maxpw) ! Search selected vector in array gbig: TODO this part can be optimized
    1976     11359723 :      igp=igp+1
    1977     12455395 :      found=ALL(gcur(:)==gbig(:,igp))
    1978              :    end do
    1979        21877 :    if (found) then ! Store it if found:
    1980        21846 :      gamma2k(igp)=ig
    1981              :    else
    1982            0 :      ierr=ierr+1
    1983              :    end if
    1984              :  end do
    1985              : 
    1986           31 : end subroutine table_gbig2kg
    1987              : !!***
    1988              : 
    1989              : !----------------------------------------------------------------------
    1990              : 
    1991              : !!****f* m_gsphere/gsph_extend
    1992              : !! NAME
    1993              : !!  gsph_extend
    1994              : !!
    1995              : !! FUNCTION
    1996              : !!  Construct a new gsphere_t with a larger cutoff energy
    1997              : !!  while preserving the ordering of the first G-vectors stored in in_Gsph
    1998              : !!
    1999              : !! INPUTS
    2000              : !!
    2001              : !! OUTPUT
    2002              : !!
    2003              : !! SOURCE
    2004              : 
    2005           36 : subroutine gsph_extend(in_Gsph, Cryst, new_ecut, new_Gsph)
    2006              : 
    2007              : !Arguments ------------------------------------
    2008              : !scalars
    2009              :  class(gsphere_t),intent(in) :: in_Gsph
    2010              :  type(crystal_t),intent(in) :: Cryst
    2011              :  real(dp),intent(in) :: new_ecut
    2012              :  class(gsphere_t),intent(out) :: new_Gsph
    2013              : 
    2014              : !Local variables-------------------------------
    2015              : !scalars
    2016              :  integer :: new_ng,in_ng,ig,ierr,sh
    2017              : !arrays
    2018           36 :  integer,allocatable :: new_gvec(:,:)
    2019              : ! *********************************************************************
    2020              : 
    2021           36 :  call new_Gsph%init(Cryst, 0, ecut=new_ecut)
    2022              : 
    2023           36 :  if (new_Gsph%ng > in_Gsph%ng) then
    2024              :    ! new_gpsh larger than in_gsph
    2025           34 :    new_ng = new_Gsph%ng
    2026           34 :    in_ng  = in_Gsph%ng
    2027              : 
    2028           34 :    ierr = 0
    2029         1800 :    do ig=1,in_ng
    2030         7098 :      if (ANY(new_Gsph%gvec(:,ig) /= in_Gsph%gvec(:,ig)) ) then
    2031            0 :        ierr = ierr + 1
    2032            0 :        write(std_out,*)" new_gvec, in_gvec",ig,new_Gsph%gvec(:,ig),in_Gsph%gvec(:,ig)
    2033              :      end if
    2034              :    end do
    2035              : 
    2036           34 :    if (ierr == 0) RETURN
    2037              : 
    2038            0 :    ierr = 0
    2039            0 :    do sh=1,in_Gsph%nsh
    2040            0 :      if (new_Gsph%shlim(sh) /= in_Gsph%shlim(sh) .or. &
    2041            0 :          ABS(new_Gsph%shlen(sh)-in_Gsph%shlen(sh)) > tol12 ) then
    2042            0 :        ierr = ierr + 1
    2043            0 :        write(std_out,*)"new_shlim, in_shlim",sh,new_Gsph%shlim(sh),in_Gsph%shlim(sh)
    2044            0 :        write(std_out,*)"new_shlen, in_shlen",sh,new_Gsph%shlen(sh),in_Gsph%shlen(sh)
    2045              :      end if
    2046              :    end do
    2047            0 :    ABI_CHECK(ierr == 0,"Wrong shells")
    2048              : 
    2049            0 :    ABI_MALLOC(new_gvec,(3, new_ng))
    2050            0 :    new_gvec = new_Gsph%gvec
    2051            0 :    new_gvec(:,1:in_ng) = in_Gsph%gvec
    2052              : 
    2053            0 :    call new_Gsph%free()
    2054            0 :    call new_Gsph%init(Cryst, new_ng, gvec=new_gvec)
    2055            0 :    ABI_FREE(new_gvec)
    2056              : 
    2057              :  else
    2058              :    ! new_gpsh smaller/equal than in_gsph
    2059            2 :    ierr = 0
    2060          132 :    do ig=1,MIN(new_Gsph%ng,in_Gsph%ng)
    2061          522 :      if (ANY(new_Gsph%gvec(:,ig) /= in_Gsph%gvec(:,ig)) ) then
    2062            0 :        ierr = ierr + 1
    2063            0 :        write(std_out,*)" new_gvec, in_gvec",ig,new_Gsph%gvec(:,ig),in_Gsph%gvec(:,ig)
    2064              :      end if
    2065              :    end do
    2066            2 :    ABI_CHECK(ierr==0,"Fatal error")
    2067              :  end if
    2068              : 
    2069              : end subroutine gsph_extend
    2070              : !!***
    2071              : 
    2072              : !----------------------------------------------------------------------
    2073              : 
    2074              : !!****f* m_gsphere/getkpgnorm
    2075              : !! NAME
    2076              : !! getkpgnorm
    2077              : !!
    2078              : !! FUNCTION
    2079              : !!  compute the norms of the k+G vectors
    2080              : !!
    2081              : !! INPUTS
    2082              : !!  gprimd(3,3)=metric tensor
    2083              : !!  kg_k(3,npw_k)= G vectors, in reduced coordinates
    2084              : !!  kpt(3)=k vector, in reduced coordinates
    2085              : !!  npw_k=size of the G-vector set
    2086              : !!
    2087              : !! OUTPUT
    2088              : !!  kpgnorm(npw_k)=norms of the k+G vectors
    2089              : !!
    2090              : !! SOURCE
    2091              : 
    2092          306 : subroutine getkpgnorm(gprimd,kpt,kg_k,kpgnorm,npw_k)
    2093              : 
    2094              : !Arguments ------------------------------------
    2095              : !scalars
    2096              :  integer,intent(in) :: npw_k
    2097              : !arrays
    2098              :  integer,intent(in) :: kg_k(3,npw_k)
    2099              :  real(dp),intent(in) :: gprimd(3,3),kpt(3)
    2100              :  real(dp),intent(out) :: kpgnorm(npw_k)
    2101              : 
    2102              : !Local variables-------------------------------
    2103              : !scalars
    2104              :  integer :: ipw
    2105              :  real(dp) :: g11,g12,g13,g21,g22,g23,g31,g32,g33,k1,k2,k3,kpg1,kpg2,kpg3,rr,xx
    2106              :  real(dp) :: yy,zz
    2107              : ! *************************************************************************
    2108              : 
    2109          306 :  k1=kpt(1) ; k2=kpt(2) ; k3=kpt(3)
    2110          306 :  g11=gprimd(1,1)
    2111          306 :  g12=gprimd(1,2)
    2112          306 :  g13=gprimd(1,3)
    2113          306 :  g21=gprimd(2,1)
    2114          306 :  g22=gprimd(2,2)
    2115          306 :  g23=gprimd(2,3)
    2116          306 :  g31=gprimd(3,1)
    2117          306 :  g32=gprimd(3,2)
    2118          306 :  g33=gprimd(3,3)
    2119              : 
    2120              : !Loop over all k+G
    2121        68931 :  do ipw=1,npw_k
    2122              : 
    2123              : !  Load k+G
    2124        68625 :    kpg1=k1+dble(kg_k(1,ipw))
    2125        68625 :    kpg2=k2+dble(kg_k(2,ipw))
    2126        68625 :    kpg3=k3+dble(kg_k(3,ipw))
    2127              : 
    2128              : !  Calculate module of k+G
    2129        68625 :    xx=g11*kpg1+g12*kpg2+g13*kpg3
    2130        68625 :    yy=g21*kpg1+g22*kpg2+g23*kpg3
    2131        68625 :    zz=g31*kpg1+g32*kpg2+g33*kpg3
    2132        68625 :    rr=sqrt(xx**2+yy**2+zz**2)
    2133        68931 :    kpgnorm(ipw) = rr
    2134              : 
    2135              :  end do ! ipw
    2136              : 
    2137          306 : end subroutine getkpgnorm
    2138              : !!***
    2139              : 
    2140              : !!****f* m_gsphere/symg
    2141              : !! NAME
    2142              : !! symg
    2143              : !!
    2144              : !! FUNCTION
    2145              : !! Treat symmetries applied to the G vectors, in view of the application
    2146              : !! to symmetrization of the dielectric matrix.
    2147              : !! Generate a list of time-reversed G vectors, as well as a list
    2148              : !! of spatially-symmetric G vectors.
    2149              : !!
    2150              : !! INPUTS
    2151              : !! kg_diel(3,npwdiel)=reduced planewave coordinates for the dielectric matrix.
    2152              : !! npwdiel=number of planewaves for the dielectric matrix
    2153              : !! nsym=number of symmetry
    2154              : !! symrel(3,3,nsym)=symmetry matrices in real space (integers)
    2155              : !! tnons(3,nsym)=reduced nonsymmorphic translations
    2156              : !! (symrel and tnons are in terms of real space primitive translations)
    2157              : !!
    2158              : !! OUTPUT
    2159              : !! phdiel(2,npwdiel,nsym)=phase associated with point symmetries applied to G
    2160              : !! sym_g(npwdiel,nsym)=index list of symmetric G vectors
    2161              : !! (could save a bit of space by suppressing isym=1, since the
    2162              : !! corresponding symmetry is the identity)
    2163              : !! tmrev_g(npwdiel)=index list of inverted G vectors (time-reversed)
    2164              : !!
    2165              : !! SOURCE
    2166              : 
    2167           82 : subroutine symg(kg_diel,npwdiel,nsym,phdiel,sym_g,symrel,tmrev_g,tnons)
    2168              : 
    2169              : !Arguments ------------------------------------
    2170              : !scalars
    2171              :  integer,intent(in) :: npwdiel,nsym
    2172              : !arrays
    2173              :  integer,intent(in) :: kg_diel(3,npwdiel),symrel(3,3,nsym)
    2174              :  integer,intent(out) :: sym_g(npwdiel,nsym),tmrev_g(npwdiel)
    2175              :  real(dp),intent(in) :: tnons(3,nsym)
    2176              :  real(dp),intent(out) :: phdiel(2,npwdiel,nsym)
    2177              : 
    2178              : !Local variables-------------------------------
    2179              : !scalars
    2180              :  integer :: g1,g2,g3,ipw,isym,j1,j2,j3,m1m,m1p,m2m,m2p,m3m,m3p,symmg,trevg
    2181              :  real(dp) :: arg,tau1,tau2,tau3
    2182              :  !character(len=500) :: msg
    2183              : !arrays
    2184           82 :  integer,allocatable :: grid(:,:,:)
    2185              : ! *************************************************************************
    2186              : 
    2187              : !Determines maximal bounds of the zone spanned by the planewaves
    2188           82 :  m1m=0 ; m2m=0 ; m3m=0 ; m1p=0 ; m2p=0 ; m3p=0
    2189        12500 :  do ipw=1,npwdiel
    2190        12418 :    g1=kg_diel(1,ipw)
    2191        12418 :    g2=kg_diel(2,ipw)
    2192        12418 :    g3=kg_diel(3,ipw)
    2193        12418 :    if(g1<m1m)m1m=g1 ; if(g1>m1p)m1p=g1
    2194        12418 :    if(g2<m2m)m2m=g2 ; if(g2>m2p)m2p=g2
    2195        12500 :    if(g3<m3m)m3m=g3 ; if(g3>m3p)m3p=g3
    2196              :  end do
    2197              : 
    2198              : !Set up grid, that associate to each point the index of the
    2199              : !corresponding planewave, if there is one
    2200          410 :  ABI_MALLOC(grid, (m1m:m1p,m2m:m2p,m3m:m3p))
    2201        28718 :  grid(:,:,:)=0
    2202        12500 :  do ipw=1,npwdiel
    2203        12418 :    g1=kg_diel(1,ipw)
    2204        12418 :    g2=kg_diel(2,ipw)
    2205        12418 :    g3=kg_diel(3,ipw)
    2206        12500 :    grid(g1,g2,g3)=ipw
    2207              :  end do
    2208              : 
    2209              : !Set up tmrev_g and sym_g arrays
    2210        12500 :  do ipw=1,npwdiel
    2211        12418 :    g1=kg_diel(1,ipw)
    2212        12418 :    g2=kg_diel(2,ipw)
    2213        12418 :    g3=kg_diel(3,ipw)
    2214              : 
    2215              : !  Treat first time-reversal symmetry
    2216        12418 :    trevg=grid(-g1,-g2,-g3)
    2217        12418 :    if(trevg==0)then
    2218            0 :      ABI_BUG('Do not find the time-reversed symmetric of a G-vector.')
    2219              :    end if
    2220        12418 :    tmrev_g(ipw)=trevg
    2221              : 
    2222              : !  Treat now spatial symmetries
    2223        98240 :    do isym=1,nsym
    2224              : 
    2225              : !    Get rotated G vector Gj for each symmetry element
    2226              : !    -- here we use the TRANSPOSE of symrel; assuming symrel expresses
    2227              : !    the rotation in real space, the transpose is then appropriate
    2228              : !    for G space symmetrization (according to Doug : see routine irrzg.f)
    2229              :      j1=symrel(1,1,isym)*g1+&
    2230        85740 : &     symrel(2,1,isym)*g2+symrel(3,1,isym)*g3
    2231              :      j2=symrel(1,2,isym)*g1+&
    2232        85740 : &     symrel(2,2,isym)*g2+symrel(3,2,isym)*g3
    2233              :      j3=symrel(1,3,isym)*g1+&
    2234        85740 : &     symrel(2,3,isym)*g2+symrel(3,3,isym)*g3
    2235        85740 :      symmg=grid(j1,j2,j3)
    2236        85740 :      if(symmg==0)then
    2237            0 :        ABI_BUG('Do not find the spatially symmetric of a G-vector.')
    2238              :      end if
    2239        85740 :      sym_g(ipw,isym)=symmg
    2240              : 
    2241              : !    Get associated phase
    2242        85740 :      tau1=tnons(1,isym)
    2243        85740 :      tau2=tnons(2,isym)
    2244        85740 :      tau3=tnons(3,isym)
    2245        98158 :      if (abs(tau1)>tol12.or.abs(tau2)>tol12.or.abs(tau3)>tol12) then
    2246              : !      compute exp(-2*Pi*I*G dot tau) using original G
    2247        31800 :        arg=two_pi*(dble(g1)*tau1+dble(g2)*tau2+dble(g3)*tau3)
    2248        31800 :        phdiel(1,ipw,isym)=cos(arg)
    2249        31800 :        phdiel(2,ipw,isym)=-sin(arg)
    2250              :      else
    2251        53940 :        phdiel(1,ipw,isym)=1._dp
    2252        53940 :        phdiel(2,ipw,isym)=0._dp
    2253              :      end if
    2254              : 
    2255              :    end do
    2256              :  end do
    2257              : 
    2258           82 :  ABI_FREE(grid)
    2259              : 
    2260           82 : end subroutine symg
    2261              : !!***
    2262              : 
    2263       717789 : end module m_gsphere
    2264              : !!***
        

Generated by: LCOV version 2.3-1