TABLE OF CONTENTS


ABINIT/m_gsphere [ Modules ]

[ Top ] [ Modules ]

NAME

  m_gsphere

FUNCTION

  The Gsphere data type defines the set of G-vectors
  centered on Gamma used to describe (chi0|epsilon|W) in the GW code.
  Note that, unlike the kg_k arrays used for wavefunctions, here the
  G-vectors are ordered in shells (increasing length). Moreover
  the sphere can be enlarged to take into account umklapps for which
  one need the knowledge of several quantities at G-G0.

COPYRIGHT

 Copyright (C) 1999-2024 ABINIT group (MG, GMR, VO, LR, RWG, MT, XG)
 This file is distributed under the terms of the
 GNU General Public License, see ~abinit/COPYING
 or http://www.gnu.org/copyleft/gpl.txt .

SOURCE

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_distribfft
33  use m_sort
34 
35  use defs_abitypes,   only : MPI_type
36  use m_fstrings,      only : sjoin, itoa
37  use m_numeric_tools, only : bisect
38  use m_geometry,      only : normv
39  use m_crystal,       only : crystal_t
40  use m_fftcore,       only : kpgsph, kgindex, sphereboundary
41  use m_mpinfo,        only : destroy_mpi_enreg, initmpi_seq
42 
43  implicit none
44 
45  private
46 
47 ! Low-level procedures.
48  public :: merge_and_sort_kg   ! Merges a set of k-centered G-spheres of cutoff ecut. Return a Gamma-centered G-spheres.
49  public :: table_gbig2kg       ! Associate the kg_k set of G-vectors with Gamma-centered G-sphere.
50  public :: get_irredg          ! Given a set of G vectors, find the set of G"s generating the others by symmetry.
51  public :: merge_kgirr         ! Merge a list of irreducible G vectors (see routine for more info)
52  public :: setshells           ! Set consistently the number of shells, the number of plane-waves, and the energy cut-off
53  public :: kg_map              ! Compute the mapping between two lists of g-vectors.
54  public :: make_istwfk_table
55  public :: getkpgnorm          ! Compute the norms of the k+G vectors
56  public :: symg

m_gpshere/setshells [ Functions ]

[ Top ] [ Functions ]

NAME

 setshells

FUNCTION

 Set consistently the number of shells, the number of plane-waves, and the energy cut-off

INPUTS

  nsym=number of symmetry operations
  gmet(3,3)=metric tensor in reciprocal space
  gprimd(3,3)=dimensional primitive vectors in reciprocal space
  symrel(3,3,nsym)=symmetry operations in real space
  tag=suffix to account for the different possibilities for these variables (npw, ecut or nsh ..)
  ucvol=unit cell volume

OUTPUT

  (see side effects)

SIDE EFFECTS

  ecut,npw,nsh=one of them is an input, the two others are output
  ecut=cut-off energy for plane wave basis sphere (Ha)
  npw=number of plane waves
  nsh=number of shells

SOURCE

1542 subroutine setshells(ecut,npw,nsh,nsym,gmet,gprimd,symrel,tag,ucvol)
1543 
1544 !Arguments ------------------------------------
1545 !scalars
1546  integer,intent(in) :: nsym
1547  integer,intent(inout) :: npw,nsh
1548  real(dp),intent(in) :: ucvol
1549  real(dp),intent(inout) :: ecut
1550  character(len=*),intent(in) :: tag
1551 !arrays
1552  integer,intent(in) :: symrel(3,3,nsym)
1553  real(dp),intent(in) :: gmet(3,3),gprimd(3,3)
1554 
1555 !Local variables-------------------------------
1556 !scalars
1557  integer :: exchn2n3d,ifound,ig,ii,ish,isym,npw_found,npwave
1558  integer :: npwwrk,nsh_found,pad=50
1559  real(dp) :: ecut_found,ecut_trial,eps,scale=1.3_dp
1560  logical :: found
1561  character(len=500) :: msg
1562  type(MPI_type) :: MPI_enreg_seq
1563 !arrays
1564  integer :: geq(3)
1565  integer,allocatable :: gvec(:,:),gvec_sh(:,:),insort(:),npw_sh(:)
1566  real(dp) :: gctr(3)
1567  real(dp),allocatable :: gnorm(:),gnorm_sh(:)
1568 
1569 !******************************************************************
1570 
1571  ! Check coherence of input variables ecut, npw, and nsh.
1572  ! 1-> one at least should be non-null
1573  if (npw==0.and.nsh==0.and.ecut<=tol6) then
1574    write(msg,'(8a)')&
1575     'One of the three variables ecut',TRIM(tag),', npw',TRIM(tag),', or nsh',TRIM(tag),ch10,&
1576     'must be non-null. Returning.'
1577    ABI_COMMENT(msg)
1578    RETURN
1579  end if
1580  ! 2-> one and only one should be non-null
1581  if (npw/=0.and.nsh/=0) then
1582    write(msg,'(6a)')&
1583     'Only one of the two variables npw',TRIM(tag),' and nsh',TRIM(tag),ch10,&
1584     'can be non-null. Modify the value of one of these in input file.'
1585    ABI_ERROR(msg)
1586  end if
1587  if (ecut>tol6.and.npw/=0) then
1588    write(msg,'(6a)')&
1589     'Only one of the two variables ecut',TRIM(tag),' and npw',TRIM(tag),ch10,&
1590     'can be non-null. Modify the value of one of these in input file.'
1591    ABI_ERROR(msg)
1592  end if
1593  if (ecut>tol6.and.nsh/=0) then
1594    write(msg,'(6a)')&
1595     'Only one of the two variables ecut',TRIM(tag),' and nsh',TRIM(tag),ch10,&
1596     'can be non-null Action : modify the value of one of these in input file.'
1597    ABI_ERROR(msg)
1598  end if
1599 
1600  ! Calculate an upper bound for npw.
1601  ! gctr is center of the g-vector sphere
1602  gctr(:)= [zero,zero,zero]
1603  if (ecut>tol6) then
1604    ! The average number of plane-waves in the cutoff sphere is given by:
1605    ! npwave = (2*ecut)**(3/2)*ucvol/(6*pi**2)
1606    ! The upper bound is calculated as npwwrk=int(scale * npwave) + pad
1607    npwave=NINT(ucvol*(two*ecut)**1.5_dp/(six*pi**2))
1608    npwwrk=NINT(DBLE(npwave)*scale)+pad
1609    ecut_trial=ecut
1610  else if (npw/=0) then
1611    ! npw is given in the input
1612    npwwrk=NINT(DBLE(npw)*scale)+pad
1613    ecut_trial=(six*pi**2*npw/ucvol)**two_thirds/two
1614  else
1615    ! If nsh is given in the input
1616    npwwrk=nsh*18+2*pad
1617    ecut_trial=(six*pi**2*nsh*18/ucvol)**two_thirds/two
1618  end if
1619 
1620  call initmpi_seq(MPI_enreg_seq)
1621 
1622  ABI_MALLOC(gvec,(3,npwwrk))
1623  ifound=0
1624  do while (ifound==0)
1625    !write(msg,'(a,f8.2)')' setshells : ecut_trial = ',ecut_trial
1626    !call wrtout(std_out,msg,'COLL')
1627    exchn2n3d=0 ! For the time being, no exchange of n2 and n3
1628 
1629    call kpgsph(ecut_trial,exchn2n3d,gmet,0,1,1,gvec,gctr,1,MPI_enreg_seq,npwwrk,npw_found)
1630 
1631    ABI_MALLOC(gnorm,(npw_found))
1632    ABI_MALLOC(insort,(npw_found))
1633 
1634    do ig=1,npw_found
1635      insort(ig)=ig
1636      gnorm(ig)=zero
1637      do ii=1,3
1638        gnorm(ig)=gnorm(ig)+(gvec(1,ig)*gprimd(ii,1)+&
1639                             gvec(2,ig)*gprimd(ii,2)+&
1640                             gvec(3,ig)*gprimd(ii,3))**2
1641      end do
1642    end do
1643    call sort_dp(npw_found,gnorm,insort,tol14)
1644 
1645    ABI_MALLOC(npw_sh,(npw_found))
1646    ABI_MALLOC(gnorm_sh,(npw_found))
1647    ABI_MALLOC(gvec_sh,(3,npw_found))
1648    npw_sh(:)=0
1649    gnorm_sh(:)=zero
1650    gvec_sh(:,:)=0
1651    ! Count the number of shells:
1652    ! (search for the G-vectors generating the others by symmetry)
1653    nsh_found=0
1654 
1655    do ig=1,npw_found
1656      eps=1.d-8*gnorm(ig)
1657      found=.FALSE.
1658      ish=1
1659      do while ((.not.found).and.(ish<=nsh_found))
1660        if (ABS(gnorm(ig)-gnorm_sh(ish))<=eps) then
1661          isym=1
1662          do while ((.not.found).and.(isym<=nsym))
1663            geq(:)=(symrel(1,:,isym)*gvec(1,insort(ig))+&
1664                   symrel(2,:,isym)*gvec(2,insort(ig))+&
1665                   symrel(3,:,isym)*gvec(3,insort(ig)))
1666 
1667            found=((geq(1)==gvec_sh(1,ish)).and.&
1668                   (geq(2)==gvec_sh(2,ish)).and.&
1669                   (geq(3)==gvec_sh(3,ish)))
1670            isym=isym+1
1671          end do
1672        end if
1673        ish=ish+1
1674      end do
1675      if (.not.found) then
1676        nsh_found=nsh_found+1
1677        gnorm_sh(nsh_found)=gnorm(ig)
1678        gvec_sh(:,nsh_found)=gvec(:,insort(ig))
1679        npw_sh(nsh_found)=1
1680      else
1681        ish=ish-1
1682        npw_sh(ish)=npw_sh(ish)+1
1683      end if
1684    end do
1685 
1686    ecut_found=two*pi**2*gnorm(npw_found)
1687 
1688    if(ecut>tol6) then
1689      ! ecut is given in the input
1690      !if (ecut_found<ecut-0.1) then
1691      !  write(msg,'(3a,e14.6,9a,e14.6,3a)')&
1692      !   'The value ecut',TRIM(tag),'=',ecut,' given in the input file leads to',ch10,&
1693      !   'the same values for nsh',TRIM(tag),' and npw',TRIM(tag),' as ecut',TRIM(tag),'=',ecut_found,ch10
1694      !  ABI_COMMENT(msg)
1695      !end if
1696      ifound=1
1697    else if (npw/=0) then
1698      ! If npw is given in the input
1699      if (npw_found==npw) then
1700        ecut_found=two*pi**2*gnorm(npw_found)
1701        ifound=1
1702      else if (npw_found>npw) then
1703        npw_found=0
1704        nsh_found=0
1705        do while (npw_found<npw)
1706          nsh_found=nsh_found+1
1707          npw_found=npw_found+npw_sh(nsh_found)
1708        end do
1709        ! check that the shell is closed
1710        if(npw_found>npw) then
1711          ! shell not closed
1712          npw_found=npw_found-npw_sh(nsh_found)
1713          nsh_found=nsh_found-1
1714          do while (ABS(gnorm_sh(nsh_found)-gnorm_sh(nsh_found+1))<0.000001)
1715            npw_found=npw_found-npw_sh(nsh_found)
1716            nsh_found=nsh_found-1
1717          end do
1718          write(msg,'(3a,i6,5a,i6,3a)')&
1719           'The value npw',TRIM(tag),'=',npw,' given in the input file does not close the shell',ch10,&
1720           'The lower closed-shell is obtained for a value npw',TRIM(tag),'=',npw_found,ch10,&
1721           'This value will be adopted for the calculation.',ch10
1722          ABI_WARNING(msg)
1723        end if
1724        ecut_found=two*pi**2*gnorm(npw_found)
1725        ifound=1
1726      end if
1727    else if (nsh/=0) then
1728      ! If nsh is given in the input
1729      if (nsh_found==nsh) then
1730        ecut_found=two*pi**2*gnorm(npw_found)
1731        ifound=1
1732      else if (nsh_found>nsh) then
1733        npw_found=0
1734        nsh_found=0
1735        do ish=1,nsh
1736          npw_found=npw_found+npw_sh(ish)
1737          nsh_found=nsh_found+1
1738        end do
1739        if (ABS(gnorm_sh(nsh_found)-gnorm_sh(nsh_found+1))<0.000001) then
1740          do while (ABS(gnorm_sh(nsh_found)-gnorm_sh(nsh_found+1))<0.000001)
1741            nsh_found=nsh_found+1
1742            npw_found=npw_found+npw_sh(nsh_found)
1743          end do
1744          write(msg,'(3a,i6,5a,i6,3a)')&
1745           'The value nsh',TRIM(tag),'=',nsh,' given in the input file corresponds to the same',ch10,&
1746           'cut-off energy as for closed-shell upto nsh',TRIM(tag),'=',nsh_found,ch10,&
1747           'This value will be adopted for the calculation.',ch10
1748          ABI_WARNING(msg)
1749        end if
1750        ecut_found=two*pi**2*gnorm(npw_found)
1751        ifound=1
1752      end if
1753    end if
1754 
1755    if (ifound==0) then
1756      ecut_trial=1.1*ecut_trial
1757      ABI_FREE(gnorm)
1758      ABI_FREE(gnorm_sh)
1759      ABI_FREE(gvec_sh)
1760      ABI_FREE(insort)
1761      ABI_FREE(npw_sh)
1762    else
1763      ! ecut was not provided as an input, then set it now!
1764      if (ecut<tol6) then
1765        ecut=ecut_found
1766      end if
1767      npw=npw_found
1768      nsh=nsh_found
1769    end if
1770 
1771  end do ! while(ifound==0)
1772 
1773  call destroy_mpi_enreg(MPI_enreg_seq)
1774 
1775  ABI_FREE(gnorm)
1776  ABI_FREE(gnorm_sh)
1777  ABI_FREE(gvec)
1778  ABI_FREE(gvec_sh)
1779  ABI_FREE(insort)
1780  ABI_FREE(npw_sh)
1781 
1782 end subroutine setshells

