!===============================================================================
!
! gamma.F90
!
!-------------------------------------------------------------------------------
!
! Copyright (C) 2000-2008 Hinnerk Stueben
!               2007, 2011 Yoshifumi Nakamura
!
! This file is part of BQCD -- Berlin Quantum ChromoDynamics program
!
! BQCD is free software: you can redistribute it and/or modify
! it under the terms of the GNU General Public License as published by
! the Free Software Foundation, either version 3 of the License, or
! (at your option) any later version.
!
! BQCD is distributed in the hope that it will be useful,
! but WITHOUT ANY WARRANTY; without even the implied warranty of
! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
! GNU General Public License for more details.
!
! You should have received a copy of the GNU General Public License
! along with BQCD.  If not, see <http://www.gnu.org/licenses/>.
!
!-------------------------------------------------------------------------------
# include "defs.h"
# include "gamma.h"

!-------------------------------------------------------------------------------
subroutine gamma5(x, volh)

  implicit none
  COMPLEX, dimension (NDIRAC, *) :: x
  integer                        :: volh 

  integer :: i
  COMPLEX :: x1, x2, x3, x4

  !$omp parallel do private(x1, x2, x3, x4)
  do i = 1, NCOL * volh
     x1 = x(1, i)
     x2 = x(2, i)
     x3 = x(3, i)
     x4 = x(4, i)
#ifdef GAMMAC
     x(1, i) = x1
     x(2, i) = x2
     x(3, i) =-x3
     x(4, i) =-x4
#else     
     x(1, i) = x3
     x(2, i) = x4
     x(3, i) = x1
     x(4, i) = x2
#endif
  enddo
end

!-------------------------------------------------------------------------------
module gamma
  implicit none
  integer, parameter :: ngop = 19

  type gamma_matrix
     complex(8) :: c(4,4)
  end type
  type(gamma_matrix), save :: gamma_op(ngop) 

  logical, save :: ginit=.false. 


  integer, dimension(4,4), save :: igamma
  COMPLEX, dimension(4,4), save :: zgamma

  character(3), save :: gtext(ngop)

  data gtext(G0 )  /"G0"/
  data gtext(G1 )  /"G1"/
  data gtext(G2 )  /"G2"/
  data gtext(G3 )  /"G3"/
  data gtext(G5 )  /"G5"/
  data gtext(G01)  /"G01"/
  data gtext(G02)  /"G02"/
  data gtext(G03)  /"G03"/
  data gtext(G05)  /"G05"/
  data gtext(G15)  /"G15"/
  data gtext(G25)  /"G25"/
  data gtext(G35)  /"G35"/
  data gtext(G12)  /"G12"/
  data gtext(G23)  /"G23"/
  data gtext(G31)  /"G31"/
  data gtext(CGm)  /"CGm"/
  data gtext(UNP)  /"UNP"/
  data gtext(POL)  /"POL"/
  data gtext(Uni)  /"Uni"/


end module gamma

!-------------------------------------------------------------------------------
subroutine gamma_init()
  use gamma
  implicit none
  complex(8), dimension(4,4) :: g1,g2,g3,g4, gc
  integer :: i, j
  COMPLEX :: i_times, c
  i_times(c) = cmplx(-aimag(c), real(c), kind = RKIND)

  if (ginit) return
  DEBUG2S("Start: gamma_init")

  g1=ZERO
  g2=ZERO
  g3=ZERO
  g4=ZERO
  gc=ZERO

  do i = 1, ngop
     gamma_op(i)%c = ZERO
  enddo

  g1(1, 4) = cmplx(ZERO,-ONE)
  g1(2, 3) = cmplx(ZERO,-ONE)
  g1(3, 2) = cmplx(ZERO, ONE)
  g1(4, 1) = cmplx(ZERO, ONE)
  g2(1, 4) = -ONE
  g2(2, 3) =  ONE
  g2(3, 2) =  ONE
  g2(4, 1) = -ONE
  g3(1, 3) = cmplx(ZERO,-ONE)
  g3(2, 4) = cmplx(ZERO, ONE)
  g3(3, 1) = cmplx(ZERO, ONE)
  g3(4, 2) = cmplx(ZERO,-ONE)
  g4(1, 1) = ONE
  g4(2, 2) = ONE
  g4(3, 3) =-ONE
  g4(4, 4) =-ONE
  gc(1, 3) = ONE
  gc(2, 4) = ONE
  gc(3, 1) = ONE
  gc(4, 2) = ONE


