TABLE OF CONTENTS


ABINIT/irreducible_set_pert [ Functions ]

[ Top ] [ Functions ]

NAME

 irreducible_set_pert

FUNCTION

 Determines a set of perturbations that form a basis
 in that, using symmetry, they can be used to generate
 all other perturbations that are asked to be calculated (target).

INPUTS

  indsym(4,nsym,natom)=indirect indexing array described above: for each
   isym,iatom, fourth element is label of atom into which iatom is sent by
   INVERSE of symmetry operation isym; first three elements are the primitive
   translations which must be subtracted after the transformation to get back
   to the original unit cell.
  mpert =maximum number of iper
  natom= number of atoms
  nsym=number of space group symmetries
  rfdir(3)=direction for the perturbations
  rfpert(mpert)=information on the perturbations
  symrec(3,3,nsym)=3x3 matrices of the group symmetries (reciprocal space)
  symrel(3,3,nsym)=3x3 matrices of the group symmetries (real space)
  symq(4,2,nsym)= (integer) three first numbers define the G vector;
   fourth number is 0 if the q-vector is not preserved, is 1 otherwise
   second index is one without time-reversal symmetry, two with time-reversal symmetry

OUTPUT

   pertsy(3,mpert)= the target perturbation is described by the two last indices (idir, and ipert),
                    the value is 0, 1 or -1, see notes.

NOTES

 Output will be in the pertsy array,
   0 for non-target perturbations
   1 for basis perturbations
  -1 for perturbations that can be found from basis perturbations

SOURCE

3475 subroutine irreducible_set_pert(indsym,mpert,natom,nsym,pertsy,rfdir,rfpert,symq,symrec,symrel)
3476 
3477 !Arguments -------------------------------
3478 !scalars
3479  integer,intent(in) :: mpert,natom,nsym
3480 !arrays
3481  integer,intent(in) :: indsym(4,nsym,natom),rfdir(3),rfpert(mpert)
3482  integer,intent(in) :: symq(4,2,nsym),symrec(3,3,nsym),symrel(3,3,nsym)
3483  integer,intent(out) :: pertsy(3,mpert)
3484 
3485 !Local variables -------------------------
3486 !scalars
3487  integer :: found,idir1,idisy1,ii,ipert1,ipesy1,isign,isym,itirev,jj
3488 !arrays
3489  integer :: sym1(3,3)
3490 
3491 ! *********************************************************************
3492 
3493 !Zero pertsy
3494  pertsy(:,:)=0
3495 
3496  do ipert1=1,mpert
3497    do idir1=1,3
3498      if(rfpert(ipert1)==1.and.rfdir(idir1)==1)then
3499 !      write(std_out,*)' for candidate idir =',idir1,' ipert = ',ipert1
3500 
3501 !      Loop on all symmetries, including time-reversal
3502        do isym=1,nsym
3503          do itirev=1,2
3504            isign=3-2*itirev
3505 
3506            if(symq(4,itirev,isym)/=0)then
3507 
3508              found=1
3509 
3510 !            Here select the symmetric of ipert1
3511              if(ipert1<=natom)then
3512                ipesy1=indsym(4,isym,ipert1)
3513                do ii=1,3
3514                  do jj=1,3
3515                    sym1(ii,jj)=symrec(ii,jj,isym)
3516                  end do
3517                end do
3518              else if(ipert1==(natom+2) .or. ipert1==(natom+6))then
3519                ipesy1=ipert1
3520                do ii=1,3
3521                  do jj=1,3
3522                    sym1(ii,jj)=symrel(ii,jj,isym)
3523                  end do
3524                end do
3525              else
3526                found=0
3527              end if
3528 
3529 !            Now that a symmetric perturbation has been obtained,
3530 !            including the expression of the symmetry matrix, see
3531 !            if the symmetric perturbations are available
3532              if( found==1 ) then
3533 
3534                do idisy1=1,3
3535                  if(sym1(idir1,idisy1)/=0)then
3536                    if(pertsy(idisy1,ipesy1)==0)then
3537                      found=0
3538                      exit
3539                    end if
3540                  end if
3541                end do
3542              end if
3543 
3544 !            Now, if still found, then it is a symmetric
3545 !            of some linear combination of existing perturbations
3546              if(found==1)then
3547 
3548 !              DEBUG
3549 !              write(std_out,*)' all found !  isym, isign= ',isym,isign
3550 !              write(std_out,1010)((sym1(ii,jj),ii=1,3),jj=1,3)
3551 !              write(std_out,1010)((sym2(ii,jj),ii=1,3),jj=1,3)
3552 !              write(std_out,*)sumr,sumi
3553 !              1010    format(9i4)
3554 !              ENDDEBUG
3555 
3556                pertsy(idir1,ipert1)=-1
3557                exit ! Exit loop on symmetry operations
3558 
3559              end if
3560 
3561            end if !  End loop on all symmetries + time-reversal
3562          end do
3563        end do
3564 
3565 !      Now that all symmetries have been examined,
3566 !      if still not symmetric of a linear combination
3567 !      of basis perturbations, then it is a basis perturbation
3568        if(pertsy(idir1,ipert1)/=-1) pertsy(idir1,ipert1)=1
3569 !      write(std_out,'(a,3i5)' ) ' irreducible_set_pert :',idir1,ipert1,pertsy(idir1,ipert1)
3570 
3571      end if ! End big loop on all elements
3572    end do
3573  end do
3574 
3575 end subroutine irreducible_set_pert

ABINIT/m_geometry [ Modules ]

[ Top ] [ Modules ]

NAME

  m_geometry

FUNCTION

  This module contains basic tools to operate on vectors expressed in reduced coordinates.

COPYRIGHT

 Copyright (C) 2008-2024 ABINIT group (MG, MT, FJ, TRangel, DCA, XG, AHR, DJA, DRH)
 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

16 #if defined HAVE_CONFIG_H
17 #include "config.h"
18 #endif
19 
20 #include "abi_common.h"
21 
22 MODULE m_geometry
23 
24  use defs_basis
25  use m_abicore
26  use m_errors
27  use m_atomdata
28  use m_sort
29 
30  use m_io_tools,       only : open_file
31  use m_numeric_tools,  only : uniformrandom, isinteger, set2unit
32  use m_symtk,          only : mati3inv, mati3det, matr3inv, symdet
33  use m_hide_lapack,    only : matr3eigval
34  use m_pptools,        only : prmat
35  use m_numeric_tools,  only : wrap2_pmhalf
36  use m_hide_lapack,    only : matrginv
37 
38  implicit none
39 
40  private
41 
42  public :: normv              ! Norm of vector(s) in reduced coordinates either in real or reciprocal space.
43  public :: vdotw              ! Scalar product between two reduced vectors either in real or reciprocal space.
44  public :: acrossb            ! Cross product of two 3-vectors.
45  public :: wigner_seitz       ! Find the grid of points falling inside the Wigner-Seitz cell.
46  public :: phdispl_cart2red   ! Calculate the displacement vectors for all branches in reduced coordinates.
47  public :: getspinrot         ! Compute the components of the spinor rotation matrix
48  public :: spinrot_cmat       ! Construct 2x2 complex matrix representing rotation operator in spin-space.
49  public :: rotmat             ! Finds the rotation matrix.
50  public :: fixsym             ! Check that iatfix does not break symmetry.
51  public :: det3r              ! Compute determinant of a 3x3 real matrix
52  public :: metric             ! Compute metric matrices.
53  public :: mkradim            ! Make rprim and acell from rprimd
54  public :: mkrdim             ! Make rprimd from acell from rprim
55  public :: chkrprimd          ! Test if {rprim,acell,rprimd} are consistent
56  public :: chkdilatmx         ! check if dilatation of unit cell is consistent with initial G-sphere
57  public :: xcart2xred         ! From cart coords to reduced
58  public :: xred2xcart         ! From reduced coords to cart.
59  public :: gred2fcart         ! Convert reduced gradients into cartesian forces
60  public :: fcart2gred         ! Convert cartesian forces into reduced gradients
61  public :: bonds_lgth_angles  ! Write GEO file
62  public :: randomcellpos      ! Creates unit cell with random atomic positions.
63  public :: ioniondist         ! Compute ion-ion distances
64  public :: dist2              ! Calculates the distance of v1 and v2 in a crystal by repeating the unit cell
65  public :: shellstruct        ! Calculates shell structure (multiplicities, radii)
66  public :: remove_inversion   ! Remove the inversion symmetry and improper rotations
67  public :: reduce2primitive   ! Find real space primitive vectors from non-primitive ones and set of translations
68  public :: symredcart         ! Convert a symmetry operation from reduced coordinates (integers) to cart coords (reals)
69  public :: strainsym          ! Symmetrize the strain tensor.
70  public :: stresssym          ! Symmetrize the stress tensor.
71  public :: stress_voigt_to_mat! Build 3x3 symmetric stress tensor from stress vector in Voigt notation.
72  public :: strconv            ! Convert from symmetric storage mode in reduced coords to cart coords.
73  public :: littlegroup_pert   ! Determines the set of symmetries that leaves a perturbation invariant.
74  public :: irreducible_set_pert  ! Determines a set of perturbations that form a basis
75  public :: wedge_basis        ! compute rprimd x gprimd vectors needed for generalized cross product
76  public :: wedge_product      ! compute wedge product given wedge basis
77 
78  interface normv
79   module procedure normv_rdp_vector
80   module procedure normv_int_vector
81   !module procedure normv_int_vector_array  ! WARNING for the time being, do not use these 2 procedures,
82   !module procedure normv_rdp_vector_array  ! sunstudio12 is not able to resolve which sub should be called.
83  end interface normv
84 
85  interface vdotw
86   module procedure vdotw_rr_vector
87   module procedure vdotw_rc_vector
88  end interface vdotw
89 
90 CONTAINS  !===========================================================

m_geometry/acrossb [ Functions ]

[ Top ] [ m_geometry ] [ Functions ]

NAME

 acrossb

FUNCTION

 Calculates the cross product of two 3-vectors

INPUTS

   a(3): real(dp) vector
   b(3): real(dp) vector

OUTPUT

   c(3): real(dp) vector = a X b

SOURCE

396 subroutine acrossb(a,b,c)
397 
398 !Arguments ---------------------------------------------
399 !arrays
400  real(dp),intent(in) :: a(3),b(3)
401  real(dp),intent(out) :: c(3)
402 
403 ! *********************************************************************
404 
405  c(1) =  a(2)*b(3) - a(3)*b(2)
406  c(2) = -a(1)*b(3) + a(3)*b(1)
407  c(3) =  a(1)*b(2) - b(1)*a(2)
408 
409 end subroutine acrossb

m_geometry/bonds_lgth_angles [ Functions ]

[ Top ] [ m_geometry ] [ Functions ]

NAME

 bonds_lgth_angles

FUNCTION

 From list of coordinates and primitive translations, output
 a list of bonds lengths and bond angles.

INPUTS

  coordn = maximum coordination number to be taken into account
  fnameabo_app_geo=name of file for _GEO data
  natom  = number of atoms in unit cell
  ntypat = number of types of atoms in unit cell.
  rprimd(3,3)  = real space dimensional primitive translations (bohr)
  typat(natom) = type integer for each atom in cell
  znucl(ntypat)= real(dp), atomic number of atom type
  xred(3,natom)= reduced coordinates of atoms

OUTPUT

 data written in file fnameabo_app_geo

NOTES

  The tolerance tol8 aims at giving a machine-independent ordering.
  (this trick is used in bonds.f, listkk.f, prtrhomxmn.f and rsiaf9.f)

SOURCE