m_gsphere/get_irredg [ Functions ]

[ Top ] [ m_gsphere ] [ Functions ]

NAME

 get_irredg

FUNCTION

  Given a set of reciprocal lattice vectors, find the set of G"s generating the others by symmetry.

INPUTS

  nsym=number of symmetry operations
  pinv=-1 if time-reversal can be used, 1 otherwise
  npw_k=number of G vectors (for this k-point, as the set of G is k-centered)
  gcurr(3,npw_k)=the list of G vectors
  gprimd(3,3)=dimensional primitive translations for reciprocal space ($\textrm{bohr}^{-1}$)
  symrec(3,3,nsym)=symmetry operations in terms of reciprocal space primitive translations.

OUTPUT

  nbasek=number of irreducible G vectors found
  cnormk(npw_k)=first nbasek elements are the norm of each irreducible G-vector
  gbasek(3,npw_k)=first nbasek elements are the irreducible G vectors

NOTES

  The search can be optimized by looping over shells. See m_skw for a faster algo

SOURCE

1353 subroutine get_irredg(npw_k,nsym,pinv,gprimd,symrec,gcurr,nbasek,gbasek,cnormk)
1354 
1355 !Arguments ------------------------------------
1356 !scalars
1357  integer,intent(in) :: npw_k,nsym,pinv
1358  integer,intent(out) :: nbasek
1359 !arrays
1360  integer,intent(in) :: gcurr(3,npw_k),symrec(3,3,nsym)
1361  integer,intent(out) :: gbasek(3,npw_k)
1362  real(dp),intent(in) :: gprimd(3,3)
1363  real(dp),intent(out) :: cnormk(npw_k)
1364 
1365 !Local variables-------------------------------
1366 !scalars
1367  integer :: ig,irr,isym,jj
1368  real(dp) :: eps,norm
1369  logical :: found
1370 !arrays
1371  integer :: gbas(3),gcur(3),geq(3)
1372  real(dp) :: gcar(3)
1373 
1374 ! *************************************************************************
1375 
1376  DBG_ENTER("COLL")
1377 
1378  if (pinv/=1.and.pinv/=-1) then
1379    ABI_BUG(sjoin('pinv should be -1 or 1, however, pinv =', itoa(pinv)))
1380  end if
1381 
1382  ! Zero irred G vectors found, zeroing output arrays.
1383  nbasek = 0; cnormk(:) = zero; gbasek(:,:) = 0
1384 
1385  do ig=1,npw_k
1386    gcur(:) = gcurr(:,ig); norm = zero
1387    do jj=1,3
1388      gcar(jj)=gcur(1)*gprimd(jj,1)+gcur(2)*gprimd(jj,2)+gcur(3)*gprimd(jj,3)
1389      norm=norm+gcar(jj)**2
1390    end do
1391    eps = tol8 * norm; found = .False.; irr = 1
1392    do while (.not.found .and. irr <= nbasek)  ! This loop can be optimized by looping inside the shell.
1393      if (abs(norm - cnormk(irr)) <= eps) then
1394        gbas(:) = gbasek(:,irr); isym = 1
1395        do while (.not.found .and. isym <= nsym)
1396          geq(:) = matmul(symrec(:,:,isym),gcur)
1397          found = all(geq(:) == gbas(:))
1398          if (pinv == -1) found = (found .or. all(geq == -gbas)) ! For time-reversal
1399          isym = isym + 1
1400        end do
1401      end if
1402      irr = irr + 1
1403    end do
1404    if (.not. found) then
1405      nbasek = nbasek + 1; cnormk(nbasek) = norm; gbasek(:,nbasek) = gcur(:)
1406    end if
1407  end do
1408 
1409  DBG_EXIT("COLL")
1410 
1411 end subroutine get_irredg

m_gsphere/getfullg [ Functions ]

[ Top ] [ m_gsphere ] [ Functions ]

NAME

 getfullg

FUNCTION

  Reconstruct a G-sphere starting from a set of irreducible lattice vectors

INPUTS

  pinv=-1 if time-reversal can be used, 1 otherwise
  nsym=number of symmetry operations
  sizepw=Max expected number of G vectors in the shere
  symrec(3,3,nsym)=symmetry operation in reciprocal space
  nbase=number of irreducible G vectors
  gbase(3,nbase)=irreducible G-vectors
  cnorm(nbase)=norm of the irreducible G vectors (supposed not yet sorted)

OUTPUT

  maxpw=Number of G vectors found
  gbig(3,sizepw)=G vectors in the sphere packed in the first maxpw columns
  shlim(nbase)=number of G vectors within each shell
  ierr= Exit status, if /=0 the number of G vectors found exceeds sizepw

SIDE EFFECTS

NOTES

  cnorm is a bit redundant since it can be calculated from gbase. However this procedure
  is called by outkss in which cnorm is already calculated and we dont want to do it twice

SOURCE

1215 subroutine getfullg(nbase,nsym,pinv,sizepw,gbase,symrec,cnorm,maxpw,gbig,shlim,ierr)
1216 
1217 !Arguments ------------------------------------
1218 !scalars
1219  integer,intent(in) :: nbase,nsym,pinv,sizepw
1220  integer,intent(out) :: ierr,maxpw
1221 !arrays
1222  integer,intent(in) :: gbase(3,nbase),symrec(3,3,nsym)
1223  integer,intent(out) :: gbig(3,sizepw),shlim(nbase)
1224  real(dp),intent(inout) :: cnorm(nbase) !sort_dp can change cnorm
1225 
1226 !Local variables-------------------------------
1227 !scalars
1228  integer :: ibase,ig,ilim,ish,isym,itim
1229  logical :: found
1230  character(len=500) :: msg
1231 !arrays
1232  integer :: gcur(3),geq(3)
1233  integer,allocatable :: gshell(:,:),insort(:),nshell(:)
1234 
1235 ! *************************************************************************
1236 
1237  if (pinv/=1.and.pinv/=-1) then
1238    write(msg,'(a,i6)')&
1239 &   ' The argument pinv should be -1 or 1, however, pinv =',pinv
1240    ABI_BUG(msg)
1241  end if
1242  !
1243  ! === Reorder base g-vectors in order of increasing module ===
1244  ABI_MALLOC(insort,(nbase))
1245  do ibase=1,nbase
1246    insort(ibase)=ibase
1247  end do
1248  call sort_dp(nbase,cnorm,insort,tol14)
1249  !
1250  ! === Generate all stars of G-vectors ===
1251  ! Star of G is the set of all symetrical images of the vector
1252  ! gshell contains the symmetrical G at fixed gbase. No need to add an additional dimension
1253  ! or initialize to zero the array inside the loop over nbase as we loop over (ish<=nshell(ibase))
1254  ABI_MALLOC(nshell,(nbase))
1255  ABI_MALLOC(gshell,(3,2*nsym))
1256  !
1257  ! === Start with zero number of G vectors found ===
1258  maxpw=0 ; ierr=0
1259  do ibase=1,nbase
1260    !
1261    ! === Loop over all different modules of G ===
1262    ! * Start with zero G vectors found in this star
1263    nshell(ibase)=0
1264    gcur(:)=gbase(:,insort(ibase))
1265    !
1266    !  === Loop over symmetries ===
1267    do isym=1,nsym
1268      do itim=pinv,1,2
1269        geq(:)=itim*MATMUL(symrec(:,:,isym),gcur)
1270        !
1271        ! * Search for symetric of g and eventually add it:
1272        found=.FALSE. ; ish=1
1273        do while ((.not.found).and. (ish<=nshell(ibase)))
1274          found=ALL(geq(:)==gshell(:,ish))
1275          ish=ish+1
1276        end do
1277        if (.not.found) then
1278          nshell(ibase)=nshell(ibase)+1
1279          gshell(:,nshell(ibase))=geq(:)
1280        end if
1281      end do
1282    end do
1283    !
1284    ! * Was sizepw large enough?
1285    if ((maxpw+nshell(ibase))>sizepw) then
1286      write(msg,'(a,i6,2a)')&
1287 &     ' Number of G in sphere exceeds maximum allowed value =',sizepw,ch10,&
1288 &     ' check the value of sizepw in calling routine '
1289      ABI_WARNING(msg)
1290      ierr=1; RETURN
1291    end if
1292    !
1293    ! === Store this shell of Gs in a big array (gbig) ===
1294    do ig=1,nshell(ibase)
1295      gbig(:,ig+maxpw)=gshell(:,ig)
1296    end do
1297    maxpw=maxpw+nshell(ibase)
1298  end do ! ibase
1299  !
1300  ! === Compute number of G"s within each shell ===
1301  ilim=0
1302  do ibase=1,nbase
1303    ilim=ilim+nshell(ibase)
1304    shlim(ibase)=ilim
1305  end do
1306  !
1307  ! === Print out shell limits ===
1308  write(msg,'(3a)')&
1309 & ' Shells found:',ch10,&
1310 & ' number of shell    number of G vectors      cut-off energy [Ha] '
1311  call wrtout(std_out,msg,'COLL')
1312 
1313  do ibase=1,nbase
1314    write(msg,'(12x,i4,17x,i6,12x,f8.3)')ibase,shlim(ibase),two*pi**2*cnorm(ibase)
1315    call wrtout(std_out,msg,'COLL')
1316  end do
1317  write(msg,'(a)')ch10
1318  call wrtout(std_out,msg,'COLL')
1319  ABI_FREE(gshell)
1320  ABI_FREE(insort)
1321  ABI_FREE(nshell)
1322 
1323 end subroutine getfullg

m_gsphere/getkpgnorm [ Functions ]

