!===============================================================================
!
! cg_d21.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"

!-------------------------------------------------------------------------------
#ifdef PRECISION_R4
# define xbound_sc2_field xbound_sc2_field_r4
#endif

!-------------------------------------------------------------------------------
#ifdef DAGGER
# define NAME cg_d21_dag
# define cg_projection cg_projection_dag
#else
# define NAME cg_d21
#endif

# define TRACE_NAME T(NAME)
!-------------------------------------------------------------------------------
subroutine T(NAME)(e, o, out, in, u, a)

!// out is of type "e" = EVEN or ODD
!// in is of type "o" = ODD or EVEN

  use typedef_simd
  use T(module_nn)
  use T(module_vol)
  implicit none
 
  integer, intent(in)        :: e, o
  spincol_FIELD, intent(out) :: out
  spincol_FIELD, intent(in)  :: in 
  g1_FIELD, intent(in)       :: u
  sc2_FIELD, intent(out)     :: a    ! scratch array

  TRACE_ENTRY
  TIMING_START(timing_bin_cg_d)

  call T(cg_projection)(a, in, volh_tot, volh)
  
  call xbound_sc2_field(a)

  call T(STRCAT(NAME, _t1))(out, a(1, 1, 1, 4, FWD), a(1, 1, 1, 4, BWD), &
                                 u(1, 1, 1, e, 4),   u(1, 1, 1, o, 4), &
                                nn(1, e, 4, FWD),   nn(1, e, 4, BWD), volh_tot, volh)

  call T(STRCAT(NAME, _z))(out,  a(1, 1, 1, 3, FWD), a(1, 1, 1, 3, BWD), &
                                 u(1, 1, 1, e, 3),   u(1, 1, 1, o, 3), &
                                nn(1, e, 3, FWD),   nn(1, e, 3, BWD), volh_tot, volh)

  call T(STRCAT(NAME, _y))(out,  a(1, 1, 1, 2, FWD), a(1, 1, 1, 2, BWD), & 
                                 u(1, 1, 1, e, 2),   u(1, 1, 1, o, 2), &
                                nn(1, e, 2, FWD),   nn(1, e, 2, BWD), volh_tot, volh)

  call T(STRCAT(NAME, _x))(out,  a(1, 1, 1, 1, FWD), a(1, 1, 1, 1, BWD), &
#ifdef SIMD
                                 u(1, 1, 1, e, 1),   u(1, 1, 1, e, 5), &
#else
                                 u(1, 1, 1, e, 1),   u(1, 1, 1, o, 1), &
#endif
                                nn(1, e, 1, FWD),   nn(1, e, 1, BWD), volh_tot, volh)


  TIMING_STOP(timing_bin_cg_d)
  TRACE_RETURN

end

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