TABLE OF CONTENTS


ABINIT/m_symfind [ Modules ]

[ Top ] [ Modules ]

NAME

  m_symfind

FUNCTION

  Symmetry finder high-level API.

COPYRIGHT

  Copyright (C) 2000-2024 ABINIT group (XG, RC)
  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_symfind
23 
24  use defs_basis
25  use m_errors
26  use m_abicore
27  use m_symlist
28 
29  use m_symtk,     only : chkprimit, mati3inv, matr3inv, symrelrot, symdet, symcharac, holocell, &
30                           smallprim, print_symmetries, sg_multable, symatm, symmetrize_tnons, symmetrize_xred
31  use m_geometry,  only : acrossb, xred2xcart
32  use m_spgdata,   only : getptgroupma, symptgroup, spgdata
33 
34  implicit none
35 
36  private

m_symfind/symanal [ Functions ]

[ Top ] [ m_symfind ] [ Functions ]

NAME

 symanal

FUNCTION

 Find the space group, Bravais lattice, including Shubnikov characteristics
 from the list of symmetries (including magnetic characteristics), and lattice parameters
 Warning: the recognition of the space group might not yet work for the
 Shubnikov group of type IV

INPUTS

 chkprim= if 1 then stop if the cell is not primitive
 msym=default maximal number of symmetries
 nsym=actual number of symmetries
 rprimd(3,3)=dimensional primitive translations for real space (bohr)
 symafm(1:msym)=(anti)ferromagnetic part of symmetry operations
 symrel(3,3,1:msym)=symmetry operations in real space in terms
  of primitive translations
 tnons(3,1:msym)=nonsymmorphic translations for symmetry operations
 tolsym=tolerance for the symmetry operations
 verbose= if true, will list the symmetry operation labels

OUTPUT

 bravais(11)=characteristics of Bravais lattice (see symlatt.F90)
 genafm(3)=magnetic translation generator (in case of Shubnikov group type IV)
 ptgroupma = magnetic point group number
 spgroup=symmetry space group

SOURCE

 885 subroutine symanal(bravais,chkprim,genafm,msym,nsym,ptgroupma,rprimd,spgroup,symafm,symrel,tnons,tolsym,verbose)
 886 
 887 !Arguments ------------------------------------
 888 !scalars
 889  integer,intent(in) :: chkprim,msym,nsym
 890  integer,intent(out) :: ptgroupma,spgroup
 891  real(dp),intent(in) :: tolsym
 892  logical,optional,intent(in) :: verbose
 893 !arrays
 894  integer,intent(out) :: bravais(11)
 895  integer,intent(in) :: symafm(msym),symrel(3,3,msym)
 896  real(dp),intent(in) :: rprimd(3,3)
 897  real(dp),intent(in) :: tnons(3,msym)
 898  real(dp),intent(out) :: genafm(3)
 899 
 900 !Local variables-------------------------------
 901 !scalars
 902  integer, parameter :: maxsym=192
 903 ! In this routine, maxsym is used either to determine the ptsymrel from the rprimd (routine symlatt),
 904 ! so, it might be up to 192 = 4*48 for FCC, and also to define the maximum number of symmetry operation labels,
 905 ! but only in case the cell is primitive, which gives the same upper bound. Thus in this routine, msym might
 906 ! be equal to nsym.
 907  integer :: iholohedry_nomagn,isym,isym_nomagn,multi
 908  integer :: nptsym,nsym_nomagn,shubnikov
 909  logical :: verbose_
 910  character(len=5) :: ptgroup,ptgroupha
 911  character(len=500) :: msg
 912 !arrays
 913  integer :: identity(3,3)
 914  integer,allocatable :: ptsymrel(:,:,:),symrel_nomagn(:,:,:)
 915  real(dp),allocatable :: tnons_nomagn(:,:)
 916  character(len=128) :: labels(maxsym)
 917 
 918 ! *************************************************************************
 919 
 920 !DEBUG
 921 !write(std_out,*)' symanal : enter'
 922 !write(std_out,*)' symanal : chkprim =',chkprim
 923 !write(std_out,*)' symanal : nsym=',nsym
 924 !do isym=1,nsym
 925 !  write(std_out,*)' symanal : symrel=',symrel(1:3,1:3,isym)
 926 !enddo
 927 !ENDDEBUG
 928 
 929  verbose_=.false.
 930  if(present(verbose))then
 931    verbose_=verbose
 932  endif
 933 
 934 !This routine finds the Bravais characteristics, without actually
 935 !looking at the symmetry operations.
 936  ABI_MALLOC(ptsymrel,(3,3,maxsym))
 937  call symlatt(bravais,dev_null,maxsym,nptsym,ptsymrel,rprimd,tolsym)
 938  ABI_FREE(ptsymrel)
 939 
 940 !Check whether the cell is primitive or not.
 941  call chkprimit(chkprim,multi,nsym,symafm,symrel)
 942 
 943  spgroup=0 ; ptgroupma=0 ; genafm(:)=zero
 944 
 945  if(multi>1)then !  Modify bravais if the cell is not primitive ; no determination of the space group
 946    bravais(1)=-bravais(1)
 947  else
 948 
 949 !  The cell is primitive, so that the space group can be
 950 !  determined. Need to distinguish Fedorov and Shubnikov groups.
 951 !  Do not distinguish Shubnikov types I and II.
 952 !  Also identify genafm, in case of Shubnikov type IV
 953    identity(:,:)=reshape((/1,0,0,0,1,0,0,0,1/),(/3,3/))
 954    shubnikov=1
 955    do isym=1,nsym
 956      if(symafm(isym)==-1)then
 957        shubnikov=3
 958        if(sum(abs(symrel(:,:,isym)-identity(:,:)))==0)then
 959          shubnikov=4
 960          genafm(:)=tnons(:,isym)
 961 !        DEBUG
 962 !        write(std_out,*)' isym=',isym
 963 !        write(std_out,*)' symrel(:,:,isym)',symrel(:,:,isym)
 964 !        write(std_out,*)' tnons(:,isym)',tnons(:,isym)
 965 !        write(std_out,*)' symafm(isym)',symafm(isym)
 966 !        ENDDEBUG
 967          exit
 968        end if
 969      end if
 970    end do
 971 
 972    if(shubnikov/=1)then
 973      if(shubnikov==3)write(msg, '(a)' )' Shubnikov space group type III'
 974      if(shubnikov==4)write(msg, '(a)' )' Shubnikov space group type IV'
 975      call wrtout(std_out,msg)
 976    end if
 977 
 978    if(shubnikov==1 .or. shubnikov==3)then
 979 !    Find the correct Bravais characteristics and point group
 980 !    Should also be used for Shubnikov groups of type IV ...
 981      call symbrav(bravais,msym,nsym,ptgroup,rprimd,symrel,tolsym)
 982 
 983 !    Find the space group
 984      call symspgr(bravais,labels,nsym,spgroup,symrel,tnons,tolsym)
 985 
 986      if(verbose_)then
 987        do isym=1,nsym
 988          write(msg,'(a,i3,2a)')' symanal : the symmetry operation no. ',isym,' is ',trim(labels(isym))
 989          call wrtout(std_out,msg)
 990        enddo
 991      endif
 992 
 993    end if
 994 
 995    if(shubnikov/=1)then
 996 
 997 !    Determine nonmagnetic symmetry operations
 998      nsym_nomagn=nsym/2
 999      ABI_MALLOC(symrel_nomagn,(3,3,nsym_nomagn))
1000      ABI_MALLOC(tnons_nomagn,(3,nsym_nomagn))
1001      isym_nomagn=0
1002      do isym=1,nsym
1003        if(symafm(isym)==1)then
1004          isym_nomagn=isym_nomagn+1
1005          symrel_nomagn(:,:,isym_nomagn)=symrel(:,:,isym)
1006          tnons_nomagn(:,isym_nomagn)=tnons(:,isym)
1007        end if
1008      end do
1009 
1010      if(shubnikov==3)then
1011 
1012 !      DEBUG
1013 !      write(std_out,*)' symanal : will enter symbrav with halved symmetry set'
1014 !      write(std_out,*)' Describe the different symmetry operations (index,symrel,tnons,symafm)'
1015 !      do isym=1,nsym_nomagn
1016 !      write(std_out,'(i3,2x,9i3,3es12.2,i3)')isym,symrel_nomagn(:,:,isym),tnons_nomagn(:,isym)
1017 !      end do
1018 !      ENDDEBUG
1019 
1020 !      Find the point group of the halved symmetry set
1021        call symptgroup(iholohedry_nomagn,nsym_nomagn,ptgroupha,symrel_nomagn)
1022 
1023 !      Deduce the magnetic point group (ptgroupma) from ptgroup and ptgroupha
1024        call getptgroupma(ptgroup,ptgroupha,ptgroupma)
1025 
1026      else if(shubnikov==4)then
1027 
1028 !      Find the Fedorov space group of the halved symmetry set
1029        call symspgr(bravais,labels,nsym_nomagn,spgroup,symrel_nomagn,tnons_nomagn,tolsym)
1030 
1031 !      The magnetic translation generator genafm has already been determined
1032 !      write(std_out,*)' genafm =',genafm, ' spgroup=',spgroup
1033 
1034        if(verbose_)then
1035 
1036          write(msg, '(a)' )' Select only the non-magnetic symmetry operations '
1037          call wrtout(std_out,msg)
1038 
1039          do isym=1,nsym
1040            if(symafm(isym)==1)then
1041              isym_nomagn=isym_nomagn+1
1042              write(msg,'(a,i3,2a)')' symspgr : the symmetry operation no. ',isym,' is ',trim(labels(isym_nomagn))
1043              call wrtout(std_out,msg)
1044            endif
1045          enddo
1046        endif
1047 
1048      end if
1049 
1050      ABI_FREE(symrel_nomagn)
1051      ABI_FREE(tnons_nomagn)
1052    end if ! Shubnikov groups
1053 
1054  end if
1055 
1056 !DEBUG
1057 !write(std_out,'(a)') ' symanal : exit '
1058 !ENDDEBUG
1059 
1060 end subroutine symanal

m_symfind/symbrav [ Functions ]

[ Top ] [ m_symfind ] [ Functions ]

NAME

 symbrav

FUNCTION

 From the list of symmetry operations, and the lattice vectors,
 determine the Bravais information (including the holohedry, the centering,
 the coordinate of the primitive vectors in the conventional vectors),
 as well as the point group.

INPUTS

 msym=dimension of symrel
 nsym=actual number of symmetries
 rprimd(3,3)=dimensional primitive translations for real space (bohr)
 symrel(3,3,msym)=symmetry operations in real space in terms
                  of primitive translations
 tolsym=tolerance for the symmetries

OUTPUT

 bravais(11): bravais(1)=iholohedry
              bravais(2)=center
              bravais(3:11)=coordinates of rprimd in the axes
              of the conventional bravais lattice (*2 if center/=0)
 ptgroup=symmetry point group
 [axis(3)]=Invariant axis in the conventional vector coordinates
   Set to (/0,0,0/) if the lattice belongs to the same holohedry as the lattice+atoms (+electric field + ...).

SOURCE