1798 subroutine bonds_lgth_angles(coordn,fnameabo_app_geo,natom,ntypat,rprimd,typat,xred,znucl)
1799 
1800 !Arguments ------------------------------------
1801 !scalars
1802  integer,intent(in) :: coordn,natom,ntypat
1803  character(len=*),intent(in) :: fnameabo_app_geo
1804 !arrays
1805  integer,intent(in) :: typat(natom)
1806  real(dp),intent(in) :: rprimd(3,3),znucl(ntypat)
1807  real(dp),intent(inout) :: xred(3,natom)
1808 
1809 !Local variables-------------------------------
1810 !scalars
1811  integer :: done,ia,ib,ic,ii,ineighb,jneighb,mneighb,mu,ndig,nu,t1,t2,t3,tmax,temp_unit
1812  real(dp) :: adotb,asq,bsq,co,length,sq,thdeg
1813 !real(dp)u1,u2,u3,v1,v2,v3
1814  character(len=500) :: msg
1815  type(atomdata_t) :: atom
1816 !arrays
1817  integer,allocatable :: list_neighb(:,:,:)
1818  real(dp) :: bab(3),bac(3),dif(3),rmet(3,3)
1819  real(dp),allocatable :: sqrlength(:),xcart(:,:)
1820  character(len=8),allocatable :: iden(:)
1821 
1822 ! *************************************************************************
1823 
1824 !Initialize the file
1825  write(msg, '(a,a,a)' )' bonds_lgth_angles : about to open file ',trim(fnameabo_app_geo),ch10
1826  call wrtout(std_out,msg,'COLL'); call wrtout(ab_out,msg,'COLL')
1827 
1828  if (open_file(fnameabo_app_geo,msg,newunit=temp_unit,status='unknown',form='formatted') /= 0) then
1829    ABI_ERROR(msg)
1830  end if
1831  rewind(temp_unit)
1832 
1833  write(msg, '(a,a)' ) ch10,' ABINIT package : GEO file '
1834  call wrtout(temp_unit,msg,'COLL')
1835 
1836 !Compute maximum number of neighbors is the neighbor list,
1837 !from the indicative coordination number
1838 !Note : the following formula includes next nearest neighbors, but not others
1839  mneighb=1+coordn+coordn*(coordn-1)
1840 
1841  write(msg, '(a,a,i2,a,a,i4,a,a,a,i4,a)' ) ch10,&
1842 & ' Maximal coordination number, as estimated by the user : ',coordn,ch10,&
1843 & '  giving a maximum of ',coordn*coordn,&
1844 & ' nearest neighbors and next nearest neighbors, ',ch10,&
1845 & '                  and ',(coordn*(coordn-1))/2,&
1846 & ' distinct angles between nearest neighbors'
1847  call wrtout(temp_unit,msg,'COLL')
1848 
1849 !Compute metric tensor in real space rmet
1850  do nu=1,3
1851    do mu=1,3
1852      rmet(mu,nu)=rprimd(1,mu)*rprimd(1,nu)+&
1853 &     rprimd(2,mu)*rprimd(2,nu)+&
1854 &     rprimd(3,mu)*rprimd(3,nu)
1855    end do
1856  end do
1857 
1858  write(msg, '(a,a)' )ch10,' Primitive vectors of the periodic cell (bohr)'
1859  call wrtout(temp_unit,msg,'COLL')
1860  do nu=1,3
1861    write(msg, '(1x,a,i1,a,3f10.5)' ) '  R(',nu,')=',rprimd(:,nu)
1862    call wrtout(temp_unit,msg,'COLL')
1863  end do
1864 
1865  write(msg, '(a,a)' ) ch10,&
1866 & ' Atom list        Reduced coordinates          Cartesian coordinates (bohr)'
1867  call wrtout(temp_unit,msg,'COLL')
1868 
1869 !Set up a list of character identifiers for all atoms : iden(ia)
1870  ABI_MALLOC(iden,(natom))
1871  iden(:)='        '
1872  do ia=1,natom
1873    ndig=int(log10(dble(ia)+0.5d0))+1
1874    call atomdata_from_znucl(atom,znucl(typat(ia)))
1875    if(ndig==1) write(iden(ia), '(a,a,i1,a)' )  atom%symbol,'(',ia,')   '
1876    if(ndig==2) write(iden(ia), '(a,a,i2,a)' )  atom%symbol,'(',ia,')  '
1877    if(ndig==3) write(iden(ia), '(a,a,i3,a)' )  atom%symbol,'(',ia,') '
1878    if(ndig==4) write(iden(ia), '(a,a,i4,a)' )  atom%symbol,'(',ia,')'
1879    if(ndig>4)then
1880      close(temp_unit)
1881      write(msg, '(a,i8,a,a)' )&
1882 &     'bonds_lgth_angles cannot handle more than 9999 atoms, while natom=',natom,ch10,&
1883 &     'Action: decrease natom, or contact ABINIT group.'
1884      ABI_BUG(msg)
1885    end if
1886  end do
1887 
1888 !Compute cartesian coordinates, and print reduced and cartesian coordinates
1889 !then print coordinates in angstrom, with the format neede for xmol
1890  ABI_MALLOC(xcart,(3,natom))
1891  call xred2xcart(natom,rprimd,xcart,xred)
1892 
1893  do ia=1,natom
1894    write(msg, '(a,a,3f10.5,a,3f10.5)' ) &
1895 &   '   ',iden(ia),(xred(ii,ia)+tol10,ii=1,3),&
1896 &   '    ',(xcart(ii,ia)+tol10,ii=1,3)
1897    call wrtout(temp_unit,msg,'COLL')
1898  end do
1899 
1900  write(msg, '(a,a,a,a,i4,a)' )ch10,&
1901 & ' XMOL data : natom, followed by cartesian coordinates in Angstrom',&
1902 & ch10,ch10,natom,ch10
1903  call wrtout(temp_unit,msg,'COLL')
1904 
1905  do ia=1,natom
1906    call atomdata_from_znucl(atom,znucl(typat(ia)))
1907    write(msg, '(a,a,3f10.5)' )'   ',atom%symbol,xcart(1:3,ia)*Bohr_Ang
1908    call wrtout(temp_unit,msg,'COLL')
1909  end do
1910 
1911  ABI_FREE(xcart)
1912 
1913  ABI_MALLOC(list_neighb,(0:mneighb+1,4,2))
1914  ABI_MALLOC(sqrlength,(0:mneighb+1))
1915 
1916 !Compute list of neighbors
1917  do ia=1,natom
1918 
1919    write(msg, '(a,a,a,a,a,a,a,a,a)' ) ch10,'===========',&
1920 &   '=====================================================================',&
1921 &   ch10,' ',iden(ia),ch10,ch10,' Bond lengths '
1922    call wrtout(temp_unit,msg,'COLL')
1923 
1924 !  Search other atoms for bonds, but must proceed
1925 !  in such a way to consider a search box sufficiently large,
1926 !  so increase the size of the search box until the
1927 !  final bond length list do not change
1928    do tmax=0,5
1929 
1930 !    Set initial list of neighbors to zero,
1931 !    and initial square of bond lengths to a very large number.
1932 !    Note that the dimension is larger than neighb to ease
1933 !    the later sorting : neighbors 0 and neighb+1 are non-existent, while
1934 !    neighbor 1 will be the atom itself ...
1935      list_neighb(0:mneighb+1,1:4,1)=0
1936      sqrlength(1:mneighb+1)=huge(zero)
1937      sqrlength(0)=-1.0d0
1938 
1939 !    Here search on all atoms inside the box defined by tmax
1940      do ib=1,natom
1941        do t3=-tmax,tmax
1942          do t2=-tmax,tmax
1943            do t1=-tmax,tmax
1944              dif(1)=xred(1,ia)-(xred(1,ib)+dble(t1))
1945              dif(2)=xred(2,ia)-(xred(2,ib)+dble(t2))
1946              dif(3)=xred(3,ia)-(xred(3,ib)+dble(t3))
1947              sq=rsdot(dif(1),dif(2),dif(3),dif(1),dif(2),dif(3),rmet)
1948 
1949 !            Insert the atom at the proper place in the neighbor list.
1950              do ineighb=mneighb,0,-1
1951 !              Note the tolerance
1952                if(sq+tol8>sqrlength(ineighb))then
1953                  sqrlength(ineighb+1)=sq
1954                  list_neighb(ineighb+1,1,1)=ib
1955                  list_neighb(ineighb+1,2,1)=t1
1956                  list_neighb(ineighb+1,3,1)=t2
1957                  list_neighb(ineighb+1,4,1)=t3
1958 !                DEBUG
1959 !                if(ineighb/=mneighb)then
1960 !                write(std_out,*)' '
1961 !                do ii=1,mneighb
1962 !                write(std_out,*)ii,sqrlength(ii)
1963 !                end do
1964 !                end if
1965 !                ENDDEBUG
1966                  exit
1967                else
1968                  sqrlength(ineighb+1)=sqrlength(ineighb)
1969                  list_neighb(ineighb+1,1:4,1)=list_neighb(ineighb,1:4,1)
1970                end if
1971              end do
1972 
1973            end do
1974          end do
1975        end do
1976 !      end ib loop:
1977      end do
1978 
1979 !    Now, check that the box defined by tmax was large enough :
1980 !    require the present and old lists to be the same
1981      done=0
1982 
1983      if(tmax>0)then
1984        done=1
1985        do ineighb=1,mneighb
1986 !        DEBUG
1987 !        write(std_out,'(5i5,f12.5)' )ineighb,list_neighb(ineighb,1:4,1),&
1988 !        &                                    sqrlength(ineighb)
1989 !        write(std_out,'(5i5)' )ineighb,list_neighb(ineighb,1:4,2)
1990 !        ENDDEBUG
1991          if( list_neighb(ineighb,1,1)/=list_neighb(ineighb,1,2) .or. &
1992 &         list_neighb(ineighb,2,1)/=list_neighb(ineighb,2,2) .or. &
1993 &         list_neighb(ineighb,3,1)/=list_neighb(ineighb,3,2) .or. &
1994 &         list_neighb(ineighb,4,1)/=list_neighb(ineighb,4,2)       )then
1995            done=0
1996          end if
1997        end do
1998      end if
1999 
2000 !    If done==1, then one can exit the loop : the correct list of
2001 !    neighbors is contained in list_neighb(1:neighb,1:4,1),
2002 !    with the first neighbor being the atom itself
2003      if(done==1)exit
2004 
2005 !    If the work is not done, while tmax==5, then there is a problem .
2006      if(tmax==5)then
2007        close(temp_unit)
2008        write(msg, '(2a)' )&
2009 &       'Did not succeed to generate a reliable list of bonds ',&
2010 &       'since tmax is exceeded.'
2011        ABI_BUG(msg)
2012      end if
2013 
2014 !    Copy the new list into the old list.
2015      list_neighb(1:mneighb,1:4,2)=list_neighb(1:mneighb,1:4,1)
2016 
2017 !    Loop on tmax (note that there are exit instruction inside the loop)
2018    end do
2019 
2020 
2021 
2022 !  Output the bond list
2023    do ineighb=2,mneighb
2024      ib=list_neighb(ineighb,1,1)
2025      length=sqrt(sqrlength(ineighb))
2026      write(msg, '(a,a,a,a,3i2,t27,a,f10.5,a,f9.5,a)' )&
2027 &     '  ',trim(iden(ia)),' - ',trim(iden(ib)),&
2028 &     list_neighb(ineighb,2:4,1),'bond length is ',&
2029 &     length,' bohr  ( or ',Bohr_Ang*length,' Angst.)'
2030      call wrtout(temp_unit,msg,'COLL')
2031    end do
2032 
2033 !  Output the angle list
2034    if(coordn>1)then
2035 
2036      write(msg, '(a,a)' ) ch10,' Bond angles '
2037      call wrtout(temp_unit,msg,'COLL')
2038 
2039      do ineighb=2,coordn
2040        do jneighb=ineighb+1,coordn+1
2041 
2042          ib=list_neighb(ineighb,1,1)
2043          ic=list_neighb(jneighb,1,1)
2044          do mu=1,3
2045            bab(mu)=xred(mu,ib)+dble(list_neighb(ineighb,1+mu,1))-xred(mu,ia)
2046            bac(mu)=xred(mu,ic)+dble(list_neighb(jneighb,1+mu,1))-xred(mu,ia)
2047          end do
2048          asq=rsdot(bab(1),bab(2),bab(3),bab(1),bab(2),bab(3),rmet)
2049          bsq=rsdot(bac(1),bac(2),bac(3),bac(1),bac(2),bac(3),rmet)
2050          adotb=rsdot(bab(1),bab(2),bab(3),bac(1),bac(2),bac(3),rmet)
2051          co=adotb/sqrt(asq*bsq)
2052          if( abs(co)-1.0d0 >= 0.0d0 )then
2053            if( abs(co)-1.0d0 <= 1.0d-12 )then
2054 !            Allows for a small numerical inaccuracy
2055              thdeg=0.0d0
2056              if(co < 0.0d0) thdeg=180.0d0
2057            else
2058              ABI_BUG('the evaluation of the angle is wrong.')
2059            end if
2060          else
2061            thdeg=acos(co)*180.d0*piinv
2062          end if
2063 
2064          write(msg, '(a,a,3i2,a,a,a,a,3i2,t44,a,f13.5,a)' )&
2065 &         '  ',trim(iden(ib)),list_neighb(ineighb,2:4,1),' - ',&
2066 &         trim(iden(ia)),' - ',trim(iden(ic)),&
2067 &         list_neighb(jneighb,2:4,1),'bond angle is ',thdeg,' degrees '
2068          call wrtout(temp_unit,msg,'COLL')
2069        end do
2070      end do
2071 
2072    end if
2073  end do !  End big ia loop:
2074 
2075  ABI_FREE(iden)
2076  ABI_FREE(list_neighb)
2077  ABI_FREE(sqrlength)
2078 
2079  close(temp_unit)
2080 
2081  contains
2082 
2083    function rsdot(u1,u2,u3,v1,v2,v3,rmet)
2084 
2085    real(dp) :: rsdot
2086    real(dp),intent(in) :: u1,u2,u3,v1,v2,v3
2087    real(dp),intent(in) :: rmet(3,3)
2088    rsdot=rmet(1,1)*u1*v1+rmet(2,1)*u2*v1+&
2089 &   rmet(3,1)*u3*v1+rmet(1,2)*u1*v2+rmet(2,2)*u2*v2+&
2090 &   rmet(3,2)*u3*v2+rmet(1,3)*u1*v3+rmet(2,3)*u2*v3+rmet(3,3)*u3*v3
2091  end function rsdot
2092 
2093 end subroutine bonds_lgth_angles

m_geometry/chkdilatmx [ Functions ]

[ Top ] [ m_geometry ] [ Functions ]

NAME

 chkdilatmx

FUNCTION

 Check whether the new rprimd does not give a too large number
 of plane waves, compared to the one booked for rprimd, taking
 into account the maximal dilatation dilatmx. Actually check whether
 the new Fermi sphere is inside the old one, dilated.

INPUTS

  chkdilatmx_ = if 1, will prevent to have any vector outside the Fermi sphere, possibly
       by rescaling (three times at most), and then stopping the execution
                if 0, simply send a warning, but continues execution
  dilatmx     = maximal dilatation factor (usually the input variable)
  rprimd      = new primitive vectors
  rprimd_orig = original primitive vectors (usually the input variable)

OUTPUT

  dilatmx_errmsg=Emptry string if calculation can continue.
            If the calculation cannot continue, dilatmx_errmsg will contain
            the message that should be reported in the output file.

            Client code should handle a possible problem with the following test:

              if (LEN_TRIM(dilatmx_errmsg) then
                dump dilatmx_errmsg to the main output file.
                handle_error
              end if

SOURCE

1430 subroutine chkdilatmx(chkdilatmx_,dilatmx,rprimd,rprimd_orig,dilatmx_errmsg)
1431 
1432 !Arguments ------------------------------------
1433 !scalars
1434  integer,intent(in) :: chkdilatmx_
1435  real(dp),intent(in) :: dilatmx
1436  character(len=500),intent(out) :: dilatmx_errmsg
1437 !arrays
1438  real(dp),intent(inout) :: rprimd(3,3)
1439  real(dp),intent(in) :: rprimd_orig(3,3)
1440 
1441 !Local variables-------------------------------
1442 !scalars
1443  integer :: ii,jj,mu
1444  real(dp) :: alpha,dilatmx_new
1445 !arrays
1446  real(dp) :: eigval(3),gprimd_orig(3,3),met(3,3),old_to_new(3,3)
1447  character(len=500) :: msg
1448 
1449 ! *************************************************************************
1450 
1451 !Generates gprimd
1452  call matr3inv(rprimd_orig,gprimd_orig)
1453 
1454 !Find the matrix that transform an original xcart to xred, then to the new xcart
1455  do mu=1,3
1456    old_to_new(mu,:)=rprimd(mu,1)*gprimd_orig(:,1)+&
1457 &   rprimd(mu,2)*gprimd_orig(:,2)+&
1458 &   rprimd(mu,3)*gprimd_orig(:,3)
1459  end do
1460 
1461 !The largest increase in length will be obtained thanks
1462 !to the diagonalization of the corresponding metric matrix :
1463 !it is the square root of its largest eigenvalue.
1464  do ii=1,3
1465    do jj=1,3
1466      met(ii,jj)=old_to_new(1,ii)*old_to_new(1,jj)+&
1467 &     old_to_new(2,ii)*old_to_new(2,jj)+&
1468 &     old_to_new(3,ii)*old_to_new(3,jj)
1469    end do
1470  end do
1471 
1472  call matr3eigval(eigval,met)
1473 
1474  dilatmx_new=sqrt(maxval(eigval(:)))
1475 
1476  dilatmx_errmsg = ""
1477  if(dilatmx_new>dilatmx+tol6)then
1478 
1479 ! MJV 2014 07 22: correct rprim to maximum jump allowed by dilatmx
1480 ! XG 20171011 : eigenvalues of "old_to_old" tensor are of course the unity !
1481 
1482    if(chkdilatmx_/=0)then
1483      alpha = (dilatmx - one) / (dilatmx_new - one)
1484 !    for safety, only 90 percent of max jump
1485      alpha = 0.9_dp * alpha
1486 
1487      rprimd = alpha * rprimd + (one - alpha) * rprimd_orig
1488 
1489      write(dilatmx_errmsg,'(3a,es16.6,4a,es16.6,2a,es16.6,a)')&
1490        'The new primitive vectors rprimd (an evolving quantity)',ch10,&
1491        'are too large with respect to the old rprimd and the accompanying dilatmx: ',dilatmx,ch10,&
1492        'This large change of unit cell parameters is not allowed by the present value of dilatmx.',ch10,&
1493        'An adequate value would have been dilatmx_new= ',dilatmx_new,ch10,&
1494        'Calculation continues with limited jump, by rescaling the projected move by the factor: ',alpha,'.'
1495    else
1496      write(msg, '(3a,es16.6,2a,es16.6,2a)' )&
1497       'The new primitive vectors rprimd (an evolving quantity)',ch10,&
1498       'are too large, given the initial rprimd and the accompanying dilatmx: ',dilatmx,ch10,&
1499       'An adequate value would have been dilatmx_new= ',dilatmx_new,ch10,&
1500       'As chkdilatmx=0, assume experienced user. Execution will continue.'
1501      ABI_WARNING(msg)
1502    end if
1503 
1504  end if
1505 
1506 end subroutine chkdilatmx

m_geometry/chkrprimd [ Functions ]

[ Top ] [ m_geometry ] [ Functions ]

NAME

 chkrprimd

FUNCTION

 Test if {rprim,acell,rprimd} are consistent
 It means that rprimd can be reconstructed from the rprim and acell
 Output a message if is not the case

INPUTS

OUTPUT

  (only writing)

SOURCE

1349 subroutine chkrprimd(acell,rprim,rprimd,iout)
1350 
1351 !Arguments ------------------------------------
1352 !scalars
1353 integer,intent(in) :: iout
1354 !arrays
1355 real(dp),intent(in) :: rprim(3,3)
1356 real(dp),intent(in) :: rprimd(3,3)
1357 real(dp),intent(in) :: acell(3)
1358 
1359 !Local variables-------------------------------
1360 !scalars
1361 integer :: ii,jj
1362 !arrays
1363 real(dp) :: rprimd_test(3,3)
1364 logical :: equal
1365 
1366 ! ***********************************************************
1367 
1368 !###########################################################
1369 !### 1. Compute rprimd from rprim and acell
1370  do ii=1,3
1371    do jj=1,3
1372      rprimd_test(ii,jj)=rprim(ii,jj)*acell(jj)
1373    end do
1374  end do
1375 
1376 
1377 !###########################################################
1378 !### 2. Compare rprimd and rprimd_test
1379 
1380  equal=.TRUE.
1381  do ii=1,3
1382    do jj=1,3
1383      if (abs(rprimd_test(ii,jj)-rprimd(ii,jj))>1.E-12) then
1384        equal=.FALSE.
1385      end if
1386    end do
1387  end do
1388 
1389  if (equal)then
1390    write(iout,*) 'chkrprimd: rprimd is consistent'
1391  else
1392    write(iout,*) 'chkrprimd: rprimd is NOT consistent ERROR'
1393  end if
1394 
1395 end subroutine chkrprimd

m_geometry/det3r [ Functions ]

[ Top ] [ m_geometry ] [ Functions ]

NAME

  det3r

FUNCTION

  Compute determinant of a 3x3 real matrix

SOURCE

1156 pure real(dp) function det3r(rprimd)
1157 
1158 !Arguments ------------------------------------
1159  real(dp),intent(in) :: rprimd(3,3)
1160 
1161 ! *************************************************************************
1162 
1163  ! Compute unit cell volume
1164  det3r = rprimd(1,1)*(rprimd(2,2)*rprimd(3,3)-rprimd(3,2)*rprimd(2,3))+&
1165          rprimd(2,1)*(rprimd(3,2)*rprimd(1,3)-rprimd(1,2)*rprimd(3,3))+&
1166          rprimd(3,1)*(rprimd(1,2)*rprimd(2,3)-rprimd(2,2)*rprimd(1,3))
1167 
1168 end function det3r

m_geometry/dist2 [ Functions ]

[ Top ] [ m_geometry ] [ Functions ]

NAME

  dist2

FUNCTION

  Calculates the distance of v1 and v2 in a crystal by repeating the unit cell

INPUTS

  v1,v2
  rprimd: dimensions of the unit cell. if not given 1,0,0/0,1,0/0,0,1 is assumed
  option: 0 v1, v2 given in cartesian coordinates (default)
          1 v1,v2 given in reduced coordinates
         -1 v1 and v2 are supposed equal, and the routine returns the length of the smallest Bravais lattice vector

OUTPUT

  dist2

SOURCE

2597 function dist2(v1,v2,rprimd,option)
2598 
2599 !Arguments ------------------------------------
2600 !scalars
2601  integer,intent(in),optional :: option
2602  real(dp) :: dist2
2603 !arrays
2604  real(dp),intent(in),optional :: rprimd(3,3)
2605  real(dp),intent(in) :: v1(3),v2(3)
2606 
2607 !Local variables-------------------------------
2608 !scalars
2609  integer :: i1,i2,i3,opt,s1,s2,s3
2610  real(dp):: min2,norm2,ucvol
2611 !arrays
2612  integer :: limits(3)
2613  real(dp) :: corner(3),dred(3),dtot(3),dv(3),dwrap(3),sh(3)
2614  real(dp) :: gmet(3,3),gprimd(3,3),rmet(3,3)
2615  real(dp) :: vprimd(3,3)
2616 
2617 ! *************************************************************************
2618 
2619  if (.not.PRESENT(rprimd)) then
2620    vprimd=reshape((/1,0,0,  0,1,0,  0,0,1/),(/3,3/))
2621  else
2622    vprimd=rprimd
2623  end if
2624 
2625  call metric(gmet,gprimd,-1,rmet,vprimd,ucvol)
2626 
2627  dv(:)=v2(:)-v1(:)
2628 
2629 !If in cartesian coordinates, need to be transformed to reduced coordinates.
2630  opt=0
2631  if(present(option))then
2632    opt=option
2633  end if
2634  if(opt==0)then
2635    dred(:)=gprimd(1,:)*dv(1)+gprimd(2,:)*dv(2)+gprimd(3,:)*dv(3)
2636  else if(opt==1)then
2637    dred(:)=dv(:)
2638  else if(opt==-1)then
2639    dred(:)=zero
2640  end if
2641 
2642 !Wrap in the ]-1/2,1/2] interval
2643  call wrap2_pmhalf(dred(1),dwrap(1),sh(1))
2644  call wrap2_pmhalf(dred(2),dwrap(2),sh(2))
2645  call wrap2_pmhalf(dred(3),dwrap(3),sh(3))
2646 
2647 !Compute the limits of the parallelipipedic box that contains the Wigner-Seitz cell
2648 !The reduced coordinates of the corners of the Wigner-Seitz cell are computed (multiplied by two)
2649 !Then, the maximal values of these reduced coordinates are stored.
2650  limits(:)=0
2651  do s1=-1,1,2
2652    do s2=-1,1,2
2653      do s3=-1,1,2
2654        corner(:)=gmet(:,1)*s1*rmet(1,1)+gmet(:,2)*s2*rmet(2,2)+gmet(:,3)*s3*rmet(3,3)
2655        limits(1)=max(limits(1),ceiling(abs(corner(1))+tol14))
2656        limits(2)=max(limits(2),ceiling(abs(corner(2))+tol14))
2657        limits(3)=max(limits(3),ceiling(abs(corner(3))+tol14))
2658      end do
2659    end do
2660  end do
2661 
2662 !Use all relevant primitive real space lattice vectors to find the minimal difference vector
2663  min2=huge(zero)
2664  do i1=-limits(1),limits(1)
2665    dtot(1)=dwrap(1)+i1
2666    do i2=-limits(2),limits(2)
2667      dtot(2)=dwrap(2)+i2
2668      do i3=-limits(3),limits(3)
2669        if(opt/=-1.or.i1/=0.or.i2/=0.or.i3/=0)then
2670          dtot(3)=dwrap(3)+i3
2671          norm2=dtot(1)*rmet(1,1)*dtot(1)+dtot(2)*rmet(2,2)*dtot(2)+dtot(3)*rmet(3,3)*dtot(3)+&
2672 &         2*(dtot(1)*rmet(1,2)*dtot(2)+dtot(2)*rmet(2,3)*dtot(3)+dtot(3)*rmet(3,1)*dtot(1))
2673          min2=min(norm2,min2)
2674        endif
2675      end do
2676    end do
2677  end do
2678  dist2=sqrt(min2)
2679 
2680 end function dist2

