!===============================================================================
!
! clover_mult.F90
!
!-------------------------------------------------------------------------------
!
! Copyright (C) 1998-2011 Hinnerk Stueben
!               2008 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/>.
!
!-------------------------------------------------------------------------------
# define CLOVER_AS_COMPLEX_ARRAY
# include "defs.h"
# include "clover.h"

!-------------------------------------------------------------------------------
subroutine clover_mult_a(out, a, in, volh)  ! out := A in

  implicit none

  COMPLEX, dimension(18, 2, *)        :: a
#ifdef FLIPSC
  COMPLEX, dimension(NCOL, NDIRAC, *) :: out, in
#else
  COMPLEX, dimension(NDIRAC, NCOL, *) :: out, in
#endif
  integer                             :: volh

  integer :: i
  COMPLEX :: x1, x2, x3, x4, x5, x6
  COMPLEX :: y1, y2, y3, y4, y5, y6

  TIMING_START(timing_bin_clover_mult_a)
#ifdef IBM
  call alignx(16, in(1,1,1))
  call alignx(16, out(1,1,1))
  call alignx(16, a(1,1,1))
#endif
  !$omp parallel do private(x1, x2, x3, x4, x5, x6, y1, y2, y3, y4, y5, y6)
  do i = 1, volh

#ifdef GAMMAC
  x1 = in(SC1, i)
  x2 = in(SC2, i)
  x3 = in(SC3, i)
  x4 = in(SC4, i)
  x5 = in(SC5, i)
  x6 = in(SC6, i)
#else
  x1 = in(SC1, i) + in(SC7, i)
  x2 = in(SC2, i) + in(SC8, i)
  x3 = in(SC3, i) + in(SC9, i)
  x4 = in(SC4, i) + in(SC10, i)
  x5 = in(SC5, i) + in(SC11, i)
  x6 = in(SC6, i) + in(SC12, i)
#endif

# undef J
# define J 1
# include "clover_mult_a.h90"

#ifdef GAMMAC
  out(SC1, i) = y1
  out(SC2, i) = y2
  out(SC3, i) = y3
  out(SC4, i) = y4
  out(SC5, i) = y5
  out(SC6, i) = y6
  x1 =  in(SC7, i)
  x2 =  in(SC8, i)
  x3 =  in(SC9, i)
  x4 =  in(SC10, i)
  x5 =  in(SC11, i)
  x6 =  in(SC12, i)
#else
  out(SC1, i) = y1
  out(SC2, i) = y2
  out(SC3, i) = y3
  out(SC4, i) = y4
  out(SC5, i) = y5
  out(SC6, i) = y6
  out(SC7, i) = y1
  out(SC8, i) = y2
  out(SC9, i) = y3
  out(SC10, i) = y4
  out(SC11, i) = y5
  out(SC12, i) = y6

  x1 = in(SC1, i) - in(SC7, i)
  x2 = in(SC2, i) - in(SC8, i)
  x3 = in(SC3, i) - in(SC9, i)
  x4 = in(SC4, i) - in(SC10, i)
  x5 = in(SC5, i) - in(SC11, i)
  x6 = in(SC6, i) - in(SC12, i)
#endif

# undef J
# define J 2
# include "clover_mult_a.h90"

#ifdef GAMMAC
  out(SC7, i)  = y1
  out(SC8, i)  = y2
  out(SC9, i)  = y3
  out(SC10, i) = y4
  out(SC11, i) = y5
  out(SC12, i) = y6
#else
  out(SC1, i) = out(SC1, i) + y1
  out(SC2, i) = out(SC2, i) + y2
  out(SC3, i) = out(SC3, i) + y3
  out(SC4, i) = out(SC4, i) + y4
  out(SC5, i) = out(SC5, i) + y5
  out(SC6, i) = out(SC6, i) + y6
  out(SC7, i) = out(SC7, i) - y1
  out(SC8, i) = out(SC8, i) - y2
  out(SC9, i) = out(SC9, i) - y3
  out(SC10, i) = out(SC10, i) - y4
  out(SC11, i) = out(SC11, i) - y5
  out(SC12, i) = out(SC12, i) - y6