1092 subroutine symbrav(bravais,msym,nsym,ptgroup,rprimd,symrel,tolsym,axis)
1093 
1094 !Arguments ------------------------------------
1095 !scalars
1096  integer,intent(in) :: msym,nsym
1097  real(dp),intent(in) :: tolsym
1098  character(len=5),intent(out) :: ptgroup
1099 !arrays
1100  integer,intent(in) :: symrel(3,3,msym)
1101  integer,optional,intent(out) :: axis(3)
1102  integer,intent(out) :: bravais(11)
1103  real(dp),intent(in) :: rprimd(3,3)
1104 
1105 !Local variables-------------------------------
1106 !scalars
1107  integer :: iaxis,ii,bravais1now,ideform,iholohedry,invariant,isym
1108  integer :: jaxis,next_stage,nptsym,problem,maxsym
1109  integer, parameter :: naxes_ortho=22, naxes_hexa=7
1110  real(dp) :: norm,scprod
1111  character(len=500) :: msg
1112 !arrays
1113  integer :: identity(3,3),axis_trial(3),hexa_axes(3,naxes_hexa),ortho_axes(3,naxes_ortho)
1114  integer,allocatable :: ptsymrel(:,:,:),symrelconv(:,:,:)
1115  real(dp) :: axes(3,3),axis_cart(3),axis_red(3)
1116  real(dp) :: rprimdconv(3,3),rprimdtry(3,3),rprimdnow(3,3)
1117  real(dp) :: rprimdconv_invt(3,3)
1118 
1119 !**************************************************************************
1120 
1121 !DEBUG
1122 !write(std_out,*)' symbrav : enter '
1123 !call flush(std_out)
1124 !ENDDEBUG
1125 
1126  identity(:,:)=0
1127  identity(1,1)=1 ; identity(2,2)=1 ; identity(3,3)=1
1128 
1129  ortho_axes(:,:)=0
1130  ortho_axes(1,1)=1
1131  ortho_axes(2,2)=1
1132  ortho_axes(3,3)=1
1133  ortho_axes(:,4)=(/0,1,1/)
1134  ortho_axes(:,5)=(/1,0,1/)
1135  ortho_axes(:,6)=(/1,1,0/)
1136  ortho_axes(:,7)=(/0,1,-1/)
1137  ortho_axes(:,8)=(/-1,0,1/)
1138  ortho_axes(:,9)=(/1,-1,0/)
1139  ortho_axes(:,10)=(/0,1,2/)
1140  ortho_axes(:,11)=(/2,0,1/)
1141  ortho_axes(:,12)=(/1,2,0/)
1142  ortho_axes(:,13)=(/1,1,1/)
1143  ortho_axes(:,14)=(/-1,1,1/)
1144  ortho_axes(:,15)=(/1,-1,1/)
1145  ortho_axes(:,16)=(/1,1,-1/)
1146  ortho_axes(:,17)=(/2,1,1/)
1147  ortho_axes(:,18)=(/1,2,1/)
1148  ortho_axes(:,19)=(/1,1,2/)
1149  ortho_axes(:,20)=(/2,1,-1/)
1150  ortho_axes(:,21)=(/-1,2,1/)
1151  ortho_axes(:,22)=(/1,-1,2/)
1152 
1153  hexa_axes(:,:)=0
1154  hexa_axes(1,1)=1
1155  hexa_axes(2,2)=1
1156  hexa_axes(3,3)=1
1157  hexa_axes(:,4)=(/1,-1,0/)
1158  hexa_axes(:,5)=(/2,1,0/)
1159  hexa_axes(:,6)=(/1,1,0/)
1160  hexa_axes(:,7)=(/1,2,0/)
1161 
1162 !Determine the point group from the list of symmetry operations.
1163 !Also determine the holohedry, up to one undeterminacy : hR versus hP
1164  call symptgroup(iholohedry,nsym,ptgroup,symrel)
1165 
1166 !DEBUG
1167 !write(std_out,*)' symbrav, after symptgroup: nsym=',nsym
1168 !call flush(std_out)
1169 !write(std_out,*)' symbrav: symrel='
1170 !do isym=1,nsym
1171 !  write(std_out,'(9i4)')symrel(:,:,isym)
1172 !enddo
1173 !write(std_out,*)' symbrav: iholohedry=',iholohedry
1174 !call flush(std_out)
1175 !ENDDEBUG
1176 
1177 !Loop over trial deformations
1178 !This is needed in case the Bravais lattice determination from the lattice vectors
1179 !has a higher holohedry than the real one, in which the symmetry
1180 !operations for the atoms (or electric field, etc) are taken into account
1181  iaxis=0
1182  invariant=0
1183  next_stage=0
1184  rprimdnow(:,:)=rprimd(:,:)
1185  rprimdtry(:,:)=rprimd(:,:)
1186  ABI_MALLOC(symrelconv,(3,3,nsym))
1187 
1188 !At most will have to try naxes_ortho*5 deformations (naxes_ortho axes, five stages)
1189 !First, test whether the current recognition of Bravais lattice is problematic (iholohedry differs from bravais(1)).
1190 !Then, if there is a problem, test different deformations of rprimd, one after the other.
1191 !For each try, there is a new rprimdtry from the different set of deformation, that is generated later in the loop
1192 !Also bravais1now and rprimdnow might changed (and progressively lowered).
1193 !The latter change induces at most 5 stages for the computation (cubic->tetragonal->orthorhombic->monoclinic->triclinic).
1194 !After an upgrade of bravais1now and rprimdnow, one has to restart the full set of deformations.
1195 !Not sure that this procedure resolves all cases, but seems to work on >40000 inaccurate POSCAR files.
1196  do ideform=1,naxes_ortho*5
1197 
1198    maxsym=max(192,msym)
1199    ABI_MALLOC(ptsymrel,(3,3,maxsym))
1200    call symlatt(bravais,std_out,maxsym,nptsym,ptsymrel,rprimdtry,tolsym)
1201    ABI_FREE(ptsymrel)
1202 
1203 !DEBUG
1204 !write(std_out,*)' symbrav: inside loop with ideform,iaxis=',ideform,iaxis
1205 !write(std_out,'(a,9f12.6)')' rprimdtry=',rprimdtry(:,:)
1206 !write(std_out,'(a,2i4)')' bravais(1:2)=',bravais(1:2)
1207 !call flush(std_out)
1208 !ENDDEBUG
1209 
1210 
1211 !  Examine the agreement with bravais(1)
1212 !  Warning : might change Bravais lattice hR to hP, if hexagonal axes
1213    problem=0
1214    select case (bravais(1))
1215    case(7)
1216      if(iholohedry<6)problem=1
1217      if(iholohedry==6)problem=2
1218    case(6)
1219      if(iholohedry<4)problem=1
1220      if(iholohedry==7 .or. iholohedry==4)problem=2
1221 !      Here, change hR into hP
1222      if(iholohedry==5)iholohedry=6
1223    case(5)
1224      if(iholohedry<4)problem=1
1225      if(iholohedry==7 .or. iholohedry==6 .or. iholohedry==4)problem=2
1226    case(4)
1227      if(iholohedry<4)problem=1
1228      if(iholohedry>4)problem=2
1229    case(3)
1230      if(iholohedry<3)problem=1
1231      if(iholohedry>3)problem=2
1232    case(2)
1233      if(iholohedry<2)problem=1
1234      if(iholohedry>2)problem=2
1235    case(1)
1236      if(iholohedry>1)problem=2
1237    end select
1238 
1239 !  This is the usual situation, in which the lattice belong to the same holohedry
1240 !  as the lattice+atoms (+electric field + ...)
1241    if(problem==0)exit
1242 
1243    if(problem==2)then
1244      if(iaxis==0)then
1245        write(msg, '(3a,i3,3a,i3,7a)' )&
1246         'The Bravais lattice determined only from the primitive',ch10,&
1247         'vectors (rprim or angdeg), bravais(1)=',bravais(1),', is not compatible',ch10,&
1248         'with the real one, iholohedry=',iholohedry,', obtained by taking into',ch10,&
1249         'account the symmetry operations. This might be due to an insufficient',ch10,&
1250         'number of digits in the specification of rprim (at least 10),',ch10,&
1251         'or to an erroneous rprim or angdeg. If this is not the case, then ...'
1252        ABI_BUG(msg)
1253      end if
1254      if(iaxis==1)then
1255        write(msg, '(3a,3i3,2a,i3,2a,i3)' )&
1256        'Could not succeed to determine the bravais lattice',ch10,&
1257        'problem,iaxis,invariant=',problem,iaxis,invariant,ch10,&
1258        'bravais(1)=',bravais(1),ch10,&
1259        'iholohedry=',iholohedry
1260        ABI_BUG(msg)
1261      end if
1262 !    Try to increase tolsym to find the Bravais lattice. 
1263      maxsym=max(192,msym)
1264      ABI_MALLOC(ptsymrel,(3,3,maxsym))
1265 !DEBUG
1266 !    write(6,*)' symbrav : will call symlatt, 3*tolsym=',3*tolsym
1267 !ENDDEBUG
1268      call symlatt(bravais,std_out,maxsym,nptsym,ptsymrel,rprimdtry,3*tolsym)
1269      ABI_FREE(ptsymrel)
1270      if(bravais(1)==iholohedry)then
1271 !      Succeeded  
1272        exit
1273      else
1274        write(msg, '(3a,3i3,2a,i3,2a,i3)' )&
1275        'Could not succeed to determine the bravais lattice, even after considering a larger tolsym',ch10,&
1276        'problem,iaxis,invariant=',problem,iaxis,invariant,ch10,&
1277        'bravais(1)=',bravais(1),ch10,&
1278        'iholohedry=',iholohedry
1279        ABI_BUG(msg)
1280      end if
1281    end if
1282 
1283    if(problem==1)then  ! One is left with the problem=1 case, basically iholohedry is lower than bravais(1)
1284      if(iaxis==0)then
1285        write(msg, '(a,a,a,i3,a,a,a,i3,a,a,a)' )&
1286        'The Bravais lattice determined only from the primitive',ch10,&
1287        'vectors, bravais(1)=',bravais(1),', is more symmetric',ch10,&
1288        'than the real one, iholohedry=',iholohedry,', obtained by taking into',ch10,&
1289        'account the atomic positions. Start deforming the primitive vector set.'
1290        ABI_COMMENT(msg)
1291        next_stage=1
1292      else if(iaxis/=0)then
1293        if(bravais(1)<bravais1now)then
1294          write(msg, '(3a,i3,3a,i3,2a)' )&
1295          'The Bravais lattice determined from modified primitive',ch10,&
1296          'vectors, bravais(1)=',bravais(1),', has a lower symmetry than before,',ch10,&
1297          'but is still more symmetric than the real one, iholohedry=',iholohedry,ch10,&
1298          'obtained by taking into account the atomic positions.'
1299          ABI_COMMENT(msg)
1300          next_stage=1
1301        else if(iaxis==1)then
1302          write(msg, '(3a,3i3,2a,i3,2a,i3)' )&
1303          'Could not succeed to determine the bravais lattice',ch10,&
1304          'problem,iaxis,invariant=',problem,iaxis,invariant,ch10,&
1305          'bravais(1)=',bravais(1),ch10,&
1306          'iholohedry=',iholohedry
1307          ABI_BUG(msg)
1308        end if
1309      end if
1310    end if ! problem==1
1311 
1312 !  One is here when problem=1 (iholohedry < bravais(1)) and either
1313 !  - iaxis=0 (no deformation has been tried yet),
1314 !  - some deformation iaxis has been tried giving bravais(1), but iholohedry < bravais(1) < bravais1now
1315 !  - some deformation iaxis has been tried giving bravais(1), but iholohedry < bravais(1) = bravais1now and iaxis/=1 .
1316 !  Also, note that next_stage is still 0 when bravais(1)=bravais1now .
1317 !  The loop has been ended (so, the search failed) when bravais(1)=bravais1now and iaxis==1.
1318 
1319    if(next_stage==1)then
1320      bravais1now=bravais(1)
1321      rprimdnow(:,:)=rprimdtry(:,:)
1322 !    Generate the symmetry operations in the conventional vector coordinates
1323      rprimdconv(:,1)=bravais(3:5)
1324      rprimdconv(:,2)=bravais(6:8)
1325      rprimdconv(:,3)=bravais(9:11)
1326      axes(:,:)=zero
1327      axes(1,1)=one ; axes(2,2)=one ; axes(3,3)=one
1328      symrelconv(:,:,1:nsym)=symrel(:,:,1:nsym)
1329      call symrelrot(nsym,rprimdconv,axes,symrelconv,tolsym)
1330      if(bravais(1)/=6)then
1331        iaxis=naxes_ortho+1
1332      else
1333        iaxis=naxes_hexa+1
1334      end if
1335      next_stage=0
1336 !DEBUG
1337 !    write(std_out,*)' symbrav: next stage, bravais(1), bravais(2) and symrelconv'
1338 !    write(std_out,'(a,2i4)')' bravais(1:2)=',bravais(1:2)
1339 !    write(std_out,'(a,9f12.6)')' rprimdconv=',rprimdconv(:,:)
1340 !    do isym=1,nsym
1341 !      write(std_out,'(9i4)')symrelconv(:,:,isym)
1342 !    enddo
1343 !    call flush(std_out)
1344 !ENDDEBUG
1345    end if
1346 
1347 !  Go to the next iaxis that will be left invariant
1348    iaxis=iaxis-1
1349    do jaxis=iaxis,1,-1
1350      if(bravais(1)/=6)then
1351        axis_trial(:)=ortho_axes(:,jaxis)
1352      else
1353        axis_trial(:)=hexa_axes(:,jaxis)
1354      end if
1355 !    DEBUG
1356 !    write(std_out,*)' symbrav : ixaxis, trial jaxis=',iaxis,jaxis
1357 !    write(std_out,*)' axis_trial=',axis_trial
1358 !    ENDDEBUG
1359      invariant=1
1360 !    Examine whether all symmetry operations leave the axis invariant (might be reversed, though)
1361      do isym=1,nsym
1362        if(sum(abs(matmul(symrelconv(:,:,isym),axis_trial)+(-axis_trial(:))))/=0 .and. &
1363        sum(abs(matmul(symrelconv(:,:,isym),axis_trial)+axis_trial(:)))/=0 )invariant=0
1364      end do
1365      if(invariant==1)then
1366        iaxis=jaxis
1367 !DEBUG
1368 !      write(msg, '(2a,i3)' )ch10,' symbrav : found invariant axis, jaxis=',jaxis
1369 !      call wrtout(std_out,msg)
1370 !ENDDEBUG
1371        exit
1372      end if
1373    end do
1374 
1375    if(invariant==0)then
1376 !    Not a single axis was invariant with respect to all operations ?!
1377 !    do isym=1,nsym; write(std_out, '(a,10i4)' )' isym,symrelconv=',isym,symrelconv(:,:,isym); enddo
1378      write(msg, '(3a,3i3,2a,i3,2a,i3)' )&
1379      'Could not succeed to determine the bravais lattice (not a single invariant)',ch10,&
1380      'problem,iaxis,invariant=',problem,iaxis,invariant,ch10,&
1381      'bravais(1)=',bravais(1),ch10,&
1382      'iholohedry=',iholohedry
1383      ABI_BUG(msg)
1384    end if
1385 
1386    call matr3inv(rprimdconv,rprimdconv_invt)
1387    axis_red(:)=axis_trial(1)*rprimdconv_invt(1,:)+ &
1388 &   axis_trial(2)*rprimdconv_invt(2,:)+ &
1389 &   axis_trial(3)*rprimdconv_invt(3,:)
1390    axis_cart(:)=axis_red(1)*rprimdnow(:,1)+ &
1391 &   axis_red(2)*rprimdnow(:,2)+ &
1392 &   axis_red(3)*rprimdnow(:,3)
1393    norm=sum(axis_cart(:)**2)
1394 !DEBUG
1395 !  write(6,*)' axis_trial =',axis_trial
1396 !  write(6,*)' axis_red =',axis_red
1397 !  write(6,*)' axis_cart =',axis_cart 
1398 !  write(6,*)' rprimdnow=',rprimdnow
1399 !ENDDEBUG
1400 !  Expand by a uniform, quite arbitrary, dilatation, along the invariant axis
1401 !  Note : make these dilatation different, according to ideform
1402 !  XG 20151221  : Still, the interplay between the size of the deformation and the tolsym is not easy to address.
1403 !  Indeed the deformation must be sufficiently large to be perceived by symlatt as a real breaking of the
1404 !  symmetry of the lattice. In order to deal with all the small values od tolsym, it has been set at a minimum of tol3,
1405 !  but it must also be larger than tolsym. Moreover, for some axis choice, the deformation is not aligned with the axis, decreasing
1406 !  the effective deformation length. An additional factor of three is thus included, actually increased to six just to be sure...
1407    do ii=1,3
1408      scprod=axis_cart(1)*rprimdnow(1,ii)+axis_cart(2)*rprimdnow(2,ii)+axis_cart(3)*rprimdnow(3,ii)
1409      rprimdtry(:,ii)=rprimdnow(:,ii)+ideform*(max(tol3,six*tolsym)-tol6)*scprod/norm*axis_cart(:)
1410    end do
1411 
1412 !DEBUG
1413 !  write(6,*)' rprimdtry=',rprimdtry
1414 !ENDDEBUG
1415 
1416  end do ! ideform
1417 
1418  if(bravais(1)/=iholohedry)then
1419    write(msg, '(3a,3i3,2a,i3,2a,i3)' )&
1420    'Despite efforts, Could not succeed to determine the bravais lattice :',ch10,&
1421    'bravais(1)=',bravais(1),ch10,&
1422    'iholohedry=',iholohedry
1423    ABI_BUG(msg)
1424  end if
1425 
1426  ABI_FREE(symrelconv)
1427 
1428  if (PRESENT(axis)) then  ! Return symmetry axis.
1429    axis=(/0,0,0/)
1430    if (iaxis/=0) then
1431      if(bravais(1)/=6)then
1432        axis=ortho_axes(:,iaxis)
1433      else
1434        axis=hexa_axes(:,iaxis)
1435      end if
1436    end if
1437  end if
1438 
1439 !DEBUG
1440 !write(std_out,'(a)')' symbrav : exit '
1441 !ENDDEBUG
1442 
1443 end subroutine symbrav

m_symfind/symfind [ Functions ]

[ Top ] [ m_symfind ] [ Functions ]

NAME

 symfind

FUNCTION

 Symmetry finder.
 From the symmetries of the Bravais lattice (ptsymrel),
 select those that leave invariant the system, and generate
 the corresponding tnons vectors and symafm information.
 Unlike symfind_expert, does NOT resymmetrize atomic positions and tnons for more robust determination of the symmetries.
 The algorithm is explained in T.G. Worlton and J.L. Warren, Comp. Phys. Comm. 3, 88 (1972) [[cite:Worlton1972]]

INPUTS

 chrgat(natom) (optional)=target charge for each atom. Not always used, it depends on the value of constraint_kind
 invardir_red (optional)=reduced coordinates of an invariant direction (only acting with symrel - not tnons)
 invar_z (optional)= if 1, the z direction must stay invariant for all symrel applied ; 
                     if 2, z must stay invariant and also there cannot be any associated tnons along z.
 gprimd(3,3)=dimensional primitive translations for reciprocal space
 msym=default maximal number of symmetries
 natom=number of atoms in cell.
 nptsym=number of point symmetries of the Bravais lattice
 nspden= number of spin-density components. When 4, the three components of spinat are taken into account, instead of only z-component.
 nucdipmom(3,natom) (optional) array of nuclear dipole moments
 ptsymrel(3,3,1:msym)= nptsym point-symmetry operations
   of the Bravais lattice in real space in terms
   of primitive translations.
 spinat(3,natom)=initial spin of each atom, in unit of hbar/2.
 tolsym=tolerance for the symmetries
 typat(natom)=integer identifying type of atom.
 use_inversion=1 if inversion and improper rotations can be included in set of symmetries
 xred(3,natom)=reduced coordinates of atoms in terms of real space
   primitive translations

OUTPUT

 ierr (optional)=if non-zero, the symmetry operations do not form a group
 nsym=actual number of symmetries
 symafm(1:msym)=(anti)ferromagnetic part of nsym symmetry operations
 symrel(3,3,1:msym)= nsym symmetry operations in real space in terms
  of primitive translations
 tnons(3,1:msym)=nonsymmorphic translations for each symmetry (would
  be 0 0 0 each for a symmorphic space group)

SOURCE

 95  subroutine symfind(gprimd,msym,natom,nptsym,nspden,nsym,&
 96 &  prtvol, ptsymrel,spinat,symafm,symrel,tnons,tolsym,typat,use_inversion,xred,&
 97 &  chrgat,ierr,nucdipmom,invardir_red,invar_z)  ! Optional
 98 
 99 !Arguments ------------------------------------