[ Top ] [ m_gsphere ] [ Functions ]

NAME

 getkpgnorm

FUNCTION

  compute the norms of the k+G vectors

INPUTS

  gprimd(3,3)=metric tensor
  kg_k(3,npw_k)= G vectors, in reduced coordinates
  kpt(3)=k vector, in reduced coordinates
  npw_k=size of the G-vector set

OUTPUT

  kpgnorm(npw_k)=norms of the k+G vectors

SOURCE

2119 subroutine getkpgnorm(gprimd,kpt,kg_k,kpgnorm,npw_k)
2120 
2121 !Arguments ------------------------------------
2122 !scalars
2123  integer,intent(in) :: npw_k
2124 !arrays
2125  integer,intent(in) :: kg_k(3,npw_k)
2126  real(dp),intent(in) :: gprimd(3,3),kpt(3)
2127  real(dp),intent(out) :: kpgnorm(npw_k)
2128 
2129 !Local variables-------------------------------
2130 !scalars
2131  integer :: ipw
2132  real(dp) :: g11,g12,g13,g21,g22,g23,g31,g32,g33,k1,k2,k3,kpg1,kpg2,kpg3,rr,xx
2133  real(dp) :: yy,zz
2134 
2135 ! *************************************************************************
2136 
2137  k1=kpt(1) ; k2=kpt(2) ; k3=kpt(3)
2138  g11=gprimd(1,1)
2139  g12=gprimd(1,2)
2140  g13=gprimd(1,3)
2141  g21=gprimd(2,1)
2142  g22=gprimd(2,2)
2143  g23=gprimd(2,3)
2144  g31=gprimd(3,1)
2145  g32=gprimd(3,2)
2146  g33=gprimd(3,3)
2147 
2148 !Loop over all k+G
2149  do ipw=1,npw_k
2150 
2151 !  Load k+G
2152    kpg1=k1+dble(kg_k(1,ipw))
2153    kpg2=k2+dble(kg_k(2,ipw))
2154    kpg3=k3+dble(kg_k(3,ipw))
2155 
2156 !  Calculate module of k+G
2157    xx=g11*kpg1+g12*kpg2+g13*kpg3
2158    yy=g21*kpg1+g22*kpg2+g23*kpg3
2159    zz=g31*kpg1+g32*kpg2+g33*kpg3
2160    rr=sqrt(xx**2+yy**2+zz**2)
2161    kpgnorm(ipw) = rr
2162 
2163  end do ! ipw
2164 
2165 end subroutine getkpgnorm

m_gsphere/gsph_extend [ Functions ]

[ Top ] [ m_gsphere ] [ Functions ]

NAME

  gsph_extend

FUNCTION

  Construct a new gsphere_t with a larger cutoff energy
  while preserving the ordering of the first G-vectors stored in in_Gsph

INPUTS

OUTPUT

SOURCE

2032 subroutine gsph_extend(in_Gsph, Cryst, new_ecut, new_Gsph)
2033 
2034 !Arguments ------------------------------------
2035 !scalars
2036  class(gsphere_t),intent(in) :: in_Gsph
2037  type(crystal_t),intent(in) :: Cryst
2038  real(dp),intent(in) :: new_ecut
2039  class(gsphere_t),intent(out) :: new_Gsph
2040 
2041 !Local variables-------------------------------
2042 !scalars
2043  integer :: new_ng,in_ng,ig,ierr,sh
2044 !arrays
2045  integer,allocatable :: new_gvec(:,:)
2046 
2047 ! *********************************************************************
2048 
2049  call new_Gsph%init(Cryst, 0, ecut=new_ecut)
2050 
2051  if (new_Gsph%ng > in_Gsph%ng) then
2052 
2053    new_ng = new_Gsph%ng
2054    in_ng  = in_Gsph%ng
2055 
2056    ierr = 0
2057    do ig=1,in_ng
2058      if (ANY(new_Gsph%gvec(:,ig) /= in_Gsph%gvec(:,ig)) ) then
2059        ierr = ierr + 1
2060        write(std_out,*)" new_gvec, in_gvec",ig,new_Gsph%gvec(:,ig),in_Gsph%gvec(:,ig)
2061      end if
2062    end do
2063 
2064    if (ierr==0) RETURN
2065 
2066    ierr = 0
2067    do sh=1,in_Gsph%nsh
2068      if ( new_Gsph%shlim(sh) /= in_Gsph%shlim(sh) .or. &
2069 &         ABS(new_Gsph%shlen(sh)-in_Gsph%shlen(sh)) > tol12 ) then
2070        ierr = ierr + 1
2071        write(std_out,*)"new_shlim, in_shlim",sh,new_Gsph%shlim(sh),in_Gsph%shlim(sh)
2072        write(std_out,*)"new_shlen, in_shlen",sh,new_Gsph%shlen(sh),in_Gsph%shlen(sh)
2073      end if
2074    end do
2075    ABI_CHECK(ierr==0,"Wrong shells")
2076 
2077    ABI_MALLOC(new_gvec,(3,new_ng))
2078    new_gvec = new_Gsph%gvec
2079    new_gvec(:,1:in_ng) = in_Gsph%gvec
2080 
2081    call new_Gsph%free()
2082    call new_Gsph%init(Cryst, new_ng, gvec=new_gvec)
2083    ABI_FREE(new_gvec)
2084 
2085  else
2086    ierr = 0
2087    do ig=1,MIN(new_Gsph%ng,in_Gsph%ng)
2088      if (ANY(new_Gsph%gvec(:,ig) /= in_Gsph%gvec(:,ig)) ) then
2089        ierr = ierr + 1
2090        write(std_out,*)" new_gvec, in_gvec",ig,new_Gsph%gvec(:,ig),in_Gsph%gvec(:,ig)
2091      end if
2092    end do
2093    ABI_CHECK(ierr==0,"Fatal error")
2094  end if
2095 
2096 end subroutine gsph_extend

m_gsphere/gsph_fft_tabs [ Functions ]

[ Top ] [ m_gsphere ] [ Functions ]

NAME

 gsph_fft_tabs

FUNCTION

INPUTS

  Gsph<gsphere_t>=Info on the G-sphere
  g0(3)
  mgfft=MAXVAL(ngfft(1:3))
  ngfftf(18)=Info on the FFT mesh.

OUTPUT

  use_padfft=1 if padded FFT can be used, 0 otherwise.
  gmg0_gbound(2*mgfft+8,2)=Tables for improved zero-padded FFTS. Calculated only if use_padfft==1
  gmg0_ifft(Gsph%ng)=Index of G-G0 in the FFT mesh defined by ngfft.

NOTES

  The routine will stop if any G-G0 happens to be outside the FFT box.

SOURCE

473 subroutine gsph_fft_tabs(Gsph, g0, mgfft, ngfft, use_padfft, gmg0_gbound, gmg0_ifft)
474 
475 !Arguments ------------------------------------
476 !scalars
477  class(gsphere_t),intent(in) :: Gsph
478  integer,intent(in) :: mgfft
479  integer,intent(out) :: use_padfft
480 !arrays
481  integer,intent(in) :: g0(3),ngfft(18)
482  integer,intent(out) :: gmg0_gbound(2*mgfft+8,2),gmg0_ifft(Gsph%ng)
483 
484 !Local variables-------------------------------
485 !scalars
486  integer :: ig,ng,ierr
487  character(len=500) :: msg
488  type(MPI_type) :: MPI_enreg_seq
489 !arrays
490  integer,allocatable :: gmg0(:,:)
491  logical,allocatable :: kg_mask(:)
492 
493 ! *************************************************************************
494 
495  if (mgfft/=MAXVAL(ngfft(1:3))) then
496    ABI_ERROR("mgfft/-MAXVAL(ngfft(1:3)")
497  end if
498 
499  ng = Gsph%ng
500 
501  ierr=0; use_padfft=0
502  ABI_MALLOC(gmg0,(3,ng))
503  do ig=1,ng
504    gmg0(:,ig) = Gsph%gvec(:,ig)-g0
505    ! Consider possible wrap around errors.
506    if ( ANY(gmg0(:,ig)>ngfft(1:3)/2) .or. ANY(gmg0(:,ig)<-(ngfft(1:3)-1)/2) ) then
507      !gmg0_ifft(ig,ig01+mg0(1)+1,ig02+mg0(2)+1,ig03+mg0(3)+1) = 0
508      write(std_out,*)" outside FFT box ",gmg0(:,ig)
509      ierr=ierr+1
510    end if
511    if (ALL(gmg0(:,ig) == 0)) use_padfft=1
512  end do
513 
514  if (ierr/=0) then
515    write(msg,'(a,i0,a)')'Found ',ierr,' G-G0 vectors falling outside the FFT box. This is not allowed '
516    ABI_ERROR(msg)
517  end if
518  !
519  ! Evaluate the tables needed for the padded FFT performed in rhotwg. Note that we have
520  ! to pass G-G0 to sphereboundary instead of G as we need FFT results on the shifted G-sphere,
521  ! If Gamma is not inside G-G0 one has to disable FFT padding as sphereboundary will give wrong tables.
522  if (use_padfft == 1) call sphereboundary(gmg0_gbound,1,gmg0,mgfft,ng)
523 
524  call initmpi_seq(MPI_enreg_seq) ! No FFT parallelism.
525  call init_distribfft_seq(MPI_enreg_seq%distribfft,'c',ngfft(2),ngfft(3),'all')
526 
527  ABI_MALLOC(kg_mask, (ng))
528  call kgindex(gmg0_ifft, gmg0, kg_mask, MPI_enreg_seq, ngfft, ng)
529 
530  ABI_CHECK(ALL(kg_mask),"FFT para not yet implemented")
531  ABI_FREE(kg_mask)
532 
533  ABI_FREE(gmg0)
534  call destroy_mpi_enreg(MPI_enreg_seq)
535 
536 end subroutine gsph_fft_tabs

m_gsphere/gsph_free [ Functions ]

[ Top ] [ m_gsphere ] [ Functions ]

NAME

 gsph_free

FUNCTION

  Deallocate the memory in a gsphere_t data type.

INPUTS

   Gsph = datatype to be freed

SOURCE

719 subroutine gsph_free(Gsph)
720 
721 !Arguments ------------------------------------
722  class(gsphere_t),intent(inout) :: Gsph
723 
724 ! *************************************************************************
725 
726  DBG_ENTER("COLL")
727 
728  !@gsphere_t
729 
730 ! integer arrays.
731  ABI_SFREE(Gsph%g2sh)
732  ABI_SFREE(Gsph%gvec)
733  ABI_SFREE(Gsph%g2mg)
734  ABI_SFREE(Gsph%rottb)
735  ABI_SFREE(Gsph%rottbm1)
736  ABI_SFREE(Gsph%shlim)
737 
738  ABI_SFREE(Gsph%shlen)
739 
740 ! complex arrays
741  ABI_SFREE(Gsph%phmGt)
742  ABI_SFREE(Gsph%phmSGt)
743 
744  DBG_EXIT("COLL")
745 
746 end subroutine gsph_free

m_gsphere/gsph_g_idx [ Functions ]

[ Top ] [ m_gsphere ] [ Functions ]

NAME

 gsph_g_idx

FUNCTION

 Return the index of G in the sphere. zero if not in the sphere

INPUTS

  Gsph<gsphere_t>=Info on the G-sphere
  gg(3)=Reduced coordinates of the G-vector.

NOTES

  The function assumes that the G-vectors are ordered with increasing length.

SOURCE