#endif

  enddo

  TIMING_STOP(timing_bin_clover_mult_a)
end

!-------------------------------------------------------------------------------
subroutine clover_mult_b(b, x, volh)  ! x := B x

  implicit none

  COMPLEX, dimension(18, 2, *)        :: b
#ifdef FLIPSC
  COMPLEX, dimension(NCOL, NDIRAC, *) :: x
#else
  COMPLEX, dimension(NDIRAC, NCOL, *) :: x
#endif
  integer                             :: volh

  integer :: i
  COMPLEX :: x1, x2, x3, x4, x5, x6
  COMPLEX :: y1, y2, y3, y4, y5, y6

  TIMING_START(timing_bin_clover_mult_b)

#ifdef IBM
  call alignx(16, x(1,1,1))
  call alignx(16, b(1,1,1))
#endif
  !$omp parallel do private(x1, x2, x3, x4, x5, x6, y1, y2, y3, y4, y5, y6)
  do i = 1, volh

#ifdef GAMMAC
     y1 = x(SC1, i)
     y2 = x(SC2, i)
     y3 = x(SC3, i)
     y4 = x(SC4, i)
     y5 = x(SC5, i)
     y6 = x(SC6, i)
#else
     y1 = x(SC1, i) + x(SC7, i)
     y2 = x(SC2, i) + x(SC8, i)
     y3 = x(SC3, i) + x(SC9, i)
     y4 = x(SC4, i) + x(SC10, i)
     y5 = x(SC5, i) + x(SC11, i)
     y6 = x(SC6, i) + x(SC12, i)
#endif

# undef J
# define J 1
# include "clover_mult_b.h90"

#ifdef GAMMAC
     y1 = x(SC7, i)
     y2 = x(SC8, i)
     y3 = x(SC9, i)
     y4 = x(SC10, i)
     y5 = x(SC11, i)
     y6 = x(SC12, i)
     x(SC1, i) = x1
     x(SC2, i) = x2
     x(SC3, i) = x3
     x(SC4, i) = x4
     x(SC5, i) = x5
     x(SC6, i) = x6
#else
     y1 = x(SC1, i) - x(SC7, i)
     y2 = x(SC2, i) - x(SC8, i)
     y3 = x(SC3, i) - x(SC9, i)
     y4 = x(SC4, i) - x(SC10, i)
     y5 = x(SC5, i) - x(SC11, i)
     y6 = x(SC6, i) - x(SC12, i)

     x(SC1, i) = x1
     x(SC2, i) = x2
     x(SC3, i) = x3
     x(SC4, i) = x4
     x(SC5, i) = x5
     x(SC6, i) = x6
     x(SC7, i) = x1
     x(SC8, i) = x2
     x(SC9, i) = x3
     x(SC10, i) = x4
     x(SC11, i) = x5
     x(SC12, i) = x6
#endif

# undef J
# define J 2
# include "clover_mult_b.h90"

#ifdef GAMMAC
     x(SC7, i)  = x1
     x(SC8, i)  = x2
     x(SC9, i)  = x3
     x(SC10, i) = x4
     x(SC11, i) = x5
     x(SC12, i) = x6
#else
     x(SC1, i) = x(SC1, i) + x1
     x(SC2, i) = x(SC2, i) + x2
     x(SC3, i) = x(SC3, i) + x3
     x(SC4, i) = x(SC4, i) + x4
     x(SC5, i) = x(SC5, i) + x5
     x(SC6, i) = x(SC6, i) + x6
     x(SC7, i) = x(SC7, i) - x1
     x(SC8, i) = x(SC8, i) - x2
     x(SC9, i) = x(SC9, i) - x3
     x(SC10, i) = x(SC10, i) - x4
     x(SC11, i) = x(SC11, i) - x5
     x(SC12, i) = x(SC12, i) - x6
#endif

  enddo

  TIMING_STOP(timing_bin_clover_mult_b)
end

!-------------------------------------------------------------------------------
subroutine clover_mult_a2_block(out, b, a, in, i1, i2)  ! out := A in

  implicit none
  REAL                                :: b
  COMPLEX, dimension(18, 2, *)        :: a