100 !scalars
101  integer,intent(in) :: msym,natom,nptsym,nspden,use_inversion
102  integer,intent(in) :: prtvol
103  integer,optional,intent(in) :: invar_z
104  integer,optional,intent(out) :: ierr
105  integer,intent(out) :: nsym
106  real(dp),intent(in) :: tolsym
107 !arrays
108  integer,intent(in) :: ptsymrel(3,3,msym),typat(natom)
109  integer,intent(inout) :: symafm(msym),symrel(3,3,msym) !vz_i
110  real(dp),intent(in) :: gprimd(3,3),spinat(3,natom),xred(3,natom)
111  real(dp),optional,intent(in) :: invardir_red(3),chrgat(natom)
112  real(dp),optional, intent(in) :: nucdipmom(3,natom)
113  real(dp),intent(inout) :: tnons(3,msym) !vz_i
114 
115 !Local variables-------------------------------
116 !scalars
117  integer :: found3,foundcl,iatom,iatom0,iatom1,iatom2,iatom3,iclass,iclass0,ierr_,ii
118  integer :: isym,jj,kk,natom0,nclass,ntrial,printed,trialafm,trialok
119  real(dp) :: det,diff1,diff2,diff3,diffr1,diffr2,diffr3,ndnorm,nucdipmomcl2,nucdipmomcl20
120  real(dp) :: spinat2,spinatcl2,spinatcl20,tolsym2
121 ! TRUE if antiferro symmetries are used with non-collinear magnetism.
122  integer :: afm_noncoll=1 !For nspden==4.  If 1, all symops are permitted ; if 0 symafm must be 1.
123 !For nspden=4. If noncoll_orthorhombic1, require the symmetry operations to be a subset of the orthorhombic symmetries, except if all spinat=0..
124  integer :: noncoll_orthorhombic=0
125  logical :: test_sameabsspin,test_samechrg
126  logical :: test_samenucdipmom
127  character(len=500) :: msg
128 !arrays
129  integer,allocatable :: class(:,:),natomcl(:),typecl(:)
130  real(dp) :: diff(3),invardir_red_rot(3),hand2(3),hand3(3),ndtest(3),rprimd(3,3),spinat0(3),xred0(3)
131  !real(dp) :: symnucdipmom2(3)
132  real(dp) :: symnucdipmom2cart(3,3),symnucdipmom2red(3,3)
133  real(dp) :: symspinat1(3),symspinat2(3),symxred2(3),trialnons(3)
134  real(dp),allocatable :: chrgat_(:)
135  real(dp),allocatable :: chrgatcl(:)
136  real(dp),allocatable :: local_nucdipmom(:,:,:),nucdipmomcl(:,:),nucdipmomred(:,:,:)
137  real(dp),allocatable :: spinatcl(:,:),spinatred(:,:)
138 
139 !**************************************************************************
140 
141 !DEBUG
142 !write(std_out,'(a)')' m_symfind%symfind : enter '
143 !call flush(std_out)
144 !ENDDEBUG
145 
146 !DEBUG
147 ! if (prtvol>1) msg="remove me later"
148 ! write(std_out,*)' symfind : enter'
149 ! call flush(6)
150 ! write(std_out,*)'   ptsymrel matrices are :'
151 ! do isym=1,nptsym
152 ! write(std_out,'(i4,4x,9i4)' )isym,ptsymrel(:,:,isym)
153 ! end do
154 ! write(std_out,*)' symfind : natom=',natom
155 ! do iatom=1,natom
156 ! write(std_out,*)'  atom number',iatom
157 ! write(std_out,*)'   typat   =',typat(iatom)
158 ! write(std_out,*)'   spinat  =',spinat(:,iatom)
159 ! write(std_out,*)'   xred    =',xred(:,iatom)
160 ! end do
161 ! write(std_out,*)' '
162 ! call flush(6)
163 !ENDDEBUG
164 
165  ABI_UNUSED(prtvol)
166 
167 !Find the number of classes of atoms (type, chrg and spinat must be identical,
168 !spinat might differ by a sign, if aligned with the z direction, or,
169 ! type and nucdipmom must be identical)
170 !natomcl(iclass) will contain the number of atoms in the class
171 !typecl(iclass) will contain the type of the atoms in the class
172 !chrgcl(iclass) will contain the charge of the atoms in the class
173 !spinatcl(1:3,iclass) will contain the spinat of the atoms in the class
174 !class(1:natomclass(iclass),iclass) will contain the index of the
175 !atoms belonging to the class
176  ABI_MALLOC(class,(natom+3,natom))
177  ABI_MALLOC(natomcl,(natom))
178  ABI_MALLOC(typecl,(natom))
179  ABI_MALLOC(chrgat_,(natom))
180  ABI_MALLOC(chrgatcl,(natom))
181  ABI_MALLOC(spinatcl,(3,natom))
182  ABI_MALLOC(local_nucdipmom,(3,3,natom))
183  ABI_MALLOC(nucdipmomcl,(3,natom))
184 
185  tolsym2=tolsym**2
186 
187  chrgat_(:)=zero
188  if(present(chrgat))then
189    chrgat_(:)=chrgat(:)
190  endif
191 
192  local_nucdipmom(:,:,:) = zero
193  if(present(nucdipmom)) then
194     local_nucdipmom(1:3,1,:) = nucdipmom(1:3,:)
195  end if
196  ! for each nuclear dipole we need a local right handed coord system, so we can
197  ! test later for whether a symmetry operation preserves the circulation induced
198  ! by the dipole
199  do iatom=1, natom
200     ndnorm=sqrt(DOT_PRODUCT(local_nucdipmom(1:3,1,iatom),local_nucdipmom(1:3,1,iatom)))
201 
202     ! if nuclear dipole has effectively zero size, move on to the next atom
203     if (ndnorm < tol8) cycle
204 
205     ! for testing purposes, we care only about direction so renormalize to unity
206     local_nucdipmom(1:3,1,iatom) = local_nucdipmom(1:3,1,iatom)/ndnorm
207 
208     ! make a random vector, each component is (0,1]
209     call random_number(ndtest)
210 
211     ! vector 2 is constructed to be orthogonal to original nuclear dipole moment vector
212     call acrossb(local_nucdipmom(1:3,1,iatom),ndtest(1:3),local_nucdipmom(1:3,2,iatom))
213 
214     ! vector 3 is orthogonal to 1 and 2, and 1,2,3 form a right-handed set
215     call acrossb(local_nucdipmom(1:3,1,iatom),local_nucdipmom(1:3,2,iatom),local_nucdipmom(1:3,3,iatom))
216  end do
217 
218  ! need rprimd later to transform back to cart coords
219  call matr3inv(gprimd,rprimd)
220 
221 !DEBUG
222 !write(std_out,'(a)')' m_symfind%symfind : before initialise with the first atom '
223 !call flush(std_out)
224 !ENDDEBUG
225 
226 !Initialise with the first atom
227  nclass=1
228  natomcl(1)=1
229  typecl(1)=typat(1)
230  chrgatcl(1)=chrgat_(1)
231  spinatcl(:,1)=spinat(:,1)
232  nucdipmomcl(:,1)=local_nucdipmom(:,1,1)
233  class(1,1)=1
234  if(natom>1)then
235    do iatom=2,natom
236 !    DEBUG
237 !    write(std_out,*)' '
238 !    write(std_out,*)' symfind : examine iatom=',iatom
239 !    ENDDEBUG
240      foundcl=0
241      do iclass=1,nclass
242 !      Compare the typat, chrg and spinat of atom iatom with existing ones.
243 !      At this stage, admit either identical spinat, or spin-flip spinat.
244        if( typat(iatom)==typecl(iclass)) then
245          test_samechrg= (abs(chrgat_(iatom)-chrgatcl(iclass))<tolsym)
246          if(nspden/=4)then
247            test_sameabsspin=(abs(abs(spinat(3,iatom))-abs(spinatcl(3,iclass)))<tolsym)
248          else if(nspden==4)then
249            spinat2  =spinat(1,iatom)**2+spinat(2,iatom)**2+spinat(3,iatom)**2
250            spinatcl2=spinatcl(1,iclass)**2+spinatcl(2,iclass)**2+spinatcl(3,iclass)**2
251            test_sameabsspin=abs(spinat2-spinatcl2)<tolsym
252          endif
253          test_samenucdipmom= &
254 &             abs(local_nucdipmom(1,1,iatom)-nucdipmomcl(1,iclass))<tolsym .and. &
255 &             abs(local_nucdipmom(2,1,iatom)-nucdipmomcl(2,iclass))<tolsym .and. &
256 &             abs(local_nucdipmom(3,1,iatom)-nucdipmomcl(3,iclass))<tolsym
257          ! note in the following test, m_chkinp/chkinp has already prevented nucdipmom to be
258          ! nonzero when spinat is nonzero
259          if( test_samechrg .and. test_sameabsspin .and. test_samenucdipmom ) then
260 !          DEBUG
261 !          write(std_out,*)' symfind : find it belongs to class iclass=',iclass
262 !          write(std_out,*)' symfind : spinat(:,iatom)=',spinat(:,iatom)
263 !          write(std_out,*)' symfind : spinatcl(:,iclass)=',spinatcl(:,iclass)
264 !          write(std_out,*)' symfind : test_sameabsspin=',test_sameabsspin
265 !          write(std_out,*)' '
266 !          ENDDEBUG
267            natomcl(iclass)=natomcl(iclass)+1
268            class(natomcl(iclass),iclass)=iatom
269            foundcl=1
270            exit
271          end if
272        end if
273      end do
274 !    If no class with these characteristics exist, create one
275      if(foundcl==0)then
276        nclass=nclass+1
277        natomcl(nclass)=1
278        typecl(nclass)=typat(iatom)
279        chrgatcl(nclass)=chrgat_(iatom)
280        spinatcl(:,nclass)=spinat(:,iatom)
281        nucdipmomcl(:,nclass)=local_nucdipmom(:,1,iatom)
282        class(1,nclass)=iatom
283      end if
284    end do
285  end if
286 
287 !DEBUG
288 !write(std_out,*)' '
289 !write(std_out,*)' symfind : found ',nclass,' nclass of atoms'
290 !do iclass=1,nclass
291 !write(std_out,*)'  class number',iclass
292 !write(std_out,*)'   natomcl =',natomcl(iclass)
293 !write(std_out,*)'   typecl  =',typecl(iclass)
294 !write(std_out,*)'   spinatcl=',spinatcl(:,iclass)
295 !write(std_out,*)'   class   =',(class(iatom,iclass),iatom=1,natomcl(iclass))
296 !end do
297 !write(std_out,*)' '
298 !ENDDEBUG
299 
300 !DEBUG
301 !write(std_out,'(a)')' m_symfind%symfind : before select the class '
302 !call flush(std_out)
303 !ENDDEBUG
304 
305 !Select the class with the least number of atoms, and non-zero spinat if any
306 !It is important to select a magnetic class of atom, if any, otherwise
307 !the determination of the initial (inclusive) set of symmetries takes only
308 !non-magnetic symmetries, and not both magnetic and non-magnetic ones, see later.
309 !On the contrary, the chrgat_ data does not play any role, it is invariant upon atomic-centered  symmetries
310  iclass0=1
311  natom0=natomcl(1)
312  spinatcl20=spinatcl(1,1)**2+spinatcl(2,1)**2+spinatcl(3,1)**2
313  nucdipmomcl20=nucdipmomcl(1,1)**2+nucdipmomcl(2,1)**2+nucdipmomcl(3,1)**2
314  if(nclass>1)then
315    do iclass=2,nclass
316      spinatcl2=spinatcl(1,iclass)**2+spinatcl(2,iclass)**2+spinatcl(3,iclass)**2
317      nucdipmomcl2=nucdipmomcl(1,iclass)**2+nucdipmomcl(2,iclass)**2+nucdipmomcl(3,iclass)**2
318      if( (natomcl(iclass)<natom0 &
319 &          .and. .not. (spinatcl20>tolsym .and. spinatcl2<tolsym) &
320 &          .and. .not. (nucdipmomcl20>tolsym .and. nucdipmomcl2<tolsym) )  &
321 &     .or. (spinatcl20<tolsym .and. spinatcl2>tolsym) &
322 &     .or. (nucdipmomcl20<tolsym .and. nucdipmomcl2>tolsym)                        )then
323        iclass0=iclass
324        natom0=natomcl(iclass)
325        spinatcl20=spinatcl2
326        nucdipmomcl20=nucdipmomcl2
327      end if
328    end do
329  end if
330 
331  printed=0
332 
333 !If non-collinear spinat have to be used, transfer them in reduced coordinates
334  if (nspden==4) then
335    ABI_MALLOC(spinatred,(3,natom))
336    do iatom=1,natom
337      do ii=1,3
338        spinatred(1:3,iatom)=MATMUL(TRANSPOSE(gprimd),spinat(1:3,iatom))
339      end do
340    end do
341  end if
342 
343 !DEBUG
344 !write(std_out,*)' '
345 !write(std_out,*)' symfind : has selected iclass0=',iclass0
346 !write(std_out,*)'  # iatom  xred                          spinat       (spinatred if nspden=4) '
347 !do iatom0=1,natomcl(iclass0)
348 !iatom=class(iatom0,iclass0)
349 !if(nspden/=4)then
350 !  write(std_out,'(2i4,6f10.4)' )iatom0,iatom,xred(:,iatom),spinat(:,iatom)
351 !else if(nspden==4)then
352 !  write(std_out,'(2i4,9f10.4)' )iatom0,iatom,xred(:,iatom),spinat(:,iatom),spinatred(:,iatom)
353 !endif
354 !end do
355 !write(std_out,*)' '
356 !ENDDEBUG
357 
358 
359  !represent nuclear dipole moments in reduced coords
360  ABI_MALLOC(nucdipmomred,(3,3,natom))
361  do iatom=1,natom
362     do ii=1,3
363        nucdipmomred(1:3,ii,iatom)=MATMUL(TRANSPOSE(gprimd),local_nucdipmom(1:3,ii,iatom))
364     end do
365  end do
366 
367 !DEBUG
368 !write(std_out,'(a)')' m_symfind%symfind : before big loop '
369 !call flush(std_out)
370 !ENDDEBUG
371 
372 !Big loop over each symmetry operation of the Bravais lattice
373  nsym=0
374  do isym=1,nptsym
375 
376 !DEBUG
377 !write(std_out,'(a,i4)')' m_symfind%symfind : enter loop isym=',isym
378 !call flush(std_out)
379 !ENDDEBUG
380 
381    if(present(invardir_red))then
382 !    ji: Check whether symmetry operation leaves invardir_red invariant
383      invardir_red_rot(:) = ptsymrel(:,1,isym)*invardir_red(1) +  &
384 &     ptsymrel(:,2,isym)*invardir_red(2) +  &
385 &     ptsymrel(:,3,isym)*invardir_red(3)
386      diff(:)=invardir_red(:)-invardir_red_rot(:)
387      if( (diff(1)**2+diff(2)**2+diff(3)**2) > tolsym**2 ) cycle
388    endif
389 
390 !DEBUG
391 !write(std_out,'(a,i4)')' m_symfind%symfind : 1'
392 !call flush(std_out)
393 !ENDDEBUG
394 
395    if (use_inversion==0) then
396      det=ptsymrel(1,1,isym)*ptsymrel(2,2,isym)*ptsymrel(3,3,isym)+&
397 &     ptsymrel(2,1,isym)*ptsymrel(3,2,isym)*ptsymrel(1,3,isym)+&
398 &     ptsymrel(1,2,isym)*ptsymrel(2,3,isym)*ptsymrel(3,1,isym) - &
399 &     (ptsymrel(3,1,isym)*ptsymrel(2,2,isym)*ptsymrel(1,3,isym)+&
400 &     ptsymrel(2,1,isym)*ptsymrel(1,2,isym)*ptsymrel(3,3,isym)+&
401 &     ptsymrel(3,2,isym)*ptsymrel(2,3,isym)*ptsymrel(1,1,isym))
402      if(det==-1) cycle
403    end if
404 
405 !DEBUG
406 !write(std_out,'(a,i4)')' m_symfind%symfind : 2'
407 !call flush(std_out)
408 !ENDDEBUG
409 
410 !  jellium slab and spatially varying chemical potential cases:
411 !  (actually, an inversion symmetry/mirror plane perpendicular to z symmetry operation might still be allowed... TO BE DONE !)
412    if(present(invar_z))then
413      if (invar_z/=0) then
414 !      check whether symmetry operation produce a rotation only in the xy plane
415        if( ptsymrel(1,3,isym)/=0 .or. ptsymrel(2,3,isym)/=0 .or. &
416 &       ptsymrel(3,1,isym)/=0 .or. ptsymrel(3,2,isym)/=0 ) cycle
417 !      check whether symmetry operation does not change the z
418        if( ptsymrel(3,3,isym)/=1 ) cycle
419      end if
420    end if
421 
422 !DEBUG
423 !write(std_out,'(a,i4)')' m_symfind%symfind : 3'
424 !call flush(std_out)
425 !ENDDEBUG
426 
427 !  If noncoll_orthorhombic=1, require orthorhombic operations of symmetries, except if spinat=0.
428    if (nspden==4 .and. noncoll_orthorhombic==1)then
429      if(sum(abs(spinat(:,:)))>tol14)then
430        if( ptsymrel(1,3,isym)/=0 .or. ptsymrel(2,3,isym)/=0 .or. &
431 &          ptsymrel(1,2,isym)/=0 .or. ptsymrel(3,2,isym)/=0 .or. &
432 &          ptsymrel(2,1,isym)/=0 .or. ptsymrel(3,2,isym)/=0 ) cycle
433      endif
434    endif
435 
436 !DEBUG
437 !write(std_out,'(a,i4)')' m_symfind%symfind : 4'
438 !call flush(std_out)
439 !ENDDEBUG
440 
441 !  Select a tentative set of associated translations
442 !  First compute the symmetric of the first atom in the smallest class,
443 !  using the point symmetry, and also the symmetric of spinat(red).
444    iatom0=class(1,iclass0)
445    xred0(:)=ptsymrel(:,1,isym)*xred(1,iatom0)+ &
446 &   ptsymrel(:,2,isym)*xred(2,iatom0)+ &
447 &   ptsymrel(:,3,isym)*xred(3,iatom0)
448    if (nspden/=4) then
449      spinat0(:)=spinat(:,iatom0)
450    else
451      spinat0(:)=ptsymrel(:,1,isym)*spinatred(1,iatom0)+ &
452 &           ptsymrel(:,2,isym)*spinatred(2,iatom0)+ &
453 &           ptsymrel(:,3,isym)*spinatred(3,iatom0)
454    endif
455 
456 !DEBUG
457 !write(std_out,'(a,i4)')' m_symfind%symfind : 5'
458 !call flush(std_out)
459 !ENDDEBUG
460 
461 !  From the set of possible images, deduce tentative translations,
462 !  and magnetic factor then test whether it send each atom on a symmetric one
463    ntrial=0
464    do ii=1,natom0
465 !DEBUG
466 !    write(std_out,'(a,2i4)')' symfind : loop isym,ii=',isym,ii
467 !ENDDEBUG
468      iatom1=class(ii,iclass0)
469 
470 !    The tentative translation is found
471      trialnons(:)=xred(:,iatom1)-xred0(:)
472 !    Compare the spinat vectors
473      if (nspden/=4) then
474        symspinat1(:)=spinat(:,iatom1)
475      else
476        symspinat1(:)=spinatred(:,iatom1)
477      end if
478 
479 !DEBUG
480 !    write(std_out,'(a,6f10.4)')' symspinat1,spinat0=',symspinat1(:),spinat0(:)
481 !ENDDEBUG
482 
483      trialafm=1
484      if(sum(abs(symspinat1(:)-spinat0(:)))>tolsym)then
485        trialafm=-1
486        if(nspden==4 .and. afm_noncoll==0)cycle
487        if(sum(abs(symspinat1(:)+spinat0(:)))>tolsym)cycle
488      endif
489 
490      if(sum(abs(local_nucdipmom(:,1,iatom1)-local_nucdipmom(:,1,iatom0)))>tolsym)then
491        write(msg,'(3a,3i5)')&
492        'Problem with matching the nuclear dipole moment within a class.',ch10,&
493        'isym,iatom0,iatom1=',isym,iatom0,iatom1
494        ABI_ERROR(msg)
495      end if
496 
497 !    jellium slab case: check whether symmetry operation has no translational
498 !    component along z
499      if(present(invar_z))then
500        if( invar_z==2 .and. abs(trialnons(3)) > tolsym ) cycle
501      endif
502      trialok=1
503 
504 !    DEBUG
505 !     write(std_out, '(a,i3,a,i3,a,i3,a,3f12.4,i3)') ' Try isym=',isym,' sending iatom0 ',iatom0,' to iatom1 ',iatom1,' with trialnons(:),trialafm =',trialnons(:),trialafm
506 !    ENDDEBUG
507 
508 !    Loop over all classes, then all atoms in the class,
509 !    to find whether they have a symmetric
510      do iclass=1,nclass
511        do jj=1,natomcl(iclass)
512 
513          iatom2=class(jj,iclass)
514 !        Generate the tentative symmetric position of iatom2
515          symxred2(:)=ptsymrel(:,1,isym)*xred(1,iatom2)+ &
516 &         ptsymrel(:,2,isym)*xred(2,iatom2)+ &
517 &         ptsymrel(:,3,isym)*xred(3,iatom2)+ trialnons(:)
518 !        Generate the tentative symmetric spinat of iatom2
519          if (nspden/=4) then
520            symspinat2(:)=trialafm*spinat(:,iatom2)
521          else
522            symspinat2(:)=trialafm*(ptsymrel(:,1,isym)*spinatred(1,iatom2)+ &
523 &           ptsymrel(:,2,isym)*spinatred(2,iatom2)+ &
524 &           ptsymrel(:,3,isym)*spinatred(3,iatom2))
525          end if
526          !        Generate the tentative symmetric nucdipmom of iatom2
527          do kk = 1, 3
528             symnucdipmom2red(:,kk)=ptsymrel(:,1,isym)*nucdipmomred(1,kk,iatom2)+ &
529                  &           ptsymrel(:,2,isym)*nucdipmomred(2,kk,iatom2)+ &
530                  &           ptsymrel(:,3,isym)*nucdipmomred(3,kk,iatom2)
531             ! transform back to cart coords for final comparison to nucdipmom
532             symnucdipmom2cart(:,kk)=MATMUL(rprimd,symnucdipmom2red(:,kk))
533          end do
534 
535 !        DEBUG
536 !        write(std_out,'(a,i4,a,3f8.4,a,3f8.4,a,3f8.4)')&
537 !&          ' Test iatom2=',iatom2,' at xred=',xred(:,iatom2),'. Is sent to',symxred2(:),' with symspinat2=',symspinat2(:)
538 !        ENDDEBUG
539 
540 !        Check whether there exists an atom of the same class at the
541 !        same location, with the correct spinat and nuclear dipole moment circulation
542          do kk=1,natomcl(iclass)
543 
544            found3=1
545            iatom3=class(kk,iclass)
546 !          Check the location
547            diffr1=xred(1,iatom3)-symxred2(1)
548            diff1=diffr1-nint(diffr1)
549            if(diff1**2>tolsym2)then
550              found3=0 ; cycle
551            else
552              diffr2=xred(2,iatom3)-symxred2(2)
553              diff2=diffr2-nint(diffr2)
554              if(diff2**2>tolsym2)then
555                found3=0 ; cycle
556              else
557                diffr3=xred(3,iatom3)-symxred2(3)
558                diff3=diffr3-nint(diffr3)
559                if( (diff1**2+diff2**2+diff3**2) > tolsym**2 )then
560                  found3=0 ; cycle
561                endif
562              endif
563            endif
564 !          Check the spinat
565            if (nspden/=4) then
566              diff(:)=spinat(:,iatom3)-symspinat2(:)
567            else
568              diff(:)=spinatred(:,iatom3)-symspinat2(:)
569            end if
570            if( (diff(1)**2+diff(2)**2+diff(3)**2) > tolsym**2 )then
571              found3=0
572              cycle
573            endif  
574            ! Check the nucdipmom
575            ! hand3 gives original circulation sense of nuclear dipole
576            call acrossb(local_nucdipmom(1:3,2,iatom3),local_nucdipmom(1:3,3,iatom3),hand3)
577 
578            ! hand2 gives circulation sense of tentative, symmetry equivalent nuclear dipole
579            call acrossb(symnucdipmom2cart(1:3,2),symnucdipmom2cart(1:3,3),hand2)
580 
581            diff(:)=hand3(:)-hand2(:)
582            if( any(abs(diff)>tolsym) )found3=0
583 
584            if(found3==1)exit
585          end do ! End loop over iatom3
586 
587          if(found3==0)then
588            trialok=0
589            exit
590          end if
591        end do ! End loop over iatom2
592 
593        if(trialok==0)exit
594      end do ! End loop over all classes
595 
596 !DEBUG
597 !    write(std_out,*)' For trial isym=',isym,', trialok = ',trialok
598 !    write(std_out,*)' '
599 !ENDDEBUG
600 
601      if(trialok==1)then
602        nsym=nsym+1
603        if(nsym>msym)then
604          write(msg,'(a,i0,2a,i0,4a)')&
605          'The number of symmetries (including non-symmorphic translations) is: ', nsym, ch10,&
606          'is larger than maxnsym: ',msym,ch10,&
607          'Action: increase maxnsym in the input, or take a cell that is primitive, ',ch10,&
608          'or at least smaller than the present one.'
609         ABI_ERROR(msg)
610        end if
611        ntrial=ntrial+1
612        symrel(:,:,nsym)=ptsymrel(:,:,isym)
613        symafm(nsym)=trialafm
614        tnons(:,nsym)=trialnons(:)-nint(trialnons(:)-tolsym)
615      end if
616 
617    end do ! End the loop on tentative translations
618  end do ! End big loop over each symmetry operation of the Bravais lattice
619 
620 !DEBUG
621 !write(std_out,'(a)')' m_symfind%symfind : after big loop, will call ABI_FREE '
622 !call flush(std_out)
623 !ENDDEBUG
624 
625  ABI_FREE(class)
626  ABI_FREE(natomcl)
627  ABI_FREE(chrgat_)
628  ABI_FREE(chrgatcl)
629  ABI_FREE(spinatcl)
630  ABI_FREE(typecl)
631  ABI_FREE(local_nucdipmom)
632  ABI_FREE(nucdipmomcl)
633  ABI_FREE(nucdipmomred)
634  if (nspden==4)   then
635    ABI_FREE(spinatred)
636  end if
637 
638 !DEBUG
639 !write(std_out,'(a,i6)')' m_symfind%symfind : call sg_multable, nsym= ',nsym
640 !call flush(std_out)
641 !ENDDEBUG
642 
643 ! The algorithm in sg_multable is still cubic in nsym, so avoid calling it uselessly when nsym is too large
644  if(present(ierr) .or. nsym<=384)then
645    call sg_multable(nsym, symafm, symrel, ierr_, tnons=tnons, tnons_tol=tolsym)
646  else
647    ierr_=0
648  endif
649 
650 !DEBUG
651 !write(std_out,'(a)')' m_symfind%symfind : call print_symmetries, ierr_= ',ierr_
652 !call flush(std_out)
653 !ENDDEBUG
654 
655  if (ierr_/=0) then
656    call print_symmetries(nsym,symrel,tnons,symafm)
657  end if
658 
659  if(.not.present(ierr))then
660    ABI_CHECK(ierr_==0,"Error in group closure")
661  else
662    ierr=ierr_
663  endif
664 
665 !DEBUG
666 !  write(msg,'(a,I0,es16.6,a)')' symfind : exit, nsym, tolsym=',nsym,tolsym,ch10
667 !  write(msg,'(2a)') trim(msg),'   symrel matrices, symafm and tnons are :'
668 !  call wrtout(std_out,msg)
669 !  do isym=1,nsym
670 !    write(msg,'(i4,4x,3i4,2x,3i4,2x,3i4,4x,i4,4x,3f8.4)' ) isym,symrel(:,:,isym),&
671 ! &   symafm(isym),tnons(:,isym)
672 !    call wrtout(std_out,msg)
673 !  end do
674 !stop
675 !ENDDEBUG
676 
677 !DEBUG
678 !write(std_out,'(a)')' m_symfind%symfind : exit '
679 !call flush(std_out)
680 !ENDDEBUG
681 
682 end subroutine symfind