m_geometry/fcart2gred [ Functions ]

[ Top ] [ m_geometry ] [ Functions ]

NAME

 fcart2gred

FUNCTION

 Convert cartesian forces into reduced forces

INPUTS

  fcart(3,natom)=forces in cartesian coordinates (Ha/Bohr)
  natom=Number of atoms in the unitary cell
  rprimd(3,3)=dimensional primitive

OUTPUT

  gred(3,natom)=symmetrized grtn = d(etotal)/d(xred)

NOTES

  Unlike gred, fcart has been corrected by enforcing
  the translational symmetry, namely that the sum of force
  on all atoms is zero.

SOURCE

1734 subroutine fcart2gred(fcart,gred,rprimd,natom)
1735 
1736 !Arguments ------------------------------------
1737 !scalars
1738  integer,intent(in) :: natom
1739 !arrays
1740  real(dp),intent(in) :: fcart(3,natom)
1741  real(dp),intent(out) :: gred(3,natom)
1742  real(dp),intent(in) :: rprimd(3,3)
1743 
1744 !Local variables-------------------------------
1745 !scalars
1746  integer :: iatom,mu
1747 
1748 ! *************************************************************************
1749 
1750 !MT, april 2012: the coding was not consistent with gred2fcart
1751  do iatom=1,natom
1752    do mu=1,3
1753      gred(mu,iatom)= - (rprimd(1,mu)*fcart(1,iatom)+&
1754 &     rprimd(2,mu)*fcart(2,iatom)+&
1755 &     rprimd(3,mu)*fcart(3,iatom))
1756    end do
1757  end do
1758 
1759 !Previous version
1760 !do iatom=1,natom
1761 !do mu=1,3
1762 !gred(mu,iatom)= - (rprimd(mu,1)*fcart(1,iatom)+&
1763 !&     rprimd(mu,2)*fcart(2,iatom)+&
1764 !&     rprimd(mu,3)*fcart(3,iatom))
1765 !end do
1766 !end do
1767 
1768 end subroutine fcart2gred

m_geometry/fixsym [ Functions ]

[ Top ] [ m_geometry ] [ Functions ]

NAME

 fixsym

FUNCTION

 Using input indsym which tells which atoms are related by symmetry,
 check that iatfix consistently fixes (freezes) all atoms which are
 related by symmetry, i.e. that iatfix does not break symmetry.

INPUTS

 iatfix(3,natom)=integer array with 1 in every position for which
  the atom is to be kept fixed
  NOTE that this is not the input data structure for iatfix but it is
  the internal data structure used through most of the subroutines
 indsym(4,nsym,natom)=indirect indexing array for symmetrically related
  atoms; 4th element is label of symmetrically related atom
 natom=number of atoms
 nsym=number of symmetries (should be > 1 when this is called)

OUTPUT

  (only checking)

 NOTE
  Stops execution with an error message if iatfix breaks symmetry.

SOURCE

1109 subroutine fixsym(iatfix,indsym,natom,nsym)
1110 
1111 !Arguments ------------------------------------
1112 !scalars
1113  integer,intent(in) :: natom,nsym
1114 !arrays
1115  integer,intent(in) :: iatfix(3,natom),indsym(4,nsym,natom)
1116 
1117 !Local variables-------------------------------
1118 !scalars
1119  integer :: iatom,isym,jatom
1120  character(len=500) :: msg
1121 
1122 ! *************************************************************************
1123 
1124  if (nsym > 1) then
1125    do iatom=1,natom
1126      do isym=1,nsym
1127        ! jatom is the label of a symmetrically related atom
1128        jatom=indsym(4,isym,iatom)
1129        ! Thus the atoms jatom and iatom must be fixed along the same directions
1130        if (iatfix(1,jatom) /=  iatfix(1,iatom) .or. &
1131            iatfix(2,jatom) /=  iatfix(2,iatom) .or. &
1132            iatfix(3,jatom) /=  iatfix(3,iatom)) then
1133          write(msg, '(a,i0,a,i0,7a)' )&
1134            'Atom number: ',jatom,' is symmetrically  equivalent to atom number: ',iatom,',',ch10,&
1135            'but according to iatfix, iatfixx, iatfixy and iatfixz, they',ch10,&
1136            'are not fixed along the same directions, which is forbidden.',ch10,&
1137            'Action: modify either the symmetry or iatfix(x,y,z) and resubmit.'
1138          ABI_ERROR(msg)
1139        end if
1140      end do
1141    end do
1142  end if
1143 
1144 end subroutine fixsym

m_geometry/getspinrot [ Functions ]

[ Top ] [ m_geometry ] [ Functions ]

NAME

 getspinrot

FUNCTION

 From the symmetry matrix symrel expressed in the coordinate system rprimd,
 compute the components of the spinor rotation matrix

INPUTS

 rprimd(3,3)=dimensional primitive translations for real space (bohr)
 symrel(3,3)=symmetry operation in real space in terms of primitive translations rprimd

OUTPUT

 spinrot(4)=components of the spinor rotation matrix:

  spinrot(1)=$\cos \phi / 2$
  spinrot(2)=$\sin \phi / 2 \times u_x$
  spinrot(3)=$\sin \phi / 2 \times u_y$
  spinrot(4)=$\sin \phi / 2 \times u_z$

  where $\phi$ is the angle of rotation, and $(u_x,u_y,u_z)$ is the normalized direction of the rotation axis

NOTES

 Only the proper part of the symmetry operation is taken into account:
 pure rotations, while the inversion part is taken away, if present.

 The whole collection of symmetry matrices is call symrel(3,3,nsym)
 symrel1 contains just one of those matrices symrel1(3,3)

SOURCE

782 subroutine getspinrot(rprimd, spinrot, symrel)
783 
784 !Arguments ------------------------------------
785 !arrays
786  integer,intent(in) :: symrel(3,3)
787  real(dp),intent(in) :: rprimd(3,3)
788  real(dp),intent(out) :: spinrot(4)
789 
790 !Local variables-------------------------------
791 !scalars
792  integer :: det,ii
793  real(dp) :: cos_phi,norminv,phi,scprod,sin_phi
794  !character(len=500) :: msg
795 !arrays
796  integer :: identity(3,3),symrel1(3,3)
797  real(dp) :: axis(3),coord(3,3),coordinvt(3,3),matr1(3,3),matr2(3,3)
798  real(dp) :: rprimd_invt(3,3),vecta(3),vectb(3),vectc(3)
799 
800 !**************************************************************************
801 
802  symrel1(:,:) = symrel(:,:)
803 
804  ! Compute determinant of the matrix
805  call mati3det(symrel1, det)
806 
807  ! Produce a rotation from an improper symmetry
808  if (det==-1) symrel1(:,:) = -symrel1(:,:)
809 
810  ! Test the possibility of the unit matrix
811  identity(:,:)=0; identity(1,1)=1; identity(2,2)=1; identity(3,3)=1
812 
813  if (sum((symrel1(:,:) - identity(:,:))**2)/=0) then
814 
815    ! Transform symmetry matrix in the system defined by rprimd
816    call matr3inv(rprimd, rprimd_invt)
817    do ii=1,3
818      coord(:,ii)=rprimd_invt(ii,:)
819    end do
820    call matr3inv(coord,coordinvt)
821    do ii=1,3
822      matr1(:,ii) = symrel1(:,1)*coord(1,ii) + symrel1(:,2)*coord(2,ii) + symrel1(:,3)*coord(3,ii)
823    end do
824    do ii=1,3
825      matr2(:,ii) = coordinvt(1,:)*matr1(1,ii) + coordinvt(2,:)*matr1(2,ii) + coordinvt(3,:)*matr1(3,ii)
826    end do
827 
828    ! Find the eigenvector with unit eigenvalue of the
829    ! rotation matrix in cartesian coordinate, matr2
830 
831    matr1(:,:)=matr2(:,:)
832    matr1(1,1)=matr1(1,1)-one
833    matr1(2,2)=matr1(2,2)-one
834    matr1(3,3)=matr1(3,3)-one
835 
836    !  Compute the axis of rotation and the cos and sin of rotation angle
837    if(matr1(1,1)**2 + matr1(2,1)**2 + matr1(3,1)**2 < tol8 )then
838      ! The first direction is the axis
839      axis(1)=one ; axis(2)=zero ; axis(3)=zero
840      cos_phi=matr2(2,2)
841      sin_phi=matr2(3,2)
842    else if(matr1(1,2)**2 + matr1(2,2)**2 + matr1(3,2)**2 < tol8 )then
843      ! The second direction is the axis
844      axis(1)=zero ; axis(2)=one ; axis(3)=zero
845      cos_phi=matr2(3,3)
846      sin_phi=matr2(1,3)
847    else
848      ! In this case, try use the first and second vector to build the
849      ! rotation axis: compute their cross product
850      axis(1)=matr1(2,1)*matr1(3,2)-matr1(2,2)*matr1(3,1)
851      axis(2)=matr1(3,1)*matr1(1,2)-matr1(3,2)*matr1(1,1)
852      axis(3)=matr1(1,1)*matr1(2,2)-matr1(1,2)*matr1(2,1)
853      ! Then, try to normalize it
854      scprod=sum(axis(:)**2)
855      if(scprod<tol8)then
856        ! The first and second vectors were linearly dependent
857        ! Thus, use the first and third vectors
858        axis(1)=matr1(2,1)*matr1(3,3)-matr1(2,3)*matr1(3,1)
859        axis(2)=matr1(3,1)*matr1(1,3)-matr1(3,3)*matr1(1,1)
860        axis(3)=matr1(1,1)*matr1(2,3)-matr1(1,3)*matr1(2,1)
861        ! Normalize the vector
862        scprod=sum(axis(:)**2)
863        if(scprod < tol8)then
864          ABI_BUG('Cannot find the rotation axis.')
865        end if
866      end if
867      norminv=one/sqrt(scprod)
868      axis(:)=axis(:)*norminv
869 
870      ! Project the axis vector out of the first unit vector,
871      ! and renormalize the projected vector
872      ! (the first vector cannot be the axis, as tested before)
873      vecta(1)=one-axis(1)**2
874      vecta(2)=-axis(1)*axis(2)
875      vecta(3)=-axis(1)*axis(3)
876      scprod=sum(vecta(:)**2)
877      norminv=one/sqrt(scprod)
878      vecta(:)=vecta(:)*norminv
879      ! Rotate the vector A, to get vector B
880      vectb(:)=matr2(:,1)*vecta(1)+matr2(:,2)*vecta(2)+matr2(:,3)*vecta(3)
881      ! Get dot product of vectors A and B, giving cos of the rotation angle
882      cos_phi=sum(vecta(:)*vectb(:))
883      ! Compute the cross product of the axis and vector A
884      vectc(1)=axis(2)*vecta(3)-axis(3)*vecta(2)
885      vectc(2)=axis(3)*vecta(1)-axis(1)*vecta(3)
886      vectc(3)=axis(1)*vecta(2)-axis(2)*vecta(1)
887      ! Get dot product of vectors B and C, giving sin of the rotation angle
888      sin_phi=sum(vectb(:)*vectc(:))
889    end if
890 
891    ! Get the rotation angle, then the parameters of the spinor rotation
892    ! Here, treat possible inaccurate values of the cosine of phi
893    if(cos_phi>  one-tol8 )cos_phi=  one-tol8
894    if(cos_phi<-(one-tol8))cos_phi=-(one-tol8)
895    phi=acos(cos_phi)
896    if(sin_phi<zero)phi=-phi
897    ! Rectify the angle, such that its absolute values corresponds to 180, 120, 90, 60, or 0 degrees
898    phi=(nint(six*phi/pi))/six*pi
899    ! Compute components of the spinor matrix
900    spinrot(1)=cos(half*phi)
901    spinrot(2)=axis(1)*sin(half*phi)
902    spinrot(3)=axis(2)*sin(half*phi)
903    spinrot(4)=axis(3)*sin(half*phi)
904 
905  else
906 
907    ! Here, the case of the unit matrix
908    axis(:)=zero
909    phi=zero
910    spinrot(1)=one
911    spinrot(2)=zero
912    spinrot(3)=zero
913    spinrot(4)=zero
914 
915  end if ! the case of the identity matrix
916 
917 !DEBUG
918 !write(std_out,*)' getspinrot :'
919 !write(std_out,*)' symre =',symrel(:,:)
920 !write(std_out,*)' symrel1 =',symrel1(:,:)
921 !write(std_out,*)' rprimd =',rprimd(:,:)
922 !write(std_out,*)' matr2 =',matr2(:,:)
923 !write(std_out,*)' matr1 =',matr1(:,:)
924 !write(std_out,*)' phi (degree)=',phi*180._dp/pi
925 !write(std_out,'(a,3d16.6)' )' axis=',axis(:)
926 !write(std_out,*)' vecta=',vecta(:)
927 !stop
928 !ENDDEBUG
929 
930 end subroutine getspinrot

m_geometry/gred2fcart [ Functions ]

[ Top ] [ m_geometry ] [ Functions ]

NAME

 gred2fcart

FUNCTION

 Convert reduced forces into cartesian forces

INPUTS

  gred(3,natom)=symmetrized grtn = d(etotal)/d(xred)
  natom=Number of atoms in the unitary cell
  Favgz_null=TRUE if the average cartesian force has to be set to zero
             FALSE if it is set to zero only in x,y directions (not z)
  gprimd(3,3)=dimensional primitive translations for reciprocal space(bohr^-1)

OUTPUT

  fcart(3,natom)=forces in cartesian coordinates (Ha/Bohr)

NOTES

    Unlike gred, fcart has been corrected by enforcing
    the translational symmetry, namely that the sum of force
    on all atoms is zero (except is a slab is used)

SOURCE

1670 subroutine gred2fcart(favg,Favgz_null,fcart,gred,gprimd,natom)
1671 
1672 !Arguments ------------------------------------
1673 !scalars
1674  integer,intent(in) :: natom
1675  logical :: Favgz_null
1676 !arrays
1677  real(dp),intent(out) :: fcart(3,natom)
1678  real(dp),intent(in) :: gred(3,natom)
1679  real(dp),intent(in) :: gprimd(3,3)
1680  real(dp),intent(out) :: favg(3)
1681 
1682 !Local variables-------------------------------
1683 !scalars
1684  integer :: iatom,mu
1685 
1686 ! *************************************************************************
1687 
1688 !Note conversion to cartesian coordinates (bohr) AND
1689 !negation to make a force out of a gradient
1690  favg(:)=zero
1691  do iatom=1,natom
1692    do mu=1,3
1693      fcart(mu,iatom)= - (gprimd(mu,1)*gred(1,iatom)+&
1694 &     gprimd(mu,2)*gred(2,iatom)+&
1695 &     gprimd(mu,3)*gred(3,iatom))
1696      favg(mu)=favg(mu)+fcart(mu,iatom)
1697    end do
1698  end do
1699 
1700 !Subtract off average force from each force component
1701 !to avoid spurious drifting of atoms across cell.
1702  favg(:)=favg(:)/dble(natom)
1703  if(.not.Favgz_null) favg(3)=zero
1704  do iatom=1,natom
1705    fcart(:,iatom)=fcart(:,iatom)-favg(:)
1706  end do
1707 
1708 end subroutine gred2fcart

m_geometry/ioniondist [ Functions ]

[ Top ] [ m_geometry ] [ Functions ]

NAME

 ioniondist

FUNCTION

  Compute ion-ion distances

INPUTS

  natom= number of atoms in unit cell
  rprimd(3,3)=dimensional real space primitive translations (bohr)
  xred(3,natom)=dimensionless reduced coordinates of atoms
  inm(natom,natom)=index (m,n) of the atom
  option= 1 output ion-ion distances / 2 output ordering of ion-ion
          distances / 3 output variables in varlist
          according to ion-ion distances * magnetic ordering
          magv magnetic ordering of atoms given als 1 and -1, if not
          given fm is assumed
  varlist=List of variables
  magv(natom)= magnetic ordering of atoms
  atp=atom on which the perturbation was done

OUTPUT

SOURCE