#ifdef GAMMA_NOTATION_CHROMA
  gamma_op(G1)%c= -g1
  gamma_op(G2)%c=  g2
  gamma_op(G3)%c= -g3
  gamma_op(G0)%c=  gc
#elif defined GAMMA_NOTATION_CHIRAL
  gamma_op(G1)%c=  g1
  gamma_op(G2)%c=  g2
  gamma_op(G3)%c=  g3
  gamma_op(G0)%c=  gc
#elif defined GAMMA_NOTATION_DDHMC
  gamma_op(G1)%c=  g1
  gamma_op(G2)%c=  g2
  gamma_op(G3)%c=  g3
  gamma_op(G0)%c= -gc
#elif defined GAMMA_NOTATION_BQCD
  gamma_op(G1)%c= -g1
  gamma_op(G2)%c= -g2
  gamma_op(G3)%c= -g3
  gamma_op(G0)%c=  g4
#endif

  call spin_mul(g1,gamma_op(G1)%c, gamma_op(G2)%c)
  call spin_mul(g2,gamma_op(G3)%c, gamma_op(G0)%c)
  call spin_mul(gamma_op(G5)%c, g1, g2)

  call spin_mul(gamma_op(G01)%c, gamma_op(G0)%c, gamma_op(G1)%c)
  call spin_mul(gamma_op(G02)%c, gamma_op(G0)%c, gamma_op(G2)%c)
  call spin_mul(gamma_op(G03)%c, gamma_op(G0)%c, gamma_op(G3)%c)

  call spin_mul(gamma_op(G05)%c, gamma_op(G0)%c, gamma_op(G5)%c)
  call spin_mul(gamma_op(G15)%c, gamma_op(G1)%c, gamma_op(G5)%c)
  call spin_mul(gamma_op(G25)%c, gamma_op(G2)%c, gamma_op(G5)%c)
  call spin_mul(gamma_op(G35)%c, gamma_op(G3)%c, gamma_op(G5)%c)

  call spin_mul(gamma_op(G12)%c, gamma_op(G1)%c, gamma_op(G2)%c)
  call spin_mul(gamma_op(G23)%c, gamma_op(G2)%c, gamma_op(G3)%c)
  call spin_mul(gamma_op(G31)%c, gamma_op(G3)%c, gamma_op(G1)%c)   !! = CG5

  g1=HALF * (gamma_op(G2)%c + cmplx(ZERO, ONE) * gamma_op(G1)%c )
  call spin_mul(g2, gamma_op(G02)%c, g1)
  gamma_op(CGm)%c = - g2

  gamma_op(UNP)%c =  gamma_op(G0)%c
  gamma_op(UNP)%c(1,1) = gamma_op(UNP)%c(1,1) + ONE
  gamma_op(UNP)%c(2,2) = gamma_op(UNP)%c(2,2) + ONE
  gamma_op(UNP)%c(3,3) = gamma_op(UNP)%c(3,3) + ONE
  gamma_op(UNP)%c(4,4) = gamma_op(UNP)%c(4,4) + ONE
  gamma_op(UNP)%c = gamma_op(UNP)%c * HALF

  do i = 1, DIM
  do j = 1, DIM
     g1(i,j) = i_times(gamma_op(G35)%c(i,j))
  enddo
  enddo
  g1(1,1) = g1(1,1) + ONE
  g1(2,2) = g1(2,2) + ONE
  g1(3,3) = g1(3,3) + ONE
  g1(4,4) = g1(4,4) + ONE

  call spin_mul(gamma_op(POL)%c, gamma_op(UNP)%c, g1)

  do i = 1, 4
     gamma_op(Uni)%c(i,i) = ONE
  enddo

  call igamma_zgamma()
  ginit=.true.

  DEBUG2S("End: gamma_init")
end