m_symfind/symfind_expert [ Functions ]

[ Top ] [ m_symfind ] [ Functions ]

NAME

 symfind_expert

FUNCTION

 Symmetry finder, with an added layer of robustness compared to symfind, 
 and for which resymmetrization of atomic positions and tnons is needed..
 From the symmetries of the Bravais lattice (ptsymrel),
 select those that leave invariant the system, and generate
 the corresponding tnons vectors and symafm information.
 Unlike symfind_expert, does NOT resymmetrize atomic positions and tnons for more robust determination of the symmetries.
 The algorithm is explained in T.G. Worlton and J.L. Warren, Comp. Phys. Comm. 3, 88 (1972) [[cite:Worton1972]]

INPUTS

 chrgat(natom) (optional)=target charge for each atom. Not always used, it depends on the value of constraint_kind
 invardir_red (optional)=reduced coordinates of an invariant direction (only acting with symrel - not tnons)
 invar_z (optional)= if 1, the z direction must stay invariant for all symrel applied ;
                     if 2, z must stay invariant and also there cannot be any associated tnons along z.
 gprimd(3,3)=dimensional primitive translations for reciprocal space
 msym=default maximal number of symmetries
 natom=number of atoms in cell.
 nptsym=number of point symmetries of the Bravais lattice
 nspden= number of spin-density components. When 4, the three components of spinat are taken into account, instead of only z-component.
 nucdipmom(3,natom) (optional) array of nuclear dipole moments
 ptsymrel(3,3,1:msym)= nptsym point-symmetry operations
   of the Bravais lattice in real space in terms
   of primitive translations.
 spinat(3,natom)=initial spin of each atom, in unit of hbar/2.
 tolsym=tolerance for the symmetries
 typat(natom)=integer identifying type of atom.
 usepaw= 0 for non paw calculation; =1 for paw calculation

OUTPUT

 nsym=actual number of symmetries
 symafm(1:msym)=(anti)ferromagnetic part of nsym symmetry operations
 symrel(3,3,1:msym)= nsym symmetry operations in real space in terms of primitive translations
 tnons(3,1:msym)=nonsymmorphic translations for each symmetry (would be 0 0 0 each for a symmorphic space group)

SIDE EFFECTS

 xred(3,natom)=reduced coordinates of atoms in terms of real space
   primitive translations. Might be changed during the resymmetrization.

SOURCE

731  subroutine symfind_expert(gprimd,msym,natom,nptsym,nspden,nsym,&
732 &  pawspnorb,prtvol,ptsymrel,spinat,symafm,symrel,tnons,tolsym,typat,usepaw,xred,&
733 &  chrgat,nucdipmom,invardir_red,invar_z)  ! Optional - although for the time being all are required ...
734 
735 !Arguments ------------------------------------
736 !scalars
737  integer,intent(in) :: msym,natom,nptsym,nspden,pawspnorb,usepaw
738  integer,intent(in) :: prtvol
739  integer,optional,intent(in) :: invar_z
740  integer,intent(out) :: nsym
741  real(dp),intent(in) :: tolsym
742 !arrays
743  integer,intent(in) :: ptsymrel(3,3,msym),typat(natom)
744  integer,intent(inout) :: symafm(msym),symrel(3,3,msym) !vz_i
745  real(dp),intent(in) :: gprimd(3,3),spinat(3,natom)
746  real(dp),intent(inout) :: xred(3,natom)
747  real(dp),optional,intent(in) :: invardir_red(3),chrgat(natom)
748  real(dp),optional, intent(in) :: nucdipmom(3,natom)
749  real(dp),intent(inout) :: tnons(3,msym) !vz_i
750 
751 !Local variables-------------------------------
752 !scalars
753  integer, save :: print_comment_tolsym=1
754  integer :: fixed_mismatch,mismatch_fft_tnons
755  integer :: ierr,isym,use_inversion
756  character(len=1000) :: msg
757 !arrays
758  integer,allocatable :: indsym(:,:,:),symrec(:,:,:) 
759  real(dp),allocatable :: tnons_new(:,:)
760  
761 
762 !**************************************************************************
763 
764 !DEBUG
765 ! write(std_out,*)' m_symfind%symfind_expert : enter '
766 !ENDDEBUG
767 
768   use_inversion=1
769   if (usepaw == 1 .and. (nspden==4.or.pawspnorb>0)) then
770     ABI_COMMENT("Removing inversion and improper rotations from initial space group because of PAW + SOC")
771     use_inversion=0
772   end if
773 
774 !DEBUG
775 ! write(std_out,*)' m_symfind%symfind_expert : before call symfind (1) '
776 !ENDDEBUG
777 
778   call symfind(gprimd,msym,natom,nptsym,nspden,nsym,&
779     prtvol,ptsymrel,spinat,symafm,symrel,tnons,tolsym,typat,use_inversion,xred,&
780     chrgat=chrgat,nucdipmom=nucdipmom,ierr=ierr,invardir_red=invardir_red,invar_z=invar_z)
781 
782 !DEBUG
783 ! write(std_out,*)' m_symfind%symfind_expert : after call symfind (1) '
784 !ENDDEBUG
785 
786   !If the group closure is not obtained, which should be exceptional, try with a larger tolsym (three times larger)
787   if(ierr/=0)then
788     ABI_WARNING('Will try to obtain group closure by using a tripled tolsym.')
789     call symfind(gprimd,msym,natom,nptsym,nspden,nsym,&
790       prtvol,ptsymrel,spinat,symafm,symrel,tnons,three*tolsym,typat,use_inversion,xred,&
791       chrgat=chrgat,nucdipmom=nucdipmom,ierr=ierr,invardir_red=invardir_red,invar_z=invar_z)
792     ABI_CHECK(ierr==0,"Error in group closure")
793     ABI_WARNING('Succeeded to obtain group closure by using a tripled tolsym.')
794   endif
795 
796   ! If the tolerance on symmetries is bigger than 1.e-8, symmetrize tnons for gliding or screw operations,
797   ! symmetrize the atomic positions and recompute the symmetry operations
798   if(tolsym>1.00001e-8)then
799 
800     call symmetrize_tnons(nsym,symrel,tnons,tolsym)
801     ABI_MALLOC(indsym,(4,natom,nsym))
802     ABI_MALLOC(symrec,(3,3,nsym))
803     do isym=1,nsym
804       call mati3inv(symrel(:,:,isym),symrec(:,:,isym))
805     end do
806     call symatm(indsym,natom,nsym,symrec,tnons,tolsym,typat,xred)
807     call symmetrize_xred(natom,nsym,symrel,tnons,xred,indsym=indsym)
808     ABI_FREE(indsym)
809     ABI_FREE(symrec)
810 
811     if(print_comment_tolsym==1)then
812       write(msg,'(a,es12.3,18a)')&
813 &      'The tolerance on symmetries =',tolsym,' is bigger than 1.0e-8.',ch10,&
814 &      'In order to avoid spurious effects, the atomic coordinates have been',ch10,&
815 &      'symmetrized before storing them in the dataset internal variable.',ch10,&
816 &      'So, do not be surprised by the fact that your input variables (xcart, xred, ...)',ch10,&
817 &      'do not correspond exactly to the ones echoed by ABINIT, the latter being used to do the calculations.',ch10,&
818 &      'This is not a problem per se.',ch10,&
819 &      'Still, in order to avoid this symmetrization (e.g. for specific debugging/development),',&
820 &      ' decrease tolsym to 1.0e-8 or lower,',ch10,&
821 &      'or (much preferred) use input primitive vectors that are accurate to better than 1.0e-8.',ch10,&
822 &      'This message will only be printed once, even if there are other datasets where tolsym is bigger than 1.0e-8.'
823       ABI_COMMENT(msg)
824       print_comment_tolsym=0
825     endif
826 
827 !DEBUG
828 !write(std_out,*)' m_symfind%symfind_expert : before call symfind (3) '
829 !ENDDEBUG
830 
831     call symfind(gprimd,msym,natom,nptsym,nspden,nsym,&
832       prtvol,ptsymrel,spinat,symafm,symrel,tnons,tolsym,typat,use_inversion,xred,&
833       chrgat=chrgat,nucdipmom=nucdipmom,invardir_red=invardir_red,invar_z=invar_z)
834 
835 !DEBUG
836 ! write(std_out,*)' m_symfind%symfind_expert : after call symfind (3) '
837 !ENDDEBUG
838 
839     !Needs one more resymmetrization, for the tnons
840     ABI_MALLOC(tnons_new,(3,nsym))
841 
842     call symmetrize_xred(natom,nsym,symrel,tnons,xred,&
843 &     fixed_mismatch=fixed_mismatch,mismatch_fft_tnons=mismatch_fft_tnons,tnons_new=tnons_new,tolsym=tolsym)
844     tnons(:,1:nsym)=tnons_new(:,:)
845     ABI_FREE(tnons_new)
846   end if ! tolsym >1.00001e-8
847 
848 !DEBUG
849 ! write(std_out,*)' m_symfind%symfind_expert : exit '
850 !ENDDEBUG
851 
852 end subroutine symfind_expert

m_symfind/symlatt [ Functions ]

[ Top ] [ m_symfind ] [ Functions ]

NAME

 symlatt

FUNCTION

 From the unit cell vectors (rprimd) and the corresponding metric tensor,
 find the Bravais lattice and its symmetry operations (ptsymrel).
 1) Find the shortest possible primitive vectors for the lattice
 2) Determines the holohedral group of the lattice, and the
    axes to be used for the conventional cell
    (this is a delicate part, in which the centering of the
    reduced cell must be taken into account)
    The idea is to determine the basis vectors of the conventional
    cell from the reduced cell basis vectors.
 3) Generate the symmetry operations of the holohedral group

INPUTS

 iout=unit number of output file
 msym=default maximal number of symmetries. WARNING : cannot be simply set to nsym, because
   the number of symmetries found here will likely be bigger than sym !
 rprimd(3,3)=dimensional primitive translations for real space (bohr)
 tolsym=tolerance for the symmetries

OUTPUT

  bravais(11): bravais(1)=iholohedry
               bravais(2)=center
               bravais(3:11)=coordinates of rprim in the axes
               of the conventional bravais lattice (*2 if center/=0)
 nptsym=number of point symmetries of the Bravais lattice
 ptsymrel(3,3,1:msym)= nptsym point-symmetry operations
 of the Bravais lattice in real space in terms of primitive translations.

NOTES

 WARNING: bravais(1) might be given a negative value in another
 routine, if the cell is non-primitive.
 The holohedral groups are numbered as follows
 (see international tables for crystallography (1983), p. 13)
 iholohedry=1   triclinic      1bar
 iholohedry=2   monoclinic     2/m
 iholohedry=3   orthorhombic   mmm
 iholohedry=4   tetragonal     4/mmm
 iholohedry=5   trigonal       3bar m
 iholohedry=6   hexagonal      6/mmm
 iholohedry=7   cubic          m3bar m
 Centering
 center=0        no centering
 center=-1       body-centered
 center=-3       face-centered
 center=1        A-face centered
 center=2        B-face centered
 center=3        C-face centered

SOURCE