2475 subroutine ioniondist(natom,rprimd,xred,inm,option,varlist,magv,atp,prtvol)
2476 
2477 !Arguments ------------------------------------
2478 !scalars
2479  integer,intent(in)              :: natom,option
2480  integer,intent(in),optional     :: atp                   !atom on which the perturbation was done
2481 !arrays
2482  real(dp),intent(in)             :: rprimd(3,3)
2483  real(dp),intent(in)             :: xred(3,natom)
2484  real(dp),intent(out)            :: inm(natom,natom)
2485  integer,intent(in),optional     :: magv(natom)
2486  real(dp),intent(in),optional    :: varlist(natom)
2487  integer,intent(in),optional     :: prtvol
2488 
2489 !Local variables-------------------------------
2490 !scalars
2491  integer                      :: iatom,jatom,katom,kdum,atpp,prtvoll
2492  !character(len=500)           :: msg
2493 !arrays
2494  integer                      :: interq(natom)
2495  real(dp)                     :: hxcart(3,natom),distm(natom,natom)
2496  real(dp)                     :: magvv(natom)
2497 
2498 ! *************************************************************************
2499 
2500  hxcart=matmul(rprimd,xred)
2501  interq=(/(iatom,iatom=1,natom)/)
2502  inm=0
2503 
2504  if (present(magv)) then
2505    magvv=magv
2506  else
2507    magvv=(/ (1, iatom=1,natom)  /)
2508  end if
2509 
2510  if (present(atp)) then
2511    atpp=atp
2512  else
2513    atpp=1
2514  end if
2515 
2516  if (present(prtvol)) then
2517    prtvoll=prtvol
2518  else
2519    prtvoll=1
2520  end if
2521 
2522  if (option==3.and.(.not.present(varlist))) then
2523    call  wrtout(std_out,'ioniondist error: option=3 but no variable list provided for symmetrization','COLL')
2524    return
2525  end if
2526 
2527 !call wrtout(std_out,' ioniondist start ','COLL')
2528 
2529  distm=0
2530  katom=atpp-1
2531  do iatom=1,natom
2532    katom=katom+1
2533    if (katom > natom) katom=1
2534    distm(iatom,iatom)=0
2535    do jatom=iatom,natom
2536      distm(iatom,jatom)=dist2(xred(:,katom),xred(:,jatom),rprimd,1)*magvv(katom)*magvv(jatom)
2537      distm(jatom,iatom)=distm(iatom,jatom)
2538    end do
2539  end do
2540 
2541  if (prtvoll>=3) then
2542    call  wrtout(std_out,'ioniondist: ionic distances:','COLL')
2543    call prmat(distm,natom,natom,natom,std_out)
2544  end if
2545 
2546  distm=anint(distm*10000_dp)/10000_dp           ! rounding needed else distm(iatom,jatom)/= distm(1,kdum) sometimes fails
2547 
2548  do iatom=1,natom
2549    if (option==1) then
2550      inm(iatom,:)=distm(iatom,:)
2551    else
2552      do jatom=iatom,natom
2553        kdum=1
2554        do while ( (kdum <= natom) .and. (distm(iatom,jatom)/= distm(1,kdum)) )
2555          kdum=kdum+1
2556        end do
2557        if (option==2) then
2558          inm(iatom,jatom)=interq(kdum)
2559        else if (option==3) then
2560          inm(iatom,jatom)=varlist(kdum)
2561        end if
2562        inm(jatom,iatom)=inm(iatom,jatom)
2563      end do
2564    end if
2565  end do
2566 
2567  if (prtvoll==2) then
2568    call wrtout(std_out,'ioniondist: symmetrized matrix:','COLL')
2569    call prmat(distm,1,natom,natom,std_out)
2570  else if (prtvoll>=3) then
2571    call wrtout(std_out,'ioniondist: symmetrized matrix:','COLL')
2572    call prmat(distm,natom,natom,natom,std_out)
2573  end if
2574 
2575 end subroutine ioniondist

m_geometry/littlegroup_pert [ Functions ]

[ Top ] [ m_geometry ] [ Functions ]

NAME

 littlegroup_pert

FUNCTION

 If syuse==0 and abs(rfmeth)==2, determines the set of symmetries that leaves a perturbation invariant.
 (Actually, all symmetries that leaves a q-wavevector invariant should be used to reduce the number
 of k-points for all perturbations. Unfortunately, one has to take into account the sign reversal of the
 perturbation under the symmetry operations, which makes GS routines not usable for the respfn code.
 The intermediate choice was to select only those that keep also the perturbation invariant.
 Note that the wavevector of the perturbation must also be invariant,
 a translation vector in real space is NOT allowed ).

INPUTS

 gprimd(3,3)=dimensional primitive translations for reciprocal space (bohr**-1)
 idir=direction of the perturbation
 indsym(4,nsym,natom)=indirect indexing of atom labels--see subroutine symatm for definition (if nsym>1)
 iout=if non-zero, output on unit iout
 ipert=characteristics of the perturbation
 natom= number of atoms
 nsym=number of space group symmetries
 rfmeth =
   1 or -1 if non-stationary block
   2 or -2 if stationary block
   3 or -3 if third order derivatives
   positive if symmetries are used to set elements to zero whenever possible, negative to prevent this to happen.
 symq(4,2,nsym)= Table computed by littlegroup_q.
   three first numbers define the G vector;
   fourth number is zero if the q-vector is not preserved, is 1 otherwise
   second index is one without time-reversal symmetry, two with time-reversal symmetry
 symafm(nsym)=(anti)ferromagnetic part of the symmetry operations
 symrec(3,3,nsym)=3x3 matrices of the group symmetries (reciprocal space)
 symrel(3,3,nsym)=3x3 matrices of the group symmetries (real space)
 syuse= flag to use the symmetries or not. If 0 usei it, if 1 do not use it.
 tnons(3,nsym)=nonsymmorphic translations of space group in terms
  of real space primitive translations (may be 0)
 [unit]=By default the routine writes to std_out and this is very annoying if we are inside a big loop.
   Use unit=dev_null or a negative integer to disable writing.

OUTPUT

 nsym1 =number of space group symmetries that leaves the perturbation invariant
 symaf1(nsym1)=(anti)ferromagnetic part of the corresponding symmetry operations
 symrl1(3,3,nsym1)=corresponding 3x3 matrices of the group symmetries (real space)
 tnons1(3,nsym1)=corresponding nonsymmorphic translations of space group in terms
   of real space primitive translations (may be 0)!!

SOURCE

3297 subroutine littlegroup_pert(gprimd,idir,indsym,iout,ipert,natom,nsym,nsym1, &
3298 &    rfmeth,symafm,symaf1,symq,symrec,symrel,symrl1,syuse,tnons,tnons1, &
3299 &    unit) ! Optional
3300 
3301 !Arguments -------------------------------
3302 !scalars
3303  integer,intent(in) :: idir,iout,ipert,natom,nsym,rfmeth,syuse
3304  integer,intent(in),optional :: unit
3305  integer,intent(out) :: nsym1
3306 !arrays
3307  integer,intent(in) :: indsym(4,nsym,natom),symafm(nsym),symq(4,2,nsym)
3308  integer,intent(in) :: symrec(3,3,nsym),symrel(3,3,nsym)
3309  integer,intent(out) :: symaf1(nsym),symrl1(3,3,nsym)
3310  real(dp),intent(in) :: gprimd(3,3),tnons(3,nsym)
3311  real(dp),intent(out) :: tnons1(3,nsym)
3312 
3313 !Local variables -------------------------
3314 !scalars
3315  integer :: idir1,ii,istr,isym,jj,nsym_test,tok,ount
3316  character(len=500) :: msg
3317 !arrays
3318  integer :: sym_test(3,3,2)
3319  real(dp) :: str_test(6)
3320 
3321 ! *********************************************************************
3322 
3323  ount = std_out; if (present(unit)) ount = unit
3324 
3325  nsym1=0
3326  if((ipert==natom+3 .or. ipert==natom+4) .and. syuse==0 .and. abs(rfmeth)==2) then
3327 !  Strain perturbation section
3328 !  Use ground state routine which symmetrizes cartesian stress as a quick
3329 !  and dirty test for the invariance of the strain (ipert,idir) under
3330 !  each candidate symmetry
3331 !  I am presently assuming that translations are acceptable because I dont
3332 !  see why not.
3333 
3334    istr=3*(ipert-natom-3)+idir
3335    nsym_test=2
3336 !  Store identity as first element for test
3337    sym_test(:,:,1)=0
3338    sym_test(1,1,1)=1; sym_test(2,2,1)=1; sym_test(3,3,1)=1
3339    do isym=1,nsym
3340      sym_test(:,:,2)=symrec(:,:,isym)
3341      str_test(:)=0.0_dp
3342      str_test(istr)=1.0_dp
3343      call stresssym(gprimd,nsym_test,str_test,sym_test)
3344      if(abs(str_test(istr)-1.0_dp)<tol8)then
3345 !      The test has been successful !
3346        nsym1=nsym1+1
3347        symaf1(nsym1)=symafm(isym)
3348        do ii=1,3
3349          tnons1(ii,nsym1)=tnons(ii,isym)
3350          do jj=1,3
3351            symrl1(ii,jj,nsym1)=symrel(ii,jj,isym)
3352          end do
3353        end do
3354      end if
3355    end do
3356 
3357  else if(ipert>natom .or. syuse/=0 .or. abs(rfmeth)/=2)then
3358 
3359 !  Not yet coded for d/dk or electric field perturbations
3360    nsym1=1
3361    do ii=1,3
3362      tnons1(ii,1)=0._dp
3363      symaf1(1)=1
3364      do jj=1,3
3365        symrl1(ii,jj,1)=0
3366        if(ii==jj)symrl1(ii,jj,1)=1
3367      end do
3368    end do
3369 
3370  else
3371 
3372    do isym=1,nsym
3373 !    Check that the symmetry operation preserves the wavevector
3374 !    (a translation is NOT allowed)
3375      if(symq(4,1,isym)==1 .and.&
3376 &     symq(1,1,isym)==0 .and.&
3377 &     symq(2,1,isym)==0 .and.&
3378 &     symq(3,1,isym)==0          )then
3379 !      Check that the symmetry operation preserves the atom
3380        if(ipert==indsym(4,isym,ipert))then
3381 !        Check if the direction is preserved
3382          tok=1
3383          do idir1=1,3
3384            if((idir1==idir.and.symrec(idir,idir1,isym)/=1) .or.&
3385 &           (idir1/=idir.and.symrec(idir,idir1,isym)/=0))then
3386              tok=0
3387            end if
3388          end do
3389          if(tok==1)then
3390 !          All the tests have been successful !
3391            nsym1=nsym1+1
3392            symaf1(nsym1)=symafm(isym)
3393            do ii=1,3
3394              tnons1(ii,nsym1)=tnons(ii,isym)
3395              do jj=1,3
3396                symrl1(ii,jj,nsym1)=symrel(ii,jj,isym)
3397              end do
3398            end do
3399          end if
3400 
3401        end if
3402      end if
3403    end do
3404  end if
3405 
3406  if (nsym1<1) then
3407    write(msg,'(a,i0,a)')' The number of selected symmetries should be > 0, while it is nsym= ',nsym1,'.'
3408    ABI_BUG(msg)
3409  end if
3410 
3411  if (nsym1 /= 1) then
3412    if (iout /= ount .and. iout > 0) then
3413      write(msg,'(a,i5,a)')' Found ',nsym1,' symmetries that leave the perturbation invariant.'
3414      call wrtout(iout,msg,'COLL')
3415    end if
3416    write(msg,'(a,i5,a)')' littlegroup_pert: found ',nsym1,' symmetries that leave the perturbation invariant: '
3417    call wrtout(ount,msg,'COLL')
3418  else
3419    if (iout /= ount .and. iout > 0) then
3420      write(msg,'(a,a)')' The set of symmetries contains',' only one element for this perturbation.'
3421      call wrtout(iout,msg,'COLL')
3422    end if
3423    write(msg,'(a)')' littlegroup_pert: only one element in the set of symmetries for this perturbation:'
3424    call wrtout(ount,msg,'COLL')
3425  end if
3426 
3427  if (ount > 0) then
3428    do isym=1,nsym1
3429      write(msg, '(9i4)' )((symrl1(ii,jj,isym),ii=1,3),jj=1,3)
3430      call wrtout(ount,msg,'COLL')
3431    end do
3432  end if
3433 
3434 end subroutine littlegroup_pert

m_geometry/metric [ Functions ]

[ Top ] [ m_geometry ] [ Functions ]

NAME

 metric

FUNCTION

 Compute first dimensional primitive translation vectors in reciprocal space
 gprimd from rprimd, and eventually writes out.
 Then, computes metrics for real and recip space rmet and gmet using length
 dimensional primitive translation vectors in columns of rprimd(3,3) and gprimd(3,3).
  gprimd is the inverse transpose of rprimd.
  i.e. $ rmet_{i,j}= \sum_k ( rprimd_{k,i}*rprimd_{k,j} )  $
       $ gmet_{i,j}= \sum_k ( gprimd_{k,i}*gprimd_{k,j} )  $
 Also computes unit cell volume ucvol in $\textrm{bohr}^3$

INPUTS

  rprimd(3,3)=dimensional primitive translations for real space (bohr)
  iout=unit number of output file.  If iout<0, do not write output.

OUTPUT

  gmet(3,3)=reciprocal space metric ($\textrm{bohr}^{-2}$).
  gprimd(3,3)=dimensional primitive translations for reciprocal space ($\textrm{bohr}^{-1}$)
  rmet(3,3)=real space metric ($\textrm{bohr}^{2}$).
  ucvol=unit cell volume ($\textrm{bohr}^{3}$).

SOURCE

1197 subroutine metric(gmet, gprimd, iout, rmet, rprimd, ucvol)
1198 
1199 !Arguments ------------------------------------
1200 !scalars
1201  integer,intent(in) :: iout
1202  real(dp),intent(out) :: ucvol
1203 !arrays
1204  real(dp),intent(in) :: rprimd(3,3)
1205  real(dp),intent(out) :: gmet(3,3),gprimd(3,3),rmet(3,3)
1206 
1207 !Local variables-------------------------------
1208 !scalars
1209  integer :: nu
1210  character(len=500) :: msg
1211 !arrays
1212  real(dp) :: angle(3)
1213 
1214 ! *************************************************************************
1215 
1216  ! Compute unit cell volume
1217  ucvol=rprimd(1,1)*(rprimd(2,2)*rprimd(3,3)-rprimd(3,2)*rprimd(2,3))+&
1218        rprimd(2,1)*(rprimd(3,2)*rprimd(1,3)-rprimd(1,2)*rprimd(3,3))+&
1219        rprimd(3,1)*(rprimd(1,2)*rprimd(2,3)-rprimd(2,2)*rprimd(1,3))
1220  !ucvol = det3r(rprimd)
1221 
1222  ! Check that the input primitive translations are not linearly dependent (and none is zero); i.e. ucvol~=0
1223  ! Also ask that the mixed product is positive.
1224  if (abs(ucvol)<tol12) then
1225    !write(std_out,*)"rprimd",rprimd,"ucvol",ucvol
1226    write(msg,'(5a)')&
1227      'Input rprim and acell gives vanishing unit cell volume.',ch10,&
1228      'This indicates linear dependency between primitive lattice vectors',ch10,&
1229      'Action: correct either rprim or acell in input file.'
1230    ABI_ERROR(msg)
1231  end if
1232  if (ucvol<zero)then
1233    write(msg,'(2a,3(a,3es16.6,a),7a)')&
1234      'Current rprimd gives negative (R1 x R2) . R3 . ',ch10,&
1235      'Rprimd =',rprimd(:,1),ch10,&
1236      '        ',rprimd(:,2),ch10,&
1237      '        ',rprimd(:,3),ch10,&
1238      'Action: if the cell size and shape are fixed (optcell==0),',ch10,&
1239      '        exchange two of the input rprim vectors;',ch10,&
1240      '        if you are optimizing the cell size and shape (optcell/=0),',ch10,&
1241      '        maybe the move was too large, and you might try to decrease strprecon.'
1242    ABI_ERROR(msg)
1243  end if
1244 
1245  ! Generate gprimd
1246  call matr3inv(rprimd,gprimd)
1247 
1248  ! Write out rprimd, gprimd and ucvol
1249  if (iout>=0) then
1250    write(msg,'(2a)')' Real(R)+Recip(G) ','space primitive vectors, cartesian coordinates (Bohr,Bohr^-1):'
1251    call wrtout(iout,msg)
1252    do nu=1,3
1253      write(msg, '(1x,a,i1,a,3f11.7,2x,a,i1,a,3f11.7)' ) &
1254       'R(',nu,')=',rprimd(:,nu)+tol10,&
1255       'G(',nu,')=',gprimd(:,nu)+tol10
1256      call wrtout(iout,msg)
1257    end do
1258    write(msg,'(a,1p,e15.7,a)') ' Unit cell volume ucvol=',ucvol+tol10,' bohr^3'
1259    call wrtout(iout,msg,'COLL')
1260    call wrtout(std_out,msg,'COLL')
1261  end if
1262 
1263  ! Compute real space metric.
1264  rmet = MATMUL(TRANSPOSE(rprimd),rprimd)
1265 
1266  ! Compute reciprocal space metric.
1267  gmet = MATMUL(TRANSPOSE(gprimd),gprimd)
1268 
1269  ! Write out the angles
1270  if (iout>=0) then
1271    angle(1)=acos(rmet(2,3)/sqrt(rmet(2,2)*rmet(3,3)))/two_pi*360.0d0
1272    angle(2)=acos(rmet(1,3)/sqrt(rmet(1,1)*rmet(3,3)))/two_pi*360.0d0
1273    angle(3)=acos(rmet(1,2)/sqrt(rmet(1,1)*rmet(2,2)))/two_pi*360.0d0
1274    write(msg, '(a,3es16.8,a)' )' Angles (23,13,12)=',angle(1:3),' degrees'
1275    call wrtout(iout,msg,'COLL')
1276    call wrtout(std_out,msg,'COLL')
1277  end if
1278 
1279 end subroutine metric

m_geometry/mkradim [ Functions ]

[ Top ] [ m_geometry ] [ Functions ]

NAME

 mkradim

FUNCTION

  Not so trivial subroutine to make dimensionless real space
  primitive translations rprim(3,3) from dimensional rprimd(3).
  also make acell(3).