767 pure function gsph_g_idx(Gsph, gg) result(g_idx)
768 
769 !Arguments ------------------------------------
770 !scalars
771  class(gsphere_t),intent(in) :: Gsph
772  integer :: g_idx
773 !arrays
774  integer,intent(in) :: gg(3)
775 
776 !Local variables-------------------------------
777 !scalars
778  integer :: ishbsc,igs,ige
779  real(dp) :: glen
780  logical :: found
781 
782 ! *************************************************************************
783 
784  ! * Use shells and bisect to find the star and stop index thus avoiding the storage of a table (ig1,ig2)
785  glen = two_pi*SQRT(DOT_PRODUCT(gg,MATMUL(Gsph%gmet,gg)))
786 
787  ishbsc = bisect(Gsph%shlen,glen)
788  if ( ANY(ishbsc==(/0,Gsph%nsh/)) ) then ! glen out of range.
789    g_idx=0; RETURN
790  end if
791 
792  igs = Gsph%shlim(ishbsc)
793  ige = Gsph%shlim(MIN(ishbsc+2,Gsph%nsh+1))-1
794 
795  g_idx=igs-1; found=.FALSE.
796  do while (.not.found .and. g_idx<ige)
797    g_idx=g_idx+1
798    found=(ALL(Gsph%gvec(:,g_idx)==gg(:)))
799  end do
800  if (.not.found) g_idx=0
801 
802 end function gsph_g_idx

m_gsphere/gsph_gmg_fftidx [ Functions ]

[ Top ] [ m_gsphere ] [ Functions ]

NAME

 gsph_gmg_fftidx

FUNCTION

 Return the index of G1-G2 in the FFT mesh defined by ngfft. zero if not found.

INPUTS

  Gsph<gsphere_t>=Info on the G-sphere
  ig1,ig2 index of g1 and g2 in the G-sphere.
  ngfft(18)=Info on the FFT mesh.

SOURCE

881 pure function gsph_gmg_fftidx(Gsph, ig1, ig2, ngfft) result(fft_idx)
882 
883 !Arguments ------------------------------------
884 !scalars
885  class(gsphere_t),intent(in) :: Gsph
886  integer,intent(in) :: ig1,ig2
887  integer :: fft_idx
888 !arrays
889  integer,intent(in) :: ngfft(18)
890 
891 !Local variables-------------------------------
892 !scalars
893  integer :: id1,id2,id3
894 !arrays
895  integer :: g1mg2(3)
896 
897 ! *************************************************************************
898 
899  g1mg2(:)=Gsph%gvec(:,ig1)-Gsph%gvec(:,ig2)
900 
901  ! Make sure G1-G2 is still in the FFT mesh.
902  ! MODULO wraps G1-G2 in the FFT box but the Fourier components are not periodic!
903  if (ANY(g1mg2(:)>ngfft(1:3)/2) .or. ANY(g1mg2(:)<-(ngfft(1:3)-1)/2)) then
904    fft_idx=0; RETURN
905  end if
906 
907  id1=MODULO(g1mg2(1),ngfft(1))
908  id2=MODULO(g1mg2(2),ngfft(2))
909  id3=MODULO(g1mg2(3),ngfft(3))
910  fft_idx= 1 + id1 + id2*ngfft(1) + id3*ngfft(1)*ngfft(2)
911 
912 end function gsph_gmg_fftidx

m_gsphere/gsph_gmg_idx [ Functions ]

[ Top ] [ m_gsphere ] [ Functions ]

NAME

 gsph_gmg_idx

FUNCTION

 Return the index of G1-G2 in the sphere. zero if not in the sphere

INPUTS

  Gsph<gsphere_t>=Info on the G-sphere
  ig1,ig2 index of g1 and g2 in the G-sphere.

NOTES

  The function assumes that the G-vectors are ordered with increasing length.

SOURCE

823 pure function gsph_gmg_idx(Gsph, ig1, ig2) result(ig1mg2)
824 
825 !Arguments ------------------------------------
826 !scalars
827  class(gsphere_t),intent(in) :: Gsph
828  integer,intent(in) :: ig1,ig2
829  integer :: ig1mg2
830 
831 !Local variables-------------------------------
832 !scalars
833  integer :: ishbsc,igs,ige
834  real(dp) :: difflen
835  logical :: found
836 !arrays
837  integer :: g1mg2(3)
838 
839 ! *************************************************************************
840 
841  g1mg2 = Gsph%gvec(:,ig1)-Gsph%gvec(:,ig2)
842 
843  ! * Use shells and bisect to find the star and stop index thus avoiding the storage of a table (ig1,ig2)
844  difflen = two_pi*SQRT(DOT_PRODUCT(g1mg2,MATMUL(Gsph%gmet,g1mg2)))
845 
846  ! FIXME It seems bisect is not portable, on my laptop test v5/t72 the number of skipped G-vectors is > 0
847  ishbsc = bisect(Gsph%shlen,difflen)
848  if ( ANY(ishbsc==(/0,Gsph%nsh/)) ) then ! difflen out of range.
849    ig1mg2=0; RETURN
850  end if
851 
852  igs = Gsph%shlim(ishbsc)
853  ige = Gsph%shlim(MIN(ishbsc+2,Gsph%nsh+1))-1
854 
855  ig1mg2=igs-1; found=.FALSE.
856  do while (.not.found .and. ig1mg2<ige)
857    ig1mg2=ig1mg2+1
858    found=(ALL(Gsph%gvec(:,ig1mg2)==g1mg2(:)))
859  end do
860  if (.not.found) ig1mg2=0
861 
862 end function gsph_gmg_idx

m_gsphere/gsph_in_fftbox [ Functions ]

[ Top ] [ m_gsphere ] [ Functions ]

NAME

 gsph_in_fftbox

FUNCTION

  Initialize the largest Gsphere contained in the FFT box.

INPUTS

  Cryst<crystal_t> = Info on unit cell and its symmetries.
  ngfft(18)=Info on the FFT box.

OUTPUT

  Gsph<gsphere_t>=Data type containing information related to the set of G vectors
   completetly initialized in output.

SOURCE

558 subroutine gsph_in_fftbox(Gsph, Cryst, ngfft)
559 
560 !Arguments ------------------------------------
561 !scalars
562  class(gsphere_t),intent(out) :: Gsph
563  type(crystal_t),intent(in) :: Cryst
564 !arrays
565  integer,intent(in) :: ngfft(18)
566 
567 !Local variables-------------------------------
568 !scalars
569  integer :: dir1,dir2,dir3,npw,ig,ist
570  real(dp) :: ecut,trial_ene
571 !arrays
572  integer :: n1_max(3),n2_max(3),n3_max(3),vec(3)
573  integer,allocatable :: gvec(:,:)
574 
575 !************************************************************************
576 
577  ! Find ecut for the largest G-sphere contained in the FFT box.
578  n1_max(1) = -(ngfft(1)-1)/2
579  n2_max(1) = -(ngfft(2)-1)/2
580  n3_max(1) = -(ngfft(3)-1)/2
581 
582  n1_max(2) = 0
583  n2_max(2) = 0
584  n3_max(2) = 0
585 
586  n1_max(3) = ngfft(1)/2
587  n2_max(3) = ngfft(2)/2
588  n3_max(3) = ngfft(3)/2
589 
590  ecut = HUGE(one)
591  do dir3=1,3
592    vec(3) = n1_max(dir3)
593    do dir2=1,3
594      vec(2) = n2_max(dir2)
595      do dir1=1,3
596        vec(1) = n1_max(dir1)
597        if (ANY(vec/=0)) then
598          trial_ene = half * normv(vec,Cryst%gmet,"G")**2
599          ecut = MIN(ecut,trial_ene)
600          !write(std_out,*)vec(:),trial_ene
601        end if
602      end do
603    end do
604  end do
605  !
606  ! Init sphere from ecut.
607  call Gsph%init(Cryst, 0, ecut=ecut)
608  !
609  ! Make sure that Gsph does not contain G vectors outside the FFT box.
610  ! kpgsph might return G whose energy is larger than the input ecut.
611  npw = Gsph%ng
612  star_loop: do ist=1,Gsph%nsh-1
613    do ig=Gsph%shlim(ist),Gsph%shlim(ist+1)
614      if ( ANY(Gsph%gvec(:,ig)>ngfft(1:3)/2) .or. ANY(Gsph%gvec(:,ig)<-(ngfft(1:3)-1)/2) ) then
615        npw = Gsph%shlim(ist)-1  ! Gsph exceeds the FFT box. Only the shells up to npw will be used.
616        EXIT star_loop
617      end if
618    end do
619  end do star_loop
620 
621  if (npw<Gsph%ng) then
622    ABI_COMMENT("Have to reinit Gpshere")
623    ABI_MALLOC(gvec,(3,npw))
624    gvec = Gsph%gvec(:,1:npw)
625    call Gsph%free()
626    call Gsph%init(Cryst, npw, gvec=gvec)
627    ABI_FREE(gvec)
628  end if
629 
630 end subroutine gsph_in_fftbox

m_gsphere/gsph_init [ Functions ]

[ Top ] [ m_gsphere ] [ Functions ]

NAME

 gsph_init

FUNCTION

  Main creation method for the Gvectors data type

INPUTS

  Cryst<crystal_t> = Info on unit cell and its symmetries
  ng=number of G vectors, needed only if gvec is passed.
  [gvec(3,ng)]=coordinates of G vectors
  [ecut]=Cutoff energy for G-sphere. gvec and ecut are mutually exclusive.

OUTPUT

  Gsph<gsphere_t>=Data type containing information related to the set of G vectors
   completetly initialized in output.

NOTES

  gvec are supposed to be ordered with increasing norm.

SOURCE