1920 subroutine symlatt(bravais,iout,msym,nptsym,ptsymrel,rprimd,tolsym)
1921 
1922 !Arguments ------------------------------------
1923 !scalars
1924  integer,intent(in) :: iout,msym
1925  integer,intent(out) :: nptsym
1926  real(dp),intent(in) :: tolsym
1927 !arrays
1928  integer,intent(out) :: bravais(11),ptsymrel(3,3,msym)
1929  real(dp),intent(in) :: rprimd(3,3)
1930 
1931 !Local variables-------------------------------
1932 !scalars
1933  integer,parameter :: mgen=4
1934  integer :: center,fact,found,foundc,ia,iaxis1,iaxis2
1935  integer :: isign1,isign2,ib,icase,igen,iholohedry,ii,index,isym
1936  integer :: itrial,jj,jsym,ngen=0,orthogonal,sign12,sign13,sign23,sumsign
1937  real(dp) :: determinant,norm2a,norm2b,norm2c,norm2trial,reduceda,reducedb,sca
1938  real(dp) :: scalarprod,scb,trace,trace_best,val
1939  character(len=500) :: msg
1940 !arrays
1941  integer,parameter :: list_holo(7)=(/7,6,4,3,5,2,1/)
1942  integer :: ang90(3),equal(3),gen(3,3,mgen),gen2xy(3,3),gen2y(3,3),gen2z(3,3)
1943  integer :: gen3(3,3),gen6(3,3),icoord(3,3),identity(3,3),nvecta(3),nvectb(3)
1944  integer :: order(mgen)
1945  real(dp) :: axes(3,3),axesinvt(3,3),axes_best(3,3),axes_try(3,3)
1946  real(dp) :: cell_base(3,3),coord(3,3),metmin(3,3)
1947  real(dp) :: minim(3,3),scprods(3,3),vecta(3),vectb(3),vectc(3),vin1(3),vin2(3),vext(3)
1948 
1949 !**************************************************************************
1950 
1951 !DEBUG
1952 !write(std_out,'(a,es14.6)') ' m_symfind%symlatt : enter, tolsym= ',tolsym
1953 !call flush(std_out)
1954 !ENDDEBUG
1955 
1956  identity(:,:)=0 ; identity(1,1)=1 ; identity(2,2)=1 ; identity(3,3)=1
1957  nvecta(1)=2 ; nvectb(1)=3
1958  nvecta(2)=1 ; nvectb(2)=3
1959  nvecta(3)=1 ; nvectb(3)=2
1960 
1961 !--------------------------------------------------------------------------
1962 !Reduce the input vectors to a set of minimal vectors
1963  call smallprim(metmin,minim,rprimd)
1964 
1965 !DEBUG
1966 !write(std_out,*)' symlatt : minim(:,1)=',minim(:,1)
1967 !write(std_out,*)' symlatt : minim(:,2)=',minim(:,2)
1968 !write(std_out,*)' symlatt : minim(:,3)=',minim(:,3)
1969 !call flush(std_out)
1970 !ENDDEBUG
1971 
1972 !--------------------------------------------------------------------------
1973 !Examine the angles and vector lengths
1974  ang90(:)=0
1975  if(metmin(1,2)**2<tolsym**2*metmin(1,1)*metmin(2,2))ang90(3)=1
1976  if(metmin(1,3)**2<tolsym**2*metmin(1,1)*metmin(3,3))ang90(2)=1
1977  if(metmin(2,3)**2<tolsym**2*metmin(2,2)*metmin(3,3))ang90(1)=1
1978  equal(:)=0
1979  if(abs(metmin(1,1)-metmin(2,2))<tolsym*half*(metmin(1,1)+metmin(2,2)))equal(3)=1
1980  if(abs(metmin(1,1)-metmin(3,3))<tolsym*half*(metmin(1,1)+metmin(3,3)))equal(2)=1
1981  if(abs(metmin(2,2)-metmin(3,3))<tolsym*half*(metmin(2,2)+metmin(3,3)))equal(1)=1
1982 
1983 !DEBUG
1984 !write(std_out,*)' ang90=',ang90(:)
1985 !write(std_out,*)' equal=',equal(:)
1986 !call flush(std_out)
1987 !ENDDEBUG
1988 
1989 !-----------------------------------------------------------------------
1990 !Identification of the centering
1991 
1992  foundc=0
1993 !Default values
1994  fact=1 ; center=0
1995  cell_base(:,:)=minim(:,:)
1996 
1997 !Examine each holohedral group
1998 !This search is ordered : should not be happy with tetragonal,
1999 !while there is FCC ...
2000  do index=1,6
2001 
2002 !  If the holohedry is already found, exit
2003    if(foundc==1)exit
2004 
2005 !  Initialize the target holohedry
2006    iholohedry=list_holo(index)
2007 
2008 !  DEBUG
2009 !  write(std_out,*)
2010 !  write(std_out,*)' symlatt : trial holohedry',iholohedry
2011 !  ENDDEBUG
2012 
2013    orthogonal=0
2014    if(iholohedry==7 .or. iholohedry==4 .or. iholohedry==3)orthogonal=1
2015 
2016 !  Now, will examine different working hypothesis.
2017 !  The set of these hypothesis is thought to cover all possible cases ...
2018 
2019 !  Working hypothesis : the basis is orthogonal
2020    if(ang90(1)+ang90(2)+ang90(3)==3 .and. orthogonal==1)then
2021      fact=1 ; center=0
2022      cell_base(:,:)=minim(:,:)
2023 !    Checks that the basis vectors are OK for the target holohedry
2024      call holocell(cell_base,0,foundc,iholohedry,tolsym)
2025    end if
2026 
2027 !  Select one trial direction
2028    do itrial=1,3
2029 
2030 !    If the holohedry is already found, exit
2031      if(foundc==1)exit
2032 
2033      ia=nvecta(itrial) ; ib=nvectb(itrial)
2034 
2035 !    This is in case of hexagonal holohedry
2036      if(foundc==0 .and. iholohedry==6 .and. ang90(ia)==1 .and. ang90(ib)==1 .and. equal(itrial)==1 )then
2037        reduceda=metmin(ib,ia)/metmin(ia,ia)
2038        fact=1 ; center=0
2039        if(abs(reduceda+0.5d0)<tolsym)then
2040          cell_base(:,1)=minim(:,ia)
2041          cell_base(:,2)=minim(:,ib)
2042          cell_base(:,3)=minim(:,itrial)
2043 !DEBUG
2044 !      write(std_out,*)' cell_base(:,1)=',cell_base(:,1)
2045 !      write(std_out,*)' cell_base(:,2)=',cell_base(:,2)
2046 !      write(std_out,*)' cell_base(:,3)=',cell_base(:,3)
2047 !ENDDEBUG
2048 !        Checks that the basis vectors are OK for the target holohedry
2049          call holocell(cell_base,0,foundc,iholohedry,tolsym)
2050        else if(abs(reduceda-0.5d0)<tolsym)then
2051          cell_base(:,1)=minim(:,ia)
2052          cell_base(:,2)=minim(:,ib)-minim(:,ia)
2053          cell_base(:,3)=minim(:,itrial)
2054 !        Checks that the basis vectors are OK for the target holohedry
2055          call holocell(cell_base,0,foundc,iholohedry,tolsym)
2056        end if
2057      end if
2058 
2059 !    Working hypothesis : the conventional cell is orthogonal,
2060 !    and the two other vectors are axes of the conventional cell
2061      if(foundc==0 .and. orthogonal==1 .and. ang90(itrial)==1)then
2062 
2063 !      Compute the reduced coordinate of trial vector in the basis
2064 !      of the two other vectors
2065        reduceda=metmin(itrial,ia)/metmin(ia,ia)
2066        reducedb=metmin(itrial,ib)/metmin(ib,ib)
2067        cell_base(:,ia)=minim(:,ia)
2068        cell_base(:,ib)=minim(:,ib)
2069        if( (abs(abs(reduceda)-0.5d0)<tolsym .and. abs(reducedb)<tolsym ) .or. &
2070 &       ( abs(reduceda)<tolsym .and. abs(abs(reducedb)-0.5d0)<tolsym)       )then
2071          if(abs(abs(reduceda)-0.5d0)<tolsym)center=ib
2072          if(abs(abs(reducedb)-0.5d0)<tolsym)center=ia
2073          fact=2
2074          cell_base(:,itrial)= &
2075 &         (minim(:,itrial)-reduceda*minim(:,ia)-reducedb*minim(:,ib) )*2.0d0
2076          call holocell(cell_base,0,foundc,iholohedry,tolsym)
2077        else if( abs(abs(reduceda)-0.5d0)<tolsym .and.&
2078 &         abs(abs(reducedb)-0.5d0)<tolsym       ) then
2079          fact=2 ; center=-1
2080          cell_base(:,itrial)= &
2081 &         (minim(:,itrial)-reduceda*minim(:,ia)-reducedb*minim(:,ib) )*2.0d0
2082          call holocell(cell_base,0,foundc,iholohedry,tolsym)
2083        end if
2084      end if
2085 
2086 !    Working hypothesis : the conventional cell is orthogonal, and
2087 !    the trial vector is one of the future axes, and the face perpendicular to it is centered
2088      if(foundc==0 .and. iholohedry==3 .and. &
2089 &     ang90(ia)==1 .and. ang90(ib)==1 .and. equal(itrial)==1 )then
2090        fact=2 ; center=itrial
2091        cell_base(:,ia)=minim(:,ia)+minim(:,ib)
2092        cell_base(:,ib)=minim(:,ia)-minim(:,ib)
2093        cell_base(:,itrial)=minim(:,itrial)
2094 !      Checks that the basis vectors are OK for the target holohedry
2095        call holocell(cell_base,0,foundc,iholohedry,tolsym)
2096      end if
2097 
2098 !    DEBUG
2099 !    write(std_out,*)' after test_b, foundc=',foundc
2100 !    ENDDEBUG
2101 
2102 !    Working hypothesis : the conventional cell is orthogonal, and
2103 !    the trial vector is one of the future axes
2104      if(foundc==0 .and. orthogonal==1)then
2105 !      Compute the projection of the two other vectors on the trial vector
2106        reduceda=metmin(itrial,ia)/metmin(itrial,itrial)
2107        reducedb=metmin(itrial,ib)/metmin(itrial,itrial)
2108 !      If both projections are half-integer, one might have found an axis
2109        if( abs(abs(reduceda)-0.5d0)<tolsym .and.&
2110 &       abs(abs(reducedb)-0.5d0)<tolsym       ) then
2111          vecta(:)=minim(:,ia)-reduceda*minim(:,itrial)
2112          vectb(:)=minim(:,ib)-reducedb*minim(:,itrial)
2113          norm2a=vecta(1)**2+vecta(2)**2+vecta(3)**2
2114          norm2b=vectb(1)**2+vectb(2)**2+vectb(3)**2
2115          scalarprod=vecta(1)*vectb(1)+vecta(2)*vectb(2)+vecta(3)*vectb(3)
2116 !        Note the order of selection : body-centered is prefered
2117 !        over face centered, which is correct for the tetragonal case
2118          if(abs(norm2a-norm2b)<tolsym*half*(norm2a+norm2b))then
2119 !          The lattice is body centered
2120            fact=2 ; center=-1
2121            cell_base(:,ia)=vecta(:)+vectb(:)
2122            cell_base(:,ib)=vecta(:)-vectb(:)
2123            cell_base(:,itrial)=minim(:,itrial)
2124            call holocell(cell_base,0,foundc,iholohedry,tolsym)
2125          else if(abs(scalarprod)<tolsym*half*(norm2a+norm2b))then
2126 !          The lattice is face centered
2127            fact=2 ; center=-3
2128            cell_base(:,ia)=2.0d0*vecta(:)
2129            cell_base(:,ib)=2.0d0*vectb(:)
2130            cell_base(:,itrial)=minim(:,itrial)
2131            call holocell(cell_base,0,foundc,iholohedry,tolsym)
2132          end if
2133        end if
2134      end if
2135 
2136 !    DEBUG
2137 !    write(std_out,*)' after test_c, foundc=',foundc
2138 !    ENDDEBUG
2139 
2140 !    Working hypothesis : the conventional cell is orthogonal,
2141 !    and body centered with no basis vector being an axis,
2142 !    in which case the basis vectors must be equal (even for orthorhombic)
2143      if(foundc==0 .and. orthogonal==1 .and. &
2144 &     equal(1)==1 .and. equal(2)==1 .and. equal(3)==1 )then
2145 !      Compute the combination of the two other vectors
2146        vecta(:)=minim(:,ia)+minim(:,ib)
2147        vectb(:)=minim(:,ia)-minim(:,ib)
2148        norm2a=vecta(1)**2+vecta(2)**2+vecta(3)**2
2149        norm2b=vectb(1)**2+vectb(2)**2+vectb(3)**2
2150 !      Project the trial vector on the first of the two vectors
2151        reduceda=( minim(1,itrial)*vecta(1)+       &
2152 &       minim(2,itrial)*vecta(2)+       &
2153 &       minim(3,itrial)*vecta(3) )/norm2a
2154        reducedb=( minim(1,itrial)*vectb(1)+       &
2155 &       minim(2,itrial)*vectb(2)+       &
2156 &       minim(3,itrial)*vectb(3) )/norm2b
2157        if( abs(abs(reduceda)-0.5d0)<tolsym )then
2158 !        The first vector is an axis
2159          fact=2 ; center=-1
2160          cell_base(:,ia)=vecta(:)
2161          vecta(:)=minim(:,itrial)-reduceda*vecta(:)
2162          vectb(:)=0.5d0*vectb(:)
2163          cell_base(:,ib)=vecta(:)+vectb(:)
2164          cell_base(:,itrial)=vecta(:)-vectb(:)
2165          call holocell(cell_base,0,foundc,iholohedry,tolsym)
2166        else if( abs(abs(reducedb)-0.5d0)<tolsym )then
2167 !        The second vector is an axis
2168          fact=2 ; center=-1
2169          cell_base(:,ib)=vectb(:)
2170          vectb(:)=minim(:,itrial)-reducedb*vectb(:)
2171          vecta(:)=0.5d0*vecta(:)
2172          cell_base(:,ia)=vectb(:)+vecta(:)
2173          cell_base(:,itrial)=vectb(:)-vecta(:)
2174          call holocell(cell_base,0,foundc,iholohedry,tolsym)
2175        end if
2176      end if
2177 
2178 !    Working hypothesis : the conventional cell is orthogonal,
2179 !    and face centered, in the case where two minimal vectors are equal
2180      if(foundc==0 .and. orthogonal==1 .and. equal(itrial)==1 ) then
2181 !      Compute the combination of these two vectors
2182        vecta(:)=minim(:,ia)+minim(:,ib)
2183        vectb(:)=minim(:,ia)-minim(:,ib)
2184        norm2a=vecta(1)**2+vecta(2)**2+vecta(3)**2
2185        norm2b=vectb(1)**2+vectb(2)**2+vectb(3)**2
2186 !      Project the trial vector on the two vectors
2187        reduceda=( minim(1,itrial)*vecta(1)+       &
2188 &       minim(2,itrial)*vecta(2)+       &
2189 &       minim(3,itrial)*vecta(3) )/norm2a
2190        reducedb=( minim(1,itrial)*vectb(1)+       &
2191 &       minim(2,itrial)*vectb(2)+       &
2192 &       minim(3,itrial)*vectb(3) )/norm2b
2193        if( (abs(abs(reduceda)-0.5d0)<tolsym .and. abs(reducedb)<tolsym ) .or. &
2194 &       ( abs(reduceda)<tolsym .and. abs(abs(reducedb)-0.5d0)<tolsym)       )then
2195          fact=2 ; center=-3
2196          cell_base(:,itrial)= &
2197 &         (minim(:,itrial)-reduceda*vecta(:)-reducedb*vectb(:) )*2.0d0
2198          cell_base(:,ia)=vecta(:)
2199          cell_base(:,ib)=vectb(:)
2200          call holocell(cell_base,0,foundc,iholohedry,tolsym)
2201        end if
2202      end if
2203 
2204 !    Working hypothesis : the conventional cell is orthogonal,
2205 !    face centered, but no two vectors are on the same "square"
2206      if(foundc==0 .and. orthogonal==1)then
2207 !      Compute the combination of these two vectors
2208        vecta(:)=minim(:,ia)+minim(:,ib)
2209        vectb(:)=minim(:,ia)-minim(:,ib)
2210        norm2a=vecta(1)**2+vecta(2)**2+vecta(3)**2
2211        norm2b=vectb(1)**2+vectb(2)**2+vectb(3)**2
2212 !      The trial vector length must be equal to one of these lengths
2213        if(abs(metmin(itrial,itrial)-norm2a)<tolsym*norm2a)then
2214          fact=2 ; center=-3
2215          cell_base(:,ia)=vecta(:)+minim(:,itrial)
2216          cell_base(:,ib)=vecta(:)-minim(:,itrial)
2217 !        Project vectb perpendicular to cell_base(:,ia) and cell_base(:,ib)
2218          norm2a=cell_base(1,ia)**2+cell_base(2,ia)**2+cell_base(3,ia)**2
2219          norm2b=cell_base(1,ib)**2+cell_base(2,ib)**2+cell_base(3,ib)**2
2220          reduceda=( cell_base(1,ia)*vectb(1)+       &
2221 &         cell_base(2,ia)*vectb(2)+       &
2222 &         cell_base(3,ia)*vectb(3) )/norm2a
2223          reducedb=( cell_base(1,ib)*vectb(1)+       &
2224 &         cell_base(2,ib)*vectb(2)+       &
2225 &         cell_base(3,ib)*vectb(3) )/norm2b
2226          if( abs(abs(reduceda)-0.5d0)<tolsym .and.         &
2227 &         abs(abs(reducedb)-0.5d0)<tolsym      )then
2228            cell_base(:,itrial)=vectb(:)-reduceda*cell_base(:,ia)-reducedb*cell_base(:,ib)
2229            call holocell(cell_base,0,foundc,iholohedry,tolsym)
2230          end if
2231        else if(abs(metmin(itrial,itrial)-norm2b)<tolsym*norm2b)then
2232          fact=2 ; center=-3
2233          cell_base(:,ia)=vectb(:)+minim(:,itrial)
2234          cell_base(:,ib)=vectb(:)-minim(:,itrial)
2235 !        Project vecta perpendicular to cell_base(:,ia) and cell_base(:,ib)
2236          norm2a=cell_base(1,ia)**2+cell_base(2,ia)**2+cell_base(3,ia)**2
2237          norm2b=cell_base(1,ib)**2+cell_base(2,ib)**2+cell_base(3,ib)**2
2238          reduceda=( cell_base(1,ia)*vecta(1)+       &
2239 &         cell_base(2,ia)*vecta(2)+       &
2240 &         cell_base(3,ia)*vecta(3) )/norm2a
2241          reducedb=( cell_base(1,ib)*vecta(1)+       &
2242 &         cell_base(2,ib)*vecta(2)+       &
2243 &         cell_base(3,ib)*vecta(3) )/norm2b
2244          if( abs(abs(reduceda)-0.5d0)<tolsym .and.         &
2245 &         abs(abs(reducedb)-0.5d0)<tolsym      )then
2246            cell_base(:,itrial)=vecta(:)-reduceda*cell_base(:,ia)-reducedb*cell_base(:,ib)
2247            call holocell(cell_base,0,foundc,iholohedry,tolsym)
2248          end if
2249        end if
2250      end if
2251 
2252 !    Working hypothesis : the cell is rhombohedral, and
2253 !    the three minimal vectors have same length and same absolute scalar product
2254      if(foundc==0 .and. iholohedry==5 .and. &
2255 &     equal(1)==1 .and. equal(2)==1 .and. equal(3)==1 )then
2256        if( abs(abs(metmin(1,2))-abs(metmin(1,3)))<tolsym*metmin(1,1) .and.     &
2257 &       abs(abs(metmin(1,2))-abs(metmin(2,3)))<tolsym*metmin(2,2)      )then
2258          fact=1 ; center=0
2259          cell_base(:,:)=minim(:,:)
2260 !        One might have to change the sign of one of the vectors
2261          sign12=1 ; sign13=1 ; sign23=1
2262          if(metmin(1,2)<0.0d0)sign12=-1
2263          if(metmin(1,3)<0.0d0)sign13=-1
2264          if(metmin(2,3)<0.0d0)sign23=-1
2265          sumsign=sign12+sign13+sign23
2266          if(sumsign==-1)then
2267            if(sign12==1)cell_base(:,3)=-cell_base(:,3)
2268            if(sign13==1)cell_base(:,2)=-cell_base(:,2)
2269            if(sign23==1)cell_base(:,1)=-cell_base(:,1)
2270          else if(sumsign==1)then
2271            if(sign12==-1)cell_base(:,3)=-cell_base(:,3)
2272            if(sign13==-1)cell_base(:,2)=-cell_base(:,2)
2273            if(sign23==-1)cell_base(:,1)=-cell_base(:,1)
2274          end if
2275          call holocell(cell_base,0,foundc,iholohedry,tolsym)
2276        end if
2277      end if
2278 
2279 !    DEBUG
2280 !    write(std_out,*)' after test_3a, foundc=',foundc
2281 !    write(std_out,*)' after test_3a, itrial=',itrial
2282 !    write(std_out,*)' after test_3a, equal(:)=',equal(:)
2283 !    ENDDEBUG
2284 
2285 !    Working hypothesis : the cell is rhombohedral, one vector
2286 !    is parallel to the trigonal axis
2287      if(foundc==0 .and. iholohedry==5 .and. equal(itrial)==1 )then
2288        vecta(:)=minim(:,ia) ; vectb(:)=minim(:,ib)
2289        norm2trial=minim(1,itrial)**2+minim(2,itrial)**2+minim(3,itrial)**2
2290        reduceda=( minim(1,itrial)*vecta(1)+       &
2291 &       minim(2,itrial)*vecta(2)+       &
2292 &       minim(3,itrial)*vecta(3) )/norm2trial
2293        reducedb=( minim(1,itrial)*vectb(1)+       &
2294 &       minim(2,itrial)*vectb(2)+       &
2295 &       minim(3,itrial)*vectb(3) )/norm2trial
2296 !      DEBUG
2297 !      write(std_out,*)' reduceda,reducedb=',reduceda,reducedb
2298 !      ENDDEBUG
2299        if(abs(abs(reduceda)-1.0d0/3.0d0)<tolsym .and.      &
2300 &       abs(abs(reducedb)-1.0d0/3.0d0)<tolsym      ) then
2301 !        Possibly change of sign to make positive the scalar product with
2302 !        the vector parallel to the trigonal axis
2303          if(reduceda<zero)vecta(:)=-vecta(:)
2304          if(reducedb<zero)vectb(:)=-vectb(:)
2305 !        Projection on the orthogonal plane
2306          vecta(:)=vecta(:)-abs(reduceda)*cell_base(:,itrial)
2307          vectb(:)=vectb(:)-abs(reducedb)*cell_base(:,itrial)
2308 !        These two vectors should have an angle of 120 degrees
2309          norm2a=vecta(1)**2+vecta(2)**2+vecta(3)**2
2310          scalarprod=vecta(1)*vectb(1)+vecta(2)*vectb(2)+vecta(3)*vectb(3)
2311 !        DEBUG
2312 !        write(std_out,*)' norm2a,scalarprod=',norm2a,scalarprod
2313 !        ENDDEBUG
2314          if(abs(two*scalarprod+norm2a)<tolsym*norm2a)then
2315            fact=1 ; center=0
2316            if(scalarprod>0.0d0)vectb(:)=-vectb(:)
2317 !          Now vecta and vectb have an angle of 120 degrees
2318            cell_base(:,1)=cell_base(:,itrial)/3.0d0+vecta(:)
2319            cell_base(:,2)=cell_base(:,itrial)/3.0d0+vectb(:)
2320            cell_base(:,3)=cell_base(:,itrial)/3.0d0-vecta(:)-vectb(:)
2321 !          DEBUG
2322 !          write(std_out,*)' cell_base(:,1)=',cell_base(:,1)
2323 !          write(std_out,*)' cell_base(:,2)=',cell_base(:,2)
2324 !          write(std_out,*)' cell_base(:,3)=',cell_base(:,3)
2325 !          ENDDEBUG
2326            call holocell(cell_base,0,foundc,iholohedry,tolsym)
2327          end if
2328        end if
2329      end if
2330 
2331 !    Working hypothesis : the cell is rhombohedral, one vector
2332 !    is in the plane perpendicular to the trigonal axis
2333      if(foundc==0 .and. iholohedry==5 .and. equal(itrial)==1 ) then
2334        vecta(:)=minim(:,ia)+minim(:,ib)
2335        vectb(:)=minim(:,ia)-minim(:,ib)
2336        norm2trial=cell_base(1,itrial)**2+cell_base(2,itrial)**2+cell_base(3,itrial)**2
2337        norm2a=vecta(1)**2+vecta(2)**2+vecta(3)**2
2338        norm2b=vecta(1)**2+vecta(2)**2+vecta(3)**2
2339        reduceda=( cell_base(1,itrial)*vecta(1)+       &
2340 &       cell_base(2,itrial)*vecta(2)+       &
2341 &       cell_base(3,itrial)*vecta(3) )/norm2trial
2342        reducedb=( cell_base(1,itrial)*vectb(1)+       &
2343 &       cell_base(2,itrial)*vectb(2)+       &
2344 &       cell_base(3,itrial)*vectb(3) )/norm2trial
2345        if(abs(norm2trial-norm2a)<tolsym*norm2a .and. &
2346 &       abs(abs(2*reduceda)-norm2trial)<tolsym*norm2trial    )then
2347          fact=1 ; center=0
2348          cell_base(:,1)=minim(:,ia)
2349          cell_base(:,2)=-minim(:,ib)
2350          cell_base(:,3)=-minim(:,ib)+2*reduceda*minim(:,itrial)
2351          call holocell(cell_base,0,foundc,iholohedry,tolsym)
2352        else if (abs(norm2trial-norm2b)<tolsym*norm2b .and. &
2353 &         abs(abs(2*reducedb)-norm2trial)<tolsym*norm2trial    )then
2354          fact=1 ; center=0
2355          cell_base(:,1)=minim(:,ia)
2356          cell_base(:,2)=minim(:,ib)
2357          cell_base(:,3)=minim(:,ib)+2*reducedb*minim(:,itrial)
2358          call holocell(cell_base,0,foundc,iholohedry,tolsym)
2359        end if
2360      end if
2361 
2362 !    Working hypothesis : the cell is rhombohedral, two vectors
2363 !    are in the plane perpendicular to the trigonal axis
2364      if(foundc==0 .and. iholohedry==5 .and. equal(itrial)==1 ) then
2365        vecta(:)=minim(:,ia) ; vectb(:)=minim(:,ib)
2366        norm2a=vecta(1)**2+vecta(2)**2+vecta(3)**2
2367        norm2b=vectb(1)**2+vectb(2)**2+vectb(3)**2
2368        scalarprod=vecta(1)*vectb(1)+vecta(2)*vectb(2)+vecta(3)*vectb(3)
2369        if(abs(abs(2*scalarprod)-norm2a)<tolsym*norm2a)then
2370 !        This is in order to have 120 angle between vecta and vectb
2371          if(scalarprod>0.0d0)vectb(:)=-vectb(:)
2372          reduceda=( cell_base(1,itrial)*vecta(1)+        &
2373 &         cell_base(2,itrial)*vecta(2)+        &
2374 &         cell_base(3,itrial)*vecta(3) )/norm2a
2375          reducedb=( cell_base(1,itrial)*vectb(1)+        &
2376 &         cell_base(2,itrial)*vectb(2)+        &
2377 &         cell_base(3,itrial)*vectb(3) )/norm2b
2378          fact=1 ; center=0
2379          cell_base(:,1)=minim(:,itrial)
2380          if(abs(reduceda-0.5d0)<tolsym .and. abs(reducedb)<tolsym )then
2381            cell_base(:,2)=minim(:,itrial)-vecta(:)
2382            cell_base(:,3)=minim(:,itrial)-vecta(:)-vectb(:)
2383            call holocell(cell_base,0,foundc,iholohedry,tolsym)
2384          else if(abs(reduceda-0.5d0)<tolsym.and. abs(reducedb+0.5d0)<tolsym )then
2385            cell_base(:,2)=minim(:,itrial)-vecta(:)
2386            cell_base(:,3)=minim(:,itrial)+vectb(:)
2387            call holocell(cell_base,0,foundc,iholohedry,tolsym)
2388          else if(abs(reduceda)<tolsym .and. abs(reducedb+0.5d0)<tolsym )then
2389            cell_base(:,2)=minim(:,itrial)+vectb(:)
2390            cell_base(:,3)=minim(:,itrial)+vecta(:)+vectb(:)
2391            call holocell(cell_base,0,foundc,iholohedry,tolsym)
2392          else if(abs(reduceda+0.5d0)<tolsym .and. abs(reducedb)<tolsym)then
2393            cell_base(:,2)=minim(:,itrial)+vecta(:)
2394            cell_base(:,3)=minim(:,itrial)+vecta(:)+vectb(:)
2395            call holocell(cell_base,0,foundc,iholohedry,tolsym)
2396          else if(abs(reduceda+0.5d0)<tolsym .and. abs(reducedb-0.5d0)<tolsym)then
2397            cell_base(:,2)=minim(:,itrial)+vecta(:)
2398            cell_base(:,3)=minim(:,itrial)-vectb(:)
2399            call holocell(cell_base,0,foundc,iholohedry,tolsym)
2400          else if(abs(reduceda)<tolsym .and. abs(reducedb-0.5d0)<tolsym )then
2401            cell_base(:,2)=minim(:,itrial)-vectb(:)
2402            cell_base(:,3)=minim(:,itrial)-vecta(:)-vectb(:)
2403            call holocell(cell_base,0,foundc,iholohedry,tolsym)
2404          end if
2405        end if
2406      end if
2407 
2408 !    Working hypothesis : monoclinic holohedry, primitive. Then, two angles are 90 degrees
2409      if(foundc==0 .and. iholohedry==2 .and. &
2410 &     ang90(ia)==1 .and. ang90(ib)==1 ) then
2411        fact=1 ; center=0
2412        cell_base(:,1)=minim(:,ia)
2413        cell_base(:,2)=minim(:,itrial)
2414        cell_base(:,3)=minim(:,ib)
2415 !      Checks that the basis vectors are OK for the target holohedry
2416        call holocell(cell_base,0,foundc,iholohedry,tolsym)
2417      end if
2418 
2419 !    Monoclinic holohedry, one-face-centered cell
2420 !    Working hypothesis, two vectors have equal length.
2421      do icase=1,5
2422        if(foundc==0 .and. iholohedry==2 .and. equal(itrial)==1 ) then
2423          vecta(:)=cell_base(:,ia)+cell_base(:,ib)
2424          vectb(:)=cell_base(:,ia)-cell_base(:,ib)
2425          norm2a=vecta(1)**2+vecta(2)**2+vecta(3)**2
2426          norm2b=vectb(1)**2+vectb(2)**2+vectb(3)**2
2427 !        The minim(:,trial) vector belongs to the
2428 !        plane parallel to the cell_base(:,ia),cell_base(:,ib) plane
2429 !        In that plane, must try minim(:,itrial),
2430 !        as well as the 4 different combinations of
2431 !        minim(:,itrial) with the vectors in the plane
2432          if(icase==1)vectc(:)=minim(:,itrial)
2433          if(icase==2)vectc(:)=minim(:,itrial)+cell_base(:,ia)
2434          if(icase==3)vectc(:)=minim(:,itrial)+cell_base(:,ib)
2435          if(icase==4)vectc(:)=minim(:,itrial)-cell_base(:,ia)
2436          if(icase==5)vectc(:)=minim(:,itrial)-cell_base(:,ib)
2437          norm2c=vectc(1)**2+vectc(2)**2+vectc(3)**2
2438          sca=vectc(1)*vecta(1)+&
2439 &         vectc(2)*vecta(2)+&
2440 &         vectc(3)*vecta(3)
2441          scb=vectc(1)*vectb(1)+&
2442 &         vectc(2)*vectb(2)+&
2443 &         vectc(3)*vectb(3)
2444 !        DEBUG
2445 !        write(std_out,*)' symlatt : test iholohedry=2, sca,scb=',sca,scb
2446 !        ENDDEBUG
2447          if(abs(sca)<tolsym*sqrt(norm2c*norm2a) .or. abs(scb)<tolsym*sqrt(norm2c*norm2b))then
2448            fact=2 ; center=3
2449 !          The itrial direction is centered
2450            cell_base(:,3)=vectc(:)
2451            if(abs(sca)<tolsym*sqrt(norm2c*norm2a))then
2452              cell_base(:,2)=vecta(:)
2453              cell_base(:,1)=vectb(:)
2454              call holocell(cell_base,0,foundc,iholohedry,tolsym)
2455            else if(abs(scb)<tolsym*sqrt(norm2c*norm2b))then
2456              cell_base(:,2)=vectb(:)
2457              cell_base(:,1)=vecta(:)
2458              call holocell(cell_base,0,foundc,iholohedry,tolsym)
2459            end if
2460          end if
2461        end if
2462      end do ! icase=1,5
2463 
2464 !    Monoclinic holohedry, one-face-centered cell, but non equivalent.
2465 !    This case, one pair of vectors is orthogonal
2466      if(foundc==0 .and. iholohedry==2 .and. ang90(itrial)==1) then
2467        vecta(:)=minim(:,ia)
2468        vectb(:)=minim(:,ib)
2469        norm2a=vecta(1)**2+vecta(2)**2+vecta(3)**2
2470        norm2b=vectb(1)**2+vectb(2)**2+vectb(3)**2
2471 !      Project the trial vector on the two vectors
2472        reduceda=( minim(1,itrial)*vecta(1)+       &
2473 &       minim(2,itrial)*vecta(2)+       &
2474 &       minim(3,itrial)*vecta(3) )/norm2a
2475        reducedb=( minim(1,itrial)*vectb(1)+       &
2476 &       minim(2,itrial)*vectb(2)+       &
2477 &       minim(3,itrial)*vectb(3) )/norm2b
2478        if(abs(abs(reduceda)-0.5d0)<tolsym .or. abs(abs(reducedb)-0.5d0)<tolsym) then
2479          fact=2 ; center=3
2480          if(abs(abs(reduceda)-0.5d0)<tolsym)then
2481            cell_base(:,2)=vecta(:)
2482            cell_base(:,3)=vectb(:)
2483            cell_base(:,1)=2*(minim(:,itrial)-reduceda*vecta(:))
2484            call holocell(cell_base,0,foundc,iholohedry,tolsym)
2485          else if(abs(abs(reducedb)-0.5d0)<tolsym)then
2486            cell_base(:,2)=vectb(:)
2487            cell_base(:,3)=vecta(:)
2488            cell_base(:,1)=2*(minim(:,itrial)-reducedb*vectb(:))
2489            call holocell(cell_base,0,foundc,iholohedry,tolsym)
2490          end if
2491        end if
2492      end if
2493 
2494 !    Monoclinic holohedry, one-face-centered cell, but non equivalent.
2495 !    This case, no pair of vectors is orthogonal, no pair of vector of equal lentgh
2496      if(foundc==0 .and. iholohedry==2)then
2497 !      Try to find a vector that belongs to the mediator plane, or the binary vector.
2498 !      There must be one such vector, if centered monoclinic and no pair of vectors of equal length,
2499 !      either among the three vectors, or among one of their differences or sums.
2500 !      And there must be, among the two other vectors, one vector whose projection
2501 !      on this vector is half the length of this vector.
2502        vecta(:)=minim(:,ia)
2503        vectb(:)=minim(:,ib)
2504 !      Try the different possibilities for the vector on which the projection will be half ...
2505        do ii=1,5
2506          if(ii==1)vectc(:)=minim(:,itrial)
2507          if(ii==2)vectc(:)=minim(:,itrial)+vecta(:)
2508          if(ii==3)vectc(:)=minim(:,itrial)-vecta(:)
2509          if(ii==4)vectc(:)=minim(:,itrial)+vectb(:)
2510          if(ii==5)vectc(:)=minim(:,itrial)-vectb(:)
2511          norm2trial=vectc(1)**2+vectc(2)**2+vectc(3)**2
2512 !        Project the two vectors on the trial vector
2513          reduceda=( vectc(1)*vecta(1)+vectc(2)*vecta(2)+vectc(3)*vecta(3) )/norm2trial
2514          reducedb=( vectc(1)*vectb(1)+vectc(2)*vectb(2)+vectc(3)*vectb(3) )/norm2trial
2515          found=0
2516          if(abs(abs(reduceda)-0.5d0)<tolsym)then
2517            vin1(:)=vectc(:)
2518            vin2(:)=2.0d0*(vecta(:)-reduceda*vectc(:))
2519            vext(:)=vectb(:)
2520            found=1
2521          else if(abs(abs(reducedb)-0.5d0)<tolsym)then
2522            vin1(:)=vectc(:)
2523            vin2(:)=2.0d0*(vectb(:)-reduceda*vectc(:))
2524            vext(:)=vecta(:)
2525            found=1
2526          end if
2527          if(found==1)exit
2528        end do
2529 !      Now, vin1 and vin2 are perpendicular to each other, and in the plane that contains the binary vector.
2530 !      One of them must be the binary vector if any.
2531 !      On the other hand, vext is out-of-plane. Might belong to the mediator plane or not.
2532 !      If C monoclinc, then the projection of this vext on the binary vector will be either 0 or +1/2 or -1/2.
2533 !      The binary axis must be stored in cell_base(:,2) for conventional C-cell
2534        if(found==1)then
2535          found=0
2536 
2537 !        Test vin1 being the binary axis
2538          norm2trial=vin1(1)**2+vin1(2)**2+vin1(3)**2
2539          reduceda=(vext(1)*vin1(1)+vext(2)*vin1(2)+vext(3)*vin1(3))/norm2trial
2540          if(abs(reduceda)<tolsym)then  ! vin1 is the binary axis and vext is in the mediator plane
2541            found=1
2542            cell_base(:,1)=vin2(:)
2543            cell_base(:,2)=vin1(:)
2544            cell_base(:,3)=vext(:)
2545          else if(abs(abs(reduceda)-0.5d0)<tolsym)then  ! vin1 is the binary axis and vext has +1/2 or -1/2 as projection
2546            found=1
2547            cell_base(:,1)=vin2(:)
2548            cell_base(:,2)=vin1(:)
2549            cell_base(:,3)=vext(:)-reduceda*vin1(:)+vin2(:)*half
2550          else
2551 !          Test vin2 being the binary axis
2552            norm2trial=vin2(1)**2+vin2(2)**2+vin2(3)**2
2553            reduceda=(vext(1)*vin2(1)+vext(2)*vin2(2)+vext(3)*vin2(3))/norm2trial
2554            if(abs(reduceda)<tolsym)then  ! vin2 is the binary axis and vext is in the mediator plane
2555              found=1
2556              cell_base(:,1)=vin1(:)
2557              cell_base(:,2)=vin2(:)
2558              cell_base(:,3)=vext(:)
2559            else if(abs(abs(reduceda)-0.5d0)<tolsym)then  ! vin2 is the binary axis and vext has +1/2 or -1/2 as projection
2560              found=1
2561              cell_base(:,1)=vin1(:)
2562              cell_base(:,2)=vin2(:)
2563              cell_base(:,3)=vext(:)-reduceda*vin2(:)+vin1(:)*half
2564            end if
2565          end if
2566 
2567          if(found==1)then
2568            fact=2 ; center=3
2569            call holocell(cell_base,0,foundc,iholohedry,tolsym)
2570          end if
2571        end if
2572      end if
2573 
2574    end do ! Do-loop on three different directions
2575  end do !  Do-loop on different target holohedries
2576 
2577  if(foundc==0)then
2578    iholohedry=1 ; fact=1 ; center=0
2579    cell_base(:,:)=minim(:,:)
2580  end if
2581 
2582 !DEBUG
2583 !write(std_out,*)' symlatt : done with centering tests, foundc=',foundc
2584 !write(std_out,*)'  center=',center
2585 !write(std_out,*)'  iholohedry=',iholohedry
2586 !call flush(std_out)
2587 !ENDDEBUG
2588 
2589 !--------------------------------------------------------------------------
2590 !Final check on the Bravais lattice, using the basis vectors
2591 
2592 !Recompute the metric tensor
2593  if(foundc==1)then
2594    do ii=1,3
2595      metmin(:,ii)=cell_base(1,:)*cell_base(1,ii)+&
2596 &     cell_base(2,:)*cell_base(2,ii)+&
2597 &     cell_base(3,:)*cell_base(3,ii)
2598    end do
2599  end if
2600 
2601 !Examine the angles and vector lengths
2602  ang90(:)=0
2603  if(metmin(1,2)**2<tolsym**2*metmin(1,1)*metmin(2,2))ang90(3)=1
2604  if(metmin(1,3)**2<tolsym**2*metmin(1,1)*metmin(3,3))ang90(2)=1
2605  if(metmin(2,3)**2<tolsym**2*metmin(2,2)*metmin(3,3))ang90(1)=1
2606  equal(:)=0
2607  if(abs(metmin(1,1)-metmin(2,2))<tolsym*half*(metmin(1,1)+metmin(2,2)))equal(3)=1
2608  if(abs(metmin(1,1)-metmin(3,3))<tolsym*half*(metmin(1,1)+metmin(3,3)))equal(2)=1
2609  if(abs(metmin(2,2)-metmin(3,3))<tolsym*half*(metmin(2,2)+metmin(3,3)))equal(1)=1
2610 
2611 !DEBUG
2612 !write(std_out,*)' symlatt : recompute the  metric tensor '
2613 !write(std_out,*)'  ang90=',ang90
2614 !write(std_out,*)'  equal=',equal
2615 !call flush(std_out)
2616 !ENDDEBUG
2617 
2618 !The axes will be aligned with the previously determined
2619 !basis vectors, EXCEPT for the tetragonal cell, see later
2620  axes(:,:)=cell_base(:,:)
2621 
2622  found=0
2623 !Check orthogonal conventional cells
2624  if(ang90(1)+ang90(2)+ang90(3)==3)then
2625 
2626 !  Cubic system
2627    if(equal(1)+equal(2)+equal(3)==3)then
2628 !    However, one-face centered is not admitted
2629      if(center==0 .or. center==-1 .or. center==-3)then
2630        iholohedry=7 ; found=1
2631        if(center==0)then
2632          write(msg,'(a,a)')ch10,' symlatt: the Bravais lattice is cP (primitive cubic)'
2633        else if(center==-1)then
2634          write(msg,'(a,a)')ch10,' symlatt: the Bravais lattice is cI (body-centered cubic)'
2635        else if(center==-3)then
2636          write(msg,'(a,a)')ch10,' symlatt: the Bravais lattice is cF (face-centered cubic)'
2637        end if
2638      end if
2639    end if
2640 
2641 !  Tetragonal system
2642    if(found==0 .and. &
2643 &   (equal(1)==1 .or. equal(2)==1 .or. equal(3)==1) )then
2644 !    However, one-face centered or face-centered is not admitted
2645      if(center==0 .or. center==-1)then
2646        iholohedry=4 ; found=1
2647        if(equal(1)==1)then
2648          axes(:,3)=cell_base(:,1) ; axes(:,1)=cell_base(:,2) ; axes(:,2)=cell_base(:,3)
2649        else if(equal(2)==1)then
2650          axes(:,3)=cell_base(:,2) ; axes(:,2)=cell_base(:,1) ; axes(:,1)=cell_base(:,3)
2651        else if(equal(3)==1)then
2652          axes(:,:)=cell_base(:,:)
2653        end if
2654        if(center==0)then
2655          write(msg,'(a,a)')ch10,' symlatt: the Bravais lattice is tP (primitive tetragonal)'
2656        else if(center==-1)then
2657          write(msg,'(a,a)')ch10,' symlatt: the Bravais lattice is tI (body-centered tetragonal)'
2658        end if
2659      end if
2660    end if
2661 
2662 !  Orthorhombic system
2663    if(found==0)then
2664      iholohedry=3 ; found=1
2665      axes(:,:)=cell_base(:,:)
2666      if(center==0)then
2667        write(msg,'(a,a)')ch10,' symlatt: the Bravais lattice is oP (primitive orthorhombic)'
2668      else if(center==-1)then
2669        write(msg,'(a,a)')ch10,' symlatt: the Bravais lattice is oI (body-centered orthorhombic)'
2670      else if(center==1 .or. center==2 .or. center==3)then
2671        write(msg,'(a,a)')ch10,' symlatt: the Bravais lattice is oC (one-face-centered orthorhombic)'
2672      else if(center==-3)then
2673        write(msg,'(a,a)')ch10,' symlatt: the Bravais lattice is oF (face-centered orthorhombic)'
2674      end if
2675    end if
2676 
2677  else
2678 
2679 !  Hexagonal system
2680    if(found==0 .and. ang90(1)==1 .and. ang90(2)==1 .and. equal(3)==1 .and. (2*metmin(2,1)+metmin(1,1))<tolsym*metmin(1,1))then
2681      iholohedry=6 ; found=1
2682      write(msg,'(a,a)')ch10,' symlatt: the Bravais lattice is hP (primitive hexagonal)'
2683    end if
2684 
2685 !  Rhombohedral system
2686    if(found==0 .and. equal(1)+equal(2)+equal(3)==3 .and.       &
2687 &   abs(metmin(2,1)-metmin(3,2))<tolsym*metmin(2,2)             .and.       &
2688 &   abs(metmin(2,1)-metmin(3,1))<tolsym*metmin(1,1) )then
2689      iholohedry=5 ; found=1
2690      write(msg,'(a,a)')ch10,' symlatt: the Bravais lattice is hR (rhombohedral)'
2691    end if
2692 
2693 !  Monoclinic system
2694    if(found==0 .and. ang90(1)+ang90(2)+ang90(3)==2 )then
2695      iholohedry=2 ; found=1
2696      if(center==0)then
2697        write(msg,'(a,a)')ch10,' symlatt: the Bravais lattice is mP (primitive monoclinic)'
2698      else if(center==3)then
2699        write(msg,'(a,a)')ch10,' symlatt: the Bravais lattice is mC (one-face-centered monoclinic)'
2700      end if
2701    end if
2702 
2703 !  Triclinic system
2704    if(found==0)then
2705      iholohedry=1 ; found=1
2706      write(msg,'(a,a)')ch10,' symlatt: the Bravais lattice is aP (primitive triclinic)'
2707    end if
2708 
2709  end if
2710 
2711  call wrtout(iout,msg)
2712 
2713 !DEBUG
2714 !write(std_out,*)' symlatt : after checking conventional orthogonal cell '
2715 !call flush(std_out)
2716 !ENDDEBUG
2717 
2718 !--------------------------------------------------------------------------
2719 !Make sure that axes form a right-handed coordinate system
2720 !(Note : this should be done in the body of the routine,
2721 !by making changes that leave the sign of the mixed product of the three
2722 !vectors invariant)
2723  determinant=axes(1,1)*axes(2,2)*axes(3,3) &
2724 & +axes(1,2)*axes(2,3)*axes(3,1) &
2725 & +axes(1,3)*axes(3,2)*axes(2,1) &
2726 & -axes(1,1)*axes(3,2)*axes(2,3) &
2727 & -axes(1,3)*axes(2,2)*axes(3,1) &
2728 & -axes(1,2)*axes(2,1)*axes(3,3)
2729  if(determinant<zero)then
2730    axes(:,:)=-axes(:,:)
2731  end if
2732 
2733 !DEBUG
2734 !write(std_out,'(a,i4)')' symlatt : before itrial do loop, iholohedry= ',iholohedry
2735 !write(std_out,'(a,3es14.6,a,3es14.6,a,3es14.6)')' rprimd=',&
2736 !&  rprimd(:,1),ch10,rprimd(:,2),ch10,rprimd(:,3)
2737 !call flush(std_out)
2738 !ENDDEBUG
2739 
2740 !--------------------------------------------------------------------------
2741 !Prefer symmetry axes on the same side as the primitive axes,
2742 !when the changes are allowed
2743  do itrial=1,100
2744 
2745 !  DEBUG
2746 !  write(std_out,'(a)')' '
2747 !  write(std_out,'(a,i5)')' symlatt : itrial do loop, itrial= ',itrial
2748 !  write(std_out,'(a,3es14.6,a,3es14.6,a,3es14.6)')' axes  =',&
2749 !  &  axes(:,1),ch10,axes(:,2),ch10,axes(:,3)
2750 !  call flush(std_out)
2751 !  ENDDEBUG
2752 
2753    do ia=1,3
2754      scprods(ia,:)=axes(1,ia)*rprimd(1,:)+&
2755 &     axes(2,ia)*rprimd(2,:)+&
2756 &     axes(3,ia)*rprimd(3,:)
2757      norm2trial=sum(axes(:,ia)**2)
2758      scprods(ia,:)=scprods(ia,:)/sqrt(norm2trial)
2759    end do
2760    do ia=1,3
2761      norm2trial=sum(rprimd(:,ia)**2)
2762      scprods(:,ia)=scprods(:,ia)/sqrt(norm2trial)
2763    end do
2764 
2765 !DEBUG
2766 !  write(std_out,'(a,3f12.6)')' diagonal scalar products ',scprods(1,1),scprods(2,2),scprods(3,3)
2767 !  call flush(std_out)
2768 !ENDDEBUG
2769 
2770 !  One should now try all the generators of the
2771 !  proper rotations of each Bravais lattice, coupled with change of
2772 !  signs of each vector. This is not done systematically in what follows ...
2773 !  Here, the third axis is left unchanged
2774    if(iholohedry/=5)then
2775      if(scprods(1,1)<-tolsym .and. scprods(2,2)<-tolsym)then
2776        axes(:,1)=-axes(:,1) ; axes(:,2)=-axes(:,2)
2777        cycle
2778      end if
2779    end if
2780 !  The first (or second) axis is left unchanged
2781    if(iholohedry/=5 .and. iholohedry/=6)then
2782      if(scprods(2,2)<-tolsym .and. scprods(3,3)<-tolsym)then
2783        axes(:,2)=-axes(:,2) ; axes(:,3)=-axes(:,3)
2784        cycle
2785      end if
2786      if(scprods(1,1)<-tolsym .and. scprods(3,3)<-tolsym)then
2787        axes(:,1)=-axes(:,1) ; axes(:,3)=-axes(:,3)
2788        cycle
2789      end if
2790    end if
2791 !  Permutation of the three axis
2792    if(iholohedry==5 .or. iholohedry==7)then
2793      trace=scprods(1,1)+scprods(2,2)+scprods(3,3)
2794      if(trace+tolsym< scprods(1,2)+scprods(2,3)+scprods(3,1))then
2795        vecta(:)=axes(:,1) ; axes(:,1)=axes(:,3)
2796        axes(:,3)=axes(:,2); axes(:,2)=vecta(:)
2797        cycle
2798      end if
2799      if(trace+tolsym < scprods(1,3)+scprods(2,1)+scprods(3,2))then
2800        vecta(:)=axes(:,1) ; axes(:,1)=axes(:,2)
2801        axes(:,2)=axes(:,3); axes(:,3)=vecta(:)
2802        cycle
2803      end if
2804 !    This case is observed when the three new vectors
2805 !    are pointing opposite to the three original vectors
2806 !    One takes their opposite, then switch two of them, then process
2807 !    them again in the loop
2808      if(sum(scprods(:,:))<-tolsym)then
2809        axes(:,1)=-axes(:,1)
2810        vecta(:)=-axes(:,2)
2811        axes(:,2)=-axes(:,3)
2812        axes(:,3)=vecta(:)
2813        cycle
2814      end if
2815    end if
2816 
2817 !  Actually, for iholohedry==7, can test specifically all possibilities
2818 !  and take the best one.
2819 !  Not activated, because changing the order of symmetries in many tests !
2820    if(iholohedry==7 .and. .false.)then
2821 !  if(iholohedry==7)then
2822 
2823 !DEBUG
2824 !write(std_out,'(a,a)')ch10,' enter search of all possibilities for iholohedry==7 '
2825 !write(std_out,'(a,3es14.6,a,3es14.6,a,3es14.6)')' axes  =',&
2826 !&  axes(:,1),ch10,axes(:,2),ch10,axes(:,3)
2827 !call flush(std_out)
2828 !ENDDEBUG
2829 
2830      do iaxis1=1,3
2831        axes_try(:,1)=axes(:,iaxis1)
2832        do iaxis2=1,2
2833          if(iaxis1==1)axes_try(:,2)=axes(:,1+iaxis2)
2834          if(iaxis1==2)axes_try(:,2)=axes(:,2*iaxis2-1)
2835          if(iaxis1==3)axes_try(:,2)=axes(:,iaxis2)
2836          if(iaxis2==1)axes_try(:,3)=axes(:,3)
2837          if(iaxis2==2)axes_try(:,3)=axes(:,1)
2838          if(iaxis1==1.and.iaxis2==2)axes_try(:,3)=axes(:,2)
2839          if(iaxis1==3.and.iaxis2==1)axes_try(:,3)=axes(:,2)
2840          do isign1=1,-1,-2
2841            axes_try(:,1)=-axes_try(:,1)
2842            do isign2=1,-1,-2
2843              axes_try(:,2)=-axes_try(:,2)
2844              determinant=axes_try(1,1)*axes_try(2,2)*axes_try(3,3) &
2845 &                       +axes_try(1,2)*axes_try(2,3)*axes_try(3,1) &
2846 &                       +axes_try(1,3)*axes_try(3,2)*axes_try(2,1) &
2847 &                       -axes_try(1,1)*axes_try(3,2)*axes_try(2,3) &
2848 &                       -axes_try(1,3)*axes_try(2,2)*axes_try(3,1) &
2849 &                       -axes_try(1,2)*axes_try(2,1)*axes_try(3,3)
2850              if(determinant<zero)axes_try(:,3)=-axes_try(:,3)
2851              do ia=1,3
2852                scprods(ia,:)=axes_try(1,ia)*rprimd(1,:)+&
2853 &                            axes_try(2,ia)*rprimd(2,:)+&
2854 &                            axes_try(3,ia)*rprimd(3,:)
2855                norm2trial=sum(axes_try(:,ia)**2)
2856                scprods(ia,:)=scprods(ia,:)/sqrt(norm2trial)
2857              end do
2858              do ia=1,3
2859                norm2trial=sum(rprimd(:,ia)**2)
2860                scprods(:,ia)=scprods(:,ia)/sqrt(norm2trial)
2861              end do
2862              trace=scprods(1,1)+scprods(2,2)+scprods(3,3)
2863              if(iaxis1==1.and.iaxis2==1.and.isign1==1.and.isign2==1)then
2864                trace_best=trace
2865                axes_best=axes_try
2866              else if (trace>trace_best+tolsym)then
2867                trace_best=trace
2868                axes_best=axes_try
2869              endif
2870            enddo ! isign2
2871          enddo ! isign1
2872        enddo ! iaxes2
2873      enddo ! iaxes1
2874      axes=axes_best
2875    endif ! iholohedry=7
2876    exit
2877  end do
2878 
2879 !--------------------------------------------------------------------------
2880 
2881 !DEBUG
2882 !write(std_out,'(a,a)')ch10,' after order/sign optimization do-loop '
2883 !write(std_out,'(a,3es14.6,a,3es14.6,a,3es14.6)')' rprimd=',&
2884 !&  rprimd(:,1),ch10,rprimd(:,2),ch10,rprimd(:,3)
2885 !write(std_out,'(a,3es14.6,a,3es14.6,a,3es14.6)')' axes  =',&
2886 !&  axes(:,1),ch10,axes(:,2),ch10,axes(:,3)
2887 !call flush(std_out)
2888 !ENDDEBUG
2889 
2890 !Compute the coordinates of rprimd in the system defined by axes(:,:)
2891  call matr3inv(axes,axesinvt)
2892  do ii=1,3
2893    coord(:,ii)=rprimd(1,ii)*axesinvt(1,:)+ &
2894 &   rprimd(2,ii)*axesinvt(2,:)+ &
2895 &   rprimd(3,ii)*axesinvt(3,:)
2896  end do
2897 
2898 !Check that the coordinates are integers, or half-integer in
2899 !the case there is a centering, and generate integer coordinates
2900  do ii=1,3
2901    do jj=1,3
2902      val=coord(ii,jj)*fact
2903      if(abs(val-nint(val))>fact*two*tolsym)then
2904        write(msg,'(4a,a,3es18.10,a,a,3es18.10,a,a,3es18.10,a,a,i4)')&
2905        'One of the coordinates of rprimd in axes is non-integer,',ch10,&
2906        'or non-half-integer (if centering), within 2*tolsym.',ch10,&
2907        'coord=',coord(:,1),ch10,&
2908        '      ',coord(:,2),ch10,&
2909        '      ',coord(:,3),ch10,&
2910        'fact=',fact
2911        ABI_BUG(msg)
2912      end if
2913      icoord(ii,jj)=nint(val)
2914    end do
2915  end do
2916 
2917 !Store the bravais lattice characteristics
2918  bravais(1)=iholohedry
2919  bravais(2)=center
2920  bravais(3:5)=icoord(1:3,1)
2921  bravais(6:8)=icoord(1:3,2)
2922  bravais(9:11)=icoord(1:3,3)
2923 
2924 !--------------------------------------------------------------------------
2925 !Initialize the set of symmetries
2926 !Bravais lattices are always invariant under identity and inversion
2927 
2928 !Identity and inversion
2929  ptsymrel(:,:,1)=identity(:,:) ; ptsymrel(:,:,2)=-identity(:,:)
2930  nptsym=2
2931 
2932 !Keep this for IFCv70 compiler
2933  if(nptsym/=2)then
2934    write(msg,'(a,a,a,a)')ch10,&
2935    ' symlatt : BUG -',ch10,&
2936    '  Crazy error, compiler bug '
2937    call wrtout(std_out,msg)
2938  end if
2939 
2940 !--------------------------------------------------------------------------
2941 !Initialize some generators
2942 !gen6 is defined in a coordinated system with gamma=120 degrees
2943  gen6(:,:)=0  ; gen6(3,3)=1  ; gen6(1,1)=1  ; gen6(1,2)=-1 ; gen6(2,1)=1
2944  gen3(:,:)=0  ; gen3(1,2)=1  ; gen3(2,3)=1  ; gen3(3,1)=1
2945  gen2xy(:,:)=0 ; gen2xy(2,1)=1 ; gen2xy(1,2)=1; gen2xy(3,3)=1
2946  gen2y(:,:)=0 ; gen2y(1,1)=-1; gen2y(2,2)=1 ; gen2y(3,3)=-1
2947  gen2z(:,:)=0 ; gen2z(1,1)=-1; gen2z(2,2)=-1; gen2z(3,3)=1
2948 
2949 !--------------------------------------------------------------------------
2950 
2951 !Define the generators for each holohedry (inversion is already included)
2952  if(iholohedry==6)then
2953    ngen=2
2954    gen(:,:,1)=gen2xy(:,:) ; order(1)=2
2955    gen(:,:,2)=gen6(:,:)   ; order(2)=6
2956  else if(iholohedry==5)then
2957    ngen=2
2958    gen(:,:,1)=gen2xy(:,:) ; order(1)=2
2959    gen(:,:,2)=gen3(:,:)   ; order(2)=3
2960  else
2961    gen(:,:,1)=gen2y(:,:)  ; order(1)=2
2962    gen(:,:,2)=gen2z(:,:)  ; order(2)=2
2963    gen(:,:,3)=gen2xy(:,:) ; order(3)=2
2964    gen(:,:,4)=gen3(:,:)   ; order(4)=3
2965    if(iholohedry<=4)ngen=iholohedry-1
2966    if(iholohedry==7)ngen=4
2967  end if
2968 
2969 !Build the point symmetry operations from generators, in the reduced system
2970 !of coordinates defined by axes(:,:)
2971  if(ngen/=0)then
2972    do igen=1,ngen
2973      do isym=1+nptsym,order(igen)*nptsym
2974        jsym=isym-nptsym
2975        do ii=1,3
2976          ptsymrel(:,ii,isym)=gen(:,1,igen)*ptsymrel(1,ii,jsym)+ &
2977 &         gen(:,2,igen)*ptsymrel(2,ii,jsym)+ &
2978 &         gen(:,3,igen)*ptsymrel(3,ii,jsym)
2979        end do
2980      end do
2981      nptsym=order(igen)*nptsym
2982 
2983    end do
2984  end if
2985 
2986 !--------------------------------------------------------------------------
2987 
2988 !Transform symmetry matrices in the system defined by rprimd
2989  call symrelrot(nptsym,axes,rprimd,ptsymrel,tolsym)
2990 
2991 !DEBUG
2992 !write(std_out,'(a)') ' symlatt : exit '
2993 !call flush(std_out)
2994 !stop
2995 !ENDDEBUG
2996 
2997 end subroutine symlatt

