!===============================================================================
!
! cg_clover_mult_a2.F90
!
!-------------------------------------------------------------------------------
!
! Copyright (C) 2012-2016 Hinnerk Stueben
!
! 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 LANGUAGE_FORTRAN
# include "defs.h"
# include "cg_defs.h"
# include "cg_clover.i"
# include "alignment.h"

!-------------------------------------------------------------------------------
# define TRACE_NAME Tclover(cg_c2)
!-------------------------------------------------------------------------------
subroutine Tclover(cg_c2)(out, b, a, in, volh_tot, varsBLOCK)  ! out := b out + A in

  use typedef_cg_clover
  implicit none
  integer, intent(in)          :: varsBLOCK
  integer, intent(in)          :: volh_tot
  spincol_FIELD, intent(in)    :: in
  clover_FLD, intent(in)       :: a
  REAL, intent(in)             :: b
  spincol_FIELD, intent(inout) :: out

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

  TRACE_ENTRY
  TIMING_START(timing_bin_cg_clover_mult_a2)

  ASSUME_ALIGNED(out)
  ASSUME_ALIGNED(a)
  ASSUME_ALIGNED(in)

#ifndef BLOCK
  !$omp parallel do private(x1, x2, x3, x4, x5, x6, y1, y2, y3, y4, y5, y6)
  do i = 1, varsBLOCK
#else
  do i = varsBLOCK
#endif

     x1 = Spincol(in, 1, 1, 1, i) + Spincol(in, 1, 2, 1, i)
     x2 = Spincol(in, 1, 1, 2, i) + Spincol(in, 1, 2, 2, i)
     x3 = Spincol(in, 1, 1, 3, i) + Spincol(in, 1, 2, 3, i)
     x4 = Spincol(in, 2, 1, 1, i) + Spincol(in, 2, 2, 1, i)
     x5 = Spincol(in, 2, 1, 2, i) + Spincol(in, 2, 2, 2, i)
     x6 = Spincol(in, 2, 1, 3, i) + Spincol(in, 2, 2, 3, i)

     SET K = 1
     DO I = 1, 6
        y %% I = &
        DO J = 1, I-1
           + cmplx(ReClover(a,K,i,J,I), -(ImClover(a,K,i,J,I)), kind=RKIND) * x %% J &
        ENDDO
           + ReClover(a,K,i,I,I) * x %% I &
        DO J = I+1, 6
           + cmplx(ReClover(a,K,i,I,J), ImClover(a,K,i,I,J), kind=RKIND) * x %% J &
        ENDDO
        ;
     ENDDO
     ENDSET

     Spincol(out, 1, 1, 1, i) = b * Spincol(out, 1, 1, 1, i) +  y1
     Spincol(out, 1, 1, 2, i) = b * Spincol(out, 1, 1, 2, i) +  y2
     Spincol(out, 1, 1, 3, i) = b * Spincol(out, 1, 1, 3, i) +  y3
     Spincol(out, 2, 1, 1, i) = b * Spincol(out, 2, 1, 1, i) +  y4
     Spincol(out, 2, 1, 2, i) = b * Spincol(out, 2, 1, 2, i) +  y5
     Spincol(out, 2, 1, 3, i) = b * Spincol(out, 2, 1, 3, i) +  y6
     Spincol(out, 1, 2, 1, i) = b * Spincol(out, 1, 2, 1, i) +  y1
     Spincol(out, 1, 2, 2, i) = b * Spincol(out, 1, 2, 2, i) +  y2
     Spincol(out, 1, 2, 3, i) = b * Spincol(out, 1, 2, 3, i) +  y3
     Spincol(out, 2, 2, 1, i) = b * Spincol(out, 2, 2, 1, i) +  y4
     Spincol(out, 2, 2, 2, i) = b * Spincol(out, 2, 2, 2, i) +  y5
     Spincol(out, 2, 2, 3, i) = b * Spincol(out, 2, 2, 3, i) +  y6

     x1 = Spincol(in, 1, 1, 1, i) - Spincol(in, 1, 2, 1, i)
     x2 = Spincol(in, 1, 1, 2, i) - Spincol(in, 1, 2, 2, i)
     x3 = Spincol(in, 1, 1, 3, i) - Spincol(in, 1, 2, 3, i)
     x4 = Spincol(in, 2, 1, 1, i) - Spincol(in, 2, 2, 1, i)
     x5 = Spincol(in, 2, 1, 2, i) - Spincol(in, 2, 2, 2, i)
     x6 = Spincol(in, 2, 1, 3, i) - Spincol(in, 2, 2, 3, i)

     SET K = 2
     DO I = 1, 6
        y %% I = &
        DO J = 1, I-1
           + cmplx(ReClover(a,K,i,J,I), -(ImClover(a,K,i,J,I)), kind=RKIND) * x %% J &
        ENDDO
           + ReClover(a,K,i,I,I) * x %% I &
        DO J = I+1, 6
           + cmplx(ReClover(a,K,i,I,J), ImClover(a,K,i,I,J), kind=RKIND) * x %% J &
        ENDDO
        ;
     ENDDO
     ENDSET

     Spincol(out, 1, 1, 1, i) = Spincol(out, 1, 1, 1, i) + y1
     Spincol(out, 1, 1, 2, i) = Spincol(out, 1, 1, 2, i) + y2
     Spincol(out, 1, 1, 3, i) = Spincol(out, 1, 1, 3, i) + y3
     Spincol(out, 2, 1, 1, i) = Spincol(out, 2, 1, 1, i) + y4
     Spincol(out, 2, 1, 2, i) = Spincol(out, 2, 1, 2, i) + y5
     Spincol(out, 2, 1, 3, i) = Spincol(out, 2, 1, 3, i) + y6
     Spincol(out, 1, 2, 1, i) = Spincol(out, 1, 2, 1, i) - y1
     Spincol(out, 1, 2, 2, i) = Spincol(out, 1, 2, 2, i) - y2
     Spincol(out, 1, 2, 3, i) = Spincol(out, 1, 2, 3, i) - y3
     Spincol(out, 2, 2, 1, i) = Spincol(out, 2, 2, 1, i) - y4
     Spincol(out, 2, 2, 2, i) = Spincol(out, 2, 2, 2, i) - y5
     Spincol(out, 2, 2, 3, i) = Spincol(out, 2, 2, 3, i) - y6

  enddo

  TIMING_STOP(timing_bin_cg_clover_mult_a2)
  TRACE_RETURN
end

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