#ifdef FLIPSC
  COMPLEX, dimension(NCOL, NDIRAC, *) :: out, in
#else
  COMPLEX, dimension(NDIRAC, NCOL, *) :: out, in
#endif
  integer                             :: i1, i2

  integer :: i
  COMPLEX :: x1, x2, x3, x4, x5, x6
  COMPLEX :: y1, y2, y3, y4, y5, y6

  !!TIMING_START(timing_bin_clover_mult_a)
#ifdef IBM
  call alignx(16, out(1,1,1))
  call alignx(16, in(1,1,1))
  call alignx(16, a(1,1,1))
#endif

  do i = i1, i2

#ifdef GAMMAC
  x1 = in(SC1, i)
  x2 = in(SC2, i)
  x3 = in(SC3, i)
  x4 = in(SC4, i)
  x5 = in(SC5, i)
  x6 = in(SC6, i)
#else
  x1 = in(SC1, i) + in(SC7, i)
  x2 = in(SC2, i) + in(SC8, i)
  x3 = in(SC3, i) + in(SC9, i)
  x4 = in(SC4, i) + in(SC10, i)
  x5 = in(SC5, i) + in(SC11, i)
  x6 = in(SC6, i) + in(SC12, i)
#endif

# undef J
# define J 1
# include "clover_mult_a.h90"

#ifdef GAMMAC
  out(SC1, i) = b * out(SC1, i) +  y1
  out(SC2, i) = b * out(SC2, i) +  y2
  out(SC3, i) = b * out(SC3, i) +  y3
  out(SC4, i) = b * out(SC4, i) +  y4
  out(SC5, i) = b * out(SC5, i) +  y5
  out(SC6, i) = b * out(SC6, i) +  y6
  x1 =  in(SC7, i)
  x2 =  in(SC8, i)
  x3 =  in(SC9, i)
  x4 =  in(SC10, i)
  x5 =  in(SC11, i)
  x6 =  in(SC12, i)
#else
  out(SC1, i) = b * out(SC1, i) +  y1
  out(SC2, i) = b * out(SC2, i) +  y2
  out(SC3, i) = b * out(SC3, i) +  y3
  out(SC4, i) = b * out(SC4, i) +  y4
  out(SC5, i) = b * out(SC5, i) +  y5
  out(SC6, i) = b * out(SC6, i) +  y6
  out(SC7, i) = b * out(SC7, i) +  y1
  out(SC8, i) = b * out(SC8, i) +  y2
  out(SC9, i) = b * out(SC9, i) +  y3
  out(SC10, i) = b * out(SC10, i) +  y4
  out(SC11, i) = b * out(SC11, i) +  y5
  out(SC12, i) = b * out(SC12, i) +  y6
  x1 = in(SC1, i) - in(SC7, i)
  x2 = in(SC2, i) - in(SC8, i)
  x3 = in(SC3, i) - in(SC9, i)
  x4 = in(SC4, i) - in(SC10, i)
  x5 = in(SC5, i) - in(SC11, i)
  x6 = in(SC6, i) - in(SC12, i)
#endif

# undef J
# define J 2
# include "clover_mult_a.h90"

#ifdef GAMMAC
  out(SC7, i) = b * out(SC7, i) +  y1
  out(SC8, i) = b * out(SC8, i) +  y2
  out(SC9, i) = b * out(SC9, i) +  y3
  out(SC10, i) = b * out(SC10, i) +  y4
  out(SC11, i) = b * out(SC11, i) +  y5
  out(SC12, i) = b * out(SC12, i) +  y6
#else
  out(SC1, i) = out(SC1, i) + y1
  out(SC2, i) = out(SC2, i) + y2
  out(SC3, i) = out(SC3, i) + y3
  out(SC4, i) = out(SC4, i) + y4
  out(SC5, i) = out(SC5, i) + y5
  out(SC6, i) = out(SC6, i) + y6
  out(SC7, i) = out(SC7, i) - y1
  out(SC8, i) = out(SC8, i) - y2
  out(SC9, i) = out(SC9, i) - y3
  out(SC10, i) = out(SC10, i) - y4
  out(SC11, i) = out(SC11, i) - y5
  out(SC12, i) = out(SC12, i) - y6