INPUTS

  rprimd(3,3)=dimensional real space primitive translations (bohr)
              where: rprimd(i,j)=rprim(i,j)*acell(j)

OUTPUT

  acell(3)=unit cell length scales (bohr)
  rprim(3,3)=dimensionless real space primitive translations

SOURCE

1301 subroutine mkradim(acell,rprim,rprimd)
1302 
1303 !Arguments ------------------------------------
1304 !arrays
1305  real(dp),intent(out) :: acell(3),rprim(3,3)
1306  real(dp),intent(in) :: rprimd(3,3)
1307 
1308 !Local variables-------------------------------
1309 !scalars
1310  integer :: ii,jj
1311  real(dp) :: rprim_maxabs
1312 
1313 ! *************************************************************************
1314 
1315 !Use a representation based on normalised rprim vectors
1316  do ii=1,3
1317    acell(ii)=sqrt(rprimd(1,ii)**2+rprimd(2,ii)**2+rprimd(3,ii)**2)
1318    rprim(:,ii)=rprimd(:,ii)/acell(ii)
1319  end do
1320 
1321 !Suppress meaningless values
1322  rprim_maxabs=maxval(abs(rprim))
1323  do ii=1,3
1324    do jj=1,3
1325      if(abs(rprim(ii,jj))<tol12*rprim_maxabs)rprim(ii,jj)=zero
1326    enddo
1327  enddo
1328 
1329 end subroutine mkradim

m_geometry/mkrdim [ Functions ]

[ Top ] [ m_geometry ] [ Functions ]

NAME

 mkrdim

FUNCTION

  Trivial subroutine to make dimensional real space
  primitive translations from length scales acell(3)
  and dimensionless translations rprim(3,3).

INPUTS

  acell(3)=unit cell length scales (bohr)
  rprim(3,3)=dimensionless real space primitive translations

OUTPUT

  rprimd(3,3)=dimensional real space primitive translations (bohr)
              where: rprimd(i,j)=rprim(i,j)*acell(j)

SOURCE

1528 subroutine mkrdim(acell,rprim,rprimd)
1529 
1530 !Arguments ------------------------------------
1531 !arrays
1532  real(dp),intent(in) :: acell(3),rprim(3,3)
1533  real(dp),intent(out) :: rprimd(3,3)
1534 
1535 !Local variables-------------------------------
1536 !scalars
1537  integer :: ii,jj
1538 
1539 ! *************************************************************************
1540 
1541  do ii=1,3
1542    do jj=1,3
1543      rprimd(ii,jj)=rprim(ii,jj)*acell(jj)
1544    end do
1545  end do
1546 
1547 end subroutine mkrdim

m_geometry/normv_int_vector [ Functions ]

[ Top ] [ m_geometry ] [ Functions ]

NAME

  normv_int_vector

FUNCTION

  Returns the norm of an integer 3D vector expressed in reduced coordinates.
  either in real or reciprocal space. In the later case the factor 2pi has
  to be included, due to the conventions used in abinit to define the reciprocal lattice.

INPUTS

OUTPUT

SOURCE

159 function normv_int_vector(xv, met, space) result(res)
160 
161 !Arguments ------------------------------------
162 !scalars
163  real(dp) :: res
164  character(len=1),intent(in) :: space
165 !arrays
166  real(dp),intent(in) :: met(3,3)
167  integer,intent(in) :: xv(3)
168 
169 ! *************************************************************************
170 
171  res =  ( xv(1)*met(1,1)*xv(1) + xv(2)*met(2,2)*xv(2) + xv(3)*met(3,3)*xv(3)  &
172 &  +two*( xv(1)*met(1,2)*xv(2) + xv(1)*met(1,3)*xv(3) + xv(2)*met(2,3)*xv(3)) )
173 
174  select case (space)
175  case ('r','R')
176    res=SQRT(res)
177  case ('g','G')
178    res=two_pi*SQRT(res)
179  case default
180    ABI_BUG('Wrong value for space')
181  end select
182 
183 end function normv_int_vector

m_geometry/normv_int_vector_array [ Functions ]

[ Top ] [ m_geometry ] [ Functions ]

NAME

  normv_int_vector_array

FUNCTION

  Returns the norm of an array of integer 3D vectors expressed in reduced coordinates.
  either in real or reciprocal space. In the later case the factor 2pi has
  to be included, due to the conventions used in abinit to define the reciprocal lattice.

INPUTS

OUTPUT

SOURCE

203 function normv_int_vector_array(xv,met,space) result(res)
204 
205 !Arguments ------------------------------------
206 !scalars
207  character(len=1),intent(in) :: space
208 !arrays
209  real(dp),intent(in) :: met(3,3)
210  integer,intent(in) :: xv(:,:)
211  !this awful trick is needed to avoid problems with abilint
212  real(dp) :: res(SIZE(xv(1,:)))
213  !real(dp) :: res(SIZE(xv,DIM=2))
214 
215 ! *************************************************************************
216 
217  res(:) = ( xv(1,:)*met(1,1)*xv(1,:) + xv(2,:)*met(2,2)*xv(2,:) + xv(3,:)*met(3,3)*xv(3,:)  &
218       +two*(xv(1,:)*met(1,2)*xv(2,:) + xv(1,:)*met(1,3)*xv(3,:) + xv(2,:)*met(2,3)*xv(3,:)) )
219 
220  select case (space)
221  case ('r','R')
222    res(:)=SQRT(res(:))
223  case ('g','G')
224    res(:)=two_pi*SQRT(res(:))
225  case default
226    ABI_BUG('Wrong value for space')
227  end select
228 
229 end function normv_int_vector_array

m_geometry/normv_rdp_vector [ Functions ]

[ Top ] [ m_geometry ] [ Functions ]

NAME

 normv_rdp_vector

FUNCTION

 Compute the norm of a vector expressed in reduced coordinates using the metric met.
 The result is multiplied by 2pi in case of a vector in reciprocal space
 to take into account the correct normalisation of the reciprocal lattice vectors

INPUTS

  xv(3)=Vector in reduced coordinates
  met(3,3)=Metric tensor
  space=Character defining whether we are working in real (r|R) or reciprocal space (g|G)

OUTPUT

  normv_rdp_vector=norm of xv

NOTES

  The routine is able to deal both with a single vector as well as arrays of vectors.
  Versions for integer and real vectors are provided.

SOURCE

116 function normv_rdp_vector(xv,met,space) result(res)
117 
118 !Arguments ------------------------------------
119 !scalars
120  real(dp) :: res
121  character(len=1),intent(in) :: space
122 !arrays
123  real(dp),intent(in) :: met(3,3),xv(3)
124 
125 ! *************************************************************************
126 
127  res =  (xv(1)*met(1,1)*xv(1) + xv(2)*met(2,2)*xv(2) + xv(3)*met(3,3)*xv(3)  &
128 &  +two*(xv(1)*met(1,2)*xv(2) + xv(1)*met(1,3)*xv(3) + xv(2)*met(2,3)*xv(3)) )
129 
130  select case (space)
131  case ('r','R')
132    res=SQRT(res)
133  case ('g','G')
134    res=two_pi*SQRT(res)
135  case default
136    ABI_BUG('Wrong value for space')
137  end select
138 
139 end function normv_rdp_vector

m_geometry/normv_rdp_vector_array [ Functions ]

[ Top ] [ m_geometry ] [ Functions ]

NAME

  normv_rdp_vector_array

FUNCTION

  Returns the norm of an array of real 3D vectors expressed in reduced coordinates.
  either in real or reciprocal space. In the later case the factor 2pi has
  to be included, due to the conventions used in abinit to define the reciprocal lattice.

INPUTS

OUTPUT

SOURCE

249 function normv_rdp_vector_array(xv,met,space) result(res)
250 
251 !Arguments ------------------------------------
252 !scalars
253  character(len=1),intent(in) :: space
254 !arrays
255  real(dp),intent(in) :: met(3,3)
256  real(dp),intent(in) :: xv(:,:)
257  !this awful trick is needed to avoid problems with abilint
258  real(dp) :: res(SIZE(xv(1,:)))
259  !real(dp) :: res(SIZE(xv,DIM=2))
260 
261 ! *************************************************************************
262 
263  res(:) = ( xv(1,:)*met(1,1)*xv(1,:) + xv(2,:)*met(2,2)*xv(2,:) + xv(3,:)*met(3,3)*xv(3,:)  &
264 &     +two*(xv(1,:)*met(1,2)*xv(2,:) + xv(1,:)*met(1,3)*xv(3,:) + xv(2,:)*met(2,3)*xv(3,:)) )
265 
266  select case (space)
267  case ('r','R')
268    res(:)=SQRT(res(:))
269  case ('g','G')
270    res(:)=two_pi*SQRT(res)
271  case default
272    ABI_BUG('Wrong value for space')
273  end select
274 
275 end function normv_rdp_vector_array

m_geometry/phdispl_cart2red [ Functions ]

[ Top ] [ m_geometry ] [ Functions ]

NAME

  phdispl_cart2red

FUNCTION

  Calculates the displacement vectors for all branches in reduced coordinates.
  $ displ_red = displ_cart \cdot gprimd $ for each phonon branch.

INPUTS

  natom=Number of atoms.
  gprimd(3,3)=Dimensional primitive translations for reciprocal space ($\textrm{bohr}^{-1}$)
  displ_cart(2,3*natom,3*natom)=Phonon displacement in Cartesian coordinates.

OUTPUT

  displ_red(2,3*natom,3*natom)=Phonon displacement in reduded coordinates.

SOURCE

703 subroutine phdispl_cart2red(natom, gprimd, displ_cart, displ_red)
704 
705 !Arguments ------------------------------------
706 !scalars
707  integer,intent(in) :: natom
708 !arrays
709  real(dp),intent(in) :: gprimd(3,3)
710  real(dp),intent(in) :: displ_cart(2,3*natom,3*natom)
711  real(dp),intent(out) :: displ_red(2,3*natom,3*natom)
712 
713 !Local variables-------------------------
714 !scalars
715  integer :: nbranch,jbranch,iatom,idir,ibranch,kdir,k1
716 
717 ! *************************************************************************
718 
719  displ_red = zero
720 
721  nbranch=3*natom
722 
723  do jbranch=1,nbranch
724    !
725    do iatom=1,natom
726      do idir=1,3
727        ibranch=idir+3*(iatom-1)
728        do kdir=1,3
729          k1 = kdir+3*(iatom-1)
730          ! WARNING: could be non-transpose of rprimd matrix : to be checked.
731          ! 23 june 2004: rprimd becomes gprimd
732          ! could be gprim and then multiply by acell...
733          ! Nope, checked and ok with gprimd 24 jun 2004
734          displ_red(1,ibranch,jbranch) = displ_red(1,ibranch,jbranch) + &
735 &         gprimd(kdir,idir) * displ_cart(1,k1,jbranch)
736 
737          displ_red(2,ibranch,jbranch) = displ_red(2,ibranch,jbranch) + &
738 &         gprimd(kdir,idir) * displ_cart(2,k1,jbranch)
739 
740        end do !kdir
741      end do !idir
742    end do !iatom
743    !
744  end do !jbranch
745 
746 end subroutine phdispl_cart2red

m_geometry/randomcellpos [ Functions ]

[ Top ] [ m_geometry ] [ Functions ]

NAME

  randomcellpos

FUNCTION

  This subroutine creates a unit cell with random atomic positions. It is
  assumed that the cell parameters are given and fixed. Several methods are
  used to generate the cell.

INPUTS

 natom=number of atoms
 npsp=number of pseudopotentials (needed for the dimension of znucl)
 ntypat=number of type of atoms
 random_atpos=input variable
   0 no generation of random atomic potision
   1 completely random atomic potisions
   2 random atomic positions, avoiding too close atoms
     (prevent coming closer than a fraction of the sum of covalent radii)
   3 same than 2 but also generates the rprim and acell randomly
    within some given ranges (angles between 50 and 130)
 ratsph(1:ntypat)=radius of the atomic sphere
 rprimd(3,3)=dimensional primitive translations in real space (bohr)
 typat(1:natom)= input variable giving the type of each atom
 znucl(1:npsp)=nuclear number of atom as specified in psp file

OUTPUT

 xred(3,natom)=reduced dimensionless atomic coordinates

SIDE EFFECTS

NOTES

SOURCE

2130 subroutine randomcellpos(natom,npsp,ntypat,random_atpos,ratsph,rprim,rprimd,typat,xred,znucl,acell)
2131 
2132 !Arguments ------------------------------------
2133 !scalars
2134  integer,intent(in) :: natom,npsp,ntypat,random_atpos
2135 !arrays
2136  integer, intent(in)   :: typat(natom)
2137  real(dp),intent(in)   :: ratsph(ntypat)
2138  real(dp), intent(inout)  :: rprim(3,3)
2139  real(dp), intent(inout)  :: rprimd(3,3)
2140  real(dp), intent(inout) :: xred(3,natom)
2141  real(dp), intent(in) :: znucl(npsp)
2142  real(dp), intent(inout) :: acell(3)
2143 
2144 !Local variables-------------------------------
2145  integer ::   iatom=0,ii,idum=-20
2146  real(dp) ::  rij(3), rijd(3), radiuscovi, radiuscovj, dist, rati, ratj, angdeg(3)
2147  real(dp) ::  cosang,aa,cc,a2
2148  character(len=500) :: msg
2149  type(atomdata_t) :: atom
2150 
2151 ! *************************************************************************
2152 
2153 !DEBUG
2154 !For the time being, print rprimd to keep it as an argument, in spite of abirule checking.
2155 !write (std_out,*) ' randomcellpos : enter'
2156 !write(std_out,*)' rprimd=',rprimd
2157 !write(std_out,*)' znucl=',znucl
2158 !write(std_out,*)' typat=',typat
2159 !write(std_out,*)' random_atpos=',random_atpos
2160 !ENDDEBUG
2161 
2162  if(random_atpos==2 .and. npsp/=ntypat)then
2163    write(msg, '(a,i5,2a,i5,a,i5,4a)' )&
2164 &   'Input variable random_atpos= ',random_atpos,ch10,&
2165 &   'However, the number of pseudopotentials ',npsp,', is not equal to the number of type of atoms ',ntypat,ch10,&
2166 &   'The use of alchemical mixing cannot be combined with the constraint based on the mixing of covalent radii.',ch10,&
2167 &   'Action: switch to another value of random_atpos.'
2168    ABI_ERROR(msg)
2169  end if
2170 
2171 !random_atpos = 0   Default value, no random initialisation
2172 !random_atpos = 1   Fully random (Is it really useful ???)
2173 !random_atpos = 2   Random, but the sum of the two covalent radii is
2174 !less than the interatomic distance
2175 !random_atpos = 3   Random, but the sum of the two (other type of)
2176 !radii is less than the interatomic distance
2177 !random_atpos = 4   Random, but the sum of the two pseudopotential
2178 !radii is less than the interatomic distance
2179 !random_atpos = 5   Random, but the interatomic distance must be bigger
2180 !than the sum of
2181 !some input variable (well, instead of defining a new variable, why
2182 !not use ratsph ?)
2183 !Right now we are not using a factor for the tested distance.. something to be done, after a new variable has been defined
2184 
2185  if (random_atpos /= 0) then
2186    select case (random_atpos)
2187    case (1)
2188      do ii=1,natom
2189        xred(1,ii)=uniformrandom(idum)
2190        xred(2,ii)=uniformrandom(idum)
2191        xred(3,ii)=uniformrandom(idum)
2192      end do
2193    case (2)
2194      iatom=0
2195      do
2196        iatom=iatom+1
2197        xred(1,iatom)=uniformrandom(idum)
2198        xred(2,iatom)=uniformrandom(idum)
2199        xred(3,iatom)=uniformrandom(idum)
2200        call atomdata_from_znucl(atom,znucl(typat(iatom)))
2201        radiuscovi = atom%rcov
2202        do ii=1,iatom-1
2203          rij=xred(:,iatom)-xred(:,ii)
2204 !          periodic boundary conditions
2205          rij = rij - 0.5
2206          rij = rij - anint (rij)
2207 !          coming back to cube between (0,1)
2208          rij = rij + 0.5
2209 !          convert reduced coordinates to cartesian coordinates
2210          call xred2xcart(1,rprimd,rijd,rij)
2211          dist=dot_product(rijd,rijd)
2212          call atomdata_from_znucl(atom,znucl(typat(ii)))
2213          radiuscovj = atom%rcov
2214          if (dist<(radiuscovj+radiuscovi)) then
2215            iatom = iatom -1
2216            EXIT
2217          end if
2218        end do
2219        if (iatom>=natom) EXIT
2220      end do
2221    case(3)
2222      iatom=0
2223      do
2224        iatom=iatom+1
2225        xred(1,iatom)=uniformrandom(idum)
2226        xred(2,iatom)=uniformrandom(idum)
2227        xred(3,iatom)=uniformrandom(idum)
2228        call atomdata_from_znucl(atom,znucl(typat(iatom)))
2229        radiuscovi = atom%rcov
2230        do ii=1,iatom-1
2231          rij=xred(:,iatom)-xred(:,ii)
2232 !          periodic boundary conditions
2233          rij = rij - 0.5
2234          rij = rij - anint (rij)
2235 !          coming back to cube between (0,1)
2236          rij = rij + 0.5
2237 !          convert reduced coordinates to cartesian coordinates
2238          call xred2xcart(1,rprimd,rijd,rij)
2239          dist=dot_product(rijd,rijd)
2240          call atomdata_from_znucl(atom,znucl(typat(ii)))
2241          radiuscovj = atom%rcov
2242          if (dist<(radiuscovj+radiuscovi)) then
2243            iatom = iatom -1
2244            EXIT
2245          end if
2246        end do
2247        if (iatom>=natom) EXIT
2248      end do
2249      do ii=1,3
2250 !        generates cells with angles between 60 and 120 degrees
2251        angdeg(ii)=60_dp+uniformrandom(idum)*60.0_dp
2252      end do
2253      if (angdeg(1)+angdeg(2)+angdeg(3)>360._dp) then
2254        angdeg(3)=360._dp-angdeg(1)-angdeg(2)
2255      end if
2256 !      check if angles are between the limits and create rprim
2257      if( abs(angdeg(1)-angdeg(2))<tol12 .and. &
2258 &     abs(angdeg(2)-angdeg(3))<tol12 .and. &
2259 &     abs(angdeg(1)-90._dp)+abs(angdeg(2)-90._dp)+abs(angdeg(3)-90._dp)>tol12 )then
2260 !        Treat the case of equal angles (except all right angles) :
2261 !        generates trigonal symmetry wrt third axis
2262        cosang=cos(pi*angdeg(1)/180.0_dp)
2263        a2=2.0_dp/3.0_dp*(1.0_dp-cosang)
2264        aa=sqrt(a2)
2265        cc=sqrt(1.0_dp-a2)
2266        rprim(1,1)=aa        ; rprim(2,1)=0.0_dp                 ; rprim(3,1)=cc
2267        rprim(1,2)=-0.5_dp*aa ; rprim(2,2)= sqrt(3.0_dp)*0.5_dp*aa ; rprim(3,2)=cc
2268        rprim(1,3)=-0.5_dp*aa ; rprim(2,3)=-sqrt(3.0_dp)*0.5_dp*aa ; rprim(3,3)=cc
2269 !        DEBUG
2270 !        write(std_out,*)' ingeo : angdeg=',angdeg(1:3)
2271 !        write(std_out,*)' ingeo : aa,cc=',aa,cc
2272 !        ENDDEBUG
2273      else
2274 !        Treat all the other cases
2275        rprim(:,:)=0.0_dp
2276        rprim(1,1)=1.0_dp
2277        rprim(1,2)=cos(pi*angdeg(3)/180.0_dp)
2278        rprim(2,2)=sin(pi*angdeg(3)/180.0_dp)
2279        rprim(1,3)=cos(pi*angdeg(2)/180.0_dp)
2280        rprim(2,3)=(cos(pi*angdeg(1)/180.0_dp)-rprim(1,2)*rprim(1,3))/rprim(2,2)
2281        rprim(3,3)=sqrt(1.0_dp-rprim(1,3)**2-rprim(2,3)**2)
2282      end if
2283 !      generate acell
2284      aa=zero
2285      do ii=1,npsp
2286        aa=znucl(ii)
2287      end do
2288      do ii=1,3
2289        acell(ii)=aa+uniformrandom(idum)*4.0
2290      end do
2291      call mkrdim(acell,rprim,rprimd)
2292    case(4)
2293      write(std_out,*) 'Not implemented yet'
2294    case(5)
2295      iatom=0
2296      do
2297        iatom=iatom+1
2298        xred(1,iatom)=uniformrandom(idum)
2299        xred(2,iatom)=uniformrandom(idum)
2300        xred(3,iatom)=uniformrandom(idum)
2301        rati=ratsph(typat(iatom))
2302        do ii=1,iatom-1
2303          ratj=ratsph(typat(ii))
2304 !          apply periodic boundary conditions
2305          rij=(xred(:,iatom)-xred(:,ii))-0.5
2306          rij = rij - ANINT ( rij )
2307          rij = rij + 0.5
2308          call xred2xcart(natom,rprimd,rijd,rij)
2309          dist=dot_product(rijd,rijd)
2310          if (dist<(rati+ratj)) EXIT
2311        end do
2312        if (iatom==natom) EXIT
2313        if (ii<(iatom-1)) iatom=iatom-1
2314      end do
2315    end select
2316  end if
2317 
2318 end subroutine randomcellpos

