TABLE OF CONTENTS
- ABINIT/m_symtk
- m_symtk/chkgrp
- m_symtk/chkorthsy
- m_symtk/chkprimit
- m_symtk/holocell
- m_symtk/littlegroup_q
- m_symtk/mati3det
- m_symtk/mati3inv
- m_symtk/matpointsym
- m_symtk/matr3inv
- m_symtk/print_symmetries
- m_symtk/sg_multable
- m_symtk/smallprim
- m_symtk/symatm
- m_symtk/symaxes
- m_symtk/symcharac
- m_symtk/symchk
- m_symtk/symdet
- m_symtk/symmetrize_rprimd
- m_symtk/symmetrize_tnons
- m_symtk/symmetrize_xred
- m_symtk/symplanes
- m_symtk/symrelrot
ABINIT/m_symtk [ Modules ]
NAME
m_symtk
FUNCTION
Low-level tools related to symmetries
COPYRIGHT
Copyright (C) 1998-2024 ABINIT group (RC, XG, GMR, MG, JWZ) 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_symtk 23 24 use defs_basis 25 use m_errors 26 use m_abicore 27 28 use m_numeric_tools, only : isinteger, wrap2_pmhalf 29 use m_hide_lapack, only : matrginv 30 31 implicit none 32 33 private
m_symtk/chkgrp [ Functions ]
[ Top ] [ m_symtk ] [ Functions ]
NAME
chkgrp
FUNCTION
Checks that a set of input symmetries constitutes a group.
INPUTS
nsym = number of symmetry operations symafm = (anti)ferromagnetic part of symmetry operations symrel = 3D matrix containg symmetry operations
OUTPUT
ierr=Status error.
TODO
SHOULD ALSO CHECK THE tnons !
SOURCE
286 subroutine chkgrp(nsym, symafm, symrel, ierr) 287 288 !Arguments ------------------------------------ 289 !scalars 290 integer,intent(in) :: nsym 291 integer,intent(out) :: ierr 292 !arrays 293 integer,intent(in) :: symafm(nsym),symrel(3,3,nsym) 294 295 !Local variables------------------------------- 296 !scalars 297 integer :: isym, jsym, ksym, symafmchk, testeq, print_warning 298 logical :: found_inv 299 character(len=500) :: msg 300 !arrays 301 integer :: chk(3,3) 302 303 ! ************************************************************************* 304 305 !DEBUG 306 !write(std_out,*)' chkgrp : enter' 307 !write(std_out,*)' isym symrel symafm ' 308 !do isym=1,nsym 309 !write(std_out,'(i3,a,9i3,a,i3)' )isym,' ',symrel(:,:,isym),' ',symafm(isym) 310 !end do 311 !ENDDEBUG 312 313 ierr = 0 314 print_warning = 1 315 316 ! 1) Identity must be the first symmetry. 317 if (ANY(symrel(:,:,1) /= identity_3d .or. symafm(1)/=1 )) then 318 ABI_WARNING("First operation must be the identity operator") 319 ierr = ierr + 1 320 end if 321 322 ! 2) The inverse of each element must belong to the group. 323 do isym=1,nsym 324 call mati3inv(symrel(:,:,isym), chk) 325 chk = transpose(chk) 326 found_inv = .FALSE. 327 do jsym=1,nsym 328 if (all(symrel(:,:,jsym) == chk) .and. (symafm(jsym) * symafm(isym) == 1)) then 329 found_inv = .TRUE.; EXIT 330 end if 331 end do 332 333 if (.not. found_inv) then 334 write(msg,'(a,i0,2a)')& 335 "Cannot find the inverse of symmetry operation ",isym,ch10,& 336 "Input symmetries do not form a group!" 337 ABI_WARNING(msg) 338 ierr = ierr + 1 339 end if 340 end do 341 342 ! Check closure under composition. 343 do isym=1,nsym 344 do jsym=1,nsym 345 346 ! Compute the product of the two symmetries 347 chk = MATMUL(symrel(:,:,jsym), symrel(:,:,isym)) 348 symafmchk = symafm(jsym) * symafm(isym) 349 350 ! Check that product array is one of the original symmetries. 351 do ksym=1,nsym 352 testeq = 1 353 if ( ANY(chk/=symrel(:,:,ksym) )) testeq = 0 354 #if 0 355 ! FIXME this check make v4/t26 and v4/t27 fails. 356 ! The rotational part is in the group but with different magnetic part! 357 if (symafmchk /= symafm(ksym)) testeq=0 358 #endif 359 if (testeq==1) exit ! The test is positive 360 end do 361 362 if (testeq == 0 .and. print_warning == 1) then 363 ! The test is negative 364 write(msg, '(a,2i3,a,9a)' )& 365 'Product of symmetries',isym,jsym,' is not in group.',ch10,& 366 'This indicates that the input symmetry elements',ch10,& 367 'do not possess closure under group composition.',ch10,& 368 'ABINIT might stop with an ERROR after trying to correct and making a few more checks.',ch10,& 369 'Action: check symrel, symafm and possibly atomic positions, and fix them.' 370 ABI_WARNING(msg) 371 ierr = ierr + 1 372 print_warning = 0 373 end if 374 375 end do ! jsym 376 end do ! isym 377 378 end subroutine chkgrp
m_symtk/chkorthsy [ Functions ]
[ Top ] [ m_symtk ] [ Functions ]
NAME
chkorthsy
FUNCTION
Check the orthogonality of the symmetry operations (lengths and absolute values of scalar products should be preserved)
INPUTS
gprimd(3,3)=dimensional primitive transl. for reciprocal space (bohr**-1) rmet=Real space metric. nsym=actual number of symmetries rprimd(3,3)=dimensional primitive translations for real space (bohr) symrel(3,3,1:nsym)=symmetry operations in real space in terms of primitive translations tolsym=defines the tolerance on the orthogonality, after multiplication by 2.
SIDE EFFECTS
iexit= if 0 at input, will do the check, and stop if there is a problem, return 0 if no problem if 1 at input, will always output, return 0 if no problem, -1 if there is a problem, also, suppresses printing of problem
SOURCE
744 subroutine chkorthsy(gprimd,iexit,nsym,rmet,rprimd,symrel,tolsym) 745 746 !Arguments ------------------------------------ 747 !scalars 748 integer,intent(in) :: nsym 749 integer,intent(inout) :: iexit 750 real(dp),intent(in) :: tolsym 751 !arrays 752 integer,intent(in) :: symrel(3,3,nsym) 753 real(dp),intent(in) :: gprimd(3,3),rmet(3,3),rprimd(3,3) 754 755 !Local variables------------------------------- 756 !scalars 757 integer :: ii,isym,jj 758 real(dp) :: residual,rmet2 759 character(len=500) :: msg 760 !arrays 761 real(dp) :: prods(3,3),rmet_sym(3,3),rprimd_sym(3,3) 762 763 ! ************************************************************************* 764 765 !DEBUG 766 !write(std_out,'(a,i3)') ' chkorthsy : enter, iexit= ',iexit 767 !write(std_out,'(a,i3)') ' nsym=',nsym 768 !do isym=1,nsym 769 ! write(std_out,'(9i4)')symrel(:,:,isym) 770 !enddo 771 !write(std_out, '(a)') ' Matrix rprimd :' 772 !do ii=1,3 773 ! write(std_out, '(3es16.8)')rprimd(:,ii) 774 !enddo 775 !write(std_out, '(a)') ' Matrix rmet :' 776 !do ii=1,3 777 ! write(std_out, '(3es16.8)')rmet(:,ii) 778 !enddo 779 !ENDDEBUG 780 781 rmet2=zero 782 do ii=1,3 783 do jj=1,3 784 rmet2=rmet2+rmet(ii,jj)**2 785 end do 786 end do 787 788 !Loop over all symmetry operations 789 do isym=1,nsym 790 791 !DEBUG 792 !write(std_out,'(a,a,i4)') ch10,' Check for isym=',isym 793 !ENDDEBUG 794 795 ! Compute symmetric of primitive vectors under point symmetry operations 796 do ii=1,3 797 rprimd_sym(:,ii)=symrel(1,ii,isym)*rprimd(:,1)+& 798 symrel(2,ii,isym)*rprimd(:,2)+& 799 symrel(3,ii,isym)*rprimd(:,3) 800 end do 801 802 ! If the new lattice is the same as the original one, 803 ! the lengths and angles are preserved 804 do ii=1,3 805 rmet_sym(ii,:)=rprimd_sym(1,ii)*rprimd_sym(1,:)+& 806 rprimd_sym(2,ii)*rprimd_sym(2,:)+& 807 rprimd_sym(3,ii)*rprimd_sym(3,:) 808 end do 809 810 residual=zero 811 do ii=1,3 812 do jj=1,3 813 residual=residual+(rmet_sym(ii,jj)-rmet(ii,jj))**2 814 end do 815 end do 816 817 if(sqrt(residual) > four*tolsym*sqrt(rmet2))then 818 if(iexit==0)then 819 write(std_out, '(a)') ' Matrix rprimd :' 820 do ii=1,3 821 write(std_out, '(3es16.8)')rprimd(:,ii) 822 enddo 823 write(std_out, '(a)') ' Matrix rmet :' 824 do ii=1,3 825 write(std_out, '(3es16.8)')rmet(:,ii) 826 enddo 827 write(std_out, '(a)') ' Matrix rprimd_sym :' 828 do ii=1,3 829 write(std_out, '(3es16.8)')rprimd_sym(:,ii) 830 enddo 831 write(std_out, '(a)') ' Matrix rmet_sym :' 832 do ii=1,3 833 write(std_out, '(3es16.8)')rmet_sym(:,ii) 834 enddo 835 write(std_out, '(a)') ' Matrix rmet_sym-rmet :' 836 do ii=1,3 837 write(std_out, '(3es16.8)')(rmet_sym(:,ii)-rmet(:,ii)) 838 enddo 839 write(msg, '(a,i0,5a,es12.4,a,es12.4,6a)' )& 840 'The symmetry operation number ',isym,' does not preserve',ch10,& 841 'vector lengths and angles.',ch10,& 842 'The value of the square root of residual is: ',sqrt(residual),& 843 & ' that is greater than threshold:', four*tolsym*sqrt(rmet2),ch10,& 844 'Action: modify rprim, acell and/or symrel so that',ch10,& 845 'vector lengths and angles are preserved.',ch10,& 846 'Beware, the tolerance on symmetry operations is very small.' 847 ABI_ERROR(msg) 848 else 849 iexit=-1 850 end if 851 end if 852 853 ! Also, the scalar product of rprimd_sym and gprimd must give integer numbers 854 do ii=1,3 855 prods(ii,:)=rprimd_sym(1,ii)*gprimd(1,:)+ & 856 rprimd_sym(2,ii)*gprimd(2,:)+ & 857 rprimd_sym(3,ii)*gprimd(3,:) 858 end do 859 860 do ii=1,3 861 do jj=1,3 862 residual=prods(ii,jj)-anint(prods(ii,jj)) 863 if(abs(residual)>two*tolsym)then 864 if(iexit==0)then 865 write(msg, '(a,i0,5a,es12.4,a,es12.4,4a)' )& 866 'The symmetry operation number ',isym,' generates',ch10,& 867 'a different lattice.',ch10,& 868 'The value of the residual is: ',residual, 'that is greater than the threshold:', two*tolsym, ch10,& 869 'Action: modify rprim, acell and/or symrel so that',ch10,& 870 'the lattice is preserved.' 871 ABI_ERROR(msg) 872 else 873 iexit=-1 874 end if 875 end if 876 end do 877 end do 878 879 if(iexit==-1) exit 880 end do ! isym 881 882 if(iexit==1)iexit=0 883 884 !DEBUG 885 !write(std_out,'(a)') ' chkorthsy : exit ' 886 !ENDDEBUG 887 888 end subroutine chkorthsy
m_symtk/chkprimit [ Functions ]
[ Top ] [ m_symtk ] [ Functions ]
NAME
chkprimit
FUNCTION
Check whether the cell is primitive or not. If chkprim/=0 and the cell is non-primitive, stops.
INPUTS
chkprim= if non-zero, check that the unit cell is primitive. nsym=actual number of symmetries symafm(nsym)= (anti)ferromagnetic part of symmetry operations symrel(3,3,nsym)= nsym symmetry operations in real space in terms of primitive translations
OUTPUT
multi=multiplicity of the unit cell translation(nsym)= (optional) set to 1 if the symetry operation is a pure translation
SOURCE
912 subroutine chkprimit(chkprim, multi, nsym, symafm, symrel, is_translation) 913 914 !Arguments ------------------------------------ 915 !scalars 916 integer,intent(in) :: chkprim,nsym 917 integer,intent(out) :: multi 918 !arrays 919 integer,intent(in) :: symafm(nsym),symrel(3,3,nsym) 920 integer,intent(out),optional :: is_translation(nsym) 921 922 !Local variables------------------------------- 923 !scalars 924 integer :: isym 925 character(len=500) :: msg 926 927 !************************************************************************** 928 929 if(present(is_translation))then 930 is_translation(:)=0 931 endif 932 933 !Loop over each symmetry operation of the Bravais lattice 934 !Find whether it is the identity, or a pure translation, 935 !without change of sign of the spin 936 multi=0 937 do isym=1,nsym 938 if( abs(symrel(1,1,isym)-1)+& 939 & abs(symrel(2,2,isym)-1)+& 940 & abs(symrel(3,3,isym)-1)+& 941 & abs(symrel(1,2,isym))+abs(symrel(2,1,isym))+& 942 & abs(symrel(2,3,isym))+abs(symrel(3,2,isym))+& 943 & abs(symrel(3,1,isym))+abs(symrel(1,3,isym))+& 944 & abs(symafm(isym)-1) == 0 )then 945 multi=multi+1 946 if(present(is_translation))then 947 is_translation(isym)=1 948 endif 949 end if 950 end do 951 952 !Check whether the cell is primitive 953 if(multi>1)then 954 if(chkprim>0)then 955 write(msg,'(a,a,a,i0,a,a,a,a,a,a,a,a,a)')& 956 'According to the symmetry finder, the unit cell is',ch10,& 957 'NOT primitive. The multiplicity is ',multi,' .',ch10,& 958 'The use of non-primitive unit cells is allowed',ch10,& 959 'only when the current chkprim is 0.',ch10,& 960 'Action: either change your unit cell (rprim or angdeg),',ch10,& 961 'or set chkprim to 0.' 962 ABI_ERROR(msg) 963 else if(chkprim==0)then 964 write(msg,'(3a,i0,a,a,a)')& 965 'According to the symmetry finder, the unit cell is',ch10,& 966 'not primitive, with multiplicity= ',multi,'.',ch10,& 967 'This is allowed, as the current chkprim is 0.' 968 ABI_COMMENT(msg) 969 end if 970 end if 971 972 end subroutine chkprimit
m_symtk/holocell [ Functions ]
[ Top ] [ m_symtk ] [ Functions ]
NAME
holocell
FUNCTION
Examine whether the trial conventional cell described by cell_base is coherent with the required holohedral group. Possibly enforce the holohedry and modify the basis vectors. Note: for iholohedry=4, the tetragonal axis is not required to be along the C axis.
INPUTS
enforce= if 0, only check; if =1, enforce exactly the holohedry iholohedry=required holohegral group (uses its absolute value, since when the multiplicity of the cell is more than one, the sign of iholohedry is changed). 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 tolsym=tolerance for the symmetry operations
OUTPUT
foundc=1 if the basis vectors supports the required holohedry ; =0 otherwise
SIDE EFFECTS
cell_base(3,3)=basis vectors of the conventional cell (changed if enforce==1, otherwise unchanged)
SOURCE
1371 subroutine holocell(cell_base,enforce,foundc,iholohedry,tolsym) 1372 1373 !Arguments ------------------------------------ 1374 !scalars 1375 integer,intent(in) :: enforce,iholohedry 1376 integer,intent(out) :: foundc 1377 real(dp),intent(in) :: tolsym 1378 !arrays 1379 real(dp),intent(inout) :: cell_base(3,3) 1380 1381 !Local variables ------------------------------ 1382 !scalars 1383 integer :: allequal,ii,orth 1384 real(dp):: aa,scprod1 1385 character(len=500) :: msg 1386 !arrays 1387 integer :: ang90(3),equal(3) 1388 real(dp) :: length(3),metric(3,3),norm(3),rbasis(3,3),rconv(3,3),rconv_new(3,3) 1389 real(dp) :: rnormalized(3,3),symmetrized_length(3) 1390 1391 !************************************************************************** 1392 1393 if(abs(iholohedry)<1 .or. abs(iholohedry)>7)then 1394 write(msg, '(a,i0)' )& 1395 & 'Abs(iholohedry) should be between 1 and 7, while iholohedry=',iholohedry 1396 ABI_BUG(msg) 1397 end if 1398 1399 do ii=1,3 1400 metric(:,ii)=cell_base(1,:)*cell_base(1,ii)+& 1401 & cell_base(2,:)*cell_base(2,ii)+& 1402 & cell_base(3,:)*cell_base(3,ii) 1403 end do 1404 1405 !Examine the angles and vector lengths 1406 ang90(:)=0 1407 if(metric(1,2)**2<tolsym**2*metric(1,1)*metric(2,2))ang90(3)=1 1408 if(metric(1,3)**2<tolsym**2*metric(1,1)*metric(3,3))ang90(2)=1 1409 if(metric(2,3)**2<tolsym**2*metric(2,2)*metric(3,3))ang90(1)=1 1410 orth=0 1411 if(ang90(1)==1 .and. ang90(2)==1 .and. ang90(3)==1) orth=1 1412 equal(:)=0 1413 if(abs(metric(1,1)-metric(2,2))<tolsym*half*(metric(1,1)+metric(2,2)))equal(3)=1 1414 if(abs(metric(1,1)-metric(3,3))<tolsym*half*(metric(1,1)+metric(3,3)))equal(2)=1 1415 if(abs(metric(2,2)-metric(3,3))<tolsym*half*(metric(2,2)+metric(3,3)))equal(1)=1 1416 allequal=0 1417 if(equal(1)==1 .and. equal(2)==1 .and. equal(3)==1) allequal=1 1418 1419 !DEBUG 1420 !write(std_out,*)' holocell : enforce, iholohedry=',enforce, iholohedry 1421 !write(std_out,*)' holocell : ang90=',ang90 1422 !write(std_out,*)' holocell : equal=',equal 1423 !!write(std_out,*)' holocell : tolsym=',tolsym 1424 !!write(std_out,*)' holocell : metric(1,1)=',metric(1,1) 1425 !!write(std_out,*)' holocell : metric(1,2)=',metric(1,2) 1426 !ENDDEBUG 1427 1428 foundc=0 1429 if(abs(iholohedry)==1) foundc=1 1430 if(abs(iholohedry)==2 .and. ang90(1)+ang90(3)==2 ) foundc=1 1431 if(abs(iholohedry)==3 .and. orth==1) foundc=1 1432 if(abs(iholohedry)==4 .and. orth==1 .and. & 1433 & (equal(3)==1 .or. equal(2)==1 .or. equal(1)==1) ) foundc=1 1434 if(abs(iholohedry)==5 .and. allequal==1 .and. & 1435 & (abs(metric(1,2)-metric(2,3))<tolsym*metric(2,2)) .and. & 1436 & (abs(metric(1,2)-metric(1,3))<tolsym*metric(1,1)) ) foundc=1 1437 if(abs(iholohedry)==6 .and. equal(3)==1 .and. & 1438 & ang90(1)==1 .and. ang90(2)==1 .and. & 1439 & abs(2*metric(1,2)+metric(1,1))<tolsym*metric(1,1) ) foundc=1 1440 if(abs(iholohedry)==7 .and. orth==1 .and. allequal==1) foundc=1 1441 1442 !DEBUG 1443 !write(std_out, '(a,2i4)' )' holocell : foundc, enforce=',foundc,enforce 1444 !ENDDEBUG 1445 1446 !------------------------------------------------------------------------------------- 1447 !Possibly enforce the holohedry (if it is to be enforced !) 1448 1449 if(foundc==0.and.enforce==1.and.abs(iholohedry)/=1)then 1450 1451 ! Copy the cell_base vectors, and possibly fix the tetragonal axis to be the c-axis 1452 ! XG20201016 WARNING : in principle, one should NOT use the 'equal' information, since precisely this enforcement 1453 ! has the aim to reinstall the symmetries while they are broken !! 1454 if(abs(iholohedry)==4.and.equal(1)==1)then 1455 rconv(:,3)=cell_base(:,1) ; rconv(:,1)=cell_base(:,2) ; rconv(:,2)=cell_base(:,3) 1456 else if (abs(iholohedry)==4.and.equal(2)==1)then 1457 rconv(:,3)=cell_base(:,2) ; rconv(:,2)=cell_base(:,1) ; rconv(:,1)=cell_base(:,3) 1458 else 1459 rconv(:,:)=cell_base(:,:) 1460 end if 1461 1462 ! Compute the length of the three conventional vectors 1463 length(1)=sqrt(sum(rconv(:,1)**2)) 1464 length(2)=sqrt(sum(rconv(:,2)**2)) 1465 length(3)=sqrt(sum(rconv(:,3)**2)) 1466 1467 ! Take care of the first conventional vector aligned with rbasis(:,3) (or aligned with the trigonal axis if rhombohedral) 1468 ! and choice of the first normalized direction 1469 if(abs(iholohedry)==5)then 1470 rbasis(:,3)=third*(rconv(:,1)+rconv(:,2)+rconv(:,3)) 1471 else 1472 rbasis(:,3)=rconv(:,3) 1473 end if 1474 norm(3)=sqrt(sum(rbasis(:,3)**2)) 1475 rnormalized(:,3)=rbasis(:,3)/norm(3) 1476 1477 ! Projection of the first conventional vector perpendicular to rbasis(:,3) 1478 ! and choice of the first normalized direction 1479 scprod1=sum(rnormalized(:,3)*rconv(:,1)) 1480 rbasis(:,1)=rconv(:,1)-rnormalized(:,3)*scprod1 1481 norm(1)=sqrt(sum(rbasis(:,1)**2)) 1482 rnormalized(:,1)=rbasis(:,1)/norm(1) 1483 1484 ! Generation of the second vector, perpendicular to the third and first 1485 rnormalized(1,2)=rnormalized(2,3)*rnormalized(3,1)-rnormalized(3,3)*rnormalized(2,1) 1486 rnormalized(2,2)=rnormalized(3,3)*rnormalized(1,1)-rnormalized(1,3)*rnormalized(3,1) 1487 rnormalized(3,2)=rnormalized(1,3)*rnormalized(2,1)-rnormalized(2,3)*rnormalized(1,1) 1488 1489 ! Compute the vectors of the conventional cell, on the basis of iholohedry 1490 if(abs(iholohedry)==2)then 1491 rconv_new(:,3)=rconv(:,3) 1492 rconv_new(:,1)=rconv(:,1) 1493 rconv_new(:,2)=rnormalized(:,2)*length(2) ! Now, the y axis is perpendicular to the two others, that have not been changed 1494 else if(abs(iholohedry)==3.or.abs(iholohedry)==4.or.abs(iholohedry)==7)then 1495 if(abs(iholohedry)==7)then 1496 symmetrized_length(1:3)=sum(length(:))*third 1497 else if(abs(iholohedry)==4)then 1498 symmetrized_length(3)=length(3) 1499 symmetrized_length(1:2)=half*(length(1)+length(2)) 1500 else if(abs(iholohedry)==3)then 1501 symmetrized_length(:)=length(:) 1502 end if 1503 do ii=1,3 1504 rconv_new(:,ii)=rnormalized(:,ii)*symmetrized_length(ii) 1505 end do 1506 else if(abs(iholohedry)==5)then 1507 ! In the normalized basis, they have coordinates (a,0,c), and (-a/2,+-sqrt(3)/2*a,c) 1508 ! c is known, but a is computed from the knowledge of the average length of the initial vectors 1509 aa=sqrt(sum(length(:)**2)*third-norm(3)**2) 1510 rconv_new(:,1)=aa*rnormalized(:,1)+rbasis(:,3) 1511 rconv_new(:,2)=aa*half*(-rnormalized(:,1)+sqrt(three)*rnormalized(:,2))+rbasis(:,3) 1512 rconv_new(:,3)=aa*half*(-rnormalized(:,1)-sqrt(three)*rnormalized(:,2))+rbasis(:,3) 1513 else if(abs(iholohedry)==6)then 1514 1515 ! In the normalized basis, they have coordinates (a,0,0), (-a/2,+-sqrt(3)/2*a,0), and (0,0,c) 1516 ! c is known, but a is computed from the knowledge of the average length of the initial vectors 1517 aa=half*(length(1)+length(2)) 1518 rconv_new(:,1)=aa*rnormalized(:,1) 1519 rconv_new(:,2)=aa*half*(-rnormalized(:,1)+sqrt(three)*rnormalized(:,2)) 1520 rconv_new(:,3)=rconv(:,3) 1521 end if 1522 1523 ! Copy back the cell_base vectors 1524 if(abs(iholohedry)==4.and.equal(1)==1)then 1525 cell_base(:,3)=rconv_new(:,2) ; cell_base(:,2)=rconv_new(:,1) ; cell_base(:,1)=rconv_new(:,3) 1526 else if (abs(iholohedry)==4.and.equal(2)==1)then 1527 cell_base(:,3)=rconv_new(:,1) ; cell_base(:,1)=rconv_new(:,2) ; cell_base(:,2)=rconv_new(:,3) 1528 else 1529 cell_base(:,:)=rconv_new(:,:) 1530 end if 1531 1532 end if 1533 1534 end subroutine holocell
m_symtk/littlegroup_q [ Functions ]
[ Top ] [ m_symtk ] [ Functions ]
NAME
littlegroup_q
FUNCTION
Determines the symmetry operations by which reciprocal vector q is preserved, modulo a primitive reciprocal lattice vector, and the time-reversal symmetry.
INPUTS
nsym=number of space group symmetries qpt(3)= vector in reciprocal space symrec(3,3,nsym)=3x3 matrices of the group symmetries (reciprocal space) [prtvol]=integer flag defining the verbosity of output. =0 if no output is provided. prtgkk= integer flag. If 1 provide output of electron-phonon "gkk" matrix elements, for further treatment by mrggkk utility or anaddb utility. If 0 no output is provided.
OUTPUT
symq(4,2,nsym)= three first numbers define the G vector; fourth number is zero if the q-vector is not preserved, 1 otherwise second index is one without time-reversal symmetry, two with time-reversal symmetry timrev=1 if the time-reversal symmetry preserves the wavevector, modulo a reciprocal lattice vector (in principle, see below).
NOTES
The condition is: $q = O S(q) - G$ with O being either the identity or the time reversal symmetry (= inversion in reciprocal space) and G being a primitive vector of the reciprocal lattice. If the time-reversal (alone) also preserves q, modulo a lattice vector, then timrev is set to 1, otherwise 0.
TODO
timrev is put to 1 only for Gamma. Better handling should be provided in further version.
SOURCE
1123 subroutine littlegroup_q(nsym,qpt,symq,symrec,symafm,timrev,prtvol,use_sym) 1124 1125 !Arguments ------------------------------- 1126 !scalars 1127 integer,intent(in) :: nsym 1128 integer,intent(in),optional :: prtvol,use_sym 1129 integer,intent(out) :: timrev 1130 !arrays 1131 integer,intent(in) :: symrec(3,3,nsym), symafm(nsym) 1132 integer,intent(out) :: symq(4,2,nsym) 1133 real(dp),intent(in) :: qpt(3) 1134 1135 !Local variables ------------------------- 1136 !scalars 1137 integer :: ii,isign,isym,itirev,my_prtvol 1138 real(dp),parameter :: tol=2.d-8 1139 real(dp) :: reduce 1140 character(len=500) :: msg 1141 !arrays 1142 real(dp) :: difq(3),qsym(3),shift(3) 1143 1144 ! ********************************************************************* 1145 1146 my_prtvol=0; if (PRESENT(prtvol)) my_prtvol=prtvol 1147 1148 ! Initialise the array symq 1149 symq = 0 1150 1151 isym = symafm(1) ! just to fool abirules and use symafm for the moment 1152 1153 do isym=1,nsym 1154 ! if (symafm(isym) /= 1) cycle ! skip afm symops 1155 ! TODO: check how much of the afm syms are coded in the rf part of the code. cf 1156 ! test v3 / 12 1157 do itirev=1,2 1158 isign=3-2*itirev ! isign is 1 without time-reversal, -1 with time-reversal 1159 1160 ! Get the symmetric of the vector 1161 do ii=1,3 1162 qsym(ii)=qpt(1)*isign*symrec(ii,1,isym)& 1163 +qpt(2)*isign*symrec(ii,2,isym)& 1164 +qpt(3)*isign*symrec(ii,3,isym) 1165 end do 1166 1167 ! Get the difference between the symmetric and the original vector 1168 symq(4,itirev,isym)=1 1169 do ii=1,3 1170 difq(ii)=qsym(ii)-qpt(ii) 1171 ! Project modulo 1 in the interval ]-1/2,1/2] such that difq = reduce + shift 1172 call wrap2_pmhalf(difq(ii),reduce,shift(ii)) 1173 if(abs(reduce)>tol)symq(4,itirev,isym)=0 1174 end do 1175 1176 ! SP: When prtgkk is asked (GKK matrix element will be output), one has to 1177 ! disable symmetries. There is otherwise a gauge problem with the unperturbed 1178 ! and the perturbed wavefunctions. This leads to a +- 5% increase in computational 1179 ! cost but provide the correct GKKs (i.e. the same as without the use of symmetries.) 1180 1181 if (PRESENT(use_sym)) then 1182 if (use_sym == 0) then 1183 symq(4,itirev,isym)=0 1184 symq(4,itirev,1)=1 1185 end if 1186 end if 1187 1188 ! If the operation succeded, change shift from real(dp) to integer, then exit loop 1189 if(symq(4,itirev,isym)/=0)then 1190 if (my_prtvol>0) then 1191 if(itirev==1)write(msg,'(a,i4,a)')' littlegroup_q : found symmetry',isym,' preserves q ' 1192 if(itirev==2)write(msg,'(a,i4,a)')' littlegroup_q : found symmetry ',isym,' + TimeReversal preserves q ' 1193 call wrtout(std_out,msg) 1194 end if 1195 ! Uses the mathematical function NINT = nearest integer 1196 do ii=1,3 1197 symq(ii,itirev,isym)=nint(shift(ii)) 1198 end do 1199 end if 1200 1201 end do !itirev 1202 end do !isym 1203 1204 ! Test time-reversal symmetry 1205 timrev=1 1206 do ii=1,3 1207 ! Unfortunately, this version does not work yet ... 1208 ! call wrap2_pmhalf(2*qpt(ii),reduce,shift(ii)) 1209 ! if(abs(reduce)>tol)timrev=0 1210 ! So, this is left ... 1211 if(abs(qpt(ii))>tol)timrev=0 1212 end do 1213 1214 if(timrev==1.and.my_prtvol>0)then 1215 write(msg, '(3a)' )& 1216 ' littlegroup_q: able to use time-reversal symmetry. ',ch10,& 1217 ' (except for gamma, not yet able to use time-reversal symmetry)' 1218 call wrtout(std_out,msg) 1219 end if 1220 1221 end subroutine littlegroup_q
m_symtk/mati3det [ Functions ]
[ Top ] [ m_symtk ] [ Functions ]
NAME
mati3det
FUNCTION
Compute the determinant of a 3x3 matrix of INTEGER elements.
INPUTS
mm = integer matrix
OUTPUT
det = determinant of the matrix
SOURCE
144 subroutine mati3det(mm, det) 145 146 !Arguments ------------------------------------ 147 !arrays 148 integer,intent(in) :: mm(3,3) 149 integer,intent(out) :: det 150 151 ! ************************************************************************* 152 det=mm(1,1)*(mm(2,2) * mm(3,3) - mm(3,2) * mm(2,3)) & 153 + mm(2,1)*(mm(3,2) * mm(1,3) - mm(1,2) * mm(3,3)) & 154 + mm(3,1)*(mm(1,2) * mm(2,3) - mm(2,2) * mm(1,3)) 155 156 end subroutine mati3det
m_symtk/mati3inv [ Functions ]
[ Top ] [ m_symtk ] [ Functions ]
NAME
mati3inv
FUNCTION
Invert and transpose orthogonal 3x3 matrix of INTEGER elements.
INPUTS
mm = integer matrix to be inverted
OUTPUT
mit = inverse of mm input matrix
NOTES
Used for symmetry operations. This routine applies to ORTHOGONAL matrices only. Since these form a group, inverses are also integer arrays. Returned array is TRANSPOSE of inverse, as needed. Note use of integer arithmetic.
SOURCE
85 subroutine mati3inv(mm, mit) 86 87 !Arguments ------------------------------------ 88 !arrays 89 integer,intent(in) :: mm(3,3) 90 integer,intent(out) :: mit(3,3) 91 92 !Local variables------------------------------- 93 !scalars 94 integer :: dd 95 character(len=500) :: msg 96 !arrays 97 integer :: tt(3,3) 98 99 ! ************************************************************************* 100 101 tt(1,1) = mm(2,2) * mm(3,3) - mm(3,2) * mm(2,3) 102 tt(2,1) = mm(3,2) * mm(1,3) - mm(1,2) * mm(3,3) 103 tt(3,1) = mm(1,2) * mm(2,3) - mm(2,2) * mm(1,3) 104 tt(1,2) = mm(3,1) * mm(2,3) - mm(2,1) * mm(3,3) 105 tt(2,2) = mm(1,1) * mm(3,3) - mm(3,1) * mm(1,3) 106 tt(3,2) = mm(2,1) * mm(1,3) - mm(1,1) * mm(2,3) 107 tt(1,3) = mm(2,1) * mm(3,2) - mm(3,1) * mm(2,2) 108 tt(2,3) = mm(3,1) * mm(1,2) - mm(1,1) * mm(3,2) 109 tt(3,3) = mm(1,1) * mm(2,2) - mm(2,1) * mm(1,2) 110 dd = mm(1,1) * tt(1,1) + mm(2,1) * tt(2,1) + mm(3,1) * tt(3,1) 111 112 ! Make sure matrix is not singular 113 if (dd /= 0) then 114 mit(:,:)=tt(:,:)/dd 115 else 116 write(msg, '(2a,2x,9(i0,1x),a)' )'Attempting to invert integer array',ch10,mm,' ==> determinant is zero.' 117 ABI_ERROR(msg) 118 end if 119 120 ! If matrix is orthogonal, determinant must be 1 or -1 121 if (abs(dd) /= 1) then 122 write(msg, '(3a,i0)' )'Absolute value of determinant should be one',ch10,'but determinant= ',dd 123 ABI_ERROR(msg) 124 end if 125 126 end subroutine mati3inv
m_symtk/matpointsym [ Functions ]
[ Top ] [ m_symtk ] [ Functions ]
NAME
matpointsym
FUNCTION
For given order of point group, symmetrizes a 3x3 input matrix using the point symmetry of the input atom
INPUTS
iatom=index of atom to symmetrize around natom=number of atoms in cell nsym=order of group rprimd(3,3)= real space primitive vectors symrel(3,3,nsym)=symmetry operators in terms of action on primitive translations tnons(3,nsym) = nonsymmorphic translations xred(3,natom)=locations of atoms in reduced coordinates
OUTPUT
SIDE EFFECTS
mat3(3,3) = matrix to be symmetrized, in cartesian frame
SOURCE
1248 subroutine matpointsym(iatom,mat3,natom,nsym,rprimd,symrel,tnons,xred) 1249 1250 use m_linalg_interfaces 1251 1252 !Arguments ------------------------------------ 1253 !scalars 1254 integer,intent(in) :: iatom,natom,nsym 1255 !arrays 1256 integer,intent(in) :: symrel(3,3,nsym) 1257 real(dp),intent(in) :: rprimd(3,3),tnons(3,nsym),xred(3,natom) 1258 real(dp),intent(inout) :: mat3(3,3) 1259 1260 !Local variables------------------------------- 1261 !scalars 1262 integer :: cell_index,cell_indexp,ii,isym,nsym_point 1263 real(dp) :: xreddiff 1264 !arrays 1265 integer :: symrel_it(3,3) 1266 real(dp) :: mat3_tri(3,3),mat3_tri_sym(3,3),rprimd_inv(3,3),tmp_mat(3,3) 1267 real(dp) :: xredp(3) 1268 1269 !************************************************************************** 1270 1271 !copy rprimd input and construct inverse 1272 rprimd_inv = rprimd 1273 call matrginv(rprimd_inv,3,3) 1274 1275 !transform input mat3 to triclinic frame with rprimd^{-1} * mat3 * rprimd 1276 call dgemm('N','N',3,3,3,one,rprimd_inv,3,mat3,3,zero,tmp_mat,3) 1277 call dgemm('N','N',3,3,3,one,tmp_mat,3,rprimd,3,zero,mat3_tri,3) 1278 1279 !loop over symmetry elements to obtain symmetrized input matrix 1280 mat3_tri_sym = zero 1281 nsym_point = 0 1282 do isym = 1, nsym 1283 1284 ! skip any nonsymmorphic symmetry elements, want to consider point elements only 1285 if(dot_product(tnons(:,isym),tnons(:,isym))>tol8) cycle 1286 1287 ! for current symmetry element, find transformed reduced coordinates of target atom 1288 ! via xredp = symrel * xred 1289 call dgemv('N',3,3,one,dble(symrel(:,:,isym)),3,xred(:,iatom),1,zero,xredp,1) 1290 1291 1292 ! shift xredp into the same unit cell as xred, for comparison 1293 ! label cells as 0..1:0 1..2:1 2..3:2 and -1..0:-1 -2..-1:-2 and so forth 1294 do ii = 1, 3 1295 1296 cell_index = int(xred(ii,iatom)) 1297 if(xred(ii,iatom) < zero) cell_index = cell_index - 1 1298 cell_indexp = int(xredp(ii)) 1299 if(xredp(ii) < zero) cell_indexp = cell_indexp - 1 1300 1301 do while (cell_indexp < cell_index) 1302 xredp(ii) = xredp(ii)+one 1303 cell_indexp = cell_indexp + 1 1304 end do 1305 do while (cell_indexp > cell_index) 1306 xredp(ii) = xredp(ii)-one 1307 cell_indexp = cell_indexp - 1 1308 end do 1309 1310 end do 1311 1312 ! now compare xredp to xred 1313 xreddiff = dot_product(xredp-xred(:,iatom),xredp-xred(:,iatom)) 1314 1315 if (xreddiff < tol8) then 1316 1317 ! accumulate symrel^{-1}*mat3_tri*symrel into mat3_tri_sym iff xredp = xred + L, 1318 ! where is a lattice vector, so symrel leaves the target atom invariant 1319 1320 ! mati3inv gives the inverse transpose of symrel 1321 call mati3inv(symrel(:,:,isym),symrel_it) 1322 call dgemm('N','N',3,3,3,one,mat3_tri,3,dble(symrel(:,:,isym)),3,zero,tmp_mat,3) 1323 call dgemm('T','N',3,3,3,one,dble(symrel_it),3,tmp_mat,3,one,mat3_tri_sym,3) 1324 nsym_point = nsym_point + 1 1325 end if 1326 1327 end do 1328 1329 !normalize by number of point symmetry operations 1330 mat3_tri_sym = mat3_tri_sym/dble(nsym_point) 1331 1332 !transform mat3_tri_sym to cartesian frame with rprimd * mat3_tri_sym * rprimd^{-1} 1333 1334 call dgemm('N','N',3,3,3,one,mat3_tri_sym,3,rprimd_inv,3,zero,tmp_mat,3) 1335 call dgemm('N','N',3,3,3,one,rprimd,3,tmp_mat,3,zero,mat3,3) 1336 1337 end subroutine matpointsym
m_symtk/matr3inv [ Functions ]
[ Top ] [ m_symtk ] [ Functions ]
NAME
matr3inv
FUNCTION
Invert and transpose general 3x3 matrix of real*8 elements.
INPUTS
aa = 3x3 matrix to be inverted
OUTPUT
ait = inverse of aa input matrix
NOTES
Returned array is TRANSPOSE of inverse, as needed to get g from r.
SOURCE
177 subroutine matr3inv(aa, ait) 178 179 !Arguments ------------------------------------ 180 !arrays 181 real(dp),intent(in) :: aa(3,3) 182 real(dp),intent(out) :: ait(3,3) 183 184 !Local variables------------------------------- 185 !scalars 186 real(dp) :: dd,det,t1,t2,t3 187 character(len=500) :: msg 188 189 ! ************************************************************************* 190 191 t1 = aa(2,2) * aa(3,3) - aa(3,2) * aa(2,3) 192 t2 = aa(3,2) * aa(1,3) - aa(1,2) * aa(3,3) 193 t3 = aa(1,2) * aa(2,3) - aa(2,2) * aa(1,3) 194 det = aa(1,1) * t1 + aa(2,1) * t2 + aa(3,1) * t3 195 196 !Make sure matrix is not singular 197 if (abs(det)>tol16) then 198 dd=one/det 199 else 200 write(msg, '(2a,2x,9es16.8,a,a,es16.8,a)' )& 201 'Attempting to invert real(8) 3x3 array',ch10,aa(:,:),ch10,' ==> determinant=',det,' is zero.' 202 ABI_BUG(msg) 203 end if 204 205 ait(1,1) = t1 * dd 206 ait(2,1) = t2 * dd 207 ait(3,1) = t3 * dd 208 ait(1,2) = (aa(3,1)*aa(2,3)-aa(2,1)*aa(3,3)) * dd 209 ait(2,2) = (aa(1,1)*aa(3,3)-aa(3,1)*aa(1,3)) * dd 210 ait(3,2) = (aa(2,1)*aa(1,3)-aa(1,1)*aa(2,3)) * dd 211 ait(1,3) = (aa(2,1)*aa(3,2)-aa(3,1)*aa(2,2)) * dd 212 ait(2,3) = (aa(3,1)*aa(1,2)-aa(1,1)*aa(3,2)) * dd 213 ait(3,3) = (aa(1,1)*aa(2,2)-aa(2,1)*aa(1,2)) * dd 214 215 end subroutine matr3inv
m_symtk/print_symmetries [ Functions ]
[ Top ] [ m_symtk ] [ Functions ]
NAME
print_symmetries
FUNCTION
Helper function to print the set of symmetries.
INPUTS
OUTPUT
SOURCE
3421 subroutine print_symmetries(nsym, symrel, tnons, symafm, unit, mode_paral) 3422 3423 !Arguments ------------------------------------ 3424 !scalars 3425 integer,intent(in) :: nsym 3426 integer,optional,intent(in) :: unit 3427 character(len=4),optional,intent(in) :: mode_paral 3428 !arrays 3429 integer,intent(in) :: symrel(3,3,nsym),symafm(nsym) 3430 real(dp),intent(in) :: tnons(3,nsym) 3431 3432 !Local variables------------------------------- 3433 integer :: my_unt,isym,isymin,isymend,ii,jj 3434 character(len=500) :: msg 3435 character(len=4) :: my_mode 3436 ! ********************************************************************* 3437 3438 my_unt =std_out; if (PRESENT(unit )) my_unt =unit 3439 my_mode='COLL' ; if (PRESENT(mode_paral)) my_mode=mode_paral 3440 3441 !write(msg,'(2a)')ch10,' Rotations Translations Symafm ' 3442 !do isym=1,nsym 3443 ! write(msg,'(1x,3(3i3,1x),4x,3(f11.7,1x),6x,i2)')symrel(:,:,isym),tnons(:,isym),symafm(isym) 3444 ! call wrtout(my_unt,msg,my_mode) 3445 !end do 3446 3447 write(msg,'(2a)')ch10,' Symmetry operations in real space (Rotation tnons AFM)' 3448 call wrtout(my_unt,msg,my_mode) 3449 do isymin=1,nsym,4 3450 isymend=isymin+3 3451 if (isymend>nsym) isymend=nsym 3452 do ii=1,3 3453 write(msg,'(4(3i3,f11.6,i3,3x))')((symrel(ii,jj,isym),jj=1,3),tnons(ii,isym),symafm(isym),isym=isymin,isymend) 3454 call wrtout(my_unt,msg,my_mode) 3455 end do 3456 write(msg,'(a)')ch10 3457 call wrtout(my_unt,msg,my_mode) 3458 end do 3459 3460 end subroutine print_symmetries
m_symtk/sg_multable [ Functions ]
[ Top ] [ m_symtk ] [ Functions ]
NAME
sg_multable
FUNCTION
Checks that a set of input symmetries constitutes a group. Treat reasonably well large set of symmetries, where pure translations are present. The translations are optional. This allows to test symrec.
INPUTS
nsym=number of symmetry operations symafm(nsym)=(anti)ferromagnetic part of symmetry operations symrel(3,3,nsym)=symmetry operations in real space. tnons(3,nsym) [optional]=Fractional translations. tnons_tol [optional]= tolerance on the match for tnons
OUTPUT
ierr=Status error. A non-zero value signals failure. [multable(4,nsym,nsym)]= Optional output. multable(1,sym1,sym2) gives the index of the symmetry product S1 * S2 in the symrel array. 0 if not found. multable(2:4,sym1,sym2)= the lattice vector that has to added to the fractional translation of the operation of index multable(1,sym1,sym2) to obtain the fractional translation of the product S1 * S2. [toinv(4,nsym)]= Optional output. toinv(1,sym1)=Gives the index of the inverse of the symmetry operation. S1 * S1^{-1} = {E, L} with E the identity and L a real-space lattice vector. toinv(2:4,sym1)=The lattice vector L Note that toinv can be easily obtained from multable but sometimes we do not need the full table.
TODO
This improved version should replace chkgrp.
SOURCE
414 subroutine sg_multable(nsym, symafm, symrel, ierr, & 415 & tnons, tnons_tol, multable, toinv) ! optional 416 417 !Arguments ------------------------------------ 418 !scalars 419 integer,intent(in) :: nsym 420 integer,intent(out) :: ierr 421 real(dp),optional,intent(in) :: tnons_tol 422 !arrays 423 integer,intent(in) :: symafm(nsym),symrel(3,3,nsym) 424 integer,optional,intent(out) :: multable(4,nsym,nsym), toinv(4,nsym) 425 real(dp),optional,intent(in) :: tnons(3,nsym) 426 427 !Local variables------------------------------- 428 !scalars 429 integer :: echo,found,ilist_symrel,nptsymm,prd_symafm,prd_ptsymm,ptsymm1,ptsymm2,ptsymm3 430 integer :: sym1,sym2,sym3 431 !integer :: isym 432 real(dp) :: tnons_tol_ 433 logical :: found_inv,iseq 434 character(len=500) :: msg 435 !arrays 436 integer :: nlist_symrel(48),prd_symrel(3,3),ptmultable(48,48),ptsymrel(3,3,48) 437 integer,allocatable :: ptsymm(:),list_symrel(:,:) 438 real(dp) :: prd_tnons(3) 439 real(dp),allocatable :: tnons_(:,:) 440 441 ! ************************************************************************* 442 443 !DEBUG 444 !write(std_out,*)' m_symtk%sg_multable : enter, nsym= ',nsym 445 !ENDDEBUG 446 447 ierr = 0 448 449 ABI_MALLOC(tnons_,(3,nsym)) 450 if(present(tnons))then 451 tnons_=tnons 452 else 453 tnons_=zero 454 endif 455 if(present(tnons_tol))then 456 tnons_tol_=tnons_tol 457 else 458 tnons_tol_=tol5 459 endif 460 461 ! 1) Identity must be the first symmetry. Do not check if tnons_ == 0 as cell might not be primitive. 462 if (any(symrel(:,:,1) /= identity_3d .or. symafm(1) /= 1)) then 463 ABI_WARNING("First operation must be the identity operator") 464 ierr = ierr + 1 465 end if 466 467 ! 2) The inverse of each element must belong to the group. 468 echo = 1 469 do sym1=1,nsym 470 found_inv = .FALSE. 471 do sym2=1,nsym 472 prd_symrel = matmul(symrel(:,:,sym1), symrel(:,:,sym2)) 473 prd_tnons = tnons_(:,sym1) + matmul(symrel(:,:,sym1), tnons_(:,sym2)) 474 prd_symafm = symafm(sym1)*symafm(sym2) 475 if ( all(prd_symrel == identity_3d) .and. isinteger(prd_tnons, tnons_tol_) .and. prd_symafm == 1 ) then 476 found_inv = .TRUE. 477 if (present(toinv)) then 478 toinv(1, sym1) = sym2; toinv(2:4, sym1) = nint(prd_tnons) 479 end if 480 exit 481 end if 482 end do 483 484 if (.not. found_inv) then 485 if(echo == 1) then 486 write(msg,'(a,i0,2a)')& 487 "Cannot find the inverse of symmetry operation ",sym1,ch10,& 488 "Input symmetries do not form a group " 489 ABI_WARNING(msg) 490 echo = 0 491 endif 492 ierr = ierr + 1 493 exit 494 end if 495 end do 496 497 ! 3) 498 !In order to avoid potential cubic scaling with number of atoms, in exotic cases, with large prefactor, 499 !set up lookup table for the point symmetry part of the symmetry operations. 500 !Still cubic, but with a reduced prefactor. To fully eliminate cubic scaling, should 501 !set up lookup table for the tnons_ as well. 502 503 ABI_MALLOC(list_symrel,(nsym,48)) 504 ABI_MALLOC(ptsymm,(nsym)) 505 506 nlist_symrel(:)=0 507 ! Initialize with the first symmetry operation 508 ptsymrel(1:3,1:3,1)=symrel(:,:,1) 509 ptsymm(1)=1 510 nptsymm=1 511 list_symrel(1,1)=1 512 nlist_symrel(1)=1 513 !If more than one symmetry operation, then loop on the other ones, find whether the ptsymm has already been found, 514 !or create one new item in the list 515 if(nsym/=1)then 516 do sym1=2,nsym 517 found=0 518 do ptsymm2=1,nptsymm 519 if(all(symrel(:,:,list_symrel(1,ptsymm2)) == symrel(:,:,sym1)))then 520 ptsymm(sym1)=ptsymm2 ; found=1 521 nlist_symrel(ptsymm2)=nlist_symrel(ptsymm2)+1 522 list_symrel(nlist_symrel(ptsymm2),ptsymm2)=sym1 523 cycle 524 endif 525 enddo 526 if(found==0)then 527 nptsymm=nptsymm+1 528 !DEBUG 529 ! write(std_out,*)' current value of nptsymm, sym1=',nptsymm, sym1 530 !ENDDEBUG 531 ptsymrel(1:3,1:3,nptsymm)=symrel(:,:,sym1) 532 ptsymm(sym1)=nptsymm 533 nlist_symrel(nptsymm)=1 534 list_symrel(1,nptsymm)=sym1 535 endif 536 enddo 537 endif 538 539 !Check that each point symmetry is associated to the same number of translations 540 if(nptsymm/=1)then 541 do ptsymm1=1,nptsymm 542 if(nlist_symrel(ptsymm1)/=nlist_symrel(1))then 543 write(msg, '(9a)' )& 544 & 'The number of translations (and possibly symafm) associated to the same symrel',ch10,& 545 & 'is not the same for all point symmetries',ch10,& 546 & 'This indicates that the input symmetry elements',ch10,& 547 & 'do not possess closure under group composition.',ch10,& 548 & 'Action: check symrel, symafm and fix them.' 549 ABI_WARNING(msg) 550 echo = 0 551 ierr = ierr + 1 552 if (present(multable)) then 553 multable(1,:,:) = 0; multable(2:4,:,:) = huge(0) 554 end if 555 exit 556 endif 557 enddo 558 endif 559 560 !DEBUG 561 ! write(std_out,*)' final value of nptsymm=',nptsymm 562 !ENDDEBUG 563 564 ! 4) 565 !Check closure under composition and construct multiplication table of ptsymrel 566 echo = 1 567 do ptsymm1=1,nptsymm 568 sym1=list_symrel(1,ptsymm1) 569 do ptsymm2=1,nptsymm 570 sym2=list_symrel(1,ptsymm2) 571 ! Compute the product of the two symmetries. 572 prd_symrel = matmul(symrel(:,:,sym1), symrel(:,:,sym2)) 573 ! Check that product array is one of the original point symmetries. 574 iseq= .false. 575 do ptsymm3=1,nptsymm 576 iseq= all(prd_symrel == symrel(:,:,list_symrel(1,ptsymm3) )) 577 if(iseq)then 578 ptmultable(ptsymm1,ptsymm2) = ptsymm3 579 exit 580 endif 581 end do 582 if (.not. iseq .and. echo == 1) then 583 if (echo == 1)then 584 ! The test is negative 585 prd_symafm = symafm(sym1) * symafm(sym2) 586 prd_tnons = tnons_(:, sym1) + matmul(symrel(:,:,sym1), tnons_(:,sym2)) 587 write(msg, '(a,2(i0,1x),2a,3i3,f11.6,i3,a,2(3i3,f11.6,a),5a)' )& 588 'Product of symmetries:',sym1,sym2,' is not in group.',ch10,& 589 prd_symrel(1,1:3),prd_tnons(1),prd_symafm,ch10,& 590 prd_symrel(2,1:3),prd_tnons(2),ch10,& 591 prd_symrel(3,1:3),prd_tnons(3),ch10,& 592 'This indicates that the input symmetry elements',ch10,& 593 'do not possess closure under group composition.',ch10,& 594 'Action: check symrel, symafm and fix them.' 595 ABI_WARNING(msg) 596 echo = 0 597 endif 598 ierr = ierr + 1 599 if (present(multable)) then 600 multable(1, sym1, sym2) = 0; multable(2:4, sym1, sym2) = huge(0) 601 end if 602 exit 603 end if 604 605 end do ! ptsymm2 606 607 !DEBUG 608 ! write(std_out,*)' ptmultable for ptsymm1=',ptsymm1,' by batch of 16 values ' 609 ! write(std_out,'(16i3)')ptmultable(ptsymm1,1:16) 610 ! write(std_out,'(16i3)')ptmultable(ptsymm1,17:32) 611 ! write(std_out,'(16i3)')ptmultable(ptsymm1,33:48) 612 !ENDDEBUG 613 614 if (echo == 0) exit 615 end do ! ptsymm1 616 617 ! 5) 618 ! Check closure under composition and construct multiplication table. 619 ! However, does this only if the ptgroup has been successfull. 620 if(echo/=0 .and. ierr==0)then 621 do sym1=1,nsym 622 ptsymm1=ptsymm(sym1) 623 do sym2=1,nsym 624 ptsymm2=ptsymm(sym2) 625 626 !The equal number of translations for each point symmetry has been checked earlier. 627 !If the full table is not requested, it is now sufficient to check that 628 !the product of all symmetry operations sym1 with a pure translation (ptsymm=1), or with one of the instances 629 !for each point symmetries is indeed present in the table. 630 !This is done to save CPU time when the number of symmetry operations is bigger than 384. 631 632 if (nsym>384 .and. .not.(present(multable))) then 633 if(ptsymm2/=1 .and. sym2/=list_symrel(1,ptsymm2))then 634 cycle 635 endif 636 end if 637 638 !DEBUG 639 !if(ptsymm2<1 .or. ptsymm2>48)then 640 !write(std_out,*)' sym1,sym2,ptsymm1,ptsymm2=',sym1,sym2,ptsymm1,ptsymm2 641 !endif 642 !ENDDEBUG 643 644 ! Compute the product of the two symmetries. Convention {A,a} {B,b} = {AB, a + Ab} 645 ! prd_symrel = matmul(symrel(:,:,sym1), symrel(:,:,sym2)) 646 prd_ptsymm=ptmultable(ptsymm1,ptsymm2) 647 prd_symrel=ptsymrel(:,:,prd_ptsymm) 648 prd_symafm = symafm(sym1) * symafm(sym2) 649 prd_tnons = tnons_(:, sym1) + matmul(symrel(:,:,sym1), tnons_(:,sym2)) 650 !DEBUG 651 !write(std_out,*)' prd_ptsymm,prdsymrel=',prd_ptsymm,prd_symrel 652 !DEBUG 653 654 ! Check that product array is one of the original symmetries. 655 ! Only explore those symmetries that have a symrel that is the product of the two symrel of sym1 and sym2. 656 iseq = .False. 657 do ilist_symrel=1,nlist_symrel(prd_ptsymm) 658 sym3=list_symrel(ilist_symrel,prd_ptsymm) 659 iseq = isinteger(prd_tnons(1) - tnons_(1,sym3), tnons_tol_) 660 if(iseq)then 661 iseq = isinteger(prd_tnons(2) - tnons_(2,sym3), tnons_tol_) 662 if(iseq)then 663 iseq = isinteger(prd_tnons(3) - tnons_(3,sym3), tnons_tol_) 664 if(iseq)then 665 iseq = (prd_symafm == symafm(sym3)) 666 if(iseq)then 667 ! The test is positive 668 if (present(multable)) then 669 multable(1,sym1,sym2) = sym3; multable(2:4,sym1,sym2) = nint(prd_tnons - tnons_(:,sym3)) 670 end if 671 exit 672 endif 673 endif 674 endif 675 endif 676 end do 677 if (.not. iseq .and. echo == 1) then 678 if (echo == 1)then 679 ! The test is negative 680 write(msg, '(a,2(i0,1x),2a,3i3,f11.6,i3,a,2(3i3,f11.6,a),5a)' )& 681 'Product of symmetries:',sym1,sym2,' is not in group.',ch10,& 682 prd_symrel(1,1:3),prd_tnons(1),prd_symafm,ch10,& 683 prd_symrel(2,1:3),prd_tnons(2),ch10,& 684 prd_symrel(3,1:3),prd_tnons(3),ch10,& 685 'This indicates that the input symmetry elements',ch10,& 686 'do not possess closure under group composition.',ch10,& 687 'Action: check symrel, symafm and fix them.' 688 ABI_WARNING(msg) 689 echo = 0 690 endif 691 ierr = ierr + 1 692 if (present(multable)) then 693 multable(1, sym1, sym2) = 0; multable(2:4, sym1, sym2) = huge(0) 694 end if 695 exit 696 end if 697 end do ! sym2 698 if (echo == 0) exit 699 end do ! sym1 700 else 701 if (present(multable)) then 702 do sym1=1,nsym 703 do sym2=1,nsym 704 multable(1, sym1, sym2) = 0; multable(2:4, sym1, sym2) = huge(0) 705 enddo 706 enddo 707 endif 708 endif 709 710 ABI_FREE(list_symrel) 711 ABI_FREE(ptsymm) 712 ABI_FREE(tnons_) 713 714 !DEBUG 715 !write(std_out,*)' m_symtk%sg_multable : exit ' 716 !ENDDEBUG 717 718 end subroutine sg_multable
m_symtk/smallprim [ Functions ]
[ Top ] [ m_symtk ] [ Functions ]
NAME
smallprim
FUNCTION
Find the smallest possible primitive vectors for an input lattice This algorithm is not as restrictive as the conditions mentioned at p.740 of the international tables for crystallography (1983). The final vectors form a right-handed basis, while their sign and ordering is chosen such as to maximize the overlap with the original vectors in order.
INPUTS
rprimd(3,3)=primitive vectors
OUTPUT
metmin(3,3)=metric for the new (minimal) primitive vectors minim(3,3)=minimal primitive translations
NOTES
The routine might as well be defined without metmin as argument, but it is more convenient to have it
SOURCE
3153 subroutine smallprim(metmin,minim,rprimd) 3154 3155 !Arguments ------------------------------------ 3156 !arrays 3157 real(dp),intent(in) :: rprimd(3,3) 3158 real(dp),intent(out) :: metmin(3,3),minim(3,3) 3159 3160 !Local variables------------------------------- 3161 !scalars 3162 integer :: ia,ib,ii,ilong,itrial,minimal 3163 integer :: iiter, maxiter = 100000 3164 real(dp) :: determinant,length2,metsum 3165 character(len=500) :: msg 3166 !arrays 3167 integer :: nvecta(3),nvectb(3) 3168 real(dp) :: rmet(3,3),scprod(3),tmpvect(3) 3169 3170 !************************************************************************** 3171 3172 !call metric(gmet,gprimd,-1,rmet,rprimd,ucvol) 3173 rmet = MATMUL(TRANSPOSE(rprimd),rprimd) 3174 3175 nvecta(1)=2 ; nvectb(1)=3 3176 nvecta(2)=1 ; nvectb(2)=3 3177 nvecta(3)=1 ; nvectb(3)=2 3178 3179 minim(:,:)=rprimd(:,:) 3180 metmin(:,:)=rmet(:,:) 3181 3182 !DEBUG 3183 !write(std_out,*)' smallprim : starting values, rprim ' 3184 !write(std_out,'(3f16.8)' )rprimd(:,1) 3185 !write(std_out,'(3f16.8)' )rprimd(:,2) 3186 !write(std_out,'(3f16.8)' )rprimd(:,3) 3187 !write(std_out,*)' smallprim : starting values, rmet ' 3188 !write(std_out,'(3f16.8)' )rmet(:,1) 3189 !write(std_out,'(3f16.8)' )rmet(:,2) 3190 !write(std_out,'(3f16.8)' )rmet(:,3) 3191 !call flush(std_out) 3192 !ENDDEBUG 3193 3194 !Note this loop without index 3195 do iiter = 1, maxiter 3196 3197 ! Will exit if minimal=1 is still valid after a trial 3198 ! to reduce the vectors of each of the three pairs 3199 minimal=1 3200 3201 do itrial=1,3 3202 3203 ia=nvecta(itrial) ; ib=nvectb(itrial) 3204 ! Make sure the scalar product is negative 3205 if(metmin(ia,ib)>tol8)then 3206 minim(:,ia)=-minim(:,ia) 3207 metmin(ia,ib)=-metmin(ia,ib) ; metmin(ib,ia)=-metmin(ib,ia) 3208 metmin(ia,itrial)=-metmin(ia,itrial) 3209 metmin(itrial,ia)=-metmin(itrial,ia) 3210 end if 3211 ! Compute the length of the sum vector 3212 length2=metmin(ia,ia)+2*metmin(ia,ib)+metmin(ib,ib) 3213 ! Replace the first vector by the sum vector if the latter is smaller 3214 if(length2/metmin(ia,ia) < one-tol8)then 3215 minim(:,ia)=minim(:,ia)+minim(:,ib) 3216 metmin(ia,ia)=length2 3217 metmin(ia,ib)=metmin(ia,ib)+metmin(ib,ib) 3218 metmin(ia,itrial)=metmin(ia,itrial)+metmin(ib,itrial) 3219 metmin(ib,ia)=metmin(ia,ib) 3220 metmin(itrial,ia)=metmin(ia,itrial) 3221 minimal=0 3222 ! Replace the second vector by the sum vector if the latter is smaller 3223 else if(length2/metmin(ib,ib) < one-tol8)then 3224 minim(:,ib)=minim(:,ia)+minim(:,ib) 3225 metmin(ib,ib)=length2 3226 metmin(ia,ib)=metmin(ia,ib)+metmin(ia,ia) 3227 metmin(itrial,ib)=metmin(itrial,ib)+metmin(itrial,ia) 3228 metmin(ib,ia)=metmin(ia,ib) 3229 metmin(ib,itrial)=metmin(itrial,ib) 3230 minimal=0 3231 end if 3232 3233 end do 3234 3235 if(minimal==1)exit 3236 end do 3237 3238 if (iiter >= maxiter) then 3239 write(msg,'(a,i0,a)') 'the loop has failed to find a set of minimal vectors in ',maxiter,' iterations.' 3240 ABI_BUG(msg) 3241 end if 3242 3243 !DEBUG 3244 !write(std_out,*)' smallprim : after pair optimization ' 3245 !write(std_out,'(2a,3es16.8,a,3es16.8,a,3es16.8)')' minim =',ch10,minim(:,1),ch10,minim(:,2),ch10,minim(:,3) 3246 !write(std_out,'(2a,3es16.8,a,3es16.8,a,3es16.8)')' metmin =',ch10,metmin(:,1),ch10,metmin(:,2),ch10,metmin(:,3) 3247 !write(std_out,*)' smallprim : will start triplet optimization ',ch10 3248 !call flush(std_out) 3249 !ENDDEBUG 3250 3251 !At this stage, the three vectors have angles between each other that are 3252 !comprised between 90 and 120 degrees. It might still be that minus the vector 3253 !that is the sum of the three vectors is smaller than the longest of these vectors 3254 do iiter = 1, maxiter 3255 3256 ! Will exit if minimal=1 is still valid after a trial 3257 ! to replace the longest of the three vectors by one of the triplet sum of the three vectors, with plus or minus sign 3258 3259 ! Find longest of the three vectors 3260 ilong=1 3261 if( metmin(2,2)/metmin(1,1) > one + tol8 )ilong=2 3262 if( metmin(3,3)/metmin(ilong,ilong) > one + tol8)ilong=3 3263 3264 ! Try combination with all same signs 3265 minimal=1 3266 metsum=sum(metmin(:,:)) 3267 itrial=0 3268 if( metsum/metmin(ilong,ilong) < one - tol8)then 3269 ! Better combination indeed ... 3270 minim(:,ilong)=minim(:,1)+minim(:,2)+minim(:,3) 3271 metmin=MATMUL(TRANSPOSE(minim),minim) 3272 minimal=0 3273 else 3274 ! Try combinations with sign of itrial different from others 3275 metsum=two*(metmin(1,1)+metmin(2,2)+metmin(3,3))-metsum 3276 do itrial=1,3 3277 ia=nvecta(itrial) ; ib=nvectb(itrial) 3278 if( (metsum+four*metmin(ia,ib))/metmin(ilong,ilong) < one - tol8)then 3279 ! Better combination indeed ... 3280 metsum=metsum+four*metmin(ia,ib) 3281 minim(:,ilong)=-minim(:,itrial)+minim(:,ia)+minim(:,ib) 3282 metmin=MATMUL(TRANSPOSE(minim),minim) 3283 minimal=0 3284 exit 3285 endif 3286 enddo 3287 endif 3288 3289 !DEBUG 3290 !write(std_out,*)' smallprim : triplet optimization, iiter,ilong,itrial= ',iiter,ilong,itrial 3291 !write(std_out,*)' smallprim : predict met for the new vector=',metsum 3292 !call flush(std_out) 3293 !ENDDEBUG 3294 3295 ! do itrial=1,3 3296 ! ia=nvecta(itrial) ; ib=nvectb(itrial) 3297 ! if(metmin(ia,ia)/metsum > one + tol8)then 3298 ! minim(:,ia)=-minim(:,1)-minim(:,2)-minim(:,3) 3299 ! metmin(ia,ib)=-sum(metmin(:,ib)) 3300 ! metmin(ia,itrial)=-sum(metmin(:,itrial)) 3301 ! metmin(ia,ia)=metsum 3302 ! metmin(ib,ia)=metmin(ia,ib) 3303 ! metmin(itrial,ia)=metmin(ia,itrial) 3304 ! minimal=0 3305 ! end if 3306 ! end do 3307 3308 !DEBUG 3309 !write(std_out,*)' smallprim : found better primitive vector using triplets, itrial= ',itrial 3310 !write(std_out,'(2a,3es16.8,a,3es16.8,a,3es16.8)')' minim =',ch10,minim(:,1),ch10,minim(:,2),ch10,minim(:,3) 3311 !write(std_out,'(2a,3es16.8,a,3es16.8,a,3es16.8)')' metmin =',ch10,metmin(:,1),ch10,metmin(:,2),ch10,metmin(:,3) 3312 !write(std_out,*)' smallprim : will continue triplet optimization ',ch10 3313 !call flush(std_out) 3314 !ENDDEBUG 3315 3316 if(minimal==1)exit 3317 3318 end do 3319 3320 if (iiter >= maxiter) then 3321 write(msg, '(a,i0,a)') 'the second loop has failed to find a set of minimal vectors in ',maxiter, 'iterations.' 3322 ABI_BUG(msg) 3323 end if 3324 3325 !DEBUG 3326 !write(std_out,'(a,3es14.6,a,3es14.6,a,3es14.6)')' rprimd=',rprimd(:,1),ch10,rprimd(:,2),ch10,rprimd(:,3) 3327 !write(std_out,'(a,3es14.6,a,3es14.6,a,3es14.6)')' minim =',minim(:,1),ch10,minim(:,2),ch10,minim(:,3) 3328 !ENDDEBUG 3329 3330 !DEBUG 3331 !Change sign of the third vector if not right-handed basis 3332 !determinant=minim(1,1)*(minim(2,2)*minim(3,3)-minim(3,2)*minim(2,3))+& 3333 !& minim(2,1)*(minim(3,2)*minim(1,3)-minim(1,2)*minim(3,3))+& 3334 !& minim(3,1)*(minim(1,2)*minim(2,3)-minim(2,2)*minim(1,3)) 3335 !write(std_out,*)' smallprim: determinant=',determinant 3336 !ENDDEBUG 3337 3338 !Choose the first vector 3339 !Compute the scalar product of the three minimal vectors with the first original vector 3340 scprod(:)=zero 3341 do ii=1,3 3342 scprod(:)=scprod(:)+minim(ii,:)*rprimd(ii,1) 3343 end do 3344 !Determine the vector with the maximal absolute overlap 3345 itrial=1 3346 if(abs(scprod(2))>abs(scprod(1))+tol8)itrial=2 3347 if(abs(scprod(3))>abs(scprod(itrial))+tol8)itrial=3 3348 !Switch the vectors if needed 3349 if(itrial/=1)then 3350 tmpvect(:)=minim(:,1) 3351 minim(:,1)=minim(:,itrial) 3352 minim(:,itrial)=tmpvect(:) 3353 end if 3354 !Choose the sign 3355 if(scprod(itrial)<tol8)minim(:,1)=-minim(:,1) 3356 3357 !DEBUG 3358 !Change sign of the third vector if not right-handed basis 3359 !determinant=minim(1,1)*(minim(2,2)*minim(3,3)-minim(3,2)*minim(2,3))+& 3360 !& minim(2,1)*(minim(3,2)*minim(1,3)-minim(1,2)*minim(3,3))+& 3361 !& minim(3,1)*(minim(1,2)*minim(2,3)-minim(2,2)*minim(1,3)) 3362 !write(std_out,*)' smallprim: determinant=',determinant 3363 !ENDDEBUG 3364 3365 !Choose the second vector 3366 !Compute the scalar product of the second and third minimal vectors with the second original vector 3367 scprod(2:3)=zero 3368 do ii=1,3 3369 scprod(2:3)=scprod(2:3)+minim(ii,2:3)*rprimd(ii,2) 3370 end do 3371 !Determine the vector with the maximal absolute overlap 3372 itrial=2 3373 if(abs(scprod(3))>abs(scprod(2))+tol8)itrial=3 3374 !Switch the vectors if needed 3375 if(itrial/=2)then 3376 tmpvect(:)=minim(:,2) 3377 minim(:,2)=minim(:,itrial) 3378 minim(:,itrial)=tmpvect(:) 3379 end if 3380 !Choose the sign 3381 if(scprod(itrial)<tol8)minim(:,2)=-minim(:,2) 3382 3383 !Change sign of the third vector if not right-handed basis 3384 determinant=minim(1,1)*(minim(2,2)*minim(3,3)-minim(3,2)*minim(2,3))+& 3385 & minim(2,1)*(minim(3,2)*minim(1,3)-minim(1,2)*minim(3,3))+& 3386 & minim(3,1)*(minim(1,2)*minim(2,3)-minim(2,2)*minim(1,3)) 3387 if(determinant<-tol8)minim(:,3)=-minim(:,3) 3388 if(abs(determinant)<tol8)then 3389 ABI_BUG('minim gives vanishing unit cell volume.') 3390 end if 3391 3392 !Final computation of metmin 3393 do ii=1,3 3394 metmin(ii,:)=minim(1,ii)*minim(1,:)+ minim(2,ii)*minim(2,:)+ minim(3,ii)*minim(3,:) 3395 end do 3396 3397 !DEBUG 3398 !write(std_out,'(2a,3es14.6,a,3es14.6,a,3es14.6)')' rprimd=',ch10,rprimd(:,1),ch10,rprimd(:,2),ch10,rprimd(:,3) 3399 !write(std_out,'(2a,3es16.8,a,3es16.8,a,3es16.8)')' minim =',ch10,minim(:,1),ch10,minim(:,2),ch10,minim(:,3) 3400 !write(std_out,'(2a,3es16.8,a,3es16.8,a,3es16.8)')' metmin =',ch10,metmin(:,1),ch10,metmin(:,2),ch10,metmin(:,3) 3401 !write(std_out,'(a)')' smallprim : exit ' 3402 !call flush(std_out) 3403 !ENDDEBUG 3404 3405 end subroutine smallprim
m_symtk/symatm [ Functions ]
[ Top ] [ m_symtk ] [ Functions ]
NAME
symatm
FUNCTION
For each symmetry operation, find the number of the position to which each atom is sent in the unit cell by the INVERSE of the symmetry operation inv(symrel); i.e. this is the atom which, when acted upon by the given symmetry element isym, gets transformed into atom iatom. This routine uses the fact that inv(symrel)=trans(symrec), the inverse of the symmetry operation expressed in the basis of real space primitive translations equals the transpose of the same symmetry operation expressed in the basis of reciprocal space primitive transl: $ xred(nu,indsym(4,isym,ia)) = symrec(mu,nu,isym)*(xred(mu,ia)-tnons(mu,isym)) - transl(mu)$ where $transl$ is also a set of integers and where translation transl places coordinates within unit cell (note sign). Note that symrec is the set of arrays which are actually input here. These arrays have integer elements. tnons is the nonsymmorphic translation or else is zero. If nsym=1 (i.e. only the identity symmetry is present) then indsym merely takes each atom into itself. The array of integer translations "transl" gets included within array "indsym" as seen below. This routine has been improved using ideas of p. 649 of notes, implementing suggestion of Andrew Horsfield: replace search for equivalent atoms using direct primitive cell translations by use of dot product relation which must produce an integer. Relation: $[inv(S(i)) * (x(a)-tnons(i)) - x(inv(S)(i,a))] = integer$ where S(i) is the symmetry matrix in real space, tnons=nonsymmorphic translation (may be 0 0 0), and $x(inv(S)(i,a))$ is sought atom into which $x(a)$ gets rotated by $inv(S)$. Integer gives primitive translation coordinates to get back to original unit cell. Equivalent to $S*t(b)+tnons-x(a)=another$ $integer$ for $x(b)=x(inv(S))$.
COPYRIGHT
Copyright (C) 1998-2024 ABINIT group (DCA, XG, GMR) This file is distributed under the terms of the GNU General Public License, see ~abinit/COPYING or http://www.gnu.org/copyleft/gpl.txt . For the initials of contributors, see ~abinit/doc/developers/contributors.txt .
INPUTS
natom=number of atoms in cell. nsym=number of space group symmetries. symrec(3,3,nsym)=symmetries expressed in terms of their action on reciprocal space primitive translations (integer). tnons(3,nsym)=nonsymmorphic translations for each symmetry (would be 0 0 0 each for a symmorphic space group) typat(natom)=integer identifying type of atom. xred(3,natom)=reduced coordinates of atoms in terms of real space primitive translations tolsym=tolerance for the symmetries [print_indsym]: Print indsym table to std_out if the number of atoms is smaller that print_indsym Default: -1 i.e. no output is provided.
OUTPUT
indsym(4,nsym,natom)=indirect indexing array described above: for each isym,iatom, fourth element is label of atom into which iatom is sent by INVERSE of symmetry operation isym; first three elements are the primitive translations which must be subtracted after the transformation to get back to the original unit cell.
SOURCE
2179 subroutine symatm(indsym, natom, nsym, symrec, tnons, tolsym, typat, xred, print_indsym) 2180 2181 !Arguments ------------------------------------ 2182 !scalars 2183 integer,intent(in) :: natom,nsym 2184 integer,optional,intent(in) :: print_indsym 2185 real(dp), intent(in) :: tolsym 2186 !arrays 2187 integer,intent(in) :: symrec(3,3,nsym),typat(natom) 2188 integer,intent(out) :: indsym(4,nsym,natom) 2189 real(dp),intent(in) :: tnons(3,nsym),xred(3,natom) 2190 2191 !Local variables------------------------------- 2192 !scalars 2193 integer :: eatom,errout,iatom,ii,isym,mu,print_indsym_ 2194 real(dp) :: difmax,err 2195 character(len=500) :: msg 2196 !arrays 2197 integer :: transl(3) 2198 real(dp) :: difmin(3),tratom(3) 2199 2200 ! ************************************************************************* 2201 2202 !DEBUG 2203 !write(std_out,'(a,i4,es12.4)')' symatm : enter, nsym,tolsym=',nsym,tolsym 2204 !write(std_out,'(a,es12.4)')' symatm : xred=' 2205 !do ii=1,natom 2206 ! write(std_out,'(i4,3es18.10)')ii,xred(1:3,ii) 2207 !enddo 2208 !write(std_out,'(a,es12.4)')' symatm : isym,symrec,tnons=' 2209 !do isym=1,nsym 2210 ! write(std_out,'(i6,9i4,3es18.10)')isym,symrec(:,:,isym),tnons(1:3,isym) 2211 !enddo 2212 !ENDDEBUG 2213 2214 err=zero 2215 errout=0 2216 2217 do isym=1,nsym 2218 do iatom=1,natom 2219 2220 do mu=1,3 ! Apply inverse transformation to original coordinates. Note transpose of symrec. 2221 tratom(mu) = dble(symrec(1,mu,isym))*(xred(1,iatom)-tnons(1,isym))& 2222 & +dble(symrec(2,mu,isym))*(xred(2,iatom)-tnons(2,isym))& 2223 & +dble(symrec(3,mu,isym))*(xred(3,iatom)-tnons(3,isym)) 2224 end do 2225 ! 2226 ! Find symmetrically equivalent atom 2227 call symchk(difmin,eatom,natom,tratom,transl,typat(iatom),typat,xred) 2228 ! 2229 ! Put information into array indsym: translations and label 2230 indsym(1,isym,iatom)=transl(1) 2231 indsym(2,isym,iatom)=transl(2) 2232 indsym(3,isym,iatom)=transl(3) 2233 indsym(4,isym,iatom)=eatom 2234 ! 2235 ! Keep track of maximum difference between transformed coordinates and 2236 ! nearest "target" coordinate 2237 difmax=max(abs(difmin(1)),abs(difmin(2)),abs(difmin(3))) 2238 err=max(err,difmax) 2239 2240 if(errout==3)then 2241 write(msg, '(a)' )& 2242 ' Suppress warning about finding symmetrically equivalent atoms, as mentioned already three times.' 2243 ABI_WARNING(msg) 2244 errout=errout+1 2245 endif 2246 2247 if (difmax>tolsym .and. errout<3) then ! Print warnings if differences exceed tolerance 2248 write(msg, '(3a,i3,a,i6,a,i3,a,a,3f18.12,3a,es12.4)' )& 2249 ' Trouble finding symmetrically equivalent atoms',ch10,& 2250 ' Applying inv of symm number',isym,' to atom number',iatom,' of typat',typat(iatom),ch10,& 2251 ' gives tratom=',tratom(1:3),'.',ch10,& 2252 ' This is further away from every atom in crystal than the allowed tolerance, tolsym=',tolsym 2253 ABI_WARNING(msg) 2254 2255 write(msg, '(a,3i3,a,a,3i3,a,a,3i3)' ) & 2256 ' The inverse symmetry matrix is',symrec(1,1:3,isym),ch10,& 2257 ' ',symrec(2,1:3,isym),ch10,& 2258 ' ',symrec(3,1:3,isym) 2259 call wrtout(std_out,msg) 2260 write(msg, '(a,3f18.12)' )' and the nonsymmorphic transl. tnons =',(tnons(mu,isym),mu=1,3) 2261 2262 call wrtout(std_out,msg) 2263 write(msg, '(a,1p,3es12.4,a,a,i5)' ) & 2264 ' The nearest coordinate differs by',difmin(1:3),ch10,& 2265 ' for indsym(nearest atom)=',indsym(4,isym,iatom) 2266 call wrtout(std_out,msg) 2267 ! 2268 ! Use errout to reduce volume of error diagnostic output 2269 if (errout==0) then 2270 write(msg,'(6a)') ch10,& 2271 ' This indicates that when symatm attempts to find atoms symmetrically',ch10, & 2272 ' related to a given atom, the nearest candidate is further away than some',ch10,& 2273 ' tolerance. Should check atomic coordinates and symmetry group input data.' 2274 call wrtout(std_out,msg) 2275 end if 2276 errout=errout+1 2277 2278 end if !difmax>tol 2279 end do !iatom 2280 end do !isym 2281 2282 ! MG: Do not change this behaviour. symatm is called many times in the EPH code in which we have tons of q-points 2283 ! and it's really annoying to see this output repeated over and over again. 2284 ! If you need to print the indsym table at the beginning of the calculation, find the call to symatm 2285 ! and pass the optional argument print_indsym_ or use `abitk crystal_print FILE --prtvol 1` 2286 print_indsym_ = -1; if (present(print_indsym)) print_indsym_ = print_indsym 2287 if (natom <= print_indsym_) then 2288 do iatom=1,natom 2289 write(msg, '(a,i0,a)' )' symatm: atom number ',iatom,' is reached starting at atom' 2290 call wrtout(std_out,msg) 2291 do ii=1,(nsym-1)/24+1 2292 if(natom<100)then 2293 write(msg, '(1x,24i3)' ) (indsym(4,isym,iatom),isym=1+(ii-1)*24,min(nsym,ii*24)) 2294 else 2295 write(msg, '(1x,24i6)' ) (indsym(4,isym,iatom),isym=1+(ii-1)*24,min(nsym,ii*24)) 2296 end if 2297 call wrtout(std_out,msg) 2298 end do 2299 end do 2300 end if 2301 2302 if (err>tolsym) then 2303 write(msg, '(1x,a,1p,e14.5,a,e12.4)' )'symatm: maximum (delta t)=',err,' is larger than tol=',tolsym 2304 ABI_WARNING(msg) 2305 end if 2306 2307 !Stop execution if error is really big 2308 if (err>0.01d0) then 2309 write(msg,'(5a)')& 2310 'Largest error (above) is so large (0.01) that either input atomic coordinates (xred)',ch10,& 2311 'are wrong or space group symmetry data is wrong.',ch10,& 2312 'Action: correct your input file.' 2313 ABI_ERROR(msg) 2314 end if 2315 2316 end subroutine symatm
m_symtk/symaxes [ Functions ]
[ Top ] [ m_symtk ] [ Functions ]
NAME
symaxes
FUNCTION
Determines the type of symmetry operation, for the proper symmetries 2,2_1,3,3_1,3_2,4,4_1,4_2,4_3,6,6_1,...6_5
INPUTS
center=type of bravais lattice 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 iholohedry=type of holohedry iholohedry=1 triclinic 1bar iholohedry=2 monoclinic 2/m iholohedry=3 orthorhombic mmm iholohedry=4 tetragonal 4/mmm iholohedry=5 trigonal 3bar m (rhombohedral Bravais latt) iholohedry=6 hexagonal 6/mmm iholohedry=7 cubic m3bar m isym=number of the symmetry operation that is currently analyzed isymrelconv=symrel matrix for the particular operation, in conv. axes ordersym=order of the symmetry operation tnons_order=order of the screw translation trialt(3)=screw translation associated with the symmetry operation in conventional axes (all components in the range ]-1/2,1/2] )
OUTPUT
label=a user friendly label for the rotation type_axis=type of the symmetry operation
NOTES
It is assumed that the symmetry operations will be entered in the symrel tnonsconv arrays, for the CONVENTIONAL cell. For proper symmetries (rotations), the associated translation is determined. There is a subtlety with translations associated with rotations : all the rotations with axis parallel to the one analysed do not all have the same translation characteristics. This is clearly seen in the extended Hermann-Mauguin symbols, see the international table for crystallography, chapter 4. In the treatment that we adopt, one will distinguish the cases of primitive Bravais lattices, and centered bravais lattices. In the latter case, in the present routine, at the exception of the trigonal axis for the cubic system, we explicitely generate the correct ratio of different translations, so that their type can be explicitely assigned, without confusion. By contrast, for primitive lattices, the "tnons" that has been transmitted to the present routine might be one of the few possible translations vectors, nearly at random. We deal with this case by the explicit examination of the system classes, and the identification of such a possibility. In particular: (1) for the trigonal axis in the rhombohedral Bravais lattice, or in the cubic system, there is an equal number of 3, 3_1, and 3_2 axes parallel to each other, in a cell that is primitive (as well as conventional). In this particular case, in the present routine, all 3, 3_1 and 3_2 axes are assigned to be 3 axes, independently of the centering. (2) for the 4- or 6- axes, no confusion is possible : in the primitive cell, there is only one possible translation, while in the centered cells, the correct ratio of translation vectors will be generated (3) for the binary axes, there is no problem when the cell is centered, but there are problems (3a) for the tP Bravais lattice, for an axis in a tertiary direction, (see the description of the lattice symmetry directions table 2.4.1 of the international tables for crystallography), where the family of axes is made equally of 2 and 2_1 axis. In this case, we attribute the binary axis to the specific class of "tertiary 2-axis". We keep track of the 2 or 2_1 characteristics of all other binary axes (3b) for the tI Bravais lattice, in all the directions, there is an equal number of 2 and 2_1 axes. We distinguish the primary and secondary family from the tertiary family. (3c) for the hP Bravais lattice, each binary axis can present no translation or be a screw axis (in the same direction). For primary axes, one need the "2" and "2_1" classification, while for secondary and tertiary axes, the associated translation vector will have not importance. However, one will need to distinguish secondary from tertiary, and these from primary axes. So, this is the most complicated case, for binary axes, with the following sets of binary axes : "2", "2_1", "secondary 2" and "tertiary 2". (3d) for the hR Bravais lattice, each binary axis can present no translation or be a screw axis (in the same direction). There is no distinction between tertiary axes and other, so that we simply assign a binary axis to "2-axis" (3e) for the cP lattice, the binary axes along tertiary directions can also have different translation vectors, while for the primary direction, there is no such ambiguity. So, we will attribute tertiary 2 axis to the "tertiary 2-axis" set (there are always 6), and attribute 2 and 2_1 primary axes to the corresponding sets.
SOURCE
2597 subroutine symaxes(center,iholohedry,isym,isymrelconv,label,ordersym,tnons_order,trialt,type_axis) 2598 2599 !Arguments ------------------------------------ 2600 !scalars 2601 integer,intent(in) :: center,iholohedry,isym,ordersym,tnons_order 2602 integer,intent(out) :: type_axis 2603 character(len=128),intent(out) :: label 2604 !arrays 2605 integer,intent(in) :: isymrelconv(3,3) 2606 real(dp),intent(in) :: trialt(3) 2607 2608 !Local variables------------------------------- 2609 !scalars 2610 logical,parameter :: verbose=.FALSE. 2611 character(len=500) :: msg 2612 integer :: direction,directiontype 2613 real(dp),parameter :: nzero=1.0d-6 2614 2615 !************************************************************************** 2616 2617 !write(std_out,*)' symaxes : enter, isym=',isym 2618 !write(std_out,*)' symaxes : iholohedry, ',iholohedry 2619 !write(std_out,*)' symaxes : center, ',center 2620 2621 select case(ordersym) 2622 2623 case(2) ! point symmetry 2 2624 ! Must characterize directiontype for cP, tP, tI, and hP Bravais lattices 2625 directiontype=1 2626 if( iholohedry==4 .or. iholohedry==7) then ! tP or cP Bravais lattices 2627 if(abs(isymrelconv(1,1))+ & 2628 & abs(isymrelconv(2,2))+ & 2629 & abs(isymrelconv(3,3)) ==1) directiontype=3 2630 else if(iholohedry==6)then ! hP Bravais lattice 2631 if(sum(isymrelconv(:,:))/=-1 )directiontype=2 2632 if(sum(isymrelconv(:,:))==0 .or. sum(isymrelconv(:,:))==-3 )& 2633 & directiontype=3 2634 ! directiontype=1 corresponds to a primary axis 2635 ! directiontype=2 corresponds to a tertiary axis 2636 ! directiontype=3 corresponds to a secondary axis 2637 end if 2638 2639 ! DEBUG 2640 ! write(std_out,*)' directiontype=',directiontype 2641 ! write(std_out,'(a,3i6)' )' isymrelconv(1:3)=',isymrelconv(:,1) 2642 ! write(std_out,'(a,3i6)' )' isymrelconv(4:6)=',isymrelconv(:,2) 2643 ! write(std_out,'(a,3i6)' )' isymrelconv(7:9)=',isymrelconv(:,3) 2644 ! write(std_out,'(a,i)' )' tnons_order=',tnons_order 2645 ! ENDDEBUG 2646 2647 ! Now, classify the 2 axes 2648 if(directiontype==2)then 2649 type_axis=4 ! secondary 2 (only in the hP Bravais latt case) 2650 write(label,'(a)') 'a secondary 2-axis ' 2651 2652 else if(directiontype==3 .and. iholohedry==4)then 2653 type_axis=21 ! tertiary 2 2654 write(label,'(a)') 'a tertiary 2-axis ' 2655 else if(directiontype==3 .and. & 2656 & center==0 .and. (iholohedry==6.or.iholohedry==7) )then 2657 type_axis=21 ! tertiary 2 2658 write(label,'(a)') 'a tertiary 2-axis ' 2659 else if(tnons_order==1 .or. (iholohedry==4 .and. center==-1) .or. & 2660 & iholohedry==5)then 2661 type_axis=9 ! 2 2662 write(label,'(a)') 'a 2-axis ' 2663 else 2664 type_axis=20 ! 2_1 2665 write(label,'(a)') 'a 2_1-axis ' 2666 end if 2667 2668 case(3) ! point symmetry 3 2669 if(tnons_order==1)then 2670 type_axis=10 ! 3 2671 write(label,'(a)') 'a 3-axis ' 2672 else if(iholohedry==5 .or. iholohedry==7)then 2673 ! This is a special situation : in the same family of parallel 3-axis, 2674 ! one will have an equal number of 3, 3_1 and 3_2 axes, so that 2675 ! it is non-sense to try to classify one of them. 2676 type_axis=10 ! 3, 3_1 or 3_2, undistinguishable 2677 write(label,'(a)') 'a 3, 3_1 or 3_2 axis ' 2678 else 2679 ! DEBUG 2680 ! write(std_out,*)'isymrelconv=',isymrelconv(:,:) 2681 ! write(std_out,*)'trialt=',trialt(:) 2682 ! ENDDEBUG 2683 ! Must recognize 3_1 or 3_2 2684 if(isymrelconv(1,1)==0)then ! 3+ 2685 if(abs(trialt(3)-third)<nzero)type_axis=22 ! 3_1 2686 if(abs(trialt(3)+third)<nzero)type_axis=23 ! 3_2 2687 else if(isymrelconv(1,1)==-1)then ! 3- 2688 if(abs(trialt(3)-third)<nzero)type_axis=23 ! 3_2 2689 if(abs(trialt(3)+third)<nzero)type_axis=22 ! 3_1 2690 end if 2691 write(label,'(a)') 'a 3_1 or 3_2-axis ' 2692 end if 2693 2694 case(4) ! point symmetry 4 2695 if(tnons_order==1)then 2696 type_axis=12 ! 4 2697 write(label,'(a)') 'a 4-axis ' 2698 else if(tnons_order==2)then 2699 type_axis=25 ! 4_2 2700 write(label,'(a)') 'a 4_2-axis ' 2701 else if(center/=0)then 2702 type_axis=24 ! 4_1 or 4_3 2703 write(label,'(a)') 'a 4_1 or 4_3-axis ' 2704 else 2705 ! DEBUG 2706 ! write(std_out,*)'isymrelconv=',isymrelconv(:,:) 2707 ! write(std_out,*)'trialt=',trialt(:) 2708 ! ENDDEBUG 2709 ! Must recognize 4_1 or 4_3, along the three primary directions 2710 do direction=1,3 2711 if(isymrelconv(direction,direction)==1)then ! 2712 if( (direction==1 .and. isymrelconv(2,3)==-1) .or. & 2713 & (direction==2 .and. isymrelconv(3,1)==-1) .or. & 2714 & (direction==3 .and. isymrelconv(1,2)==-1) )then ! 4+ 2715 if(abs(trialt(direction)-quarter)<nzero)type_axis=24 ! 4_1 2716 if(abs(trialt(direction)+quarter)<nzero)type_axis=26 ! 4_3 2717 else if( (direction==1 .and. isymrelconv(2,3)==1) .or. & 2718 & (direction==2 .and. isymrelconv(3,1)==1) .or. & 2719 & (direction==3 .and. isymrelconv(1,2)==1) )then ! 4- 2720 if(abs(trialt(direction)-quarter)<nzero)type_axis=26 ! 4_3 2721 if(abs(trialt(direction)+quarter)<nzero)type_axis=24 ! 4_1 2722 end if 2723 end if 2724 end do 2725 write(label,'(a)') 'a 4_1 or 4_3-axis ' 2726 end if 2727 2728 case(6) ! point symmetry 6 2729 if(tnons_order==1)then 2730 type_axis=14 ! 6 2731 write(label,'(a)') 'a 6-axis ' 2732 else if(tnons_order==2)then 2733 type_axis=29 ! 6_3 2734 write(label,'(a)') 'a 6_3-axis ' 2735 else if(tnons_order==3)then 2736 !write(std_out,*)'isymrelconv=',isymrelconv(:,:) 2737 !write(std_out,*)'trialt=',trialt(:) 2738 !Must recognize 6_2 or 6_4 2739 if(isymrelconv(1,1)==1)then ! 6+ 2740 if(abs(trialt(3)-third)<nzero)type_axis=28 ! 6_2 2741 if(abs(trialt(3)+third)<nzero)type_axis=30 ! 6_4 2742 else if(isymrelconv(1,1)==0)then ! 6- 2743 if(abs(trialt(3)-third)<nzero)type_axis=30 ! 6_4 2744 if(abs(trialt(3)+third)<nzero)type_axis=28 ! 6_2 2745 end if 2746 write(label,'(a)') 'a 6_2 or 6_4-axis ' 2747 else 2748 !write(std_out,*)'isymrelconv=',isymrelconv(:,:) 2749 !write(std_out,*)'trialt=',trialt(:) 2750 !Must recognize 6_1 or 6_5 2751 if(isymrelconv(1,1)==1)then ! 6+ 2752 if(abs(trialt(3)-sixth)<nzero)type_axis=27 ! 6_1 2753 if(abs(trialt(3)+sixth)<nzero)type_axis=31 ! 6_5 2754 else if(isymrelconv(1,1)==0)then ! 6- 2755 if(abs(trialt(3)-sixth)<nzero)type_axis=31 ! 6_5 2756 if(abs(trialt(3)+sixth)<nzero)type_axis=27 ! 6_1 2757 end if 2758 write(label,'(a)') 'a 6_1 or 6_5-axis ' 2759 end if 2760 2761 end select 2762 2763 if (verbose) then 2764 write(msg,'(a,i3,a,a)')' symaxes : the symmetry operation no. ',isym,' is ', trim(label) 2765 call wrtout(std_out,msg) 2766 end if 2767 2768 end subroutine symaxes
m_symtk/symcharac [ Functions ]
[ Top ] [ m_symtk ] [ Functions ]
NAME
symcharac
FUNCTION
Get the type of axis for the symmetry.
INPUTS
center=bravais(2) determinant=the value of the determinant of sym iholohedry=bravais(1) isym=number of the symmetry operation that is currently analyzed order=the order of the symmetry symrel(3,3)= the symmetry matrix tnons(3)=nonsymmorphic translations
OUTPUT
label=a human readable text for the characteristic of the symmetry type_axis=an identifier for the type of symmetry
SOURCE
2341 subroutine symcharac(center, determinant, iholohedry, isym, label, symrel, tnons, type_axis) 2342 2343 !Arguments ------------------------------------ 2344 !scalars 2345 integer, intent(in) :: determinant, center, iholohedry, isym 2346 integer, intent(out) :: type_axis 2347 character(len = 128), intent(out) :: label 2348 !arrays 2349 integer,intent(in) :: symrel(3,3) 2350 real(dp),intent(in) :: tnons(3) 2351 2352 !Local variables------------------------------- 2353 !scalars 2354 logical,parameter :: verbose=.FALSE. 2355 integer :: tnons_order, identified, ii, order, iorder 2356 character(len=500) :: msg 2357 !arrays 2358 integer :: identity(3,3),matrix(3,3),trial(3,3) 2359 real(dp) :: reduced(3),trialt(3) 2360 2361 !************************************************************************** 2362 2363 identity(:,:)=0 2364 identity(1,1)=1 ; identity(2,2)=1 ; identity(3,3)=1 2365 trial(:,:)=identity(:,:) 2366 matrix(:,:)=symrel(:,:) 2367 2368 order=0 2369 do iorder=1,6 2370 trial=matmul(matrix,trial) 2371 if(sum((trial-identity)**2)==0)then 2372 order=iorder 2373 exit 2374 end if 2375 if(sum((trial+identity)**2)==0)then 2376 order=iorder 2377 exit 2378 end if 2379 end do 2380 2381 if(order==0)then 2382 type_axis = -2 2383 return 2384 end if 2385 2386 !Determination of the characteristics of proper symmetries (rotations) 2387 if(determinant==1)then 2388 2389 ! Determine the translation vector associated to the rotations 2390 ! and its order : apply the symmetry operation 2391 ! then analyse the resulting vector. 2392 identified=0 2393 trialt(:)=zero 2394 do ii=1,order 2395 trialt(:)=matmul(symrel(:,:),trialt(:))+tnons(:) 2396 end do 2397 ! Gives the associated translation, with components in the 2398 ! interval [-0.5,0.5] . 2399 reduced(:)=trialt(:)-nint(trialt(:)-tol6) 2400 2401 if(sum(abs(reduced(:)))<tol6)identified=1 2402 if( (center==1 .or. center==-3) .and. & 2403 & sum(abs(reduced(:)-(/zero,half,half/)))<tol6 )identified=2 2404 if( (center==2 .or. center==-3) .and. & 2405 & sum(abs(reduced(:)-(/half,zero,half/)))<tol6 )identified=3 2406 if( (center==3 .or. center==-3) .and. & 2407 & sum(abs(reduced(:)-(/half,half,zero/)))<tol6 )identified=4 2408 if(center==-1.and. sum(abs(reduced(:)-(/half,half,half/)))<tol6 )identified=5 2409 2410 ! If the symmetry operation has not been identified, there is a problem ... 2411 if(identified==0) then 2412 type_axis = -1 2413 return 2414 end if 2415 2416 ! Compute the translation vector associated with one rotation 2417 trialt(:)=trialt(:)/order 2418 trialt(:)=trialt(:)-nint(trialt(:)-tol6) 2419 2420 ! Analyse the resulting vector. 2421 identified=0 2422 do ii=1,order 2423 reduced(:)=ii*trialt(:)-nint(ii*trialt(:)-tol6) 2424 if(sum(abs(reduced(:)))<tol6)identified=1 2425 if( (center==1 .or. center==-3) .and. & 2426 & sum(abs(reduced(:)-(/zero,half,half/)))<tol6 )identified=2 2427 if( (center==2 .or. center==-3) .and. & 2428 & sum(abs(reduced(:)-(/half,zero,half/)))<tol6 )identified=3 2429 if( (center==3 .or. center==-3) .and. & 2430 & sum(abs(reduced(:)-(/half,half,zero/)))<tol6 )identified=4 2431 if(center==-1.and. sum(abs(reduced(:)-(/half,half,half/)))<tol6 )identified=5 2432 2433 if(identified/=0)then 2434 tnons_order=ii 2435 exit 2436 end if 2437 end do ! ii 2438 2439 ! Determinant (here=+1, as we are dealing with proper symmetry operations), 2440 ! order, tnons_order and identified are enough to 2441 ! determine the kind of symmetry operation 2442 2443 select case(order) 2444 case(1) ! point symmetry 1 2445 if(identified==1) then 2446 type_axis=8 ! 1 2447 write(label,'(a)') 'the identity' 2448 else 2449 type_axis=7 ! t 2450 write(label,'(a)') 'a pure translation ' 2451 end if 2452 2453 if (verbose) then 2454 write(msg,'(a,i3,2a)')' symspgr : the symmetry operation no. ',isym,' is ',trim(label) 2455 call wrtout(std_out,msg) 2456 end if 2457 2458 case(2,3,4,6) ! point symmetry 2,3,4,6 - rotations 2459 call symaxes(center,iholohedry,isym,symrel,label,order,tnons_order,trialt,type_axis) 2460 end select 2461 2462 else if (determinant==-1)then 2463 2464 ! Now, take care of the improper symmetry operations. 2465 ! Their treatment is relatively easy, except for the mirror planes 2466 select case(order) 2467 case(1) ! point symmetry 1 2468 type_axis=5 ! -1 2469 write(label,'(a)') 'an inversion' 2470 case(2) ! point symmetry 2 - planes 2471 call symplanes(center,iholohedry,isym,symrel,tnons,label,type_axis) 2472 case(3) ! point symmetry 3 2473 type_axis=3 ! -3 2474 write(label,'(a)') 'a -3 axis ' 2475 case(4) ! point symmetry 1 2476 type_axis=2 ! -4 2477 write(label,'(a)') 'a -4 axis ' 2478 case(6) ! point symmetry 1 2479 type_axis=1 ! -6 2480 write(label,'(a)') 'a -6 axis ' 2481 end select 2482 2483 if (order /= 2 .and. verbose) then 2484 write(msg,'(a,i3,2a)')' symspgr : the symmetry operation no. ',isym,' is ',trim(label) 2485 call wrtout(std_out,msg) 2486 end if 2487 2488 end if ! determinant==1 or -1 2489 2490 end subroutine symcharac
m_symtk/symchk [ Functions ]
[ Top ] [ m_symtk ] [ Functions ]
NAME
symchk
FUNCTION
Symmetry checker for atomic coordinates. Checks for translated atomic coordinate tratom(3) to agree with some coordinate xred(3,iatom) where atomic types agree too. All coordinates are "reduced", i.e. given in terms of primitive reciprocal translations.
INPUTS
natom=number of atoms in unit cell tratom(3)=reduced coordinates for a single atom which presumably result from the application of a symmetry operation to an atomic coordinate trtypat=type of atom (integer) translated to tratom typat(natom)=types of all atoms in unit cell (integer) xred(3,natom)=reduced coordinates for all atoms in unit cell
OUTPUT
difmin(3)=minimum difference between apparently equivalent atoms (give value separately for each coordinate)--note that value may be NEGATIVE so take abs later if needed eatom=atom label of atom which is SAME as tratom to within a primitive cell translation ("equivalent atom") transl(3)=primitive cell translation to make iatom same as tratom (integers)
SOURCE
2030 subroutine symchk(difmin,eatom,natom,tratom,transl,trtypat,typat,xred) 2031 2032 !Arguments ------------------------------------ 2033 !scalars 2034 integer,intent(in) :: natom,trtypat 2035 integer,intent(out) :: eatom 2036 !arrays 2037 integer,intent(in) :: typat(natom) 2038 integer,intent(out) :: transl(3) 2039 real(dp),intent(in) :: tratom(3),xred(3,natom) 2040 real(dp),intent(out) :: difmin(3) 2041 2042 !Local variables------------------------------- 2043 !scalars 2044 integer :: iatom,jatom,trans1,trans2,trans3 2045 real(dp) :: test,test1,test2,test3,testmn 2046 2047 ! ************************************************************************* 2048 2049 !DEBUG 2050 ! write(std_out,'(a,a,i4,3f18.12)') ch10,' symchk : enter, trtypat,tratom=',trtypat,tratom 2051 !ENDDEBUG 2052 2053 !Start testmn out at large value 2054 testmn=1000000.d0 2055 2056 !Loop through atoms-- 2057 !when types agree, check for agreement after primitive translation 2058 jatom=1 2059 do iatom=1,natom 2060 if (trtypat/=typat(iatom)) cycle 2061 2062 ! Check all three components 2063 test1=tratom(1)-xred(1,iatom) 2064 test2=tratom(2)-xred(2,iatom) 2065 test3=tratom(3)-xred(3,iatom) 2066 ! Find nearest integer part of difference 2067 trans1=nint(test1) 2068 trans2=nint(test2) 2069 trans3=nint(test3) 2070 ! Check whether, after translation, they agree 2071 test1=test1-dble(trans1) 2072 test2=test2-dble(trans2) 2073 test3=test3-dble(trans3) 2074 test=abs(test1)+abs(test2)+abs(test3) 2075 if (test<tol10) then 2076 ! Note that abs() is not taken here 2077 difmin(1)=test1 2078 difmin(2)=test2 2079 difmin(3)=test3 2080 jatom=iatom 2081 transl(1)=trans1 2082 transl(2)=trans2 2083 transl(3)=trans3 2084 ! Break out of loop when agreement is within tolerance 2085 exit 2086 else 2087 ! Keep track of smallest difference if greater than tol10 2088 if (test<testmn) then 2089 testmn=test 2090 ! Note that abs() is not taken here 2091 difmin(1)=test1 2092 difmin(2)=test2 2093 difmin(3)=test3 2094 jatom=iatom 2095 transl(1)=trans1 2096 transl(2)=trans2 2097 transl(3)=trans3 2098 end if 2099 end if 2100 2101 ! End loop over iatom. Note a "cycle" and an "exit" inside the loop 2102 end do 2103 2104 eatom=jatom 2105 2106 end subroutine symchk
m_symtk/symdet [ Functions ]
[ Top ] [ m_symtk ] [ Functions ]
NAME
symdet
FUNCTION
Compute determinant of each input symmetry matrix sym(3,3,i) and check that the determinant is always +/- 1. Integer arithmetic.
INPUTS
nsym=number of symmetry operations sym(3,3,nsym)=integer symmetry array
OUTPUT
determinant(nsym)=determinant of each symmetry operation
SOURCE
235 subroutine symdet(determinant, nsym, sym) 236 237 !Arguments ------------------------------------ 238 !scalars 239 integer,intent(in) :: nsym 240 !arrays 241 integer,intent(in) :: sym(3,3,nsym) 242 integer,intent(out) :: determinant(nsym) 243 244 !Local variables------------------------------- 245 !scalars 246 integer :: det,isym 247 character(len=500) :: msg 248 249 ! ************************************************************************* 250 251 do isym=1,nsym 252 call mati3det(sym(:,:,isym),det) 253 determinant(isym)=det 254 if (abs(det)/=1) then 255 write(msg,'(2(a,i0), 5a)')& 256 'Abs(determinant) for symmetry number ',isym,' is ',det,' .',ch10,& 257 'For a legitimate symmetry, abs(determinant) must be 1.',ch10,& 258 'Action: check your symmetry operations (symrel) in input file.' 259 ABI_ERROR(msg) 260 end if 261 end do 262 263 end subroutine symdet
m_symtk/symmetrize_rprimd [ Functions ]
[ Top ] [ m_symtk ] [ Functions ]
NAME
symmetrize_rprimd
FUNCTION
Supposing the input rprimd does not preserve the length and angles following the symmetries, will generates a new set rprimd, on the basis of the expected characteristics of the conventional cell, as specified in bravais(:)
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,1:nsym)=symmetry operations in real space in terms of primitive translations tolsym=tolerance for the symmetry operations (only for checking purposes, the new set rprimd will be coherent with the symmetry operations at a much accurate level).
SIDE EFFECTS
rprimd(3,3)=dimensional primitive translations for real space (bohr)
SOURCE
1561 subroutine symmetrize_rprimd(bravais,nsym,rprimd,symrel,tolsym) 1562 1563 !Arguments ------------------------------------ 1564 !scalars 1565 integer,intent(in) :: nsym 1566 real(dp),intent(in) :: tolsym 1567 !arrays 1568 integer,intent(in) :: bravais(11),symrel(3,3,nsym) 1569 real(dp),intent(inout) :: rprimd(3,3) 1570 1571 !Local variables------------------------------- 1572 !scalars 1573 integer :: foundc,iexit,ii,jj 1574 real(dp):: rprimd_maxabs 1575 !character(len=500) :: msg 1576 !arrays 1577 real(dp):: aa(3,3),ait(3,3),cell_base(3,3),gprimd(3,3),rmet(3,3),rprimd_new(3,3) 1578 1579 ! ************************************************************************* 1580 1581 !DEBUG 1582 !write(std_out,'(a)') ' symmetrize_rprimd : enter ' 1583 !ENDDEBUG 1584 1585 !Build the conventional cell basis vectors in cartesian coordinates 1586 aa(:,1)=bravais(3:5) 1587 aa(:,2)=bravais(6:8) 1588 aa(:,3)=bravais(9:11) 1589 !Inverse transpose 1590 call matr3inv(aa,ait) 1591 do ii=1,3 1592 cell_base(:,ii)=ait(ii,1)*rprimd(:,1)+ait(ii,2)*rprimd(:,2)+ait(ii,3)*rprimd(:,3) 1593 end do 1594 1595 !DEBUG 1596 !write(std_out,'(a)') ' before holocell, cell_base =' 1597 !do ii=1,3 1598 ! write(std_out,'(3es16.8)') cell_base(:,ii) 1599 !enddo 1600 !ENDDEBUG 1601 1602 !Enforce the proper holohedry on the conventional cell vectors. 1603 call holocell(cell_base,1,foundc,bravais(1),tolsym) 1604 1605 !DEBUG 1606 !write(std_out,'(a)') ' after holocell, cell_base =' 1607 !do ii=1,3 1608 ! write(std_out,'(3es16.8)') cell_base(:,ii) 1609 !enddo 1610 !ENDDEBUG 1611 1612 !Reconstruct the dimensional primitive vectors 1613 do ii=1,3 1614 rprimd_new(:,ii)=aa(1,ii)*cell_base(:,1)+aa(2,ii)*cell_base(:,2)+aa(3,ii)*cell_base(:,3) 1615 end do 1616 1617 !Suppress meaningless values 1618 rprimd_maxabs=maxval(abs(rprimd_new)) 1619 do ii=1,3 1620 do jj=1,3 1621 if(abs(rprimd(ii,jj))<tol12*rprimd_maxabs)rprimd(ii,jj)=zero 1622 enddo 1623 enddo 1624 1625 rprimd(:,:)=rprimd_new(:,:) 1626 1627 !Check whether the symmetry operations are consistent with the lattice vectors 1628 rmet = MATMUL(TRANSPOSE(rprimd), rprimd) 1629 call matr3inv(rprimd, gprimd) 1630 !call metric(gmet,gprimd,-1,rmet,rprimd,ucvol) 1631 iexit=0 1632 1633 call chkorthsy(gprimd,iexit,nsym,rmet,rprimd,symrel,tolsym) 1634 1635 !DEBUG 1636 !write(std_out,'(a)') ' symmetrize_rprimd : exit ' 1637 !ENDDEBUG 1638 1639 end subroutine symmetrize_rprimd
m_symtk/symmetrize_tnons [ Functions ]
[ Top ] [ m_symtk ] [ Functions ]
NAME
symmetrize_tnons
FUNCTION
Given the order of a symmetry operation, make sure that tnons is such that applying "order" times the symmetry operation generate the unity operation, accurately.
INPUTS
nsym=actual number of symmetries symrel(3,3,1:nsym)=symmetry operations in real space in terms of primitive translations tolsym=tolerance that was used to determine the symmetry operations
SIDE EFFECTS
tnons(3,1:nsym)= non-symmorphic translation vectors
SOURCE
1661 subroutine symmetrize_tnons(nsym,symrel,tnons,tolsym) 1662 1663 !Arguments ------------------------------------ 1664 !scalars 1665 integer,intent(in) :: nsym 1666 real(dp),intent(in) :: tolsym 1667 !arrays 1668 integer,intent(in) :: symrel(3,3,nsym) 1669 real(dp),intent(inout) :: tnons(3,nsym) 1670 1671 !Local variables------------------------------- 1672 !scalars 1673 integer :: iorder,isym,order 1674 !character(len=500) :: msg 1675 !arrays 1676 integer :: symrel_mult(3,3) 1677 integer :: unitmat(3,3) 1678 real(dp):: tnons_mult(3) 1679 1680 ! ************************************************************************* 1681 1682 !DEBUG 1683 !write(std_out,'(a)') ' symmetrize_tnons : enter ' 1684 !ENDDEBUG 1685 1686 unitmat=0 1687 unitmat(1,1)=1 ; unitmat(2,2)=1 ; unitmat(3,3)=1 1688 1689 do isym=1,nsym 1690 1691 !DEBUG 1692 !write(std_out,'(a,i4,9i3,3es16.6)') ' isym,symrel,tnons=',isym,symrel(:,:,isym),tnons(:,isym) 1693 !ENDDEBUG 1694 1695 symrel_mult(:,:)=symrel(:,:,isym) ; tnons_mult(:)=tnons(:,isym) 1696 order=0 1697 !Determine the order of the operation 1698 do iorder=1,48 1699 symrel_mult(:,:)=matmul(symrel(:,:,isym),symrel_mult(:,:)) 1700 tnons_mult(:)=matmul(symrel(:,:,isym),tnons_mult(:))+tnons(:,isym) 1701 if(sum(abs(symrel_mult-unitmat))==0)then 1702 if(abs(tnons_mult(1)-nint(tnons_mult(1)))<tolsym*iorder .and. & 1703 & abs(tnons_mult(2)-nint(tnons_mult(2)))<tolsym*iorder .and. & 1704 & abs(tnons_mult(3)-nint(tnons_mult(3)))<tolsym*iorder)then 1705 !The order has been found 1706 order=iorder+1 1707 !Now, adjust the tnons vector, in order to obtain the exact identity 1708 !operation at order "order" 1709 tnons_mult(:)=(tnons_mult(:)-nint(tnons_mult(:)))/(dble(order)) 1710 if(abs(tnons_mult(1))>1.00001e-8) tnons(1,isym)=tnons(1,isym)-tnons_mult(1) 1711 if(abs(tnons_mult(2))>1.00001e-8) tnons(2,isym)=tnons(2,isym)-tnons_mult(2) 1712 if(abs(tnons_mult(3))>1.00001e-8) tnons(3,isym)=tnons(3,isym)-tnons_mult(3) 1713 exit 1714 endif 1715 endif 1716 1717 enddo ! iorder 1718 1719 if(order==0)then 1720 ABI_BUG("Was unable to find order of operation") 1721 endif 1722 enddo 1723 1724 !DEBUG 1725 !write(std_out,'(a)') ' symmetrize_tnons : exit ' 1726 !ENDDEBUG 1727 1728 end subroutine symmetrize_tnons
m_symtk/symmetrize_xred [ Functions ]
[ Top ] [ m_symtk ] [ Functions ]
NAME
symmetrize_xred
FUNCTION
Symmetrize atomic coordinates. Two tasks can be executed : A. If optional argument indsym is present. Using input symmetry matrices symrel which are expressed in terms of the basis of real space primitive translations (array elements are integers), use indsym to make all corresponding atoms coordinate fullfil exactly symmetry operations. Input array indsym(4,isym,iatom) gives label of atom into which iatom is rotated by INVERSE of symmetry element isym and also gives primitive translation to get back to unit cell. This version uses improvement in algorithm suggested by Andrew Horsfield (see symatm.f). B. If optional argument tolsym AND tnons_new are defined. Might also adjust xred in order for tnons to be aligned with the FFT grids. This will deliver new tnons_new. NOTE : Actually, should make two separate routines !
INPUTS
indsym(4,nsym,natom)=(optional) indirect indexing array giving label of atom into which iatom is rotated by symmetry element isym natom=number of atoms nsym=number of symmetries in group symrel(3,3,nsym)=symmetry matrices in terms of real space primitive translations tnons(3,nsym)=nonsymmorphic translations for symmetries tolsym=(optional) tolerance on symmetries. When defined, one will try to align the symmetry operations with the FFT grid, if the modification is less than tolsym. Take tolsym equal to 1 to deliver possibly large changes of xred, giving suggestions of xred modifications, to be proposed to users.
OUTPUT
tnons_new(3,nsym)=(optional)nonsymmorphic translations for symmetries
SIDE EFFECTS
Input/Output xred(3,natom)= (input) atomic coordinates in terms of real space translations (output) symmetrized atomic coordinates in terms of real space translations fixed_mismatch=(optional) At input, needs to be present for tnons_new to be computed At output : 1 if there is a mismatch and this mismatch has been fixed, 0 otherwise mismatch_fft_tnons=(optional) At input, needs to be present for tnons_new to be computed Atd output : non-zero if there is a mismatch between the fft grid and the tnons, gives the number of the first symmetry operation for which there is such a mismatch. Zero otherwise.
SOURCE
1783 subroutine symmetrize_xred(natom,nsym,symrel,tnons,xred,fixed_mismatch,indsym,mismatch_fft_tnons,tnons_new,tolsym) 1784 1785 !Arguments ------------------------------------ 1786 !scalars 1787 integer,intent(in) :: natom,nsym 1788 integer,intent(out),optional :: fixed_mismatch,mismatch_fft_tnons 1789 !arrays 1790 integer,intent(in),optional :: indsym(4,nsym,natom) 1791 integer,intent(in) :: symrel(3,3,nsym) 1792 real(dp),intent(in) :: tnons(3,nsym) 1793 real(dp),intent(in),optional :: tolsym 1794 real(dp),intent(out),optional :: tnons_new(3,nsym) 1795 real(dp),intent(inout) :: xred(3,natom) 1796 1797 !Local variables------------------------------- 1798 !scalars 1799 integer :: iatom,ib,ii,info,irank,isym,isym2 1800 integer :: jj,mismatch_fft_tnons_current 1801 real(dp) :: diff 1802 logical :: dissimilar 1803 !arrays 1804 real(dp) :: delta(4),fc(3),mat(3,3),mult(4)=(/eight,nine,ten,three*four/) 1805 real(dp) :: sgval(3),tsum(3),tt(3),work(15),xredshift(3,1) 1806 real(dp),allocatable :: xredsym(:,:) 1807 real(dp) :: transl(3) ! translation vector 1808 1809 ! ************************************************************************* 1810 ! 1811 !Check whether group contains more than identity; 1812 !if not then simply return after possible copying 1813 if(present(tnons_new))then 1814 tnons_new(:,1:nsym)=tnons(:,1:nsym) 1815 endif 1816 if(present(fixed_mismatch))fixed_mismatch=0 1817 if(present(mismatch_fft_tnons))mismatch_fft_tnons=0 1818 1819 if (nsym>1) then 1820 1821 !DEBUG 1822 ! write(std_out,*) 1823 ! write(std_out,'(a,i4)') 'symmetrize_xred: enter, nsym=',nsym 1824 ! do iatom=1,natom 1825 ! write(std_out,'(a,i4,3es16.6)') 'iatom,xred=',iatom,xred(:,iatom) 1826 ! enddo 1827 ! do isym=1,nsym 1828 ! write(std_out,'(a,i4,9i3,3es16.6)') 'isym,symrel,tnons',isym,symrel(:,:,isym),tnons(:,isym) 1829 ! enddo 1830 ! write(std_out,*)' present(tnons_new),present(tolsym)=',present(tnons_new),present(tolsym) 1831 ! write(std_out,*) 1832 !ENDDEBUG 1833 1834 ABI_MALLOC(xredsym,(3,natom)) 1835 xredsym(:,:)=xred(:,1:natom) 1836 1837 if(present(indsym))then 1838 1839 ! Loop over atoms to determine new, symmetrized positions. 1840 do iatom=1,natom 1841 tsum(:)=0.0d0 1842 ! 1843 ! Loop over symmetries 1844 do isym=1,nsym 1845 ! atom ib is atom into which iatom is rotated by inverse of 1846 ! symmetry isym (inverse of symrel(mu,nu,isym)) 1847 ib=indsym(4,isym,iatom) 1848 ! Find the reduced coordinates after translation=t(indsym)+transl 1849 fc(:)=xred(:,ib)+dble(indsym(1:3,isym,iatom)) 1850 ! Compute [S * (x(indsym)+transl) ] + tnonsymmorphic 1851 tt(:)=dble(symrel(:,1,isym))*fc(1)+& 1852 & dble(symrel(:,2,isym))*fc(2)+& 1853 & dble(symrel(:,3,isym))*fc(3)+ tnons(:,isym) 1854 1855 ! Average over nominally equivalent atomic positions 1856 tsum(:)=tsum(:)+tt(:) 1857 end do ! isym 1858 ! 1859 ! Set symmetrized result to sum over number of terms 1860 xredsym(:,iatom)=tsum(:)/dble(nsym) 1861 1862 end do ! iatom 1863 endif ! present(indsym) 1864 1865 !DEBUG 1866 !do iatom=1,natom 1867 ! write(std_out,'(a,i4,3es20.10)') 'iatom,xredsym=',iatom,xredsym(:,iatom) 1868 !enddo 1869 !ENDDEBUG 1870 1871 ! Loop over symmetry operations to determine possibly new tnons, as well as symmetrized positions. 1872 if(present(tolsym) .and. present(tnons_new) .and. present(fixed_mismatch) .and. present(mismatch_fft_tnons))then 1873 fixed_mismatch=0 1874 mismatch_fft_tnons=0 1875 !The use of tolsym here is only to favor 0.5 over -0.5 1876 tnons_new(:,:)=tnons(:,:)-nint(tnons(:,:)-tolsym) 1877 do isym=1,nsym 1878 mismatch_fft_tnons_current=0 1879 do ii=1,3 1880 delta(:)=tnons(ii,isym)*mult(:) 1881 delta(:)=delta(:)-nint(delta(:)) 1882 ! Is there is a mismatch between FFT and isym for all multipliers ? 1883 if( all(abs(delta(:))>tol8*mult(:)) ) mismatch_fft_tnons_current=1 1884 enddo 1885 !Declare the first symmetry operation that induces a problem 1886 if(mismatch_fft_tnons_current>0 .and. (mismatch_fft_tnons==0)) mismatch_fft_tnons=isym 1887 1888 ! However, also try to propose a solution. 1889 if(mismatch_fft_tnons_current==1)then 1890 ! Compute the pseudo-inverse of symrel-1, then multiply tnons 1891 mat(:,:)=zero; mat(1,1)=one; mat(2,2)=one; mat(3,3)=one 1892 ! This is symrel-1 1893 mat(:,:)=symrel(:,:,isym)-mat(:,:) 1894 do ii=1,3 1895 !Select the smallest modification tnons 1896 delta(:)=tnons(ii,isym)*mult(:) 1897 delta(:)=(delta(:)-nint(delta(:)))/mult(:) 1898 xredshift(ii,1)=delta(1) 1899 do jj=2,4 1900 if(abs(delta(jj))<abs(xredshift(ii,1)))xredshift(ii,1)=delta(jj) 1901 enddo 1902 enddo 1903 call dgelss(3,3,1,mat,3,xredshift(:,1),3,sgval,tol5,irank,work,15,info) 1904 1905 ! xredshift(:,1) is now the tentative shift, to be tested for all symmetries 1906 if( all(abs(xredshift(:,1))<tolsym) )then 1907 fixed_mismatch=1 1908 do isym2=1, nsym 1909 tnons_new(:,isym2)=tnons(:,isym2)+xredshift(:,1)-matmul(symrel(:,:,isym2),xredshift(:,1)) 1910 do ii=1,3 1911 !tnons might now be slighly non-zero. Set to zero such values 1912 if(abs(tnons_new(ii,isym2))<tol6**2)tnons_new(ii,isym2)=zero 1913 delta(:)=tnons_new(ii,isym2)*mult(:) 1914 delta(:)=delta(:)-nint(delta(:)) 1915 ! Is the mismatch between FFT and symmetries still present for all the multipliers ?? 1916 if( all(abs(delta(:))>tol8*mult(:)) ) fixed_mismatch=0 1917 enddo 1918 if(fixed_mismatch==0)exit 1919 enddo 1920 endif 1921 if(fixed_mismatch==1)exit 1922 endif ! mismatch_fft_tnons_current==1 1923 end do ! isym 1924 if(mismatch_fft_tnons/=0)then 1925 if(fixed_mismatch==1)then 1926 do iatom=1,natom 1927 xredsym(:,iatom)=xredsym(:,iatom)+xredshift(:,1) 1928 enddo 1929 endif 1930 endif 1931 1932 !DEBUG 1933 ! write(std_out,*) ' ' 1934 ! write(std_out,*) ' mismatch_fft_tnons, fixed_mismatch=',mismatch_fft_tnons, fixed_mismatch 1935 ! do iatom=1,natom 1936 ! write(std_out,'(a,i4,3es20.10)') ' iatom,xredsym=',iatom,xredsym(:,iatom) 1937 ! enddo 1938 !ENDDEBUG 1939 1940 endif ! present(tolsym) .and. present(tnons_new) 1941 1942 ! -------------------------------------------------------------- 1943 ! Will update the atomic positions only if it is worth to do so. 1944 1945 transl(:)=xredsym(:,1)-nint(xredsym(:,1)) 1946 1947 ! Compute the smallest translation to an integer 1948 do jj=2,natom 1949 do ii=1,3 1950 diff=xredsym(ii,jj)-nint(xredsym(ii,jj)) 1951 if (diff<transl(ii)) transl(ii)=diff 1952 end do 1953 end do 1954 1955 ! Test if the translation on each direction is small 1956 ! Tolerance 1E-13 1957 do ii=1,3 1958 if (abs(transl(ii))>1e-13) transl(ii)=0.0 1959 end do 1960 1961 ! Execute translation 1962 do jj=1,natom 1963 do ii=1,3 1964 xredsym(ii,jj)=xredsym(ii,jj)-transl(ii) 1965 end do 1966 end do 1967 1968 ! Test if xredsym is too similar to xred 1969 ! Tolerance 1E-15 1970 dissimilar=.FALSE. 1971 do jj=1,natom 1972 do ii=1,3 1973 if (abs(xredsym(ii,jj)-xred(ii,jj))>1E-15) dissimilar=.TRUE. 1974 end do 1975 end do 1976 1977 if (dissimilar) xred(:,:)=xredsym(:,:) 1978 ABI_FREE(xredsym) 1979 1980 ! End condition of nsym/=1 1981 end if 1982 1983 !DEBUG 1984 !write(std_out,*) 1985 !write(std_out,'(a)') 'symmetrize_xred : exit' 1986 !do iatom=1,natom 1987 ! write(std_out,'(a,i4,3es20.10)') 'iatom,xred=',iatom,xred(:,iatom) 1988 !enddo 1989 !if(present(tnons_new))then 1990 ! do isym=1,nsym 1991 ! write(std_out,'(a,i4,9i3,3es20.10)') 'isym,symrel,tnons_new',isym,symrel(:,:,isym),tnons_new(:,isym) 1992 ! enddo 1993 !endif 1994 !write(std_out,*) 1995 !ENDDEBUG 1996 1997 end subroutine symmetrize_xred
m_symtk/symplanes [ Functions ]
[ Top ] [ m_symtk ] [ Functions ]
NAME
symplanes
FUNCTION
Determines the type of symmetry mirror planes: m,a,b,c,d,n,g. This is used (see symlist.f) to identify the space group.
INPUTS
center=type of bravais lattice 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 iholohedry=type of holohedry 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 isym=number of the symmetry operation that is currently analyzed isymrelconv=symrel matrix for the particular operation, in conv. coord. itnonsconv=tnons vector for the particular operation, in conv. coord
OUTPUT
label=user friendly label of the plane type_axis=type of the symmetry operation
NOTES
One follows the conventions explained in table 1.3 of the international tables for crystallography. In the case of the rhombohedral system, one takes into account the first footnote of this table 1.3 . In general, we will assign the different symmetries to the following numbers : m -> 15 , (a, b or c) -> 16, d -> 17, n -> 18 , g -> 19 However, there is the same problem as for binary axes, namely, for parallel mirror planes, one can find different translation vectors, and these might be found at random, depending on the input tnons. (1) In the tP case, one will distinguish tertiary mirror plane, for which it is important to know whether they are m or c (for tertiary planes in tP, g is equivalent to m and n is equivalent to c). On the other hand, it is important to distinguish among primary and secondary mirror planes, those that are m,(a or b),c, or n. To summarize, the number of the symmetry will be : m (primary, secondary or tertiary) -> 15 , secondary (a or b) -> 16, secondary c -> 17, primary or secondary n -> 18 , tertiary c -> 19 (2) In the tI case, one will distinguish tertiary mirror plane, for which it is important to know whether they are m or d (for tertiary planes in tI, c is equivalent to m. On the other hand, it is important to distinguish among primary and secondary mirror planes, those that are m (equivalent to n), or a,b or c. To summarize, the number of the symmetry will be : m (primary, secondary, tertiary) -> 15 , a,b or c (primary or secondary) -> 16, tertiary d -> 17 (3) For hP and hR, a m plane is always coupled to a a or b plane, while a c plane is always coupled to an n plane. On the other hand, it is important to distinguish between primary or secondary mirror planes, and tertiary mirror planes. So we will keep the following sets : m non-tertiary (that includes a or b non-tertiary) -> 15, c non-tertiary (that includes n non-tertiary) -> 16, m tertiary (that includes a or b non-tertiary) -> 17, c tertiary (that includes n non-tertiary) -> 18. For hR, all mirror planes are secondary. (4) For the cP lattice, in the same spirit, one can see that the tertiary m and g mirror planes are to be classified as "m" -> 15, while n, a and c are to be classified as "n" -> 18. There is no need to distinguish between primary, secondary or tertiary axes.
SOURCE
2849 subroutine symplanes(center,iholohedry,isym,isymrelconv,itnonsconv,label,type_axis) 2850 2851 !Arguments ------------------------------------ 2852 !scalars 2853 integer,intent(in) :: center,iholohedry,isym 2854 integer,intent(out) :: type_axis 2855 character(len = 128), intent(out) :: label 2856 !arrays 2857 integer,intent(in) :: isymrelconv(3,3) 2858 real(dp),intent(in) :: itnonsconv(3) 2859 2860 !Local variables------------------------------- 2861 !scalars 2862 logical,parameter :: verbose=.FALSE. 2863 character(len=500) :: msg 2864 integer :: directiontype,sum_elements 2865 real(dp),parameter :: nzero=1.0d-6 2866 !arrays 2867 integer :: identity(3,3),mirrormxy(3,3),mirrormyz(3,3),mirrormzx(3,3) 2868 integer :: mirrorx(3,3),mirrorxy(3,3),mirrory(3,3),mirroryz(3,3),mirrorz(3,3) 2869 integer :: mirrorzx(3,3) 2870 real(dp) :: trialt(3) 2871 ! real(dp) :: itnonsconv2(3),trialt2(3) 2872 2873 !************************************************************************** 2874 2875 !write(std_out,*)' symplanes : enter' 2876 !write(std_out,*)' center,iholohedry,isym,isymrelconv,itnonsconv=',center,iholohedry,isym,isymrelconv,itnonsconv 2877 2878 identity(:,:)=0 2879 identity(1,1)=1 ; identity(2,2)=1 ; identity(3,3)=1 2880 2881 !Will be a mirror plane, but one must characterize 2882 !(1) the type of plane (primary, secondary or tertiary) 2883 !(2) the gliding vector. One now defines a few matrices. 2884 mirrorx(:,:)=identity(:,:) ; mirrorx(1,1)=-1 2885 mirrory(:,:)=identity(:,:) ; mirrory(2,2)=-1 2886 mirrorz(:,:)=identity(:,:) ; mirrorz(3,3)=-1 2887 mirrorxy(:,:)=0 ; mirrorxy(1,2)=1 ; mirrorxy(2,1)=1 ; mirrorxy(3,3)=1 2888 mirrorzx(:,:)=0 ; mirrorzx(1,3)=1 ; mirrorzx(3,1)=1 ; mirrorzx(2,2)=1 2889 mirroryz(:,:)=0 ; mirroryz(2,3)=1 ; mirroryz(3,2)=1 ; mirroryz(1,1)=1 2890 mirrormxy(:,:)=0 ; mirrormxy(1,2)=-1 ; mirrormxy(2,1)=-1 ; mirrormxy(3,3)=1 2891 mirrormzx(:,:)=0 ; mirrormzx(1,3)=-1 ; mirrormzx(3,1)=-1 ; mirrormzx(2,2)=1 2892 mirrormyz(:,:)=0 ; mirrormyz(2,3)=-1 ; mirrormyz(3,2)=-1 ; mirrormyz(1,1)=1 2893 2894 !Determine the type of plane. At the end, 2895 !directiontype=1 will correspond to a primary axis (or equivalent 2896 !axes for orthorhombic) 2897 !directiontype=2 will correspond to a secondary axis 2898 !directiontype=3 will correspond to a tertiary axis 2899 !See table 2.4.1, 11.2 and 11.3 of the international tables for crystallography 2900 directiontype=0 2901 !The sum of elements of the matrices allow to characterize them 2902 sum_elements=sum(isymrelconv(:,:)) 2903 2904 if(sum_elements==1)then 2905 ! The mirror plane perpendicular to the c axis is always primary 2906 if( sum(abs(isymrelconv(:,:)-mirrorz(:,:)))==0 )then 2907 directiontype=1 2908 ! All the other planes with a symrel matrix whose sum of elements is 1 2909 ! are a or b planes. They are primary or 2910 ! secondary planes, depending the holohedry. 2911 else if(sum(isymrelconv(:,:))==1)then 2912 if( iholohedry==2 .or. iholohedry==3 .or. iholohedry==7 )then 2913 directiontype=1 2914 else if(iholohedry==4 .or. iholohedry==6)then 2915 directiontype=2 2916 end if 2917 end if 2918 end if 2919 2920 !All the planes with a symrel matrix whose sum of elements 2921 !is 2 are secondary planes (table 11.3). 2922 if( sum_elements==2 ) directiontype=2 2923 2924 !The planes with a symrel matrix whose sum of elements 2925 !is 3 or 0 are tertiary planes 2926 if( sum_elements==3 .or. sum_elements==0 )directiontype=3 2927 2928 !One is left with sum_elements=-1, tertiary for tetragonal 2929 !or cubic, secondary for hexagonal 2930 if( sum_elements==-1)then 2931 if(iholohedry==4 .or. iholohedry==7)directiontype=3 2932 if(iholohedry==6)directiontype=2 2933 end if 2934 2935 2936 !Now, determine the gliding vector 2937 !First, apply the symmetry operation 2938 !to itnonsconv, in order to get the translation vector 2939 !under the application of twice the symmetry operation 2940 trialt(:)=matmul(isymrelconv(:,:),itnonsconv(:)) +itnonsconv(:) 2941 !Get the translation associated with one application, 2942 !and force its components to be in the interval ]-0.5,0.5] . 2943 trialt(:)=trialt(:)*half 2944 trialt(:)=trialt(:)-nint(trialt(:)-nzero) 2945 2946 !If there is a glide vector for the initial choice of itnonsconv, 2947 !it might be that it disappears if itnonsconv is translated by a 2948 !lattice vector of the conventional cell 2949 !if(trialt(1)**2+trialt(2)**2+trialt(3)**2>tol5)then 2950 !do ii=1,3 2951 !itnonsconv2(:)=itnonsconv(:) 2952 !itnonsconv2(ii)=itnonsconv(ii)+one 2953 !trialt2(:)=matmul(isymrelconv(:,:),itnonsconv2(:)) +itnonsconv2(:) 2954 !trialt2(:)=trialt2(:)*half 2955 !trialt2(:)=trialt2(:)-nint(trialt2(:)-nzero) 2956 !if(trialt2(1)**2+trialt2(2)**2+trialt2(3)**2<tol5)then 2957 !trialt(:)=trialt2(:) 2958 !endif 2959 !enddo 2960 !endif 2961 2962 write(msg,'(a)') ' symplanes...' 2963 2964 !Must use the convention of table 1.3 of the international 2965 !tables for crystallography, see also pp 788 and 789. 2966 !Often, one needs to specialize the selection according 2967 !to the Bravais lattice or the system. 2968 2969 if(sum(abs(trialt(:)))<nzero .and. iholohedry/=6)then 2970 type_axis=15 ! m 2971 write(label,'(a)') 'a mirror plane' 2972 else if(iholohedry==4 .and. center==0)then ! primitive tetragonal 2973 2974 if(directiontype==1)then 2975 type_axis=18 ! primary n 2976 write(label,'(a)') 'a primary n plane' 2977 else if(directiontype==2)then 2978 if(sum(abs(trialt(:)-(/half,zero,zero/)))<nzero .or. sum(abs(trialt(:)-(/zero,half,zero/)))<nzero)then 2979 type_axis=16 ! secondary a or b 2980 write(label,'(a)') 'a secondary a or b plane' 2981 else if(sum(abs(trialt(:)-(/zero,zero,half/)))<nzero)then 2982 type_axis=17 ! secondary c 2983 write(label,'(a)') 'a secondary c plane' 2984 else 2985 type_axis=18 ! secondary n 2986 write(label,'(a)') 'a secondary n plane' 2987 end if ! directiontype==2 2988 else if(directiontype==3)then 2989 if( abs(trialt(3))<nzero )then 2990 type_axis=15 ! tertiary m 2991 write(label,'(a)') 'a tertiary m plane' 2992 else if( abs(trialt(3)-half)<nzero )then 2993 type_axis=19 ! tertiary c 2994 write(label,'(a)') 'a tertiary c plane' 2995 end if 2996 end if 2997 2998 else if(iholohedry==4 .and. center==-1)then ! inner tetragonal 2999 3000 if(directiontype==1 .or. directiontype==2)then 3001 if(sum(abs(trialt(:)-(/half,zero,zero/)))<nzero .or. & 3002 sum(abs(trialt(:)-(/zero,half,zero/)))<nzero .or. & 3003 sum(abs(trialt(:)-(/zero,zero,half/)))<nzero )then 3004 type_axis=16 ! a, b, or c 3005 write(label,'(a)') 'an a, b or c plane' 3006 else if(sum(abs(trialt(:)-(/half,half,zero/)))<nzero .or. & 3007 sum(abs(trialt(:)-(/zero,half,half/)))<nzero .or. & 3008 sum(abs(trialt(:)-(/half,zero,half/)))<nzero )then 3009 type_axis=15 ! n plane, equivalent to m 3010 write(label,'(a)') 'a m plane' 3011 end if ! directiontype==1 or 2 3012 else if(directiontype==3)then 3013 if( abs(trialt(3))<nzero .or. abs(trialt(3)-half)<nzero )then 3014 type_axis=15 ! tertiary c, equivalent to m 3015 write(label,'(a)') 'a tertiary m plane' 3016 else 3017 type_axis=17 ! tertiary d 3018 write(label,'(a)') 'a tertiary d plane' 3019 end if 3020 end if 3021 3022 else if(iholohedry==5)then ! hR 3023 3024 if( abs(sum(abs(trialt(:)))-one) < nzero) then 3025 type_axis=15 ! secondary m 3026 write(label,'(a)') 'a secondary m plane' 3027 else if( abs(sum(abs(trialt(:)))-half) < nzero .or. abs(sum(abs(trialt(:)))-three*half) < nzero )then 3028 type_axis=16 ! secondary c 3029 write(label,'(a)') 'a secondary c plane' 3030 end if 3031 3032 else if(iholohedry==6)then ! hP 3033 3034 if(directiontype==1)then 3035 if( abs(trialt(3)) <nzero )then 3036 type_axis=15 ! primary m 3037 write(label,'(a)') 'a primary m plane' 3038 end if 3039 else if(directiontype==2)then 3040 if( abs(trialt(3)) <nzero )then 3041 type_axis=15 ! secondary m 3042 write(label,'(a)') 'a secondary m plane' 3043 else if( abs(trialt(3)-half) < nzero ) then 3044 type_axis=16 ! secondary c 3045 write(label,'(a)') 'a secondary c plane' 3046 end if 3047 else if(directiontype==3)then 3048 if( abs(trialt(3)) <nzero )then 3049 type_axis=17 ! tertiary m 3050 write(label,'(a)') 'a tertiary m plane' 3051 else if( abs(trialt(3)-half) < nzero ) then 3052 type_axis=18 ! tertiary c 3053 write(label,'(a)') 'a tertiary c plane' 3054 end if 3055 end if ! directiontype 3056 3057 ! else if(iholohedry==7 .and. center==0)then ! cP 3058 else if(iholohedry==7)then ! cP 3059 3060 if(directiontype==1)then 3061 if((sum(abs(isymrelconv(:,:)-mirrorx(:,:)))==0 .and. & 3062 sum(abs(two*abs(trialt(:))-(/zero,half,half/)))<nzero ).or. & 3063 (sum(abs(isymrelconv(:,:)-mirrory(:,:)))==0 .and. & 3064 sum(abs(two*abs(trialt(:))-(/half,zero,half/)))<nzero ).or. & 3065 (sum(abs(isymrelconv(:,:)-mirrorz(:,:)))==0 .and. & 3066 sum(abs(two*abs(trialt(:))-(/half,half,zero/)))<nzero ) ) then 3067 type_axis=17 ! d 3068 write(label,'(a)') 'a d plane' 3069 else 3070 type_axis=18 ! primary n 3071 write(label,'(a)') 'a primary n plane' 3072 end if 3073 else if(directiontype==3)then 3074 if(sum(abs(two*abs(trialt(:))-(/half,half,half/)))<nzero )then 3075 type_axis=17 ! d 3076 write(label,'(a)') 'a d plane' 3077 else if( abs(sum(abs(trialt(:)))-half) < nzero .or. abs(sum(abs(trialt(:)))-three*half) < nzero ) then 3078 type_axis=18 ! tertiary n 3079 write(label,'(a)') 'a tertiary n plane' 3080 else if( abs(sum(abs(trialt(:)))-one) < nzero )then 3081 type_axis=15 ! tertiary m 3082 write(label,'(a)') 'a tertiary m plane' 3083 end if 3084 end if 3085 3086 ! Now, treat all other cases (including other centered Bravais lattices) 3087 else if(sum(abs(trialt(:)-(/half,zero,zero/)))<nzero .or. & 3088 sum(abs(trialt(:)-(/zero,half,zero/)))<nzero .or. & 3089 sum(abs(trialt(:)-(/zero,zero,half/)))<nzero )then 3090 type_axis=16 ! a, b or c 3091 write(label,'(a)') 'an a,b, or c plane' 3092 else if( (directiontype==1 .or. directiontype==2) .and. & 3093 (sum(abs(trialt(:)-(/half,half,zero/)))<nzero .or. & 3094 sum(abs(trialt(:)-(/zero,half,half/)))<nzero .or. & 3095 sum(abs(trialt(:)-(/half,zero,half/)))<nzero ) )then 3096 type_axis=18 ! n 3097 write(label,'(a)') 'an n plane' 3098 else if( directiontype==3 .and. sum(abs(trialt(:)-(/half,half,half/)))<nzero )then 3099 type_axis=18 ! n 3100 write(label,'(a)') 'an n plane' 3101 else if((sum(abs(isymrelconv(:,:)-mirrorx(:,:)))==0 .and. & 3102 sum(abs(two*abs(trialt(:))-(/zero,half,half/)))<nzero ).or. & 3103 (sum(abs(isymrelconv(:,:)-mirrory(:,:)))==0 .and. & 3104 sum(abs(two*abs(trialt(:))-(/half,zero,half/)))<nzero ).or. & 3105 (sum(abs(isymrelconv(:,:)-mirrorz(:,:)))==0 .and. & 3106 sum(abs(two*abs(trialt(:))-(/half,half,zero/)))<nzero ) ) then 3107 type_axis=17 ! d 3108 write(label,'(a)') 'a d plane' 3109 else if( directiontype==3 .and. sum(abs(two*abs(trialt(:))-(/half,half,half/)))<nzero)then 3110 type_axis=17 ! d 3111 write(label,'(a)') 'a d plane' 3112 else 3113 type_axis=19 ! g (all other planes with 3114 ! unconventional glide vector) 3115 write(label,'(a)') 'a g plane' 3116 end if 3117 3118 if (verbose) then 3119 write(msg,'(a,i3,a,a)')' symplanes : the symmetry operation no. ',isym,' is ', trim(label) 3120 call wrtout(std_out,msg) 3121 end if 3122 3123 end subroutine symplanes
m_symtk/symrelrot [ Functions ]
[ Top ] [ m_symtk ] [ Functions ]
NAME
symrelrot
FUNCTION
Transform the symmetry matrices symrel expressed in the coordinate system rprimd, to symmetry matrices symrel expressed in the new coordinate system rprimd_new
INPUTS
nsym=number of symmetries rprimd(3,3)=dimensional primitive translations for real space (bohr) rprimd_new(3,3)=new dimensional primitive translations for real space (bohr)
OUTPUT
(see side effects)
SIDE EFFECTS
Input/Output ierr= (at input) if present, will deal with error code outside of the routine. (at output) return 0 if no problem, 1 otherwise symrel(3,3,nsym)=symmetry operations in real space in terms of primitive translations rprimd at input and rprimd_new at output
SOURCE
1000 subroutine symrelrot(nsym, rprimd, rprimd_new, symrel, tolsym, ierr) 1001 1002 !Arguments ------------------------------------ 1003 !scalars 1004 integer,intent(in) :: nsym 1005 integer,intent(inout),optional :: ierr 1006 real(dp),intent(in) :: tolsym 1007 !arrays 1008 integer,intent(inout) :: symrel(3,3,nsym) 1009 real(dp),intent(in) :: rprimd(3,3),rprimd_new(3,3) 1010 1011 !Local variables------------------------------- 1012 !scalars 1013 integer :: ierr_,ii,isym,jj 1014 real(dp) :: val 1015 character(len=500) :: msg 1016 !arrays 1017 integer :: symrel_tmp(3,3,nsym) 1018 real(dp) :: coord(3,3),coordinvt(3,3),matr1(3,3),matr2(3,3),rprimd_invt(3,3) 1019 1020 !************************************************************************** 1021 1022 ierr_=0 1023 1024 !Compute the coordinates of rprimd_new in the system defined by rprimd(:,:) 1025 call matr3inv(rprimd,rprimd_invt) 1026 do ii=1,3 1027 coord(:,ii)=rprimd_new(1,ii)*rprimd_invt(1,:)+ & 1028 & rprimd_new(2,ii)*rprimd_invt(2,:)+ & 1029 & rprimd_new(3,ii)*rprimd_invt(3,:) 1030 end do 1031 1032 !Transform symmetry matrices in the system defined by rprimd_new 1033 call matr3inv(coord,coordinvt) 1034 do isym=1,nsym 1035 do ii=1,3 1036 matr1(:,ii)=symrel(:,1,isym)*coord(1,ii)+& 1037 & symrel(:,2,isym)*coord(2,ii)+& 1038 & symrel(:,3,isym)*coord(3,ii) 1039 end do 1040 do ii=1,3 1041 matr2(:,ii)=coordinvt(1,:)*matr1(1,ii)+& 1042 & coordinvt(2,:)*matr1(2,ii)+& 1043 & coordinvt(3,:)*matr1(3,ii) 1044 end do 1045 1046 !DEBUG 1047 ! write(std_out, '(a,10i4)')' symrelrot : isym, symrel=',isym,symrel(:,:,isym) 1048 ! write(std_out, '(a,9es16.6)')' transformed to ', matr2(:,:) 1049 !ENDDEBUG 1050 1051 ! Check that the new symmetry matrices are made of integers, and store them 1052 do ii=1,3 1053 do jj=1,3 1054 val=matr2(ii,jj) 1055 ! Need to allow for ten times tolsym, in case of centered Bravais lattices (but do it for all lattices ...) 1056 if(abs(val-nint(val))>ten*tolsym)then 1057 ierr_=1 1058 if(.not.(present(ierr))) then 1059 write(msg,'(2a,a,i3,a,a,3es14.6,a,a,3es14.6,a,a,3es14.6)')& 1060 'One of the components of symrel is non-integer within 10*tolsym,',ch10,& 1061 ' for isym=',isym,ch10,& 1062 ' symrel=',matr2(:,1),ch10,& 1063 ' ',matr2(:,2),ch10,& 1064 ' ',matr2(:,3) 1065 ABI_ERROR_CLASS(msg, "TolSymError") 1066 endif 1067 end if 1068 symrel_tmp(ii,jj,isym)=nint(val) 1069 end do 1070 end do 1071 end do ! isym 1072 1073 if(ierr_==0)then 1074 ! Upgrade symrel only if there is no error 1075 symrel(:,:,:)=symrel_tmp(:,:,:) 1076 endif 1077 1078 if(present(ierr))then 1079 ierr=ierr_ 1080 endif 1081 1082 end subroutine symrelrot