281 subroutine gsph_init(Gsph, Cryst, ng, gvec, ecut)
282 
283 !Arguments ------------------------------------
284 !scalars
285  class(gsphere_t),intent(out) :: Gsph
286  integer,intent(in) :: ng
287  real(dp),optional,intent(in) :: ecut
288  type(crystal_t),target,intent(in) :: Cryst
289 
290 !arrays
291  integer,optional,intent(in) :: gvec(3,ng)
292 !Local variables-------------------------------
293 !scalars
294  integer,parameter :: nkpt1=1
295  integer :: ig,isearch,img,ish,isym,nsh,nsym,timrev,pinv,g1,g2,g3,ss,ee
296  real(dp) :: eps,norm,norm_old,max_ecut,gsq
297 !arrays
298  real(dp),parameter :: k_gamma(3)=(/zero,zero,zero/)
299  integer :: sg(3),gsearch(3)
300  integer,allocatable :: shlim(:)
301  integer,pointer :: symrec(:,:,:),gvec_ptr(:,:)
302  real(dp) :: kptns1(3,nkpt1)
303  real(dp),allocatable :: shlen(:)
304  real(dp),pointer :: tnons(:,:)
305 
306 !************************************************************************
307 
308  DBG_ENTER("COLL")
309 
310  !@gsphere_t
311  ! === Copy info on symmetries ===
312  nsym   =  Cryst%nsym
313  timrev =  Cryst%timrev
314  symrec => Cryst%symrec
315  tnons  => Cryst%tnons
316  !
317  ! === Initialize the object ===
318  Gsph%istwfk = 1           ! Time reversal is not used here.
319  Gsph%nsym   = nsym
320  Gsph%timrev = timrev
321 
322  Gsph%gmet   = Cryst%gmet
323  Gsph%gprimd = Cryst%gprimd
324 
325  if (PRESENT(gvec)) then
326    if (PRESENT(ecut)) then
327      ABI_BUG("ecut cannot be present when gvec is used")
328    end if
329    Gsph%ng= ng
330    ABI_MALLOC(Gsph%gvec,(3,ng))
331    Gsph%gvec=gvec
332    !
333    ! Calculate cutoff energy.of the sphere.
334    max_ecut=-one
335    do ig=1,ng
336      g1=gvec(1,ig)
337      g2=gvec(2,ig)
338      g3=gvec(3,ig)
339      gsq=       Cryst%gmet(1,1)*g1**2+Cryst%gmet(2,2)*g2**2+Cryst%gmet(3,3)*g3**2+ &
340 &          two*(Cryst%gmet(1,2)*g1*g2+Cryst%gmet(1,3)*g1*g3+Cryst%gmet(2,3)*g2*g3)
341      max_ecut=MAX(max_ecut,gsq)
342    end do
343    max_ecut=two*max_ecut*pi**2
344    Gsph%ecut= max_ecut
345 
346  else
347    ! To be consistent with the previous implementation.
348    ABI_WARNING("Init from ecut has to be tested")
349    !call setshells(ecut,npw,nsh,nsym,Cryst%gmet,Cryst%gprimd,Cryst%symrel,tag,Cryst%ucvol)
350    Gsph%ecut = ecut
351    pinv=+1; kptns1(:,1)=k_gamma
352    call merge_and_sort_kg(nkpt1,kptns1,ecut,Cryst%nsym,pinv,Cryst%symrel,Cryst%gprimd,gvec_ptr,0)
353    Gsph%ng = SIZE(gvec_ptr,DIM=2)
354    ABI_MALLOC(Gsph%gvec, (3,Gsph%ng))
355    Gsph%gvec = gvec_ptr
356    ABI_FREE(gvec_ptr)
357  end if
358  !
359  ! Calculate phase exp{-i2\pi G.\tau}
360  ABI_MALLOC(Gsph%phmGt, (Gsph%ng,nsym))
361  do isym=1,nsym
362    do ig=1,Gsph%ng
363     Gsph%phmGt(ig, isym) = EXP(-j_dpc*two_pi*DOT_PRODUCT(Gsph%gvec(:,ig), tnons(:,isym)))
364    end do
365  end do
366  !
367  ! === Calculate phase phsgt= exp{-i2\pi SG\cdot t} ===
368  ! TODO Here we can store only one of this arrays but I have to rewrite screeening!
369  ABI_MALLOC(Gsph%phmSGt,(Gsph%ng,nsym))
370  do ig=1,Gsph%ng
371    do isym=1,nsym
372      sg=MATMUL(symrec(:,:,isym),Gsph%gvec(:,ig))
373      Gsph%phmSGt(ig,isym)=EXP(-j_dpc*two_pi*DOT_PRODUCT(sg,tnons(:,isym)))
374    end do
375  end do
376  !
377  ! === Calculate number of shells and corresponding starting index ===
378  ! * Shells are useful to speed up search algorithms see e.g setup_G_rotation.
379  ! * The last shell ends at ng+1, thus gvec is supposed to be closed.
380 
381  ABI_CHECK(ALL(Gsph%gvec(1:3,1)==0),'First G must be 0')
382 
383  ABI_MALLOC(Gsph%g2sh,(Gsph%ng))
384  Gsph%g2sh(1)=1 ! This table is useful if we dont loop over shell
385 
386  ! For each shell, gives the index of the initial G-vector.
387  ABI_MALLOC(shlim,(Gsph%ng+1))
388  shlim(1)=1
389 
390  ! For each shell, gives the radius of the shell.
391  ABI_MALLOC(shlen,(Gsph%ng))
392  shlen(1)=zero
393 
394  nsh=1; norm_old=zero
395  do ig=2,Gsph%ng
396    norm=two_pi*SQRT(DOT_PRODUCT(Gsph%gvec(:,ig),MATMUL(Cryst%gmet,Gsph%gvec(:,ig))))
397    eps=norm*tol8
398    if (ABS(norm-norm_old)>eps) then
399      norm_old = norm; nsh = nsh + 1
400      shlim(nsh)=ig
401      shlen(nsh)=norm
402    end if
403    Gsph%g2sh(ig)=nsh
404  end do
405  shlim(nsh+1)=Gsph%ng+1
406 
407  ! === Save info on the shells ===
408  Gsph%nsh=nsh
409  ABI_MALLOC(Gsph%shlim,(nsh+1))
410  Gsph%shlim=shlim(1:nsh+1)
411  ABI_MALLOC(Gsph%shlen,(nsh  ))
412  Gsph%shlen=shlen(1:nsh)
413  ABI_FREE(shlim)
414  ABI_FREE(shlen)
415 
416  ! Calculate tables for rotated G"s
417  ABI_MALLOC(Gsph%rottb  , (Gsph%ng,timrev,nsym))
418  ABI_MALLOC(Gsph%rottbm1, (Gsph%ng,timrev,nsym))
419 
420  call setup_G_rotation(nsym, symrec, timrev, Gsph%ng, Gsph%gvec,&
421    Gsph%g2sh, Gsph%nsh, Gsph%shlim, Gsph%rottb, Gsph%rottbm1)
422 
423  ! Store Mapping G --> -G
424  ! (we use a specialized table instead of rootb since rottb assumes time-reversal symmetry.
425  ABI_MALLOC(gsph%g2mg, (gsph%ng))
426 
427  do ig=1,gsph%ng
428    ish=gsph%g2sh(ig)
429    ss=gsph%shlim(ish); ee=gsph%shlim(ish+1)-1
430    gsearch = -gsph%gvec(:,ig)
431    img = 0
432    ! Loop on shells to speed up the search.
433    do isearch=ss,ee
434      if (all(gsph%gvec(:,isearch) == gsearch)) then
435        img = isearch; exit
436      end if
437    end do
438    if (img==0) ABI_ERROR("Cannot find -G in G-sphere!")
439    gsph%g2mg(ig) = img
440  end do
441 
442  !call Gsph%print(unit=std_out,prtvol=1)
443 
444  DBG_EXIT("COLL")
445 
446 end subroutine gsph_init

m_gsphere/gsph_print [ Functions ]

[ Top ] [ m_gsphere ] [ Functions ]

NAME

 gsph_print

FUNCTION

  Print the content of a gvectors data type

INPUTS

  Gsph<gsphere_t>=Info on the G-sphere
  unit=the unit number for output
  prtvol = verbosity level
  mode_paral =either "COLL" or "PERS"

OUTPUT

  Only writing.

SOURCE

653 subroutine gsph_print(Gsph, unit, prtvol, mode_paral)
654 
655 !Arguments ------------------------------------
656 !scalars
657  class(gsphere_t),intent(in) :: Gsph
658  integer,intent(in),optional :: prtvol,unit
659  character(len=4),intent(in),optional :: mode_paral
660 
661 !Local variables-------------------------------
662 !scalars
663  integer :: ish,nsc,my_unt,my_prtvol
664  real(dp) :: fact,kin
665  character(len=4) :: my_mode
666  character(len=500) :: msg
667 
668 ! *************************************************************************
669 
670  my_unt    =std_out; if (PRESENT(unit      )) my_unt    =unit
671  my_prtvol=0       ; if (PRESENT(prtvol    )) my_prtvol=prtvol
672  my_mode   ='COLL' ; if (PRESENT(mode_paral)) my_mode   =mode_paral
673 
674  write(msg,'(3a,2(a,i8,a))')ch10,&
675    ' ==== Info on the G-sphere ==== ',ch10,&
676    '  Number of G vectors ... ',Gsph%ng,ch10,&
677    '  Number of shells ...... ',Gsph%nsh,ch10
678  call wrtout(my_unt,msg,my_mode)
679 
680  SELECT CASE (Gsph%timrev)
681  CASE (1)
682    call wrtout(my_unt,' Time reversal symmetry cannot be used',my_mode)
683  CASE (2)
684    call wrtout(my_unt,' Time reversal symmetry is used',my_mode)
685  CASE DEFAULT
686    ABI_BUG("Wrong timrev")
687  END SELECT
688 
689  if (my_prtvol/=0) then
690    fact=half*two_pi**2
691    write(msg,'(a)')
692    call wrtout(my_unt,' Shell   Tot no. of Gs   Cutoff [Ha]',my_mode)
693    do ish=1,Gsph%nsh
694      nsc=Gsph%shlim(ish+1)-1
695      kin=half*Gsph%shlen(ish)**2
696      write(msg,'(2x,i4,10x,i6,5x,f8.3)')ish,nsc,kin
697      call wrtout(my_unt,msg,'COLL')
698    end do
699    call wrtout(my_unt,ch10,my_mode)
700  end if
701 
702 end subroutine gsph_print

m_gsphere/gsphere_t [ Types ]

[ Top ] [ m_gsphere ] [ Types ]

NAME

 gsphere_t

FUNCTION

 The gsphere_t data type contains information related to the set of G vectors
 used during a screening or a GW calculation, as well as symmetry tables relating
 these vectors. Presently the following quantities are stored

 1) The reduced coordinates of the G vectors (arrays gvec)
 2) Tables giving the correspondence between a G-vector and its rotated image
    through a symmetry operation in reciprocal space.
 3) List of the irreducible G pairs
 4) Tables giving, for each pair in the full reciprocal space, the corresponding
    irreducible pair as well as the symmetry operation in reciprocal space

 Note that, unlike the GS part, the basis set does not depend on the k-point.

NOTES

 To indicate the indices in the arrays grottb, grottbm1 we use the following notation:

  g defines the index of the reciprocal lattice vector in the array gvec
  s  indicates the index of the symmetry operation in reciprocal space
  i  can  be one or two. 1 is used to indicate the identity operator

SOURCE

 89  type,public :: gsphere_t
 90 
 91   integer :: ng
 92   ! Total number of G vectors in the sphere taking into account umklapps
 93   ! it defines the size of the array gvec and it accounts for possible umklapps for which
 94   ! one has to shift the sphere.
 95 
 96   ! TODO: The sphere should be enlarged in gpairs_init using mg0 and (ecut|ng) as input.
 97   ! For the time being we keep the old implementation.
 98   !%integer :: ng_eff
 99   ! Effective number of G vectors, i.e. the number of G in the smaller sphere without umklapps.
100   ! ng_eff<=ng and should be used to loop over the elements of (chi0|epsilon|W).
101   !
102   ! TODO: Add info on FFT including zero-padding algorithm.
103   ! table must be recalculated for each G0 and rho_tw_g should accept gpshere in input.
104 
105   integer :: nsh                   ! Number of shells
106   integer :: nsym                  ! The number of symmetry operations
107   integer :: timrev                ! 2 if time-reversal is used, 1 otherwise
108   integer :: istwfk=1              ! Storage mode. At present time-reversal is not used.
109 
110   !integer :: mg0(3)=0
111   ! For each reduced direction gives the max G0 component to account for umklapp processes.
112 
113   real(dp) :: ecut
114   ! Cutoff energy of the sphere.
115 
116   real(dp) :: gmet(3,3)
117   ! Reciprocal space metric ($\textrm{bohr}^{-2}$).
118 
119   real(dp) :: gprimd(3,3)
120   ! Dimensional reciprocal space primitive translations (bohr^{-1})
121 
122   integer,allocatable :: g2sh(:)
123   ! g2sh(ng)
124   ! For each G, it gives the index of the shell to which it belongs.
125 
126   integer,allocatable :: gvec(:,:)
127   ! gvec(3,ng)
128   ! Reduced coordinates of G vectors.
129 
130   integer,allocatable :: g2mg(:)
131   ! g2mg(ng)
132   ! Correspondence G --> -G
133 
134   integer,allocatable :: rottb(:,:,:)
135   ! rottb(ng,timrev,nsym)
136   ! rottb(G,I,S) is the index of (SI) G in the array gvec
137   ! where I is either the identity or the inversion.
138 
139   integer,allocatable :: rottbm1(:,:,:)
140   ! rottb(ng,timrev,nsym)
141   ! rottbm1(G,I,S) is the index of IS{^-1} G in the array gvec
142 
143   integer,allocatable :: shlim(:)
144   ! shlim(nsh+1)
145   ! Index of the first G vector in each shell, =ng+1 for nsh+1
146 
147   real(dp),allocatable :: shlen(:)
148   ! shlen(nsh)
149   ! Radius of each shell.
150 
151   !TODO switch to dpc
152   complex(gwpc),allocatable :: phmGt(:,:)
153   ! phmGt(ng,nsym)
154   ! Phase factor e^{-i2\pi(G.\tau)} where $\tau$ is the fractional translation associated to isym.
155 
156   complex(gwpc),allocatable :: phmSGt(:,:)
157   ! phmSGt(ng,nsym)
158   ! Phase factor e^{-i2\pi(SG.\tau)} where S is one of the symmetry properties in reciprocal space.
159 
160   contains
161 
162    procedure  :: init        => gsph_init           ! Initialize the G-sphere.
163    procedure  :: fft_tabs    => gsph_fft_tabs       ! Returns useful tables for FFT (with or without padding).
164    procedure  :: in_fftbox   => gsph_in_fftbox      ! Initialize the largest Gsphere contained in the FFT box.
165    procedure  :: print       => gsph_print          ! Printout of basic dimensions.
166    procedure  :: free        => gsph_free           ! Free memory allocated in the object.
167    procedure  :: g_idx       => gsph_g_idx          ! Returns the index of G from its reduced coordinates.
168    procedure  :: gmg_idx     => gsph_gmg_idx        ! Returns the index of G1-G2 from their indices
169    procedure  :: gmg_fftidx  => gsph_gmg_fftidx     ! Returns the index of G1-G2 in the FFT mesh defined by ngfft.
170    procedure  :: extend      => gsph_extend         ! Construct a new gsphere_t with a larger cutoff energy
171 
172  end type gsphere_t