m_geometry/remove_inversion [ Functions ]

[ Top ] [ m_geometry ] [ Functions ]

NAME

 remove_inversion

FUNCTION

  Remove the inversion symmetry from a symmetry set as well
  all the improper rotations (if present)

INPUTS

  nsym=initial number of symmetries
  symrel(3,3,nsym)=Initial set of symmetry operarations in real space
  tnons(3,nsym)=Initial fractional translations

OUTPUT

  nsym_out=Number of symmetries in the set without improper rotation
  symrel_out(:,:) [pointer] = output symmetries without improper rotations
  tnons_out(:) [pointer] = fractional translations associated to symrel_out
  pinv=-1 if the inversion has been removed, 1 otherwise

NOTES

  Note the use of pointers, memory is allocated inside the procedure and passed back
  to the caller. Thus memory deallocation is relegated to the caller. To be on the safe side
  the pointers should be nullified before entering.

SOURCE

2709 subroutine remove_inversion(nsym,symrel,tnons,nsym_out,symrel_out,tnons_out,pinv)
2710 
2711 !Arguments ------------------------------------
2712 !scalars
2713  integer,intent(in) :: nsym
2714  integer,intent(out) :: nsym_out,pinv
2715 !arrays
2716  integer,intent(in) :: symrel(3,3,nsym)
2717  integer,pointer :: symrel_out(:,:,:)
2718  real(dp),intent(in) :: tnons(3,nsym)
2719  real(dp),pointer :: tnons_out(:,:)
2720 
2721 !Local variables-------------------------------
2722 !scalars
2723  integer :: is,is2,is_discarded,is_inv,is_retained,nsym2
2724  logical :: found
2725  character(len=500) :: msg
2726 !arrays
2727  integer :: determinant(nsym),inversion(3,3),symrel2(3,3,nsym)
2728  real(dp) :: dtnons(3),tnons2(3,nsym)
2729 
2730 ! *********************************************************************
2731 
2732  ABI_WARNING('Removing inversion related symmetrie from initial set')
2733 
2734  ! Find the occurence of the inversion symmetry.
2735  call set2unit(inversion) ; inversion=-inversion
2736 
2737  is_inv=0; found=.FALSE.
2738  do while (is_inv<nsym .and. .not.found)
2739    is_inv=is_inv+1; found=ALL(symrel(:,:,is_inv)==inversion)
2740  end do
2741  if (found) then
2742    write(msg,'(a,i3)')' The inversion is symmetry operation no. ',is_inv
2743  else
2744    write(msg,'(a)')' The inversion was not found in the symmetries list.'
2745  end if
2746  call wrtout(std_out,msg,'COLL')
2747 
2748  ! Find the symmetries that are related through the inversion symmetry
2749  call symdet(determinant,nsym,symrel)
2750  nsym2=0
2751  do is=1,nsym-1
2752    do is2=is+1,nsym
2753 
2754      dtnons(:)=tnons(:,is2)-tnons(:,is)-tnons(:,is_inv)
2755      found=ALL(symrel(:,:,is)==-symrel(:,:,is2)).and.isinteger(dtnons,tol8)
2756 
2757      if (found) then
2758        nsym2=nsym2+1
2759        ! Retain symmetries with positive determinant
2760        if (ALL(tnons(:,is2)<tol8).and.ALL(tnons(:,is)<tol8)) then
2761          is_retained=is2 ; is_discarded=is
2762          if (determinant(is)==1) then
2763            is_retained=is  ; is_discarded=is2
2764          end if
2765        else if (ALL(tnons(:,is2)<tol8)) then
2766          is_retained=is2 ; is_discarded=is
2767        else
2768          is_retained=is ;  is_discarded=is2
2769        end if
2770 
2771        symrel2(:,:,nsym2)=symrel(:,:,is_retained)
2772        tnons2   (:,nsym2)=tnons   (:,is_retained)
2773        write(msg,'(a,i3,a,i3,3a,i3,a)')&
2774 &       ' Symmetry operations no. ',is,' and no. ',is2,&
2775 &       ' are related through the inversion.',ch10,&
2776 &       ' Symmetry operation no. ',is_discarded,' will be suppressed.'
2777        call wrtout(std_out,msg,'COLL')
2778      end if ! found
2779 
2780    end do !is2
2781  end do !is
2782 
2783  if (nsym2/=(nsym/2).or.nsym==1) then
2784    call wrtout(std_out, ' Program uses the original set of symmetries ', 'COLL')
2785    nsym_out=nsym
2786    ABI_MALLOC(symrel_out,(3,3,nsym))
2787    ABI_MALLOC(tnons_out,(3,nsym))
2788    symrel_out(:,:,:)=symrel(:,:,1:nsym)
2789    tnons_out(:,:)=tnons(:,1:nsym)
2790    pinv=1
2791  else
2792    write(msg,'(a)')' Inversion related operations have been suppressed from symmetries list.'
2793    call wrtout(std_out,msg,'COLL')
2794    nsym_out=nsym2
2795    ABI_MALLOC(symrel_out,(3,3,nsym2))
2796    ABI_MALLOC(tnons_out,(3,nsym2))
2797    symrel_out(:,:,:)=symrel2(:,:,1:nsym2)
2798    tnons_out(:,:)=tnons(:,1:nsym2)
2799    pinv=-1
2800  end if
2801 
2802 end subroutine remove_inversion

m_geometry/rotmat [ Functions ]

[ Top ] [ m_geometry ] [ Functions ]

NAME

 rotmat

FUNCTION

 Finds the rotation matrix.

INPUTS

  xaxis(3)= vectors defining the x axis
  zaxis(3)= vectors defining the z axis

OUTPUT

  inversion_flag = flag that indicates that an inversion operation
   on the coordinate system should be done
  umat(3,3)= matrix that rotates the x=(1 0 0) and z=(0 0 1) to the new
   values defined in xaxis and zaxis

NOTES

 Here I set that the axe x is originally at the 1 0 0 direction and z is originally 0 0 1.
 So calling rotmat(x',z') will find the rotation
 matrix for the case in which we rotate the x and z
 axes from their default values to x' and z'.

SOURCE

1012 subroutine rotmat(xaxis,zaxis,inversion_flag,umat)
1013 
1014 !Arguments ------------------------------------
1015 !scalars
1016  integer,intent(out) :: inversion_flag
1017 !arrays
1018  real(dp),intent(in) :: xaxis(3),zaxis(3)
1019  real(dp),intent(out) :: umat(3,3)
1020 
1021 !Local variables-------------------------------
1022 !scalars
1023  real(dp) :: cosine,xmod,zmod
1024  character(len=500) :: msg
1025 !arrays
1026  real(dp) :: yaxis(3)
1027 
1028 ! *************************************************************************
1029 
1030  xmod = sqrt(xaxis(1)**2 + xaxis(2)**2 + xaxis(3)**2)
1031  zmod = sqrt(zaxis(1)**2 + zaxis(2)**2 + zaxis(3)**2)
1032 
1033  if(xmod < 1.d-8)then
1034    write(msg,'(a,a,a,i6)')&
1035 &   'The module of the xaxis should be greater than 1.d-8,',ch10,&
1036 &   'however, |xaxis|=',xmod
1037    ABI_BUG(msg)
1038  end if
1039 
1040  if(zmod < 1.d-8)then
1041    write(msg,'(a,a,a,i6)')&
1042 &   'The module of the zaxis should be greater than 1.d-8,',ch10,&
1043 &   'however, |zaxis|=',zmod
1044    ABI_ERROR(msg)
1045  end if
1046 
1047 !verify that both axis are perpendicular
1048  cosine = (xaxis(1)*zaxis(1) + xaxis(2)*zaxis(2) &
1049 & + xaxis(3)*zaxis(3))/(xmod*zmod)
1050 
1051  if(abs(cosine) > 1.d-8)then
1052    write(msg,'(a,a,a,i6)')&
1053 &   'xaxis and zaxis should be perpendicular,',ch10,&
1054 &   'however, cosine=',cosine
1055    ABI_BUG(msg)
1056  end if
1057 
1058 !new y axis as cross product
1059  yaxis(1) = (zaxis(2)*xaxis(3) - xaxis(2)*zaxis(3))/(xmod*zmod)
1060  yaxis(2) = (zaxis(3)*xaxis(1) - xaxis(3)*zaxis(1))/(xmod*zmod)
1061  yaxis(3) = (zaxis(1)*xaxis(2) - xaxis(1)*zaxis(2))/(xmod*zmod)
1062 
1063 !hack to allow inversion operation on coordinate transformation
1064 !uses unlikely large but legal values of proj_x and/or proj_z
1065 !to flag inversion
1066  inversion_flag=0
1067  if(xmod>10._dp .or. zmod>10._dp) then
1068    inversion_flag=1
1069    write(msg, '(4a)' )&
1070 &   'inversion operation will be appended to axis transformation',ch10,&
1071 &   'Action: If you did not intend this, make |z|<10 and |x|<10 ',ch10
1072    call wrtout(std_out,msg)
1073  end if
1074 
1075  umat(1,:) = xaxis(:)/xmod
1076  umat(2,:) = yaxis(:)
1077  umat(3,:) = zaxis(:)/zmod
1078 
1079 end subroutine rotmat

m_geometry/shellstruct [ Functions ]

[ Top ] [ m_geometry ] [ Functions ]

NAME

  shellstruct

FUNCTION

  Calculates shell structure (multiplicities, radii) of an atomic configuration

INPUTS

  natom=number of atoms in unit cell
  xred=reduced coordinates of atoms
  rprimd=unit cell vectors
  magv = magnetic ordering of atoms given as 1 and -1, if not given fm is assumed
  atp = atom on which the perturbation was done

OUTPUT

  sdisv(nat)= distance of each shell to central atom (only the first nsh entries are relevant)
  nsh= number of shells
  mult(nat) = number of atoms on shell (only the first nsh entries are relevant)

SOURCE

2342 subroutine shellstruct(xred,rprimd,natom,magv,distv,smult,sdisv,nsh,atp,prtvol)
2343 
2344 !Arguments ------------------------------------
2345 !scalars
2346  integer,intent(in)              :: natom
2347  integer,intent(in),optional     :: atp
2348  integer,intent(in),optional     :: prtvol
2349  integer,intent(out)             :: nsh
2350 !arrays
2351  real(dp),intent(in)             :: rprimd(3,3)
2352  real(dp),intent(in)             :: xred(3,natom)
2353  integer,intent(out)             :: smult(natom)
2354  integer,intent(in),optional     :: magv(natom)
2355  real(dp),intent(out)            :: sdisv(natom)
2356  real(dp),intent(out)            :: distv(natom)
2357 
2358 !Local variables-------------------------------
2359 !scalars
2360  integer                      :: iatom,atpp,ish,prtvoll
2361  character(len=500)           :: msg
2362  real(dp),parameter           :: rndfact=10000_dp
2363 !arrays
2364  integer                      :: iperm(natom),jperm(natom)
2365  real(dp)                     :: distvh(natom,natom)
2366  real(dp)                     :: magvv(natom)
2367 
2368 ! *************************************************************************
2369 
2370  if (present(magv)) then
2371    magvv=magv
2372  else
2373    magvv=(/ (1, iatom=1,natom)  /)
2374  end if
2375 
2376  if (present(atp)) then
2377    atpp=atp
2378  else
2379    atpp=1
2380  end if
2381 
2382  if (present(prtvol)) then
2383    prtvoll=prtvol
2384  else
2385    prtvoll=1
2386  end if
2387 
2388 !DEBUB
2389  write(std_out,*)'shellstruct start'
2390 !END DEBUG
2391 
2392 !Calculate ionic distances
2393  call ioniondist(natom,rprimd,xred,distvh,1,magv=int(magvv),atp=atpp)
2394  distv=distvh(1,:)
2395 
2396  if (prtvol>2) then
2397    write(std_out,'(a)')' shellstruct ionic distances in cell (distv) : '
2398    call prmat(distv(1:natom),1,natom,1,std_out)
2399  end if
2400 
2401  iperm=(/ (iatom, iatom=1,natom ) /)
2402  jperm=iperm
2403  distv=anint(distv*rndfact)/rndfact
2404 !Sort distances
2405  call sort_dp(natom,distv,iperm,10d-5)
2406  call sort_int(natom,iperm,jperm)
2407 
2408  smult=0
2409  sdisv=dot_product(rprimd(1,:),rprimd(1,:))+dot_product(rprimd(2,:),rprimd(2,:))+dot_product(rprimd(3,:),rprimd(3,:))
2410 
2411  nsh=1
2412  smult(1)=1
2413  sdisv(1)=distv(1)
2414 
2415  do iatom=2,natom
2416    do ish=1,natom
2417      if (distv(iatom)>sdisv(ish)) then
2418        cycle
2419      else if (distv(iatom)==sdisv(ish)) then
2420        smult(ish)=smult(ish)+1
2421        exit
2422      else if (distv(iatom)<sdisv(ish)) then
2423        smult(ish+1:natom)=smult(ish:natom-1)
2424        sdisv(ish+1:natom)=sdisv(ish:natom-1)
2425        smult(ish)=1
2426        sdisv(ish)=distv(iatom)
2427        nsh=nsh+1
2428        exit
2429      end if
2430    end do
2431  end do
2432 
2433  distv=(/ ( distv(jperm(iatom)),iatom=1,natom ) /)
2434 
2435  if (prtvoll>2) then
2436    write(msg,'(a,i4,a)')' shellstruct found ',nsh,' shells at distances (sdisv) '
2437    call wrtout(std_out,msg,'COLL')
2438    call prmat(sdisv(1:nsh),1,nsh,1,std_out)
2439    write(msg,fmt='(a,150i4)')' and multiplicities (smult) ', smult(1:nsh)
2440    call wrtout(std_out,msg,'COLL')
2441  end if
2442 
2443 !DEBUB
2444  write(std_out,*)'shellstruct leave'
2445 !END DEBUG
2446 
2447 end subroutine shellstruct

m_geometry/spinrot_cmat [ Functions ]

[ Top ] [ m_geometry ] [ Functions ]

NAME

  spinrot_cmat

FUNCTION

  Construct 2x2 complex matrix representing the rotation operator in spin-space.

INPUTS

  spinrot(4)=components of the spinor rotation matrix computed by getspinrot

OUTPUT

  spinrot(2,2)=Rotation matrix (complex array)

SOURCE

