#/*
#==============================================================================
#
# cg_d2.h
#
#------------------------------------------------------------------------------
#
# Copyright (C) 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/>.
#
#------------------------------------------------------------------------------
#*/

#if SC_KIND == 1
#ifdef LANGUAGE_FORTRAN
   integer, parameter :: re = 0
   integer, parameter :: im = 1

   REAL, dimension (re:im, NDIRAC2, NDIRAC2, NCOL, *), intent(inout) :: b
   REAL, dimension (re:im, NDIRAC2, NDIRAC2, NCOL, *), intent(in) :: a_fwd, a_bwd
   REAL, dimension (re:im, NCOL, NCOL, *), intent(in) :: u_fwd, u_bwd
   INTEGER, dimension(*), intent(in) :: nn_fwd, nn_bwd

# define reIN_fwd(ii,jj,kk) a_fwd(re, ii, jj, kk, jf)  
# define imIN_fwd(ii,jj,kk) a_fwd(im, ii, jj, kk, jf)  
# define reIN_bwd(ii,jj,kk) a_fwd(re, ii, jj, kk, jb)  
# define imIN_bwd(ii,jj,kk) a_fwd(im, ii, jj, kk, jb)  

# define reU_fwd(ii,jj) u_fwd(re, ii, jj, i)
# define imU_fwd(ii,jj) u_fwd(im, ii, jj, i)
# define reU_bwd(ii,jj) u_bwd(re, ii, jj, jb)
# define imU_bwd(ii,jj) u_bwd(im, ii, jj, jb)

# define reOUT(ii,jj,kk) b(re, ii, jj, kk, i)
# define imOUT(ii,jj,kk) b(im, ii, jj, kk, i)

#else
    REAL     b[][NCOL][NDIRAC2][NDIRAC2][2],
    REAL a_fwd[][NCOL][NDIRAC2][NDIRAC2][2],
    REAL a_bwd[][NCOL][NDIRAC2][NDIRAC2][2],
    REAL u_fwd[][NCOL][NCOL][2],
    REAL u_bwd[][NCOL][NCOL][2],
    INTEGER nn_fwd[], 
    INTEGER nn_bwd[],

# define reIN_fwd(ii,jj,kk) a_fwd[jf][kk-1][jj-1][ii-1][0]
# define imIN_fwd(ii,jj,kk) a_fwd[jf][kk-1][jj-1][ii-1][1]
# define reIN_bwd(ii,jj,kk) a_fwd[jb][kk-1][jj-1][ii-1][0]
# define imIN_bwd(ii,jj,kk) a_fwd[jb][kk-1][jj-1][ii-1][1]

# define reU_fwd(ii,jj) u_fwd[i][jj-1][ii-1][0]
# define imU_fwd(ii,jj) u_fwd[i][jj-1][ii-1][1]
# define reU_bwd(ii,jj) u_bwd[jb][jj-1][ii-1][0]
# define imU_bwd(ii,jj) u_bwd[jb][jj-1][ii-1][1]

# define reOUT(ii,jj,kk) b[i][kk-1][jj-1][ii-1][0]
# define imOUT(ii,jj,kk) b[i][kk-1][jj-1][ii-1][1]
#endif
#endif

#if SC_KIND == 22
#ifdef LANGUAGE_FORTRAN
   integer, parameter :: re = 0
   integer, parameter :: im = 1

   REAL, dimension (re:im, NDIRAC2, NCOL, volh_tot, NDIRAC2), intent(inout) :: b
   REAL, dimension (re:im, NDIRAC2, NCOL, volh_tot, NDIRAC2), intent(in) :: a_fwd, a_bwd
   REAL, dimension (re:im, NCOL, NCOL, *), intent(in) :: u_fwd, u_bwd
   INTEGER, dimension(*), intent(in) :: nn_fwd, nn_bwd

# define reIN_fwd(ii,jj,kk) a_fwd(re, ii, kk, jf, jj)  
# define imIN_fwd(ii,jj,kk) a_fwd(im, ii, kk, jf, jj)  
# define reIN_bwd(ii,jj,kk) a_fwd(re, ii, kk, jb, jj)  
# define imIN_bwd(ii,jj,kk) a_fwd(im, ii, kk, jb, jj)  

# define reU_fwd(ii,jj) u_fwd(re, ii, jj, i)
# define imU_fwd(ii,jj) u_fwd(im, ii, jj, i)
# define reU_bwd(ii,jj) u_bwd(re, ii, jj, jb)
# define imU_bwd(ii,jj) u_bwd(im, ii, jj, jb)

# define reOUT(ii,jj,kk) b(re, ii, kk, i, jj)
# define imOUT(ii,jj,kk) b(im, ii, kk, i, jj)

#else
    REAL     b[][NCOL][NDIRAC2][2],
    REAL a_fwd[][NCOL][NDIRAC2][2],
    REAL a_bwd[][NCOL][NDIRAC2][2],
    REAL u_fwd[][NCOL][NCOL][2],
    REAL u_bwd[][NCOL][NCOL][2],
    INTEGER nn_fwd[], 
    INTEGER nn_bwd[],

# define reIN_fwd(ii,jj,kk) STRCAT(a, jj)[jf][kk-1][ii-1][0]
# define imIN_fwd(ii,jj,kk) STRCAT(a, jj)[jf][kk-1][ii-1][1]
# define reIN_bwd(ii,jj,kk) STRCAT(a, jj)[jb][kk-1][ii-1][0]
# define imIN_bwd(ii,jj,kk) STRCAT(a, jj)[jb][kk-1][ii-1][1]

# define reU_fwd(ii,jj) u_fwd[i][jj-1][ii-1][0]
# define imU_fwd(ii,jj) u_fwd[i][jj-1][ii-1][1]
# define reU_bwd(ii,jj) u_bwd[jb][jj-1][ii-1][0]
# define imU_bwd(ii,jj) u_bwd[jb][jj-1][ii-1][1]

# define reOUT(ii,jj,kk) STRCAT(b, jj)[i][kk-1][ii-1][0]
# define imOUT(ii,jj,kk) STRCAT(b, jj)[i][kk-1][ii-1][1]
#endif
#endif

# define Load(x) x
# define Store(out, in) out = in
# define Add(a, b) a + b
# define Sub(a, b) a - b
# define Mul(a, b) a * b
# define Fmadd(a, b, c) a * b + c
# define Fmsub(a, b, c) a * b - c

# define Two TWO