m_symfind/symspgr [ Functions ]

[ Top ] [ m_symfind ] [ Functions ]

NAME

 symspgr

FUNCTION

 Find the type of each symmetry operation (calling symcharac):
   proper symmetries 1,2,2_1,3,3_1,3_2,4,4_1,4_2,4_3,6,6_1,...6_5
   improper symmetries -1,m,a,b,c,d,n,g,-3,-4,-6 ,
 Then, build an array with the number of such operations.
 Then, call symlist to identify the space group.

INPUTS

 bravais(11): bravais(1)=iholohedry
              bravais(2)=center
              bravais(3:11)=coordinates of rprimd in the axes
              of the conventional bravais lattice (*2 if center/=0)
 nsym=actual number of symmetries
 symrel(3,3,nsym)= nsym symmetry operations in real space in terms
   of primitive translations
 tnons(3,nsym)=nonsymmorphic translations for each symmetry (would
   be 0 0 0 each for a symmorphic space group)

OUTPUT

 labels(maxsym=192)= labels of the symmetry operations
 spgroup=symmetry space group number

NOTES

 It is assumed that the symmetry operations will be entered in the
 symrel tnons arrays, for the PRIMITIVE cell. The matrix of transformation
 from the primitive cell to the conventional cell is described
 in the array "bravais" (see symlatt.F90).
 The present routine first make the transformation from the
 primitive coordinates to the conventional ones, then eventually
 generate additional symmetries, taking into account the
 centering translations.
 Then, the order and determinant of each symmetry operation
 is determined.

 For proper symmetries (rotations), the
 associated translation is also determined.
 However, left or right handed screw rotations are
 not (presently) distinguished, and will be attributed equally
 to left or right.

 For the detailed description of the labelling of the axes,
 see symaxes.f and symplanes.f