m_gsphere/kg_map [ Functions ]

[ Top ] [ m_gsphere ] [ Functions ]

NAME

  kg_map

FUNCTION

  Compute the mapping between two lists of g-vectors.

INPUTS

   npw1, kg1(3,npw1)=First list of G-vectors
   npw2, kg2(3,npw2)=Second list of G-vectors

OUTPUT

   g2g1(npw2) = Mapping kg2 index --> kg1 index.
                Set to 0 if kg2(:,ig) not in kg1
   nmiss = Number of G-vectors in kg2 not found in kg1

SOURCE

1805 subroutine kg_map(npw1, kg1, npw2, kg2, g2g1, nmiss)
1806 
1807 !Arguments ------------------------------------
1808 !scalars
1809  integer,intent(in) :: npw1,npw2
1810  integer,intent(out) :: nmiss
1811 !arrays
1812  integer,intent(in) :: kg1(3,npw1),kg2(3,npw2)
1813  integer,intent(out) :: g2g1(npw2)
1814 
1815 !Local variables ------------------------------
1816 !scalars
1817  integer :: ii,ipw,i1,i2,i3,n1,n2,n3
1818 !arrays
1819  integer :: gmax(3),g1_max(3),g2_max(3)
1820  integer,allocatable :: iwork(:,:,:)
1821 
1822 !************************************************************************
1823 
1824  g1_max = maxval(abs(kg1))
1825  g2_max = maxval(abs(kg2))
1826  do ii=1,3
1827    gmax(ii) = max(g1_max(ii), g2_max(ii))
1828  end do
1829  gmax = 2*gmax + 1
1830  n1 = gmax(1); n2 = gmax(2); n3 = gmax(3)
1831 
1832  ABI_MALLOC(iwork, (n1, n2, n3))
1833 
1834  ! Insert kg1 into work with extra 0 s around outside:
1835  iwork = 0
1836  do ipw=1,npw1
1837    i1 = kg1(1,ipw); if (i1<0) i1=i1+n1; i1=i1+1
1838    i2 = kg1(2,ipw); if (i2<0) i2=i2+n2; i2=i2+1
1839    i3 = kg1(3,ipw); if (i3<0) i3=i3+n3; i3=i3+1
1840    iwork(i1,i2,i3) = ipw
1841  end do
1842 
1843  g2g1 = 0; nmiss = 0
1844  do ipw=1,npw2
1845    i1 = kg2(1,ipw); if (i1<0) i1=i1+n1; i1=i1+1
1846    i2 = kg2(2,ipw); if (i2<0) i2=i2+n2; i2=i2+1
1847    i3 = kg2(3,ipw); if (i3<0) i3=i3+n3; i3=i3+1
1848    g2g1(ipw) = iwork(i1,i2,i3)
1849    if (g2g1(ipw) == 0) nmiss = nmiss + 1
1850  end do
1851 
1852  ABI_FREE(iwork)
1853 
1854 end subroutine kg_map

m_gsphere/make_istwk_table [ Functions ]

[ Top ] [ m_gsphere ] [ Functions ]

NAME

 make_istwfk_table

FUNCTION

INPUTS

  ng1,ng2,ng3

OUTPUT

NOTES

   Useful relations:
     u_k(G) = u_{k+G0}(G-G0); u_{-k}(G) = u_k(G)^*
   and therefore:
     u_{G0/2}(G) = u_{G0/2}(-G-G0)^*.

SOURCE

1878 subroutine make_istwfk_table(istwf_k,ng1,ng2,ng3,ig1_inver,ig2_inver,ig3_inver)
1879 
1880 !Arguments ------------------------------------
1881 !scalars
1882  integer,intent(in) :: ng1,ng2,ng3,istwf_k
1883 !arrays
1884  integer,intent(out) :: ig1_inver(ng1),ig2_inver(ng2),ig3_inver(ng3)
1885 
1886 !Local variables ------------------------------
1887 !scalars
1888  integer :: i1,i2,i3
1889  character(len=500) :: msg
1890 
1891 !************************************************************************
1892 
1893 ! Initialize the inverse coordinates
1894  select case (istwf_k)
1895 
1896  case (1)
1897    ig1_inver(1)=1
1898    do i1=2,ng1
1899      ig1_inver(i1)=ng1+2-i1
1900    end do
1901    ig2_inver(1)=1
1902    do i2=2,ng2
1903      ig2_inver(i2)=ng2+2-i2
1904    end do
1905    ig3_inver(1)=1
1906    do i3=2,ng3
1907      ig3_inver(i3)=ng3+2-i3
1908    end do
1909 
1910  case (2:8)
1911    if (istwf_k==2 .or. istwf_k==4 .or. istwf_k==6 .or. istwf_k==8) then
1912      ig1_inver(1)=1
1913      do i1=2,ng1
1914        ig1_inver(i1)=ng1+2-i1
1915      end do
1916    else
1917      do i1=1,ng1
1918        ig1_inver(i1)=ng1+1-i1
1919      end do
1920    end if
1921    if (istwf_k>=2 .and. istwf_k<=5) then
1922      ig2_inver(1)=1
1923      do i2=2,ng2
1924        ig2_inver(i2)=ng2+2-i2
1925      end do
1926    else
1927      do i2=1,ng2
1928        ig2_inver(i2)=ng2+1-i2
1929      end do
1930    end if
1931    if (istwf_k==2 .or. istwf_k==3 .or. istwf_k==6 .or. istwf_k==7) then
1932      ig3_inver(1)=1
1933      do i3=2,ng3
1934        ig3_inver(i3)=ng3+2-i3
1935      end do
1936    else
1937      do i3=1,ng3
1938        ig3_inver(i3)=ng3+1-i3
1939      end do
1940    end if
1941 
1942  case default
1943    write(msg,'(a,i0)')" Wrong value for istwf_k: ",istwf_k
1944    ABI_ERROR(msg)
1945  end select
1946 
1947 end subroutine make_istwfk_table

m_gsphere/merge_and_sort_kg [ Functions ]

[ Top ] [ m_gsphere ] [ Functions ]

NAME

  merge_and_sort_kg

FUNCTION

  This routine merges a set of k-centered G-spheres of cutoff energy ecut and
  returns a Gamma-centered G-spheres. The elements in the final G-spheres are packed with increasing module.

INPUTS

  nkpt=Number of k-points
  kptns(3,nkpt)=The k-points in reduced coordinates defining the k-centered G-spheres.
  ecut=Cutoff energy for the k-centered G-spheres.
  nsym2=Number of symmetry operations.
  pinv=-1 if time-reversal can be used, 1 otherwise
  symrel2(3,3,nsym2)=symmetry operations in real space.
  gprimd(3,3)=dimensional primitive translations for reciprocal space ($\textrm{bohr}^{-1}$)
  prtvol=Flag defining the verbosity level.

SIDE EFFECTS

  gbig(:,:)
    in input : pointer to NULL
    in output: gbig(3,1:npw) contains the set of G-vectors ordered by shell obtained by
               merging the k-centered sphere.
  shlim_p(:)
    in input : pointer to NULL
    in output: shlim_p(nbase)=Cumulative number of G-vectors for each shell.
               where nbase is the number of irreducible G"s found.

SOURCE

 947 subroutine merge_and_sort_kg(nkpt,kptns,ecut,nsym2,pinv,symrel2,gprimd,gbig,prtvol,shlim_p)
 948 
 949 !Arguments ------------------------------------
 950 !scalars
 951  integer,intent(in) :: nkpt,nsym2,pinv,prtvol
 952  real(dp),intent(in) :: ecut
 953 !arrays
 954  integer,intent(in) :: symrel2(3,3,nsym2)
 955  real(dp),intent(in) :: kptns(3,nkpt),gprimd(3,3)
 956  integer,pointer :: gbig(:,:)
 957  integer,optional,pointer :: shlim_p(:)
 958 
 959 !Local variables-------------------------------
 960 !scalars
 961  integer,parameter :: mkmem_=1
 962  integer :: ikg,ig,ikpt,nbase,sizepw,in,maxpw,is,iinv,ish,ilim,mpw
 963  integer :: exchn2n3d,istwf_k,onpw_k,ierr,npw_k,ii,isym,sizeold
 964  logical :: found
 965  character(len=500) :: msg
 966  type(MPI_type) :: MPI_enreg_seq
 967 !arrays
 968  integer :: gcur(3),geq(3)
 969  integer :: symrec2t(3,3,nsym2)
 970  integer :: dum_kg(3,0)
 971  integer,allocatable :: gbase(:,:),gbasek(:,:,:)
 972  integer,allocatable :: gcurr(:,:),gshell(:,:),insort(:),gtmp(:,:)
 973  integer,allocatable :: nbasek(:),nshell(:),shlim(:)
 974  integer,allocatable :: npwarr(:)
 975  real(dp) :: kpoint(3),gmet(3,3)
 976  real(dp),allocatable :: cnorm(:),cnormk(:,:),ctmp(:)
 977 
 978 ! *********************************************************************
 979 
 980  ! * Fake MPI_type for the sequential part.
 981  ! This routine should not be parallelized as communicating gbig and other
 982  ! tables takes more time than recalculating them in sequential.
 983  call initmpi_seq(MPI_enreg_seq)
 984 
 985 !Compute reciprocal space metrics
 986  do ii=1,3
 987    gmet(ii,:)=gprimd(1,ii)*gprimd(1,:)+&
 988 &   gprimd(2,ii)*gprimd(2,:)+&
 989 &   gprimd(3,ii)*gprimd(3,:)
 990  end do
 991 
 992  ! * Here we use TRANSPOSE(symrel2) instead of the more intuitive symrel2^{-1t} for historical reasons
 993  ! It does not affect the results since in the code below we only check the module of G
 994  do isym=1,nsym2
 995    symrec2t(:,:,isym)=TRANSPOSE(symrel2(:,:,isym))
 996  end do
 997  !
 998  ! ==============================================
 999  ! ==== Find irreducible G-vectors at each k ====