948 pure function spinrot_cmat(spinrot)
949 
950 !Arguments ------------------------------------
951  real(dp),intent(in) :: spinrot(4)
952  complex(dpc) :: spinrot_cmat(2,2)
953 
954 ! *************************************************************************
955 
956  ! Build rotation matrix from spinrot:
957  !
958  ! ( cos(phi/2) + i n_z sin(phi/2),  (+n_y + i n_x) sin(phi/2)      )
959  ! ( (-n_y + i n_x) sin(phi/2)    ,  cos(phi/2) - i n_z sin(phi/2)  )
960 
961  ! spinrot(1)=cos(half*phi)
962  ! spinrot(2)=axis(1)*sin(half*phi)
963  ! spinrot(3)=axis(2)*sin(half*phi)
964  ! spinrot(4)=axis(3)*sin(half*phi)
965 
966  ! Rotation in spinor space (same equations as in wfconv)
967  ! TODO: Be careful here as wfconv uses symrel^T to map k-points (listkk)
968  ! thus the inverse of the corresponding symrec.
969  ! This may explain why all the terms with sin(phi/2) change sign (phi --> -phi)
970 
971  spinrot_cmat(1,1) = spinrot(1) + j_dpc*spinrot(4)
972  spinrot_cmat(1,2) = spinrot(3) + j_dpc*spinrot(2)
973  spinrot_cmat(2,1) =-spinrot(3) + j_dpc*spinrot(2)
974  spinrot_cmat(2,2) = spinrot(1) - j_dpc*spinrot(4)
975 
976  ! My equation
977  !spinrot_cmat(1,1) = spinrot(1) - j_dpc*spinrot(4)
978  !spinrot_cmat(1,2) =-spinrot(3) - j_dpc*spinrot(2)
979  !spinrot_cmat(2,1) = spinrot(3) - j_dpc*spinrot(2)
980  !spinrot_cmat(2,2) = spinrot(1) + j_dpc*spinrot(4)
981 
982 end function spinrot_cmat

m_geometry/strainsym [ Functions ]

[ Top ] [ m_geometry ] [ Functions ]

NAME

 strainsym

FUNCTION

 For given order of point group, symmetrizes the strain tensor,
 then produce primitive vectors based on the symmetrized strain.

INPUTS

 nsym=order of group.
 rprimd(3,3)= primitive vectors, to be symmetrized
 rprimd0(3,3)= reference primitive vectors, already symmetrized
 symrel(3,3,nsym)=symmetry operators in terms of action on primitive translations

OUTPUT

 rprimd_symm(3,3)= symmetrized primitive vectors

SOURCE

2982 subroutine strainsym(nsym,rprimd0,rprimd,rprimd_symm,symrel)
2983 
2984  use m_linalg_interfaces
2985 
2986 !Arguments ------------------------------------
2987 !scalars
2988  integer,intent(in) :: nsym
2989 !arrays
2990  integer,intent(in) :: symrel(3,3,nsym)
2991  real(dp),intent(in) :: rprimd(3,3),rprimd0(3,3)
2992  real(dp),intent(out) :: rprimd_symm(3,3)
2993 
2994 !Local variables-------------------------------
2995 !scalars
2996  integer :: isym
2997 !arrays
2998  integer :: symrel_it(3,3)
2999  real(dp) :: rprimd0_inv(3,3),strain(3,3),strain_symm(3,3),tmp_mat(3,3)
3000 
3001 !**************************************************************************
3002 
3003 !copy initial rprimd input and construct inverse
3004  rprimd0_inv = rprimd0
3005  call matrginv(rprimd0_inv,3,3)
3006 
3007 !define strain as rprimd = strain * rprimd0 (in cartesian frame)
3008 !so strain = rprimd * rprimd0^{-1}
3009 !transform to triclinic frame with rprimd0^{-1} * strain * rprimd0
3010 !giving strain as rprimd0^{-1} * rprimd
3011  call dgemm('N','N',3,3,3,one,rprimd0_inv,3,rprimd,3,zero,strain,3)
3012 
3013 !loop over symmetry elements to obtain symmetrized strain matrix
3014  strain_symm = zero
3015  do isym = 1, nsym
3016 
3017 !  this loop accumulates symrel^{-1}*strain*symrel into strain_symm
3018 
3019 !  mati3inv gives the inverse transpose of symrel
3020    call mati3inv(symrel(:,:,isym),symrel_it)
3021    call dgemm('N','N',3,3,3,one,strain,3,dble(symrel(:,:,isym)),3,zero,tmp_mat,3)
3022    call dgemm('T','N',3,3,3,one,dble(symrel_it),3,tmp_mat,3,one,strain_symm,3)
3023 
3024  end do
3025 
3026 !normalize by number of symmetry operations
3027  strain_symm = strain_symm/dble(nsym)
3028 
3029 !this step is equivalent to r_new = r_old * strain * r_old^{-1} * r_old,
3030 !that is, convert strain back to cartesian frame and then multipy by r_old,
3031 !to get the r_new primitive vectors
3032 
3033  call dgemm('N','N',3,3,3,one,rprimd0,3,strain_symm,3,zero,rprimd_symm,3)
3034 
3035 end subroutine strainsym

m_geometry/strconv [ Functions ]

[ Top ] [ m_geometry ] [ Functions ]

NAME

 strconv

FUNCTION

 If original gprimd is input, convert from symmetric storage mode
 3x3 tensor in reduced coordinates "frac" to symmetric storage mode
 symmetric tensor in cartesian coordinates "cart".

INPUTS

  frac(6)=3x3 tensor in symmetric storage mode, reduced coordinates
  gprimd(3,3)=reciprocal space dimensional primitive translations (bohr^-1)

OUTPUT

  cart(6)=symmetric storage mode for symmetric 3x3 tensor in cartesian coords.

NOTES

 $cart(i,j)=G(i,a) G(j,b) frac(a,b)$
 "Symmetric" storage mode for 3x3 tensor is 6 element array with
 elements 11, 22, 33, 32, 31, and 21.
 "cart" may be same array as "frac".
 If rprimd transpose is input instead of gprimd, then convert tensor
 in cartesian coordinates to reduced coordinates

SOURCE

3199 subroutine strconv(frac,gprimd,cart)
3200 
3201 !Arguments ------------------------------------
3202 !arrays
3203  real(dp),intent(in) :: frac(6),gprimd(3,3)
3204  real(dp),intent(inout) :: cart(6) ! alias of frac   !vz_i
3205 
3206 !Local variables-------------------------------
3207 !scalars
3208  integer :: ii,jj
3209 !arrays
3210  real(dp) :: work1(3,3),work2(3,3)
3211 
3212 ! *************************************************************************
3213 
3214  work1(1,1)=frac(1)
3215  work1(2,2)=frac(2)
3216  work1(3,3)=frac(3)
3217  work1(3,2)=frac(4) ; work1(2,3)=frac(4)
3218  work1(3,1)=frac(5) ; work1(1,3)=frac(5)
3219  work1(2,1)=frac(6) ; work1(1,2)=frac(6)
3220 
3221 ! TODO: these are matmuls, replace or get BLAS
3222 ! work2 = work1 * gprimd^T
3223  do ii=1,3
3224    work2(:,ii)=zero
3225    do jj=1,3
3226      work2(:,ii)=work2(:,ii)+gprimd(ii,jj)*work1(:,jj)
3227    end do
3228  end do
3229 
3230 ! work1 = gprimd * work2 = gprimd * input * gprimd^T
3231  do ii=1,3
3232    work1(ii,:)=zero
3233    do jj=1,3
3234      work1(ii,:)=work1(ii,:)+gprimd(ii,jj)*work2(jj,:)
3235    end do
3236  end do
3237 
3238  cart(1)=work1(1,1)
3239  cart(2)=work1(2,2)
3240  cart(3)=work1(3,3)
3241  cart(4)=work1(2,3)
3242  cart(5)=work1(1,3)
3243  cart(6)=work1(1,2)
3244 
3245 end subroutine strconv

m_geometry/stress_voigt_to_mat [ Functions ]

[ Top ] [ m_geometry ] [ Functions ]

NAME

  stress_voigt_to_mat

FUNCTION

  Build 3x3 symmetric stress tensor from stress vector in Voigt notation.

INPUTS

OUTPUT

SOURCE

3155 subroutine stress_voigt_to_mat(stress6, stress_mat)
3156 
3157  real(dp),intent(in) :: stress6(6)
3158  real(dp),intent(out) :: stress_mat(3,3)
3159 
3160  stress_mat(1,1) = stress6(1)
3161  stress_mat(2,2) = stress6(2)
3162  stress_mat(3,3) = stress6(3)
3163  stress_mat(2,3) = stress6(4)
3164  stress_mat(3,2) = stress6(4)
3165  stress_mat(1,3) = stress6(5)
3166  stress_mat(3,1) = stress6(5)
3167  stress_mat(1,2) = stress6(6)
3168  stress_mat(2,1) = stress6(6)
3169 
3170 end subroutine stress_voigt_to_mat

m_geometry/stresssym [ Functions ]

[ Top ] [ m_geometry ] [ Functions ]

NAME

 stresssym

FUNCTION

 For given order of point group, symmetrizes the stress tensor,
 in symmetrized storage mode and cartesian coordinates, using input
 3x3 symmetry operators in reduced coordinates.
 symmetrized tensor replaces input tensor.

INPUTS

 gprimd(3,3)=dimensional primitive translations for reciprocal space (bohr**-1)
 nsym=order of group.
 sym(3,3,nsym)=symmetry operators (usually symrec=expressed in terms
               of action on reciprocal lattice primitive translations); integers.

SIDE EFFECTS

 stress(6)=stress tensor, in cartesian coordinates, in symmetric storage mode

SOURCE

3059 subroutine stresssym(gprimd,nsym,stress,sym)
3060 
3061 !Arguments ------------------------------------
3062 !scalars
3063  integer,intent(in) :: nsym
3064 !arrays
3065  integer,intent(in) :: sym(3,3,nsym)
3066  real(dp),intent(in) :: gprimd(3,3)
3067  real(dp),intent(inout) :: stress(6)
3068 
3069 !Local variables-------------------------------
3070 !scalars
3071  integer :: ii,isym,mu,nu
3072  real(dp) :: summ,tmp
3073 !arrays
3074  real(dp) :: rprimd(3,3),rprimdt(3,3),strfrac(6),tensor(3,3),tt(3,3)
3075 
3076 !*************************************************************************
3077 
3078 !Obtain matrix of real space dimensional primitive translations
3079 !(inverse tranpose of gprimd), and its transpose
3080  call matr3inv(gprimd,rprimd)
3081  rprimdt=transpose(rprimd)
3082 
3083 !Compute stress tensor in reduced coordinates
3084 ! strfrac =  rprimd^T * stress * rprimd
3085  call strconv(stress,rprimdt,strfrac)
3086 
3087 !Switch to full storage mode
3088  tensor(1,1)=strfrac(1)
3089  tensor(2,2)=strfrac(2)
3090  tensor(3,3)=strfrac(3)
3091  tensor(3,2)=strfrac(4)
3092  tensor(3,1)=strfrac(5)
3093  tensor(2,1)=strfrac(6)
3094  tensor(2,3)=tensor(3,2)
3095  tensor(1,3)=tensor(3,1)
3096  tensor(1,2)=tensor(2,1)
3097 
3098 ! these loops are useless - trivial action:
3099 ! tt = tensor / dble(nsym)
3100 ! tensor = zero
3101  do nu=1,3
3102    do mu=1,3
3103      tt(mu,nu)=tensor(mu,nu)/dble(nsym)
3104      tensor(mu,nu)=0.0_dp
3105    end do
3106  end do
3107 
3108 !loop over all symmetry operations:
3109 ! tensor =  symrec * tt * symrec^T = symrec * rprimd^T * input * rprimd symrec^T
3110 ! TODO: this should be replaced by a little BLAS call or two
3111  do isym=1,nsym
3112    do mu=1,3
3113      do nu=1,3
3114        summ=0._dp
3115        do ii=1,3
3116          tmp=tt(ii,1)*sym(nu,1,isym)+tt(ii,2)*sym(nu,2,isym)+&
3117 &         tt(ii,3)*sym(nu,3,isym)
3118          summ=summ+sym(mu,ii,isym)*tmp
3119        end do
3120        tensor(mu,nu)=tensor(mu,nu)+summ
3121      end do
3122    end do
3123  end do
3124 
3125 !Switch back to symmetric storage mode
3126  strfrac(1)=tensor(1,1)
3127  strfrac(2)=tensor(2,2)
3128  strfrac(3)=tensor(3,3)
3129  strfrac(4)=tensor(3,2)
3130  strfrac(5)=tensor(3,1)
3131  strfrac(6)=tensor(2,1)
3132 
3133 !Convert back stress tensor (symmetrized) in cartesian coordinates
3134 ! stress = gprimd * symrec * rprimd^T * input * rprimd symrec^T * gprimd^T
3135 ! symrec_cart = gprimd * symrec * rprimd^T
3136 ! sym_cart    = symrec_cart^-1 ^T = rprimd * sym * gprimd^T
3137  call strconv(strfrac,gprimd,stress)
3138 
3139 end subroutine stresssym

m_geometry/symredcart [ Functions ]

[ Top ] [ m_geometry ] [ Functions ]

NAME

 symredcart

FUNCTION

 Convert a symmetry operation from reduced coordinates (integers)
 to cartesian coordinates (reals). Can operate in real or reciprocal space

INPUTS

 symred(3,3)=symmetry matrice in reduced coordinates (integers) (real or reciprocal space)
 aprim(3,3)=real or reciprocal space dimensional primitive translations (see below)
 bprim(3,3)=real or reciprocal space dimensional primitive translations (see below)

OUTPUT

 symcart(3,3)=symmetry matrice in cartesian coordinates (reals)

NOTES

 When aprim=rprimd and bprim=gprimd, the routine operates in real space (on a real space symmetry)
 When aprim=gprimd and bprim=rprimd, the routine operates in reciprocal space (on a real space symmetry)

SOURCE

2920 subroutine symredcart(aprim,bprim,symcart,symred)
2921 
2922 !Arguments ------------------------------------
2923 !arrays
2924  integer,intent(in) :: symred(3,3)
2925  real(dp),intent(in) :: aprim(3,3),bprim(3,3)
2926  real(dp),intent(out) :: symcart(3,3)
2927 
2928 !Local variables-------------------------------
2929 !scalars
2930  integer :: ii,jj,kk
2931  real(dp) :: symtmp
2932 !arrays
2933  real(dp) :: work(3,3)
2934 
2935 ! *************************************************************************
2936 
2937  work=zero
2938  do kk=1,3
2939    do jj=1,3
2940      symtmp=dble(symred(jj,kk))
2941      do ii=1,3
2942        work(ii,jj)=work(ii,jj)+bprim(ii,kk)*symtmp
2943      end do
2944    end do
2945  end do
2946 
2947  ! work = bprim * symred^T
2948 
2949  symcart=zero
2950  do kk=1,3
2951    do jj=1,3
2952      symtmp=work(jj,kk)
2953      do ii=1,3
2954        ! symcart = aprim * work^T = aprim * symred * bprim^T
2955        symcart(ii,jj)=symcart(ii,jj)+aprim(ii,kk)*symtmp
2956      end do
2957    end do
2958  end do
2959 
2960 end subroutine symredcart

m_geometry/vdotw_rc_vector [ Functions ]

[ Top ] [ m_geometry ] [ Functions ]

NAME

 vdotw_rc_vector

FUNCTION

 Compute the scalar product between two vectors expressed in reduced coordinates
 First vector is real, the second one is complex.
 The result is multiplied by (2pi)**2 in case of vectors in reciprocal space
 to take into account the correct normalisation of the reciprocal lattice vectors

INPUTS

  xv(3),xw(3)=Vectors in reduced coordinates
  met(3,3)=Metric tensor
  space=Character defining whether we are working in real (r) or reciprocal space (g)

OUTPUT

  res=complex scalar product of xv and xw

SOURCE

349 complex(dp) function vdotw_rc_vector(xv, xw, met, space) result(res)
350 
351 !Arguments ------------------------------------
352  character(len=1),intent(in) :: space
353 !arrays
354  real(dp),intent(in) :: met(3,3),xv(3)
355  complex(dpc),intent(in) :: xw(3)
356 
357 ! *************************************************************************
358 
359  res = (  met(1,1)* xv(1)*xw(1)                &
360          +met(2,2)* xv(2)*xw(2)                &
361          +met(3,3)* xv(3)*xw(3)                &
362          +met(1,2)*(xv(1)*xw(2) + xv(2)*xw(1)) &
363          +met(1,3)*(xv(1)*xw(3) + xv(3)*xw(1)) &
364          +met(2,3)*(xv(2)*xw(3) + xv(3)*xw(2)) )
365 
366  select case (space)
367  case ('r', 'R')
368    return
369  case ('g', 'G')
370    res= res * (two_pi**2)
371  case default
372    ABI_BUG('Wrong value for space')
373  end select
374 
375 end function vdotw_rc_vector

m_geometry/vdotw_rr_vector [ Functions ]

[ Top ] [ m_geometry ] [ Functions ]

NAME

 vdotw_rr_vector

FUNCTION

 Compute the scalar product between two vectors expressed in reduced coordinates
 The result is multiplied by (2pi)**2 in case of vectors in reciprocal space
 to take into account the correct normalisation of the reciprocal lattice vectors

INPUTS

  xv(3),xw(3)=Vectors in reduced coordinates
  met(3,3)=Metric tensor
  space=Character defining whether we are working in real (r) or reciprocal space (g)

OUTPUT

  res=scalar product of xv and xw

SOURCE

299 real(dp) function vdotw_rr_vector(xv,xw,met,space) result(res)
300 
301 !Arguments ------------------------------------
302  character(len=1),intent(in) :: space
303 !arrays
304  real(dp),intent(in) :: met(3,3),xv(3),xw(3)
305 
306 ! *************************************************************************
307 
308  res = (  met(1,1)* xv(1)*xw(1)                &
309          +met(2,2)* xv(2)*xw(2)                &
310          +met(3,3)* xv(3)*xw(3)                &
311          +met(1,2)*(xv(1)*xw(2) + xv(2)*xw(1)) &
312          +met(1,3)*(xv(1)*xw(3) + xv(3)*xw(1)) &
313          +met(2,3)*(xv(2)*xw(3) + xv(3)*xw(2)) )
314 
315  select case (space)
316  case ('r', 'R')
317    return
318  case ('g', 'G')
319    res= res * (two_pi**2)
320  case default
321    ABI_BUG('Wrong value for space')
322  end select
323 
324 end function vdotw_rr_vector

m_geometry/wedge_basis [ Functions ]