SOURCE

1495 subroutine symspgr(bravais,labels,nsym,spgroup,symrel,tnons,tolsym)
1496 
1497  use m_numeric_tools, only : OPERATOR(.x.)
1498 
1499 !Arguments ------------------------------------
1500 !scalars
1501  integer,intent(in) :: nsym
1502  integer,intent(out) :: spgroup
1503  real(dp),intent(in) :: tolsym
1504 !arrays
1505  integer,intent(in) :: bravais(11),symrel(3,3,nsym)
1506  real(dp),intent(in) :: tnons(3,nsym)
1507  character(len=128),intent(out) :: labels(192) ! 192 = maxsym
1508 
1509 !Local variables-------------------------------
1510 !scalars
1511 ! logical,parameter :: verbose=.FALSE.
1512  integer :: additional_info,brvltt,center,direction=0,found,iholohedry,ii
1513  integer :: ishift,isym,jj,nshift,nsymconv,spgaxor,spgorig,sporder
1514  character(len=1) :: brvsb
1515  character(len=15) :: intsb,ptintsb,ptschsb,schsb
1516  character(len=35) :: intsbl
1517  character(len=500) :: msg
1518 !arrays
1519  integer :: ivec1(3), ivec2(3)
1520  integer :: n_axes(31),n_axest(31),prime(5),test_direction(3),symrel_uni(3,3)
1521  integer :: uniaxis(3),uniaxis_try(3)
1522  integer,allocatable :: determinant(:),symrelconv(:,:,:),t_axes(:)
1523  real(dp) :: axes(3,3),rprimdconv(3,3),vect(3,3)
1524  real(dp),allocatable :: shift(:,:),tnonsconv(:,:)
1525 
1526 !**************************************************************************
1527 
1528  DBG_ENTER("COLL")
1529 
1530 !Initialize brvltt, from bravais(2) and bravais(1)
1531  center=bravais(2)
1532  iholohedry=bravais(1)
1533  brvltt=1
1534  if(center==-1)brvltt=2  ! Inner centering
1535  if(center==-3)brvltt=3  ! Face centering
1536  if(center==1)brvltt=5  ! A-Face centering
1537  if(center==2)brvltt=6  ! B-Face centering
1538  if(center==3)brvltt=4  ! C-Face centering
1539  if(iholohedry==5)brvltt=7  ! Rhombohedral
1540 
1541 !Produce the symmetry operations, in the axis of the conventional cell
1542  nsymconv=nsym
1543  if(center/=0)nsymconv=2*nsymconv
1544  if(center==-3)nsymconv=4*nsym
1545  ABI_MALLOC(symrelconv,(3,3,nsymconv))
1546  ABI_MALLOC(tnonsconv,(3,nsymconv))
1547 
1548 !Produce symrel and tnons in conventional axes,
1549 !name them symrelconv and tnonsconv
1550  rprimdconv(:,1)=bravais(3:5)
1551  rprimdconv(:,2)=bravais(6:8)
1552  rprimdconv(:,3)=bravais(9:11)
1553 
1554  if(center/=0)rprimdconv(:,:)=rprimdconv(:,:)*half
1555 
1556  axes(:,:)=zero
1557  axes(1,1)=one ; axes(2,2)=one ; axes(3,3)=one
1558  symrelconv(:,:,1:nsym)=symrel(:,:,1:nsym)
1559 !Note that the number of symmetry operations is still nsym
1560  call symrelrot(nsym,rprimdconv,axes,symrelconv,tolsym)
1561 
1562  call xred2xcart(nsym,rprimdconv,tnonsconv,tnons)
1563 !Gives the associated translation, with components in the
1564 !interval ]-0.5,0.5] .
1565  tnonsconv(:,1:nsym)=tnonsconv(:,1:nsym)-nint(tnonsconv(:,1:nsym)-tol6)
1566 
1567 !If the Bravais lattice is centered, duplicate or quadruplicate
1568 !the number of symmetry operations, using the Bravais
1569 !lattice shifts
1570  nshift=1
1571  if(center/=0)nshift=2
1572  if(center==-3)nshift=4
1573  ABI_MALLOC(shift,(3,nshift))
1574  shift(:,1)=zero
1575  if(center/=0 .and. center/=-3)then
1576    shift(:,2)=half
1577    if(center==1)shift(1,2)=zero
1578    if(center==2)shift(2,2)=zero
1579    if(center==3)shift(3,2)=zero
1580  else if(center==-3)then
1581    shift(:,2)=half ; shift(1,2)=zero
1582    shift(:,3)=half ; shift(2,3)=zero
1583    shift(:,4)=half ; shift(3,4)=zero
1584  end if ! center/=0 or -3
1585  if(nshift/=1)then
1586    do ishift=2,nshift
1587      symrelconv(:,:,(ishift-1)*nsym+1:ishift*nsym)=symrelconv(:,:,1:nsym)
1588      do isym=1,nsym
1589        tnonsconv(:,(ishift-1)*nsym+isym)=tnonsconv(:,isym)+shift(:,ishift)
1590      end do
1591    end do ! ishift
1592  end if ! nshift/=1
1593 
1594 !At this stage, all the symmetry operations are available,
1595 !expressed in the conventional axis, and also include
1596 !the Bravais lattive translations, and associated operations...
1597 
1598  n_axes(:)=0
1599 
1600  ABI_MALLOC(determinant,(nsymconv))
1601 
1602 !Get the determinant
1603  call symdet(determinant,nsymconv,symrelconv)
1604 
1605 !Get the order of each the symmetry operation, as well as the maximal order
1606 !Also, examine whether each symmetry operation is the inversion, or a root
1607 !of the inversion (like -3)
1608 !Decide which kind of point symmetry operation it is
1609 !Finally assign tnonsconv order and decide the space symmetry operation
1610 
1611  ABI_MALLOC(t_axes,(nsymconv))
1612 
1613  do isym=1,nsymconv
1614 
1615 !  Note : nsymconv might be bigger than 192, but only for non-primitive cells, in which case labels will not be echoed anywhere.
1616 !  192 is the fixed dimension of labels, so this avoids possible memory problems.
1617    call symcharac(center, determinant(isym), iholohedry, isym, labels(mod(isym-1,192)+1), &
1618    symrelconv(:,:,isym), tnonsconv(:,isym), t_axes(isym))
1619    if (t_axes(isym) == -1) then
1620      write(msg, '(a,a,i3,a,3(a,3i4,a),a,3es22.12,a,a,3es22.12)' )ch10,&
1621      ' symspgr: problem with isym=',isym,ch10,&
1622      '  symrelconv(:,1,isym)=',symrelconv(:,1,isym),ch10,&
1623      '  symrelconv(:,2,isym)=',symrelconv(:,2,isym),ch10,&
1624      '  symrelconv(:,3,isym)=',symrelconv(:,3,isym),ch10,&
1625      '  tnonsconv(:,isym)=',tnonsconv(:,isym)
1626      call wrtout(std_out,msg)
1627      write(msg, '(a,i4,2a)' )&
1628        'The space symmetry operation number',isym,ch10,'is not a (translated) root of unity'
1629      ABI_BUG(msg)
1630    else if (t_axes(isym) == -2) then
1631      write(msg, '(a,i0,a)' )'The symmetry operation number ',isym,' is not a root of unity'
1632      ABI_BUG(msg)
1633    end if
1634 
1635    n_axes(t_axes(isym))=n_axes(t_axes(isym))+1
1636 
1637  end do ! isym=1,nsymconv
1638 
1639  if (sum(n_axes)-nsymconv/=0) then
1640    write(msg, '(7a)' )&
1641 &   'Not all the symmetries have been recognized. ',ch10,&
1642 &   'This might be due either to an error in the input file',ch10,&
1643 &   'or to a BUG in ABINIT',ch10,&
1644 &   'Please contact the ABINIT group.'
1645    ABI_WARNING(msg)
1646  end if
1647 
1648 !DEBUG
1649 !write(std_out,*)' symspgr : brvltt,nsymconv=',brvltt,nsymconv
1650 !write(std_out,*)' n_axes(1:10)=',n_axes(1:10)
1651 !write(std_out,*)' n_axes(11:20)=',n_axes(11:20)
1652 !write(std_out,*)' n_axes(21:31)=',n_axes(21:31)
1653 !ENDDEBUG
1654 
1655 !Treat cases in which the space group cannot be identified on the
1656 !basis of n_axes one need additional information
1657  if(brvltt==1)then
1658 !  If the bravais lattice is primitive
1659    if(nsymconv==4)then
1660      n_axest=(/0,0,0,0,0,0,0,1,1,0,  0,0,0,0,0,2,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0/)
1661      if(sum((n_axes-n_axest)**2)==0)then    ! Spgroup 27 (Pcc2) or 32 (Pba2)
1662        write(std_out,*)' symspgr: 27 or 32'
1663        additional_info=2
1664 !      Select binary axis
1665        do isym=1,nsymconv
1666          if(t_axes(isym)==8)then
1667 !          Find direction of binary axis
1668            if(symrelconv(1,1,isym)==1)direction=1
1669            if(symrelconv(2,2,isym)==1)direction=2
1670            if(symrelconv(3,3,isym)==1)direction=3
1671          end if
1672        end do
1673 !      Examine the projection of the translation vector of the a, b or c mirror planes
1674 !      onto the binary axis
1675        do isym=1,nsymconv
1676          if(t_axes(isym)==16)then
1677            if(abs(tnonsconv(direction,isym))>tol8)additional_info=1
1678          end if
1679        end do
1680      end if
1681    else if(nsymconv==8)then
1682      n_axest=(/0,0,0,0,1,0,0,1,1,0,  0,0,0,0,1,2,0,0,0,2,  0,0,0,0,0,0,0,0,0,0,0/)
1683      if(sum((n_axes-n_axest)**2)==0)then    ! Spgroup 55 (Pbam) or 57 (Pbcm)
1684        write(std_out,*)' symspgr: 55 or 57'
1685        additional_info=1
1686 !      Select mirror plane m
1687        do isym=1,nsymconv
1688          if(t_axes(isym)==15)then
1689 !          Find direction of mirror plane
1690            if(symrelconv(1,1,isym)==-1)direction=1
1691            if(symrelconv(2,2,isym)==-1)direction=2
1692            if(symrelconv(3,3,isym)==-1)direction=3
1693          end if
1694        end do
1695 !      Examine the projection of the translation vector of the a, b, or c mirror planes
1696 !      onto the binary axis
1697        do isym=1,nsymconv
1698          if(t_axes(isym)==16)then
1699            if(abs(tnonsconv(direction,isym))>tol8)additional_info=2
1700          end if
1701        end do
1702      end if
1703      n_axest=(/0,0,0,0,1,0,0,1,1,0,  0,0,0,0,0,2,0,1,0,2,  0,0,0,0,0,0,0,0,0,0,0/)
1704      if(sum((n_axes-n_axest)**2)==0)then    ! Spgroup 56 (Pccn) or 60 (Pbcn)
1705        write(std_out,*)' symspgr: 56 or 60'
1706        additional_info=1
1707 !      Select mirror plane n
1708        do isym=1,nsymconv
1709          if(t_axes(isym)==18)then
1710 !          Find direction of mirror plane
1711            if(symrelconv(1,1,isym)==-1)direction=1
1712            if(symrelconv(2,2,isym)==-1)direction=2
1713            if(symrelconv(3,3,isym)==-1)direction=3
1714          end if
1715        end do
1716 !      Examine the projection of the translation vector of the a, b, or c mirror planes
1717 !      onto the binary axis
1718        do isym=1,nsymconv
1719          if(t_axes(isym)==16)then
1720            if(abs(tnonsconv(direction,isym))<tol8)additional_info=2
1721          end if
1722        end do
1723      end if
1724    end if
1725  else if(brvltt==2)then
1726 !  In the few next lines, use additional_info as a flag
1727    additional_info=0
1728 !  If the bravais lattice is inner-centered
1729    if(nsymconv==8)then
1730 !    Test spgroup 23 (I222) or 24 (I2_{1}2_{1}2_{1})
1731      n_axest=(/0,0,0,0,0,0,1,1,3,0,  0,0,0,0,0,0,0,0,0,3,  0,0,0,0,0,0,0,0,0,0,0/)
1732      if(sum((n_axes-n_axest)**2)==0) additional_info=1
1733    else if(nsymconv==24)then
1734 !    Test spgroup 197 (I23) or 199 (I2_{1}3)
1735      n_axest=(/0,0,0,0,0,0,1,1,3,16, 0,0,0,0,0,0,0,0,0,3,  0,0,0,0,0,0,0,0,0,0,0/)
1736      if(sum((n_axes-n_axest)**2)==0) additional_info=1
1737    end if
1738    if(additional_info==1)then
1739      write(std_out,*)' symspgr: (23 or 24) or (197 or 199)'
1740 !    Select the three binary axes (they might be 2 or 2_1 !)
1741      test_direction(:)=0
1742      do isym=1,nsymconv
1743        if(t_axes(isym)==20)then
1744 !        Find direction of axis
1745          do direction=1,3
1746            if(symrelconv(direction,direction,isym)==1)then
1747              test_direction(direction)=1
1748              if(abs(tnonsconv(direction,isym))<tol8)then
1749                vect(:,direction)=tnonsconv(:,isym)
1750              else
1751                vect(:,direction)=tnonsconv(:,isym)+half
1752              end if
1753              vect(:,direction)=vect(:,direction)-nint(vect(:,direction)-tol8)
1754              vect(direction,direction)=zero
1755            end if
1756          end do ! direction=1,3
1757        end if ! if binary axis
1758      end do ! isym
1759      if(test_direction(1)/=1 .or. test_direction(2)/=1 .and. test_direction(3)/=1)then
1760        write(msg, '(5a,3i4)' )&
1761        'For space groups 23, 24, 197 or 197, the three binary axes',ch10,&
1762        'are not equally partitioned along the x, y and z directions',ch10,&
1763        'test_direction(1:3)=',test_direction(:)
1764        ABI_BUG(msg)
1765      end if
1766      additional_info=1
1767      if(abs(vect(1,2)-vect(1,3))>tol8 .or. abs(vect(2,1)-vect(2,3))>tol8 .or. &
1768         abs(vect(3,1)-vect(3,2))>tol8) additional_info=2
1769    end if ! additional information are needed
1770  end if ! brvltt==1
1771 
1772  if (brvltt==0 .or. brvltt==1) then ! Primitive
1773    call symlist_prim(additional_info,nsymconv,n_axes,spgroup)
1774  else if(brvltt==2)then
1775    call symlist_bcc(additional_info,nsymconv,n_axes,spgroup)
1776  else if(brvltt==3)then
1777    call symlist_fcc(nsymconv,n_axes,spgroup)
1778  else
1779    call symlist_others(brvltt,nsymconv,n_axes,spgroup)
1780  end if
1781 
1782  if(spgroup==0) then
1783    write(msg, '(a,a,a,a,a)' )&
1784    'Could not find the space group.',ch10,&
1785    'This often happens when the user selects a restricted set of symmetries ',ch10,&
1786    'in the input file, instead of letting the code automatically find symmetries.'
1787    ABI_WARNING(msg)
1788  end if
1789 
1790  spgorig=1 ; spgaxor=1
1791  call spgdata(brvsb,intsb,intsbl,ptintsb,ptschsb,schsb,spgaxor,spgroup,sporder,spgorig)
1792 
1793  if(spgroup/=0)then
1794    write(msg, '(a,i4,2x,a,a,a,a,a)' ) ' symspgr: spgroup=',spgroup,trim(brvsb),trim(intsb),'   (=',trim(schsb),')'
1795    call wrtout(std_out,msg)
1796  end if
1797 
1798  if(bravais(1)==7)then
1799    write(msg, '(a)' ) ' symspgr: optical characteristics = isotropic '
1800    call wrtout(std_out,msg)
1801  else if(bravais(1)==4 .or. bravais(1)==5 .or. bravais(1)==6)then
1802    write(msg, '(a)' ) ' symspgr: optical characteristics = uniaxial '
1803    call wrtout(std_out,msg)
1804 !  Identify the first symmetry operation that is order 3, 4 or 6
1805    found=0
1806    do isym=1,nsym
1807 !    Proper rotations
1808      if( minval( abs( t_axes(isym)-(/10,12,14,22,23,24,25,26,27,28,29,30,31/) ))==0) then
1809        found=1 ; exit
1810 !   Improper symmetry operations
1811      else if( minval( abs( t_axes(isym)-(/1,2,3/) ))==0) then
1812        found=-1 ; exit
1813      end if
1814    end do
1815    if(found==-1 .or. found==1)then
1816      symrel_uni=symrel(:,:,isym)
1817      if(found==-1)symrel_uni=-symrel_uni
1818 !    Now, symrel_uni is a rotation of order 3, 4, 6, for which the axis must be identified
1819 !    It is actually the only eigenvector with eigenvalue 1. It can be found by cross products
1820 !    Subtract the unit matrix.
1821      do ii=1,3
1822        symrel_uni(ii,ii)=symrel_uni(ii,ii)-1
1823      end do
1824      found=0
1825      do ii=1,3
1826        jj=ii+1 ; if(jj==4)jj=1
1827 !      Cross product
1828        ivec1 = symrel_uni(ii,:); ivec2 = symrel_uni(jj,:)
1829        uniaxis = ivec1 .x. ivec2
1830        if(sum(uniaxis**2)/=0)then
1831          found=1 ; exit
1832        end if
1833      end do
1834      if(found==1)then
1835 !      Try to reduce the length, by an integer factor (try only primes 2, 3, 5, 7, 11)
1836        prime=(/2,3,5,7,11/)
1837        ii=1
1838        do while (ii<6)
1839          uniaxis_try=uniaxis/prime(ii)
1840          if(sum(abs(uniaxis_try*prime(ii)-uniaxis))==0)then
1841            uniaxis=uniaxis_try
1842          else
1843            ii=ii+1
1844          end if
1845        end do
1846        write(msg, '(a,3i4)' ) ' Optical axis (in reduced coordinates, real space ) :',uniaxis
1847      end if
1848    end if
1849    if(found==0)then
1850      write(msg, '(a)' ) ' However, the axis has not been found. Sorry for this.'
1851    end if
1852    call wrtout(std_out,msg)
1853  end if
1854 
1855  ABI_FREE(determinant)
1856  ABI_FREE(shift)
1857  ABI_FREE(symrelconv)
1858  ABI_FREE(tnonsconv)
1859  ABI_FREE(t_axes)
1860 
1861  DBG_EXIT("COLL")
1862 
1863 end subroutine symspgr