!-------------------------------------------------------------------------------
subroutine spin_mul(g1, g2, g3) ! g1 = g2 * g3
  implicit none
  complex(8), dimension(4,4) :: g1, g2, g3
  integer :: i, j, k

  g1=0
  do i=1, 4
  do j=1, 4
  do k=1, 4
     g1(i,j) = g1(i,j) + g2(i, k) * g3(k, j)
  enddo
  enddo
  enddo
end

!-------------------------------------------------------------------------------
COMPLEX function spintr(g)
  implicit none
  complex(8), dimension(4,4) :: g
  integer :: i

  spintr=0
  do i=1, 4
     spintr = spintr + g(i,i)
  enddo
end

!===============================================================================
! C= gamma2 gamma4
! gamma- = (gamma2 + i gamma1)/2
!
!
! Definition used:          ( 1  0  0  0 )
!                           ( 0  0  0  0 )
!                 Cgamma- = ( 0  0  1  0 )
!                           ( 0  0  0  0 )
!
!
subroutine cgmxcgmt(out, in)                          ! (Cgamma- * in Cgamma-)^T
  implicit none
  COMPLEX, dimension(4,4), intent(out)  :: out
  COMPLEX, dimension(4,4), intent(in)   :: in

  out(1,1) =  in(1,1)
  out(2,1) =  ZERO
  out(3,1) =  in(1,3)
  out(4,1) =  ZERO

  out(1,2) =  ZERO
  out(2,2) =  ZERO
  out(3,2) =  ZERO
  out(4,2) =  ZERO

  out(1,3) =  in(3,1)
  out(2,3) =  ZERO
  out(3,3) =  in(3,3)
  out(4,3) =  ZERO

  out(1,4) =  ZERO
  out(2,4) =  ZERO
  out(3,4) =  ZERO
  out(4,4) =  ZERO

end

!-------------------------------------------------------------------------------
!//
!// copy from K.-I. Ishikawa's code
!// This is same as BQCD gamma notation
!//
subroutine igamma_zgamma()
  use gamma
  implicit none
  COMPLEX, parameter :: z1=(ONE, ZERO), zi=(ZERO, ONE)
  integer :: mu

      mu=1
      igamma(1,mu) = 4
      zgamma(1,mu) = -zi
      igamma(2,mu) = 3
      zgamma(2,mu) = -zi
      igamma(3,mu) = 2
      zgamma(3,mu) = zi
      igamma(4,mu) = 1
      zgamma(4,mu) = zi
      mu=2
      igamma(1,mu) = 4
      zgamma(1,mu) = -z1
      igamma(2,mu) = 3
      zgamma(2,mu) = z1
      igamma(3,mu) = 2
      zgamma(3,mu) = z1
      igamma(4,mu) = 1
      zgamma(4,mu) = -z1
      mu=3
      igamma(1,mu) = 3
      zgamma(1,mu) = -zi
      igamma(2,mu) = 4
      zgamma(2,mu) = zi
      igamma(3,mu) = 1
      zgamma(3,mu) = zi
      igamma(4,mu) = 2
      zgamma(4,mu) = -zi
      mu=4
      igamma(1,mu) = 1
      zgamma(1,mu) = z1
      igamma(2,mu) = 2
      zgamma(2,mu) = z1
      igamma(3,mu) = 3
      zgamma(3,mu) = -z1
      igamma(4,mu) = 4
      zgamma(4,mu) = -z1

end

!-------------------------------------------------------------------------------
!//
!// copy from Dirk's T3E version
!//
subroutine g31xg31t(out, in)                                  ! (G31 * in G31)^T
  implicit none
  COMPLEX, dimension(4,4), intent(out)  :: out
  COMPLEX, dimension(4,4), intent(in)   :: in

  out(1,1) = -in(2,2)
  out(2,1) =  in(2,1)
  out(3,1) = -in(2,4)
  out(4,1) =  in(2,3)

  out(1,2) =  in(1,2)
  out(2,2) = -in(1,1)
  out(3,2) =  in(1,4)
  out(4,2) = -in(1,3)

  out(1,3) = -in(4,2)
  out(2,3) =  in(4,1)
  out(3,3) = -in(4,4)
  out(4,3) =  in(4,3)

  out(1,4) =  in(3,2)
  out(2,4) = -in(3,1)
  out(3,4) =  in(3,4)
  out(4,4) = -in(3,3)

end
