#/*
#==============================================================================
#
# cg_defs.h
#
#------------------------------------------------------------------------------
#
# 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/>.
#
#------------------------------------------------------------------------------
#*/

#ifdef LANGUAGE_FORTRAN
#ifdef PRECISION_R4
# define SIMD_REAL type(simd_real_r4)
# define SIMD_IMAGINARY type(simd_imaginary_r4)
# define SIMD_COMPLEX type(simd_complex_r4)
# define type_COMPLEX type(complex_r4)
#endif
#ifdef PRECISION_R8
# define SIMD_REAL type(simd_real_r8)
# define SIMD_IMAGINARY type(simd_imaginary_r8)
# define SIMD_COMPLEX type(simd_complex_r8)
# define type_COMPLEX type(complex_r8)
#endif
#endif

#ifdef LANGUAGE_C
typedef struct { REAL r[SIMD_WIDTH]; } SIMD_REAL;
typedef struct { REAL i[SIMD_WIDTH]; } SIMD_IMAGINARY;
typedef struct { REAL r[SIMD_WIDTH]; REAL i[SIMD_WIDTH]; } SIMD_COMPLEX;
#endif

#ifdef SIMD
# define TYPE_COMPLEX SIMD_COMPLEX
#else
# define TYPE_COMPLEX COMPLEX
#endif

#ifdef LANGUAGE_FORTRAN
#ifdef SC_KIND
#ifndef SIMD
# undef TYPE_COMPLEX
# define TYPE_COMPLEX type_COMPLEX
#endif
#endif
#endif

# define spincol_FIELD STRCAT(SPINCOL_TYPE, _FIELD)
# define spincol_FLD   STRCAT(SPINCOL_TYPE, _FLD)

#ifdef LANGUAGE_FORTRAN
# define sc_FIELD    TYPE_COMPLEX, dimension(NDIRAC, NCOL, volh_tot)
# define sc_FLD      TYPE_COMPLEX, dimension(NDIRAC, NCOL, *)

# define sc2_FIELD   TYPE_COMPLEX, dimension(NDIRAC2, NCOL, volh_tot, DIM, FWD:BWD)
# define sc2_FLD     TYPE_COMPLEX, dimension(NDIRAC2, NCOL, *)

# define sc22_FIELD  TYPE_COMPLEX, dimension(NDIRAC2, NCOL, volh_tot, NDIRAC2)
# define sc22_FLD    TYPE_COMPLEX, dimension(NDIRAC2, NCOL, *)

# define sc422_FIELD TYPE_COMPLEX, dimension(NDIRAC2, NDIRAC2, NCOL, volh_tot)
# define sc422_FLD   TYPE_COMPLEX, dimension(NDIRAC2, NDIRAC2, NCOL, *)

# define g1_FIELD    TYPE_COMPLEX, dimension(NCOL, NCOL, volh_tot, EVEN:ODD, DIM+1)
# define g1_FLD      TYPE_COMPLEX, dimension(NCOL, NCOL, *)

# define g2_FIELD    TYPE_COMPLEX, dimension(NCOL * FWD_BWD, NCOL, volh, EVEN:ODD, DIM)
# define g2_FLD      TYPE_COMPLEX, dimension(NCOL * FWD_BWD, NCOL, *)
#endif

#ifdef LANGUAGE_C
typedef TYPE_COMPLEX (*sc_FIELD)[NCOL][NDIRAC];
typedef TYPE_COMPLEX (*sc_FLD)[NCOL][NDIRAC];

typedef TYPE_COMPLEX (*sc2_FLD)[NCOL][NDIRAC2];

typedef TYPE_COMPLEX (*sc22_FLD)[NCOL][NDIRAC2];

typedef TYPE_COMPLEX (*sc422_FIELD)[NCOL][NDIRAC2][NDIRAC2];
typedef TYPE_COMPLEX (*sc422_FLD)[NCOL][NDIRAC2][NDIRAC2];

typedef TYPE_COMPLEX (*g1_FLD)[NCOL][NCOL];
typedef TYPE_COMPLEX (*g2_FLD)[NCOL][NCOL * FWD_BWD];
#endif

# define Spincol STRCAT(Spincol_, SPINCOL_TYPE)

#ifdef LANGUAGE_FORTRAN
# define Spincol_sc(array, s1, s2, c, i) array((s1)+(s2-1)*NDIRAC2, c, i)
# define Spincol_sc2(array, s1, dummy, c, i) array(s1, c, i)
# define Spincol_sc22(array, s1, s2, c, i) array(s1, c, i, s2)
# define Spincol_sc422(array, s1, s2, c, i) array(s1, s2, c, i)
# define Gauge(array, c1, c2, i) array(c1, c2, i)
#endif

#ifdef LANGUAGE_C
# define Spincol_sc(array, s1, s2, c, i) array[i][c-1][(s2-1)*NDIRAC2+(s1-1)]
# define Spincol_sc2(array, s1, dummy, c, i) array[i][c-1][s1-1]
# define Spincol_sc22(array, s1, s2, c, i) STRCAT(array, s2)[i][c-1][s1-1]
# define Spincol_sc422(array, s1, s2, c, i) array[i][c-1][s2-1][s1-1]
# define Gauge(array, c1, c2, i) array[i][c2-1][c1-1]
#endif

# define T(name) STRCAT6(name, nameBLOCK, SPINCOL_TYPE, namePRECISION, nameSIMD, nameUNDERSCORE)

#ifdef BLOCK
# define nameBLOCK _block_
#else
# define nameBLOCK _
#endif

#ifdef PRECISION_R4
# define namePRECISION _r4
#endif

#ifdef PRECISION_R8
# define namePRECISION _r8
#endif

#ifdef SIMD
# define nameSIMD s
#else
# define nameSIMD
#endif

#ifdef NamesToLower_
# define nameUNDERSCORE _
#else
# define nameUNDERSCORE
#endif

#ifdef DIR_X
# define nameXYZT x
#endif

#ifdef DIR_Y
# define nameXYZT y
#endif

#ifdef DIR_Z
# define nameXYZT z
#endif

#ifdef DIR_T
# define nameXYZT t
#endif

#ifdef FIRST
# define nameFIRST 1
#else
# define nameFIRST
#endif

#ifdef DAGGER
# define nameDAGGER _dag_
#else
# define nameDAGGER _
#endif

#ifndef varsBLOCK
#ifdef BLOCK
# define varsBLOCK i1, i2
#else
# define varsBLOCK volh
#endif
#endif

#ifdef BLOCK
#ifdef TIMING
# undef  TIMING_START
# define TIMING_START(bin)
# undef  TIMING_STOP
# define TIMING_STOP(bin)
#endif
#endif
