rotmat.f90 Source File


Source Code

!-----------------------------------------------------------------------------------------!
! Copyright (c) 2018 Peter Grünberg Institut, Forschungszentrum Jülich, Germany           !
! This file is part of Jülich KKR code and available as free software under the conditions!
! of the MIT license as expressed in the LICENSE.md file in more detail.                  !
!-----------------------------------------------------------------------------------------!

!------------------------------------------------------------------------------------
!> Summary: Converts rotation/rotoinversion matrix
!> Author:
!> Converts rotation/rotoinversion matrix `<-> (nrot,vecg,li)`
!------------------------------------------------------------------------------------
module mod_rotmat

contains

  !-------------------------------------------------------------------------------
  !> Summary: Converts rotation/rotoinversion matrix
  !> Author: 
  !> Category: numerical-tools, geometry, KKRhost
  !> Deprecated: False 
  !> Converts rotation/rotoinversion matrix `<-> (nrot,vecg,li)`
  !-------------------------------------------------------------------------------
  subroutine rotmat(iopt, li, nrot, symopm, vecg)
    ! ----------------------------------------------------------------------
    ! i Inputs:
    ! i   iopt  := -1 to convert (nrot,vecg,li) in symopm
    ! i          =  1 to convert symopm in (nrot,vecg,li)
    ! i Inputs/Outputs:
    ! io  li    :if T: inversion or rotoinversion
    ! io  nrot  :rotation angle = 2*pi/nrot
    ! io  symopm:symmetry operation matrix
    ! io  vecg  :rotation axis
    ! ----------------------------------------------------------------------
    use :: mod_datatypes, only: dp
    use :: mod_ddet33
    use :: mod_errmsg
    use :: mod_nrmliz
    use :: mod_rinit
    use :: mod_constants, only: pi
    implicit none
    ! Passed parameters:
    integer :: iopt, nrot
    real (kind=dp) :: vecg(3), symopm(3, 3)
    logical :: li
    ! Local parameters:
    integer :: i, idamax, in, j
    real (kind=dp) :: costbn, detop, dnrm2, omcos, sintbn, sinpb3, tiny, twopi, vfac
    character (len=144) :: messg
    parameter (twopi=2.0_dp*pi)
    parameter (tiny=1.0e-3_dp)

    if (iopt==-1) then
      call rinit(9, symopm)
      in = abs(nrot)
      if (in==1) then
        call dcopy(3, 1.e0_dp, 0, symopm, 4)
      else if (in==2 .or. in==3 .or. in==4 .or. in==6) then
        sintbn = sin(twopi/nrot)
        costbn = cos(twopi/nrot)
        omcos = 1.e0_dp - costbn
        if (dnrm2(3,vecg,1)<tiny) call errmsg(' ROTMAT: zero rotation vector.$', 4)
        call nrmliz(1, vecg, vecg)
        symopm(1, 1) = omcos*vecg(1)*vecg(1) + costbn
        symopm(1, 2) = omcos*vecg(1)*vecg(2) - sintbn*vecg(3)
        symopm(1, 3) = omcos*vecg(1)*vecg(3) + sintbn*vecg(2)
        symopm(2, 1) = omcos*vecg(2)*vecg(1) + sintbn*vecg(3)
        symopm(2, 2) = omcos*vecg(2)*vecg(2) + costbn
        symopm(2, 3) = omcos*vecg(2)*vecg(3) - sintbn*vecg(1)
        symopm(3, 1) = omcos*vecg(3)*vecg(1) - sintbn*vecg(2)
        symopm(3, 2) = omcos*vecg(3)*vecg(2) + sintbn*vecg(1)
        symopm(3, 3) = omcos*vecg(3)*vecg(3) + costbn
      else
        call errmsg(' ROTMAT: bad nrot.$', 3)
      end if
      if (li) call dscal(9, -1.e0_dp, symopm(1,1), 1)

    else if (iopt==1) then
      ! ----- First calculate determinant.
      detop = ddet33(symopm)
      if (abs(abs(detop)-1.0e0_dp)>tiny) call errmsg(' ROTMAT: determinant is not +/- 1$', 4)
      detop = sign(1.e0_dp, detop)
      li = detop < 0.e0_dp
      ! ----- multiply operation symopm with detop
      call dscal(9, detop, symopm(1,1), 1)
      ! ----- For the rotation angle we have due to the normalization of v:
      ! ----- sum_i symopm(i,i) = sum_i (1-cos) v_i*v_i+3*cos = 1 + 2 * cos,
      costbn = -0.5e0_dp
      call daxpy(3, 0.5e0_dp, symopm(1,1), 4, costbn, 0)
      if (abs(costbn-1.e0_dp)<tiny) then
        nrot = 1
        call rinit(3, vecg)
      else
        nrot = nint(twopi/acos(max(-1.e0_dp,costbn)))
        ! ------- for nrot > 2 the matrix is non-symmetric and the rotation
        ! ------- axis can be calculated from the antisymmetric part.
        ! ------- for nrot = 2 this not possible. However, the squared vector
        ! ------- components are given by:  mat(i,i) = 2 v_i * v_i - 1.
        ! ------- This is used for the largest component. The others are taken
        ! ------- from: mat(i,j) = 2 v_i * v_j for i ne j. This way we also
        ! ------- get the right phases between the components.
        if (nrot==2) then
          do i = 1, 3
            vecg(i) = 0.5e0_dp*(symopm(i,i)+1.0e0_dp)
          end do
          j = idamax(3, vecg, 1)
          if (vecg(j)<0.0e0_dp) then
            write (messg, 100) j, symopm(j, j)
            call errmsg(messg, 4)
          end if
          vecg(j) = sqrt(vecg(j))
          vfac = 0.5e0_dp/vecg(j)
          do i = 1, 3
            if (i/=j) vecg(i) = vfac*symopm(i, j)
          end do
        else
          vecg(1) = symopm(3, 2) - symopm(2, 3)
          vecg(2) = symopm(1, 3) - symopm(3, 1)
          vecg(3) = symopm(2, 1) - symopm(1, 2)
        end if
        ! ------- next renormalize at least one component to 1 in order to
        ! ------- allow for abbreviations as 'D', 'X', 'Y' or 'Z'
        sinpb3 = sqrt(.75e0_dp)
        if (abs((sinpb3-abs(vecg(1)))*(sinpb3-abs(vecg(2)))*(sinpb3-abs(vecg(3))))>tiny) then
          do j = 3, 1, -1
            vfac = abs(vecg(j))
            if (vfac>tiny) call dscal(3, 1.e0_dp/vfac, vecg, 1)
          end do
        end if
      end if
      call dscal(9, detop, symopm(1,1), 1)
    end if

100 format (' ROTMAT: Bad component ', i1, ' of operation ', '. Diagonal element =', f9.5, '$')
  end subroutine rotmat

end module mod_rotmat