1000  ! ==============================================
1001 
1002  ABI_MALLOC(npwarr,(nkpt))
1003  exchn2n3d=0; ikg=0
1004  do ikpt=1,nkpt
1005    kpoint=kptns(:,ikpt); istwf_k=1
1006    call kpgsph(ecut,exchn2n3d,gmet,ikg,0,istwf_k,dum_kg,kpoint,0,MPI_enreg_seq,0,npwarr(ikpt))
1007  end do
1008  mpw = MAXVAL(npwarr)
1009 
1010  ABI_MALLOC(nbasek,(nkpt))
1011  ABI_MALLOC(gbasek,(3,mpw,nkpt))
1012  ABI_MALLOC(cnormk,(mpw,nkpt))
1013  nbasek=0     ! # of irreducible G at each k.
1014  cnormk=zero  ! Norm of each irreducible G.
1015  gbasek=0     ! The set of irreducible G"s at each k.
1016 
1017  do ikpt=1,nkpt
1018 
1019    kpoint = kptns(:,ikpt)
1020    npw_k  = npwarr(ikpt)
1021 
1022    exchn2n3d=0; ikg=0; istwf_k=1
1023    ABI_MALLOC(gcurr,(3,npw_k))
1024    call kpgsph(ecut,exchn2n3d,gmet,ikg,0,istwf_k,gcurr,kpoint,mkmem_,MPI_enreg_seq,npw_k,onpw_k)
1025 
1026    if (ANY(gcurr(:,1)/=0)) then
1027      ABI_BUG("gcurr(:,1)/=0")
1028    end if
1029    !
1030    ! * Search for the G"s generating the others by symmetry.
1031    !  NB: Here we use symrec2t=TRANSPOSE(symrel2) for historical reasons, see note above
1032    call get_irredg(npw_k,nsym2,pinv,gprimd,symrec2t,gcurr,nbasek(ikpt),gbasek(:,:,ikpt),cnormk(:,ikpt))
1033 
1034    ABI_FREE(gcurr)
1035  end do
1036  !
1037  ! === Reduce info over k-points ===
1038  ! * Here symrec2t=TRANSPOSE(symrel2) for historical reasons, see note above
1039  sizepw=2*mpw
1040  ABI_MALLOC(gbase,(3,sizepw))
1041  ABI_MALLOC(cnorm,(sizepw))
1042  nbase=0                    ! # of irred G found.
1043 
1044  call merge_kgirr(nsym2,pinv,nkpt,mpw,sizepw,symrec2t,nbasek,cnormk,gbasek,nbase,gbase,cnorm,ierr)
1045  if (ierr/=0) then
1046    ABI_ERROR('merge_kgirr returned a non-zero status error')
1047  end if
1048 
1049  ABI_FREE(nbasek)
1050  ABI_FREE(cnormk)
1051  ABI_FREE(gbasek)
1052  !
1053  !=== Reorder base G-vectors in order of increasing module ===
1054  !
1055  !Generate all shells of G-vectors: star of a g==set of all symetrics of this g
1056  ABI_MALLOC(gshell,(3,2*nsym2))
1057  ABI_MALLOC(shlim,(nbase))
1058 
1059  ABI_MALLOC(gbig,(3,sizepw))
1060 !
1061 !TODO
1062 #if 0
1063 !* Here symrec2t=TRANSPOSE(symrel2) for historical reasons, see note above
1064  call getfullg(nbase,nsym2,pinv,sizepw,gbase,symrec2t,cnorm,maxpw,gbig,shlim,ierr)
1065  if (ierr/0) RETURN
1066 
1067 #else
1068  ABI_MALLOC(insort,(nbase))
1069  ABI_MALLOC(nshell,(nbase))
1070  do in=1,nbase
1071    insort(in)=in
1072  end do
1073  call sort_dp(nbase,cnorm,insort,tol14)
1074 !
1075 !Loop over all different modules of g''s (=shells):
1076  maxpw=0
1077  do in=1,nbase
1078    nshell(in)=0
1079    gcur(:)=gbase(:,insort(in))
1080 
1081    do is=1,nsym2 !  Loop over all symetries:
1082      do iinv=pinv,1,2
1083        geq(:)=iinv*(symrel2(1,:,is)*gcur(1)+symrel2(2,:,is)*gcur(2)+symrel2(3,:,is)*gcur(3))
1084 
1085        found=.FALSE.; ish=1
1086        do while ((.not.found) .and. (ish<=nshell(in))) ! Search for symetric of g and eventually add it:
1087          found=ALL(geq(:)==gshell(:,ish))
1088          ish=ish+1
1089        end do
1090        if (.not.found) then
1091          nshell(in)=nshell(in)+1
1092          gshell(:,nshell(in))=geq(:)
1093        end if
1094      end do
1095    end do
1096 
1097    if ((maxpw+nshell(in)) > sizepw) then
1098      ! We need to increase the size of the gbase, gbig and cnorm arrays while still keeping their content.
1099      ! This is done using two temporary arrays gtmp and ctmp
1100      ABI_WARNING("Had to reallocate gbase, gbig, cnorm. Perhaps geometry too inaccurate. Possible fix: correct your input file.")
1101      ABI_MALLOC(ctmp,(sizepw))
1102      ABI_MALLOC(gtmp,(3,sizepw))
1103      sizeold=sizepw
1104      sizepw=maxpw+nshell(in)
1105 
1106      ctmp(:)=cnorm(:)
1107      gtmp(:,:)=gbase(:,:)
1108 
1109      ABI_FREE(cnorm)
1110      ABI_MALLOC(cnorm,(sizepw))
1111      cnorm(1:sizeold)=ctmp(1:sizeold)
1112      cnorm(sizeold+1:sizepw)=zero
1113      ABI_FREE(ctmp)
1114 
1115 !    MG why this? gbase should not be changed!
1116      ABI_FREE(gbase)
1117      ABI_MALLOC(gbase,(3,sizepw))
1118      gbase(:,:sizeold)=gtmp(:,:sizeold)
1119      gbase(:,sizeold+1:sizepw)=0
1120      gtmp(:,:)=gbig(:,:)
1121 
1122      ABI_FREE(gbig)
1123      ABI_MALLOC(gbig,(3,sizepw))
1124      gbig(:,:sizeold)=gtmp(:,:sizeold)
1125      gbig(:,sizeold+1:sizepw)=0
1126      ABI_FREE(gtmp)
1127    end if
1128    !
1129    ! Store this shell of g''s in a big array of g (gbig):
1130    do ig=1,nshell(in)
1131      gbig(:,ig+maxpw)=gshell(:,ig)
1132    end do
1133    maxpw=maxpw+nshell(in)
1134 
1135  end do ! End loop over shells
1136  !
1137  ! * Compute shell limits
1138  ilim=0
1139  do in=1,nbase
1140    ilim=ilim+nshell(in)
1141    shlim(in)=ilim
1142  end do
1143 
1144  if (PRESENT(shlim_p)) then ! Return shlim_p
1145   ABI_MALLOC(shlim_p,(nbase))
1146   shlim_p = shlim
1147  end if
1148 
1149  ! Re-allocate gbig with correct sizes so that caller can inquire the size
1150  ABI_MALLOC(gtmp,(3,ilim))
1151  gtmp = gbig(:,1:ilim)
1152  ABI_FREE(gbig)
1153  ABI_MALLOC(gbig,(3,ilim))
1154  gbig=gtmp
1155  ABI_FREE(gtmp)
1156 
1157  if (prtvol>10) then ! Print out shell limits
1158    write(msg,'(3a)')&
1159 &    ' Shells found:',ch10,&
1160 &    ' number of shell    number of G vectors      cut-off energy [Ha} '
1161    call wrtout(std_out,msg,'COLL')
1162    do in=1,nbase
1163      write(msg,'(12x,i4,17x,i6,12x,f8.3)')in,shlim(in),2*pi**2*cnorm(in)
1164      call wrtout(std_out,msg,'COLL')
1165    end do
1166    call wrtout(std_out,ch10,'COLL')
1167  end if
1168 
1169  ABI_FREE(gshell)
1170  ABI_FREE(insort)
1171  ABI_FREE(nshell)
1172 #endif
1173 
1174  call destroy_mpi_enreg(MPI_enreg_seq)
1175  ABI_FREE(gbase)
1176  ABI_FREE(shlim)
1177  ABI_FREE(cnorm)
1178  ABI_FREE(npwarr)
1179 
1180 end subroutine merge_and_sort_kg

m_gsphere/merge_kgirr [ Functions ]

[ Top ] [ m_gsphere ] [ Functions ]

NAME

 merge_kgirr

FUNCTION

  Given a list of irreducible reciprocal vectors associated to different k-centered spheres,
  this subroutine finds the minimal set of G vectors needed to reconstruct the union of the spheres
  through symmetry operations.

INPUTS

 nsym=number of symmetry operations
 pinv=-1 if time-reversal can be used, 0 otherwise
 nkpt=number of k-points for k-centered spheres
 mpw=Max number of G vectors for each k-point
 sizepw=Max expected number of G vectors found
 symrec(3,3,nsym)=symmetries in reciprocal space given in reduced coordinates
 nbasek(nkpt)=number of irred G for each k-point
 cnormk(mpw,nkpt)=the norm of each k-centered G (only 1:nbase(ik)) is used
 gbasek(3,mpw,nkpt)

OUTPUT

 nbase=number of irreducible G needed to reconstruct the initial set of spheres
 gbase(3,sizepw)=irreducible G found in reciprocal coordinates
 cnorm(sizepw)=Norm of each irred G vector
 ierr= Exit status, if /=0 the number of G vectors found exceeds sizepw

SOURCE

1444 subroutine merge_kgirr(nsym,pinv,nkpt,mpw,sizepw,symrec,nbasek,cnormk,gbasek,nbase,gbase,cnorm,ierr)
1445 
1446 !Arguments ------------------------------------
1447 !scalars
1448  integer,intent(in) :: mpw,nkpt,nsym,pinv,sizepw
1449  integer,intent(out) :: ierr,nbase
1450 !arrays
1451  integer,intent(in) :: gbasek(3,mpw,nkpt),nbasek(nkpt),symrec(3,3,nsym)
1452  integer,intent(inout) :: gbase(3,sizepw) !vz_i
1453  real(dp),intent(in) :: cnormk(mpw,nkpt)
1454  real(dp),intent(inout) :: cnorm(sizepw) !vz_i
1455 
1456 !Local variables-------------------------------
1457 !scalars
1458  integer :: ikpt,inb,irgk,isym
1459  real(dp) :: eps,norm
1460  logical :: found
1461  character(len=500) :: msg
1462 !arrays
1463  integer :: gbas(3),gcur(3),geq(3)
1464 
1465 ! *************************************************************************
1466 
1467  DBG_ENTER("COLL")
1468 
1469  if (pinv/=1.and.pinv/=-1) then
1470    write(msg,'(a,i6)')' The argument pinv should be -1 or 1, however, pinv =',pinv
1471    ABI_BUG(msg)
1472  end if
1473  !
1474  ! === Start with zero number of G found ===
1475  nbase=0 ; ierr=0
1476  do ikpt=1,nkpt
1477    do irgk=1,nbasek(ikpt)
1478      gcur(:)=gbasek(:,irgk,ikpt)
1479      norm=cnormk(irgk,ikpt) ; eps=tol8*norm
1480      found=.FALSE. ; inb=1
1481      do while ((.not.found).and.(inb<=nbase))
1482        if (ABS(norm-cnorm(inb))<=eps) then
1483          gbas(:)=gbase(:,inb)
1484          isym=1
1485          do while ((.not.found).and.(isym<=nsym))
1486            geq(:)=MATMUL(symrec(:,:,isym),gcur)
1487            found=ALL(geq(:)==gbas(:))
1488            if (pinv==-1) found= (found.or.ALL(geq(:)==-gbas(:)) ) ! For time-reversal
1489            isym=isym+1
1490          end do
1491        end if
1492        inb=inb+1
1493      end do
1494      if (.not.found) then
1495        ! === Add to the list ===
1496        nbase=nbase+1
1497        if (nbase>sizepw) then
1498          write(msg,'(2(a,i5),a)')&
1499 &         ' nbase (',nbase,') became greater than sizepw = ',sizepw,' returning ierr=1 '
1500          ABI_WARNING(msg)
1501          ierr=1; RETURN
1502        end if
1503        cnorm(nbase)=cnormk(irgk,ikpt)
1504        gbase(:,nbase)=gcur(:)
1505      end if
1506    end do
1507  end do
1508 
1509  DBG_EXIT("COLL")
1510 
1511 end subroutine merge_kgirr