[ Top ] [ m_geometry ] [ Functions ]

NAME

 wedge_basis

FUNCTION

 Calculates the basis vectors a ^ a* for a in rprimd and
 a* in gprimd, needed for some generalized cross products

INPUTS

   rprimd(3,3) : real(dp) matrix
   gprimd(3,3) : real(dp) matrix
   normalize,optional : whether to normalize the output vectors

OUTPUT

   wedge(3,3,3) : 9 basis vectors of rprimd ^ gprimd

SOURCE

430 subroutine wedge_basis(gprimd,rprimd,wedge,normalize)
431 
432  !Arguments ---------------------------------------------
433  ! scalars
434  logical,optional,intent(in) :: normalize
435 !arrays
436  real(dp),intent(in) :: gprimd(3,3),rprimd(3,3)
437  real(dp),intent(out) :: wedge(3,3,3)
438 
439  ! local
440  !scalars
441  integer :: igprimd, irprimd
442  real(dp) :: nfac
443  logical :: nvec
444 
445 ! *********************************************************************
446 
447  if(present(normalize)) then
448     nvec = normalize
449  else
450     nvec = .FALSE.
451  end if
452 
453  do irprimd = 1, 3
454     do igprimd = 1, 3
455        wedge(1,irprimd,igprimd) = rprimd(2,irprimd)*gprimd(3,igprimd) - rprimd(3,irprimd)*gprimd(2,igprimd)
456        wedge(2,irprimd,igprimd) = rprimd(3,irprimd)*gprimd(1,igprimd) - rprimd(1,irprimd)*gprimd(3,igprimd)
457        wedge(3,irprimd,igprimd) = rprimd(1,irprimd)*gprimd(2,igprimd) - rprimd(2,irprimd)*gprimd(1,igprimd)
458     end do
459  end do
460 
461  if (nvec) then
462     do irprimd = 1, 3
463        do igprimd = 1, 3
464           if(any(abs(wedge(1:3,irprimd,igprimd)).GT.tol8)) then
465              nfac = SQRT(DOT_PRODUCT(wedge(1:3,irprimd,igprimd),wedge(1:3,irprimd,igprimd)))
466              wedge(1:3,irprimd,igprimd) = wedge(1:3,irprimd,igprimd)/nfac
467           end if
468        end do
469     end do
470  end if
471 
472 end subroutine wedge_basis

m_geometry/wedge_product [ Functions ]

[ Top ] [ m_geometry ] [ Functions ]

NAME

 wedge_product

FUNCTION

 Calculates the wedge product u^w, given the wedge product basis a^b
 typically u=(u1 a + u2 b + u3 c) and w = (w1 a* + w2 b* + w3 c*)

INPUTS

   u(3) :: real(dp) input vector
   v(3) :: real(dp) input vector
   wedgebasis(3,3,3) :: real(dp) input matrix

OUTPUT

   produv(3) :: real(dp) output vector

SOURCE

493 subroutine wedge_product(produv,u,v,wedgebasis)
494 
495 !Arguments ---------------------------------------------
496 !arrays
497  real(dp),intent(in) :: u(3),v(3),wedgebasis(3,3,3)
498  real(dp),intent(out) :: produv(3)
499 
500 ! local
501 !scalars
502  integer :: igprimd, ii, irprimd
503 
504 ! *********************************************************************
505 
506  produv(:) = zero
507  do irprimd = 1, 3
508     do igprimd = 1, 3
509        do ii = 1, 3
510           produv(ii) = produv(ii) + u(irprimd)*v(igprimd)*wedgebasis(ii,irprimd,igprimd)
511        end do
512     end do
513  end do
514 
515 end subroutine wedge_product

m_geometry/wigner_seitz [ Functions ]

[ Top ] [ m_geometry ] [ Functions ]

NAME

 wigner_seitz

FUNCTION

 Calculates a grid of points that falls inside of (and eventually on the surface of)
 the Wigner-Seitz supercell centered on the origin of the B lattice with primitive
 translations nmonkh(1)*a_1+nmonkh(2)*a_2+nmonkh(3)*a_3.
 Subroutine taken from the Wannier90 code. Modified by MG to fulfil abinit coding rules.
 API slightly changed wrt the wannier90 version.

COPYRIGHT

 Copyright (C) 2007 Jonathan Yates, Arash Mostofi,
 Young-Su Lee, Nicola Marzari, Ivo Souza, David Vanderbilt.
 This file is distributed under the terms of the
 GNU General Public License, see ~abinit/COPYING
 or http://www.gnu.org/copyleft/gpl.txt .

INPUTS

  center(3)=The Wigner-Seitz cell is centered on this point in reduced coordinates.
  rmet(3,3)=Real space metric ($\textrm{bohr}^{2}$).
  kptrlatt(3)=Values defining the supercell.
  prtvol=If different from 0 print out the points falling inside the W-S cell and the correponding weights.
  lmax(3)=see Notes below.

OUTPUT

  npts=number of points falling inside the Wigner-Seitz cell
  irvec(3,npts)=Reduced coordinated of the points inside the W-S cell
  ndegen(npts)=Weigths associated to each point.

SIDE EFFECTS

  irvec and ndegen are are allocated with the correct
  size inside the routine and returned to the caller.

NOTES

 The Wannier functions live in a supercell of the real space unit cell.
 This supercell is mp_grid unit cells long in each direction
 The algorithm loops over grid points r on a unit cell that is 8 times larger than this
 primitive supercell.
 One of these points is in the W-S cell if it is closer to center(:)
 than any of the other points R where R are the translation vectors of the supercell.
 In the end npts contains the total number of grid points that have been found in the Wigner-Seitz cell
 The number of lattice vectors R along each direction of the supercell is defined by lmax.

SOURCE

564 subroutine wigner_seitz(center, lmax, kptrlatt, rmet, npts, irvec, ndegen, prtvol)
565 
566 !Arguments ------------------------------------
567 !scalars
568  integer,optional,intent(in) :: prtvol
569  integer,intent(out) :: npts
570 !arrays
571  integer,intent(in) :: kptrlatt(3,3),lmax(3)
572  integer,allocatable,intent(out) :: irvec(:,:),ndegen(:)
573  real(dp),intent(in) :: center(3),rmet(3,3)
574 
575 !Local variables-------------------------------
576 !scalars
577  integer :: in1,in2,in3,l1,l2,l3,ii,icount,n1,n2,n3
578  integer :: l0,l1_max,l2_max,l3_max,nl,verbose,mm1,mm2,mm3
579  real(dp) :: tot,dist_min
580  real(dp),parameter :: TOL_DIST=tol7
581  character(len=500) :: msg
582 !arrays
583  real(dp) :: diff(3)
584  real(dp),allocatable :: dist(:),swap2(:,:),swap1(:)
585 
586 ! *************************************************************************
587 
588  verbose = 0; if (PRESENT(prtvol)) verbose = prtvol
589 
590  if (kptrlatt(1,2) /= 0 .or. kptrlatt(2,1) /= 0 .or. &
591      kptrlatt(1,3) /= 0 .or. kptrlatt(3,1) /= 0 .or. &
592      kptrlatt(2,3) /= 0 .or. kptrlatt(3,2) /= 0 ) then
593    ABI_ERROR('Off-diagonal elements of kptrlatt must be zero')
594  end if
595 
596  n1 = kptrlatt(1,1); n2 = kptrlatt(2,2); n3 = kptrlatt(3,3)
597  l1_max = lmax(1); l2_max = lmax(2); l3_max = lmax(3)
598 
599  nl=(2*l1_max+1)*(2*l2_max+1)*(2*l3_max+1)
600  l0=1+l1_max*(1+(2*l2_max+1)**2+(2*l3_max+1)) ! Index of the origin.
601  ABI_MALLOC(dist,(nl))
602 
603  ! Allocate with maximum size
604  mm1 = 2 * n1 + 1
605  mm2 = 2 * n2 + 1
606  mm3 = 2 * n3 + 1
607  ABI_MALLOC(irvec, (3, mm1*mm2*mm3))
608  ABI_MALLOC(ndegen, (mm1*mm2*mm3))
609 
610  npts = 0
611  do in1=-n1,n1
612    do in2=-n2,n2
613      do in3=-n3,n3
614 
615       ! Loop over the nl points R. R=0 corresponds to l1=l2=l3=1, or icount=l0
616       icount = 0
617       do l1=-l1_max,l1_max
618         do l2=-l2_max,l2_max
619           do l3=-l3_max,l3_max
620             ! Calculate |r - R -r0|^2.
621             diff(1) = in1 - l1 * n1 - center(1)
622             diff(2) = in2 - l2 * n2 - center(2)
623             diff(3) = in3 - l3 * n3 - center(3)
624             icount = icount+1
625             dist(icount) = DOT_PRODUCT(diff, MATMUL(rmet, diff))
626           end do
627         end do
628       end do
629 
630       dist_min = MINVAL(dist)
631 
632       if (ABS(dist(l0) - dist_min) < TOL_DIST) then
633         npts = npts + 1
634         ndegen (npts) = 0
635         do ii=1,nl
636           if (ABS(dist(ii) - dist_min) < TOL_DIST) ndegen(npts) = ndegen(npts) + 1
637         end do
638         irvec(:, npts) = [in1, in2, in3]
639       end if
640      end do !in3
641    end do !in2
642  end do !in1
643 
644  if (verbose >= 1) then
645    write(msg,'(a,i0)')' lattice points in Wigner-Seitz supercell: ',npts
646    call wrtout(std_out,msg,'COLL')
647    do ii=1,npts
648      write(msg,'(a,3(i3),a,i4)')'  vector ', irvec(:,ii),' degeneracy: ', ndegen(ii)
649      call wrtout(std_out,msg,'COLL')
650    end do
651  end if
652 
653  ! Check the "sum rule"
654  tot = zero
655  do ii=1,npts
656    tot = tot + one/ndegen(ii)
657  end do
658  if (ABS(tot-(n1*n2*n3)) > tol8) then
659    write(msg,'(a,es16.8,a,i0)')'Something wrong in the generation of WS mesh: tot ',tot,' /= ',n1*n2*n3
660    ABI_ERROR(msg)
661  end if
662 
663  ABI_FREE(dist)
664 
665  ! Reallocate the output with correct size.
666  ABI_MALLOC(swap1,(npts))
667  swap1(:)=ndegen(1:npts)
668  ABI_FREE(ndegen)
669  ABI_MALLOC(ndegen,(npts))
670  ndegen=swap1
671  ABI_FREE(swap1)
672 
673  ABI_MALLOC(swap2,(3,npts))
674  swap2(:,:)=irvec(1:3,1:npts)
675  ABI_FREE(irvec)
676  ABI_MALLOC(irvec,(3,npts))
677  irvec=swap2
678  ABI_FREE(swap2)
679 
680 end subroutine wigner_seitz

m_geometry/xcart2xred [ Functions ]

[ Top ] [ m_geometry ] [ Functions ]

NAME

 xcart2xred

FUNCTION

 Convert from cartesian coordinates xcart(3,natom) in bohr to
 dimensionless reduced coordinates xred(3,natom) by using
 xred(mu,ia)=gprimd(1,mu)*xcart(1,ia)
            +gprimd(2,mu)*xcart(2,ia)
            +gprimd(3,mu)*xcart(3,ia)
 where gprimd is the inverse of rprimd
 Note that the reverse operation is done by xred2xcart

INPUTS

  natom=number of atoms in unit cell
  rprimd(3,3)=dimensional real space primitive translations (bohr)
  xcart(3,natom)=cartesian coordinates of atoms (bohr)

OUTPUT

  xred(3,natom)=dimensionless reduced coordinates of atoms

SOURCE

1573 subroutine xcart2xred(natom,rprimd,xcart,xred)
1574 
1575 !Arguments ------------------------------------
1576 !scalars
1577  integer,intent(in) :: natom
1578 !arrays
1579  real(dp),intent(in) :: rprimd(3,3),xcart(3,natom)
1580  real(dp),intent(out) :: xred(3,natom)
1581 
1582 !Local variables-------------------------------
1583 !scalars
1584  integer :: iatom,mu
1585 !arrays
1586  real(dp) :: gprimd(3,3)
1587 
1588 ! *************************************************************************
1589 
1590  call matr3inv(rprimd,gprimd)
1591  do iatom=1,natom
1592    do mu=1,3
1593      xred(mu,iatom)= gprimd(1,mu)*xcart(1,iatom)+gprimd(2,mu)*xcart(2,iatom)+gprimd(3,mu)*xcart(3,iatom)
1594    end do
1595  end do
1596 
1597 end subroutine xcart2xred

m_geometry/xred2xcart [ Functions ]

[ Top ] [ m_geometry ] [ Functions ]

NAME

 xred2xcart

FUNCTION

 Convert from dimensionless reduced coordinates xred(3,natom)
 to cartesian coordinates xcart(3,natom) in bohr by using
 xcart(mu,ia)=rprimd(mu,1)*xred(1,ia)
             +rprimd(mu,2)*xred(2,ia)
             +rprimd(mu,3)*xred(3,ia)
 Note that the reverse operation is done by xcart2xred.F90

INPUTS

  natom=number of atoms in unit cell
  rprimd(3,3)=dimensional real space primitive translations (bohr)
  xred(3,natom)=dimensionless reduced coordinates of atoms

OUTPUT

  xcart(3,natom)=cartesian coordinates of atoms (bohr)

SOURCE

1622 subroutine xred2xcart(natom,rprimd,xcart,xred)
1623 
1624 !Arguments ------------------------------------
1625 !scalars
1626  integer,intent(in) :: natom
1627 !arrays
1628  real(dp),intent(in) :: rprimd(3,3),xred(3,natom)
1629  real(dp),intent(out) :: xcart(3,natom)
1630 
1631 !Local variables-------------------------------
1632 !scalars
1633  integer :: iatom,mu
1634 
1635 ! *************************************************************************
1636 
1637  do iatom=1,natom
1638    do mu=1,3
1639      xcart(mu,iatom)=rprimd(mu,1)*xred(1,iatom)+rprimd(mu,2)*xred(2,iatom)+rprimd(mu,3)*xred(3,iatom)
1640    end do
1641  end do
1642 
1643 end subroutine xred2xcart

m_symtk/reduce2primitive [ Functions ]

[ Top ] [ m_symtk ] [ Functions ]

NAME

 reduce2primitive

FUNCTION

 Find real space primitive vectors from non-primitive ones and the set of non-integer translations
 that leave the system invariant

INPUTS

 ntranslat=number of translations
 rprimd(3,3)=dimensional non-primitive vectors in real space (bohr)
 tolsym=tolerance for the symmetry operations
 translations(3,ntranslat)=translation vectors, in reduced coordinates

OUTPUT

 rprimd_primitive(3,3)=dimensional primitive vectors in real space (bohr)

SOURCE

2824 subroutine reduce2primitive(ntranslat, rprimd, rprimd_primitive, tolsym, translations)
2825 
2826 !Arguments ------------------------------------
2827 !scalars
2828  integer,intent(in) :: ntranslat
2829  real(dp),intent(in) :: tolsym
2830 !arrays
2831  real(dp),intent(in) :: rprimd(3,3),translations(3,ntranslat)
2832  real(dp),intent(out) :: rprimd_primitive(3,3)
2833 
2834 
2835 !Local variables-------------------------------
2836 !scalars
2837  integer :: idir,itentative,itrans,replace
2838  character(len=500) :: msg
2839 !arrays
2840  real(dp) :: trans_cart(3,ntranslat),trans_red(3,ntranslat)
2841 
2842 !**************************************************************************
2843 
2844 !These translations should form the primitive lattice when combined with the non-primitive vectors.
2845 !Each translation, in reduced coordinates, should be constituted of rational numbers.
2846 !They should pave the non-primitive cell homogeneously. The issue is to replace
2847 !at least one (or more) of the non-primitive vectors by one (or more) selected translation vectors among the list.
2848 !All translation vectors should be an integer linear combination of the vectors of the new basis.
2849 
2850  rprimd_primitive(:,:)=rprimd(:,:)
2851 
2852 !First, the reduced coordinates of translation vectors are transferred to the [0,1[ interval
2853  trans_red(:,1:ntranslat)=translations(:,1:ntranslat)-nint(translations(:,1:ntranslat)-tolsym)
2854 
2855 !Then, one of the translation vectors with the smallest non-zero first coordinate will replace the first vector, if any.
2856 !Similarly for the three directions.
2857  do idir=1,3
2858    replace=0
2859    do itrans=1,ntranslat
2860      if(trans_red(idir,itrans)>tolsym)then
2861        if(replace==0)then
2862          replace=1 ; itentative=itrans
2863        else
2864          if(trans_red(idir,itentative)>trans_red(idir,itrans)+tolsym)then
2865            itentative=itrans
2866          endif
2867        endif
2868      endif
2869    enddo
2870    if(replace==1)then
2871      ! Change the trans vectors to cartesian coordinates, using "old" rprimd
2872      call xred2xcart(ntranslat,rprimd_primitive,trans_cart,trans_red)
2873      ! Replace rprimd vector with index idir by the selected trans_cart vector
2874      rprimd_primitive(:,idir)=trans_cart(:,itentative)
2875      ! Change the translation vectors to new reduced coordinates using updated rprimd_primitive
2876      call xcart2xred(ntranslat,rprimd_primitive,trans_cart,trans_red)
2877      !Transfer to the [0,1[ interval
2878      trans_red(:,1:ntranslat)=trans_red(:,1:ntranslat)-nint(trans_red(:,1:ntranslat)-tolsym)
2879    endif
2880  enddo ! idir
2881 
2882 !Now, check that all translation vectors have zero reduced coordinates.
2883  do itrans=1,ntranslat
2884    do idir=1,3
2885      if (abs(trans_red(idir,itrans))>tolsym) then
2886        write(msg,'(5a)')&
2887         'Did not succeed to find primitive cell from non-primitive one.',ch10,&
2888         'Indeed, there remains a non-vanishing pure translation after reduction.',ch10,&
2889         'Action: this is a bug, contact ABINIT group. Then, use a primitive cell in your input file.'
2890        ABI_ERROR(msg)
2891      end if
2892    enddo
2893  enddo
2894 
2895 end subroutine reduce2primitive