#endif

  enddo

  !!TIMING_STOP(timing_bin_clover_mult_a)
end

!-------------------------------------------------------------------------------
subroutine clover_mult_ao2_block(out, a, in, i1, i2)  ! out := A in

  implicit none

  COMPLEX, dimension(18, 2, *)        :: a
#ifdef FLIPSC
  COMPLEX, dimension(NCOL, NDIRAC, *) :: out, in
#else
  COMPLEX, dimension(NDIRAC, NCOL, *) :: out, in
#endif
  integer                             :: i1, i2

  integer :: i
  COMPLEX :: x1, x2, x3, x4, x5, x6
  COMPLEX :: y1, y2, y3, y4, y5, y6

  !!TIMING_START(timing_bin_clover_mult_ao)
#ifdef IBM
  call alignx(16, out(1,1,1))
  call alignx(16, in(1,1,1))
  call alignx(16, a(1,1,1))
#endif
  do i = i1, i2

#ifdef GAMMAC
     x1 = in(SC1, i)
     x2 = in(SC2, i)
     x3 = in(SC3, i)
     x4 = in(SC4, i)
     x5 = in(SC5, i)
     x6 = in(SC6, i)
#else
     x1 = in(SC1, i) + in(SC7, i)
     x2 = in(SC2, i) + in(SC8, i)
     x3 = in(SC3, i) + in(SC9, i)
     x4 = in(SC4, i) + in(SC10, i)
     x5 = in(SC5, i) + in(SC11, i)
     x6 = in(SC6, i) + in(SC12, i)
#endif

# undef J
# define J 1
# include "clover_mult_a.h90"

#ifdef GAMMAC
     out(SC1, i) = y1
     out(SC2, i) = y2
     out(SC3, i) = y3
     out(SC4, i) = y4
     out(SC5, i) = y5
     out(SC6, i) = y6
     x1 = in(SC7, i)
     x2 = in(SC8, i)
     x3 = in(SC9, i)
     x4 = in(SC10, i)
     x5 = in(SC11, i)
     x6 = in(SC12, i)
#else
     x1 = in(SC1, i) - in(SC7, i)
     x2 = in(SC2, i) - in(SC8, i)
     x3 = in(SC3, i) - in(SC9, i)
     x4 = in(SC4, i) - in(SC10, i)
     x5 = in(SC5, i) - in(SC11, i)
     x6 = in(SC6, i) - in(SC12, i)

     out(SC1, i) = y1
     out(SC2, i) = y2
     out(SC3, i) = y3
     out(SC4, i) = y4
     out(SC5, i) = y5
     out(SC6, i) = y6
     out(SC7, i) = y1
     out(SC8, i) = y2
     out(SC9, i) = y3
     out(SC10, i) = y4
     out(SC11, i) = y5
     out(SC12, i) = y6
#endif

# undef J
# define J 2
# include "clover_mult_a.h90"

#ifdef GAMMAC
     out(SC7, i)  = y1
     out(SC8, i)  = y2
     out(SC9, i)  = y3
     out(SC10, i) = y4
     out(SC11, i) = y5
     out(SC12, i) = y6
#else
     out(SC1, i) = out(SC1, i) + y1
     out(SC2, i) = out(SC2, i) + y2
     out(SC3, i) = out(SC3, i) + y3
     out(SC4, i) = out(SC4, i) + y4
     out(SC5, i) = out(SC5, i) + y5
     out(SC6, i) = out(SC6, i) + y6
     out(SC7, i) = out(SC7, i) - y1
     out(SC8, i) = out(SC8, i) - y2
     out(SC9, i) = out(SC9, i) - y3
     out(SC10, i) = out(SC10, i) - y4
     out(SC11, i) = out(SC11, i) - y5
     out(SC12, i) = out(SC12, i) - y6
#endif

  enddo

  !!TIMING_STOP(timing_bin_clover_mult_ao)
end

!===============================================================================