m_gsphere/setup_G_rotation [ Functions ]

[ Top ] [ m_gsphere ] [ Functions ]

NAME

 setup_G_rotation

FUNCTION

 Set up tables indicating rotation of G-vectors.

INPUTS

 nsym=Number of symmetry operations.
 symrec(3,3,nsym)=Symmetry operations in reciprocal space.
 timrev=2 if time reversal can be used, 1 otherwise.
 npw=Number of planewaves in the sphere.
 gvec(3,npw)=Coordinates of plane waves, supposed to be ordered in increasing modulus
 g2sh(npw)=For each G, it gives the index of the shell to which it belongs.
 nsh=Number of shells
 shlim(nsh+1)=Index of the first G vector in each shell, =npw+1 for nsh+1

OUTPUT

  grottb  (npw,2,nsym)= grottb(G,I,S) is the index of (SI) G in the array gvec.
  grottbm1(npw,2,nsym)= index of IS^{-1} G.

 NOTES:
  I is either the identity or the inversion (time reversal in reciprocal space).
  S is one of the symmetry operation in reciprocal space belonging to the Space group.

SOURCE

205 subroutine setup_G_rotation(nsym,symrec,timrev,npw,gvec,g2sh,nsh,shlim,grottb,grottbm1)
206 
207 !Arguments ------------------------------------
208 !scalars
209  integer,intent(in) :: npw,nsh,nsym,timrev
210 !arrays
211  integer,intent(in) :: g2sh(npw),gvec(3,npw),shlim(nsh+1),symrec(3,3,nsym)
212  integer,intent(inout) :: grottb  (npw,timrev,nsym)
213  integer,intent(inout) :: grottbm1(npw,timrev,nsym)
214 
215 !Local variables ------------------------------
216 !scalars
217  integer :: ee,ig1,ig2,ish1,isym,itim,ss
218  logical :: found
219  character(len=500) :: msg
220 !arrays
221  integer :: gbase(3),grot(3)
222 
223 !************************************************************************
224  !
225  ! === Set up G-rotation table ===
226  do ig1=1,npw
227    ish1=g2sh(ig1) ; ss=shlim(ish1) ; ee=shlim(ish1+1)-1
228    gbase(:)=gvec(:,ig1)
229 
230    do itim=1,timrev
231      do isym=1,nsym
232        grot=(3-2*itim)*MATMUL(symrec(:,:,isym),gbase)
233        found=.FALSE.
234        ! * Loop on the shell of ig1 to speed up the search.
235        do ig2=ss,ee
236          if (ALL(ABS(grot(:)-gvec(:,ig2))==0)) then
237            found=.TRUE.
238            grottb  (ig1,itim,isym)=ig2
239            grottbm1(ig2,itim,isym)=ig1
240          end if
241        end do
242        if (.not.found) then
243          write(msg,'(3a,i5,a,i5,1x,2(3i5,a),a,i3,a,i3)')&
244           'G-shell not closed',ch10,&
245           '  Initial G vector ',ig1,'/',npw,gbase(:),' Rotated G vector ',grot(:),ch10,&
246           '  Through sym ',isym,' and itim ',itim
247          ABI_ERROR(msg)
248        end if
249      end do
250    end do
251 
252  end do !ig1
253 
254 end subroutine setup_G_rotation

m_gsphere/symg [ Functions ]

[ Top ] [ m_gsphere ] [ Functions ]

NAME

 symg

FUNCTION

 Treat symmetries applied to the G vectors, in view of the application
 to symmetrization of the dielectric matrix.
 Generate a list of time-reversed G vectors, as well as a list
 of spatially-symmetric G vectors.

INPUTS

 kg_diel(3,npwdiel)=reduced planewave coordinates for the dielectric matrix.
 npwdiel=number of planewaves for the dielectric matrix
 nsym=number of symmetry
 symrel(3,3,nsym)=symmetry matrices in real space (integers)
 tnons(3,nsym)=reduced nonsymmorphic translations
 (symrel and tnons are in terms of real space primitive translations)

OUTPUT

 phdiel(2,npwdiel,nsym)=phase associated with point symmetries applied to G
 sym_g(npwdiel,nsym)=index list of symmetric G vectors
 (could save a bit of space by suppressing isym=1, since the
 corresponding symmetry is the identity)
 tmrev_g(npwdiel)=index list of inverted G vectors (time-reversed)

SOURCE

2195 subroutine symg(kg_diel,npwdiel,nsym,phdiel,sym_g,symrel,tmrev_g,tnons)
2196 
2197 !Arguments ------------------------------------
2198 !scalars
2199  integer,intent(in) :: npwdiel,nsym
2200 !arrays
2201  integer,intent(in) :: kg_diel(3,npwdiel),symrel(3,3,nsym)
2202  integer,intent(out) :: sym_g(npwdiel,nsym),tmrev_g(npwdiel)
2203  real(dp),intent(in) :: tnons(3,nsym)
2204  real(dp),intent(out) :: phdiel(2,npwdiel,nsym)
2205 
2206 !Local variables-------------------------------
2207 !scalars
2208  integer :: g1,g2,g3,ipw,isym,j1,j2,j3,m1m,m1p,m2m,m2p,m3m,m3p,symmg,trevg
2209  real(dp) :: arg,tau1,tau2,tau3
2210  !character(len=500) :: msg
2211 !arrays
2212  integer,allocatable :: grid(:,:,:)
2213 
2214 ! *************************************************************************
2215 
2216 !Determines maximal bounds of the zone spanned by the planewaves
2217  m1m=0 ; m2m=0 ; m3m=0 ; m1p=0 ; m2p=0 ; m3p=0
2218  do ipw=1,npwdiel
2219    g1=kg_diel(1,ipw)
2220    g2=kg_diel(2,ipw)
2221    g3=kg_diel(3,ipw)
2222    if(g1<m1m)m1m=g1 ; if(g1>m1p)m1p=g1
2223    if(g2<m2m)m2m=g2 ; if(g2>m2p)m2p=g2
2224    if(g3<m3m)m3m=g3 ; if(g3>m3p)m3p=g3
2225  end do
2226 
2227 !Set up grid, that associate to each point the index of the
2228 !corresponding planewave, if there is one
2229  ABI_MALLOC(grid, (m1m:m1p,m2m:m2p,m3m:m3p))
2230  grid(:,:,:)=0
2231  do ipw=1,npwdiel
2232    g1=kg_diel(1,ipw)
2233    g2=kg_diel(2,ipw)
2234    g3=kg_diel(3,ipw)
2235    grid(g1,g2,g3)=ipw
2236  end do
2237 
2238 !Set up tmrev_g and sym_g arrays
2239  do ipw=1,npwdiel
2240    g1=kg_diel(1,ipw)
2241    g2=kg_diel(2,ipw)
2242    g3=kg_diel(3,ipw)
2243 
2244 !  Treat first time-reversal symmetry
2245    trevg=grid(-g1,-g2,-g3)
2246    if(trevg==0)then
2247      ABI_BUG('Do not find the time-reversed symmetric of a G-vector.')
2248    end if
2249    tmrev_g(ipw)=trevg
2250 
2251 !  Treat now spatial symmetries
2252    do isym=1,nsym
2253 
2254 !    Get rotated G vector Gj for each symmetry element
2255 !    -- here we use the TRANSPOSE of symrel; assuming symrel expresses
2256 !    the rotation in real space, the transpose is then appropriate
2257 !    for G space symmetrization (according to Doug : see routine irrzg.f)
2258      j1=symrel(1,1,isym)*g1+&
2259 &     symrel(2,1,isym)*g2+symrel(3,1,isym)*g3
2260      j2=symrel(1,2,isym)*g1+&
2261 &     symrel(2,2,isym)*g2+symrel(3,2,isym)*g3
2262      j3=symrel(1,3,isym)*g1+&
2263 &     symrel(2,3,isym)*g2+symrel(3,3,isym)*g3
2264      symmg=grid(j1,j2,j3)
2265      if(symmg==0)then
2266        ABI_BUG('Do not find the spatially symmetric of a G-vector.')
2267      end if
2268      sym_g(ipw,isym)=symmg
2269 
2270 !    Get associated phase
2271      tau1=tnons(1,isym)
2272      tau2=tnons(2,isym)
2273      tau3=tnons(3,isym)
2274      if (abs(tau1)>tol12.or.abs(tau2)>tol12.or.abs(tau3)>tol12) then
2275 !      compute exp(-2*Pi*I*G dot tau) using original G
2276        arg=two_pi*(dble(g1)*tau1+dble(g2)*tau2+dble(g3)*tau3)
2277        phdiel(1,ipw,isym)=cos(arg)
2278        phdiel(2,ipw,isym)=-sin(arg)
2279      else
2280        phdiel(1,ipw,isym)=1._dp
2281        phdiel(2,ipw,isym)=0._dp
2282      end if
2283 
2284    end do
2285  end do
2286 
2287  ABI_FREE(grid)
2288 
2289 end subroutine symg

m_gsphere/table_gbig2kg [ Functions ]

[ Top ] [ m_gsphere ] [ Functions ]

NAME

  table_gbig2kg

FUNCTION

  Associate the kg_k set of g-vectors with the big array of gbig
  The array gbig(3,maxpw) contains all g-vectors used for all k-points, in order of
  increasing shells. For a each k-point, the wave-functions are defined only on a particular set
  of g-vectors kg_k (included in gbig). This set is defined by array gamma2k:
  The array gamma2k(ig=1,maxpw) translates the index of the gbig (from 1 to maxpw) into the corresponding
  index in array kg_k. If gbig(ig) does not exist in kg_k, gamma2k(ig) contains npw_k+1.

INPUTS

  npw_k=Number of planewaves in the k-centered basis set
  kg_k(3,npw_k)=The k-centered basis set
  maxpw=Number of G in gbig
  gbig(3,maxpw)=The union of the G-spheres at different k-points.

OUTPUT

  ierr=Status error. It gives the number of G of kg_k not contained in gbig.
  gamma2k(maxpw)=Mapping gbig -> kg_k

SOURCE

1976 pure subroutine table_gbig2kg(npw_k,kg_k,maxpw,gbig,gamma2k,ierr)
1977 
1978 !Arguments ------------------------------------
1979 !scalars
1980  integer,intent(in) :: npw_k,maxpw
1981  integer,intent(out) :: ierr
1982 !arrays
1983  integer,intent(in) :: kg_k(3,npw_k)
1984  integer,intent(in) :: gbig(3,maxpw)
1985  integer,intent(out) :: gamma2k(maxpw)
1986 
1987 !Local variables-------------------------------
1988 !scalars
1989  integer :: ig,igp
1990  logical :: found
1991 !arrays
1992  integer :: gcur(3)
1993 
1994 ! *********************************************************************
1995 
1996  ierr=0
1997  gamma2k(:)=npw_k+1  ! Initialize array gamma2k
1998 
1999  do ig=1,npw_k       ! Loop over g-vectors, for this k point.
2000    gcur(:)=kg_k(:,ig)
2001    igp=0; found=.FALSE.
2002    do while ((.not.found) .and. igp<maxpw) ! Search selected vector in array gbig: TODO this part can be optimized
2003      igp=igp+1
2004      found=ALL(gcur(:)==gbig(:,igp))
2005    end do
2006    if (found) then ! Store it if found:
2007      gamma2k(igp)=ig
2008    else
2009      ierr=ierr+1
2010    end if
2011  end do
2012 
2013 end subroutine table_gbig2kg