#/*
#===============================================================================
#
# defs.h
#
#-------------------------------------------------------------------------------
#
# Copyright (C) 1998-2016 Hinnerk Stueben
#               2005-2013 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/>.
#
#-------------------------------------------------------------------------------
#*/
#ifndef BQCD_DEFS_H
#define BQCD_DEFS_H

# define MAX_TEMPER 50

# define CAT(A,B) A ## B
# define CAT3(A,B,C) A ## B ## C
# define CAT4(A,B,C,D) A ## B ## C ## D
# define CAT5(A,B,C,D,E) A ## B ## C ## D ## E
# define CAT6(A,B,C,D,E,F) A ## B ## C ## D ## E ## F
# define CAT7(A,B,C,D,E,F,G) A ## B ## C ## D ## E ## F ## G
# define CAT8(A,B,C,D,E,F,G,H) A ## B ## C ## D ## E ## F ## G ## H
# define CAT9(A,B,C,D,E,F,G,H,I) A ## B ## C ## D ## E ## F ## G ## H ## I

# define STRCAT(A,B) CAT(A,B)
# define STRCAT3(A,B,C) CAT3(A,B,C)
# define STRCAT4(A,B,C,D) CAT4(A,B,C,D)
# define STRCAT5(A,B,C,D,E) CAT5(A,B,C,D,E)
# define STRCAT6(A,B,C,D,E,F) CAT6(A,B,C,D,E,F)
# define STRCAT7(A,B,C,D,E,F,G) CAT7(A,B,C,D,E,F,G)
# define STRCAT8(A,B,C,D,E,F,G,H) CAT8(A,B,C,D,E,F,G,H)
# define STRCAT9(A,B,C,D,E,F,G,H,I) CAT9(A,B,C,D,E,F,G,H,I)

#ifdef PRECISION_R4
#// efine D_R4_INTERNAL
# define RKIND 4
# define DKIND 8
# define BQCD_REAL mpi_real4
# include "../include_auto/precision_r4.h"
#elif defined(PRECISION_R16)
#// efine D_R16_INTERNAL
# define RKIND 16
# define DKIND 16
# define BQCD_REAL mpi_real16
# include "../include_auto/precision_r16.h"
# define global_sum_vec global_sum_vec_r16
# define global_sum global_sum_r16
# define global_min global_min_r16
# define global_max global_max_r16
#else
# define RKIND 8
# define DKIND 8
# define BQCD_REAL mpi_real8
#endif

#ifdef ILDG_R4
# define ILDG_KIND 4
# define ILDG_REAL mpi_real4
#else
# define ILDG_KIND 8
# define ILDG_REAL mpi_real8
#endif

# define BQCD_REAL4 mpi_real4

# define BQCD_CHECK_SUM mpi_integer8
# define BQCD_SEED mpi_integer8

# define CHECK_SUM integer(8)
# define SEED integer(8)
# define SECONDS real(8)
# define COMM_METHOD character(80)
# define RAN_NAME character(40)
# define FILENAME character(len=80)
# define FILENAME_FORMAT character(len=80)


# define REAL real(RKIND)
# define DOUBLE real(DKIND)
# define REAL4 real(4)
# define REAL8 real(8)
# define REAL16 real(16)
# define COMPLEX complex(RKIND)
# define COMPLEX4 complex(4)
# define COMPLEX8 complex(8)
# define COMPLEX16 complex(16)
# define INTEGER integer(4)
# define INT4 integer(4)
# define INT8 integer(8)

# define SU3 COMPLEX, dimension (NCOL, NCOL)
# define GENERATOR REAL, dimension (NGEN)

# define GAUGE_FIELD_IO  COMPLEX, dimension(NCOL, NCOL-1, DIM, 0:NX-1, 0:NY-1, 0:NZ-1, 0:NT-1)
# define GAUGE_FIELD_ILDG  complex(ILDG_KIND), dimension(NCOL, NCOL, DIM, 0:NX-1, 0:NY-1, 0:NZ-1, 0:NT-1)
# define SPINCOL_FIELD_IO  COMPLEX, dimension(NDIRAC, NCOL, 0:NXH-1, 0:NY-1, 0:NZ-1, 0:NT-1)

# define SU3_FIELD COMPLEX, dimension (NCOL, NCOL, volh_tot)
# define GAUGE_FIELD COMPLEX, dimension (NCOL, NCOL, volh_tot, EVEN:ODD, DIM)
# define GENERATOR_FIELD REAL, dimension (NGEN, volh_tot, EVEN:ODD, DIM)
# define SPINCOL_FIELD COMPLEX, dimension (NDIRAC, NCOL, volh_tot)
# define SC22_FIELD COMPLEX, dimension (NDIRAC2, NCOL, volh_tot, NDIRAC2)
# define SC2_FIELD COMPLEX, dimension(NDIRAC2, NCOL, volh_tot, DIM, FWD:BWD)
# define CLOVER_FIELD_A type(type_clover_a), dimension(2, volh, EVEN:ODD)
# define CLOVER_FIELD_B type(type_clover_b), dimension(2, volh, EVEN:ODD)
# define CLOVER_FIELD_C COMPLEX, dimension(NDIRAC, NCOL, NDIRAC, NCOL, volh)
# define CLOVER_FIELD_C2 COMPLEX, dimension(NDIRAC, NDIRAC, NCOL, NCOL, volh)
# define CLOVER_FIELD12 type(type_clover12), dimension(volh, EVEN:ODD)


# define P_GAUGE_FIELD COMPLEX, dimension(:, :, :, :, :), pointer
# define P_GAUGE_FIELD_IO COMPLEX, dimension(:, :, :, :, :, :, :), pointer
# define P_GAUGE_FIELD_ILDG COMPLEX, dimension(:, :, :, :, :, :, :), pointer
# define P_GENERATOR_FIELD REAL, dimension(:, :, :, :), pointer
# define P_SPINCOL_FIELD COMPLEX, dimension(:, :, :), pointer
# define P_SPINCOL_FIELD_IO COMPLEX, dimension(:, :, :, :, :, :), pointer
# define P_SC2_FIELD COMPLEX, dimension(:, :, :, :, :), pointer
# define P_CLOVER_FIELD_A type(type_clover_a), dimension(:, :, :), pointer
# define P_CLOVER_FIELD_B type(type_clover_b), dimension(:, :, :), pointer
# define P_CLOVER_FIELD12 type(type_clover12), dimension(:, :), pointer

# define SPINCOL_OVERINDEXED REAL, dimension(SIZE_COMPLEX*NDIRAC*NCOL*volh_tot)
# define P_SPINCOL_OVERINDEXED REAL, dimension(:), pointer

# define U1_GENERATOR_FIELD REAL, dimension (volh_tot, EVEN:ODD, DIM)
# define U1_GENERATOR_FIELD_ILDG real(ILDG_KIND), dimension (DIM, 0:NX-1, 0:NY-1, 0:NZ-1, 0:NT-1)
# define P_U1_GENERATOR_FIELD REAL, dimension (:, :, :), pointer
# define P_U1_GENERATOR_FIELD_ILDG REAL, dimension(:, :, :, :, :), pointer

# define AXION_FIELD REAL, dimension (volh_tot, EVEN:ODD)
# define AXION_FIELD_ILDG real(ILDG_KIND), dimension (0:NX-1, 0:NY-1, 0:NZ-1, 0:NT-1)
# define AXION_MOMENTUM_FIELD REAL, dimension (volh, EVEN:ODD)
# define P_AXION_FIELD REAL, dimension (:, :), pointer
# define P_AXION_FIELD_ILDG REAL, dimension(:, :, :, :), pointer
# define P_AXION_MOMENTUM_FIELD REAL, dimension (:, :), pointer

# define ALLOCATE_G_FIELD(x) if (.not. associated(x)) call allocate_g_field(x)
# define ALLOCATE_G_FIELD_IO(x) if (.not. associated(x)) call allocate_g_field_io(x)
# define ALLOCATE_G_FIELD_ILDG(x) if (.not. associated(x)) call allocate_g_field_ildg(x)
# define ALLOCATE_GEN_FIELD(x) if (.not. associated(x)) call allocate_gen_field(x)
# define ALLOCATE_SC_FIELD(x) if (.not. associated(x)) call allocate_sc_field(x)
# define ALLOCATE_SC_FIELD_IO(x) if (.not. associated(x)) call allocate_sc_field_io(x)
# define ALLOCATE_SC_OVERINDEXED(x) if (.not. associated(x)) call allocate_sc_overindexed(x)
# define ALLOCATE_SC2_FIELD(x) if (.not. associated(x)) call allocate_sc2_field(x)
# define ALLOCATE_U1GEN_FIELD(x) if (.not. associated(x)) call allocate_u1gen_field(x)
# define ALLOCATE_U1GEN_FIELD_ILDG(x) if (.not. associated(x)) call allocate_u1gen_field_ildg(x)
# define ALLOCATE_AXION_FIELD(x) if (.not. associated(x)) call allocate_axion_field(x)
# define ALLOCATE_AXION_FIELD_ILDG(x) if (.not. associated(x)) call allocate_axion_field_ildg(x)
# define ALLOCATE_AXION_MOMENTUM_FIELD(x) if (.not. associated(x)) call allocate_axion_momentum_field(x)


# define DIM    4
# define NCOL   3
# define NDIRAC 4
# define NDIRAC2 2
# define NGEN   8
# define EVEN   0
# define ODD    1
# define FWD    0
# define BWD    1

# define SIZE_COMPLEX 2
# define EVEN_ODD 2
# define FWD_BWD 2

# define PI    STRCAT(3.1415926535897932384626433832795028841971_, RKIND)
# define TWOPI STRCAT(6.2831853071795864769252867665590057683943_, RKIND)
# define SQRT3 STRCAT(1.7320508075688772935274463415058723669428_, RKIND)
# define SQRT33 STRCAT(0.57735026918962576450914878050195745564760_, RKIND)

# define ZERO  STRCAT(0.0_, RKIND)
# define ONE   STRCAT(1.0_, RKIND)
# define TWO   STRCAT(2.0_, RKIND)
# define THREE STRCAT(3.0_, RKIND)
# define FOUR  STRCAT(4.0_, RKIND)
# define SIX   STRCAT(6.0_, RKIND)
# define EIGHT STRCAT(8.0_, RKIND)

# define HALF   STRCAT(0.5_, RKIND)
# define EIGHTH STRCAT(0.125_, RKIND)

#include "../include_auto/timing.h"

# define timing_bin_d_dag_xf timing_bin_d_xf 
# define timing_bin_d_dag_xb timing_bin_d_xb 
# define timing_bin_d_dag_yf timing_bin_d_yf 
# define timing_bin_d_dag_yb timing_bin_d_yb 
# define timing_bin_d_dag_zf timing_bin_d_zf 
# define timing_bin_d_dag_zb timing_bin_d_zb 
# define timing_bin_d_dag_t  timing_bin_d_t  
# define timing_bin_d_t0     timing_bin_d_t  
# define timing_bin_d_dag    timing_bin_d    

#ifdef TIMING

# define TIMING_START(bin) call timing_start(bin)
# define TIMING_STOP(bin) call timing_stop(bin)
# define TIMING_WRITE(unit) call timing_write(unit)

#else

# define TIMING_START(bin)
# define TIMING_STOP(bin)
# define TIMING_WRITE(unit)

#endif

#ifdef TRACE
# define TRACE_ENTRY call trace_entry(STRING(TRACE_NAME))
# define TRACE_RETURN call trace_return()
#else
# define TRACE_ENTRY
# define TRACE_RETURN
#endif

# define STDERR 0
# define UINPUT 1
# define UCONF 2
# define URAN 3
# define UCOUNT 4
# define UREC 6
# define UINFO 7
# define ULIST 8
# define UTEMPLATE 9
# define UXML 10
# define UCPUINFO 12
# define UHPARA 15
# define UDIAG 99

# define START_HOT 0
# define START_COLD 1
# define START_CONT 2
# define START_FILE 3

# define SWAP_DOWN -1
# define SWAP_RANDOM 0
# define SWAP_UP 1

# define HMC_TEST_FORWARDS 1
# define HMC_TEST_NONE 0
# define HMC_TEST_BACKWARDS -1

# define CG_MATRIX_M 1
# define CG_MATRIX_W 2


# define FULL_SOURCE   0
# define RANDOM_SOURCE 1
# define WALL_SOURCE   2
# define LOCAL_SOURCE   3

# define EO_NORMAL   1
# define DD_NORMAL   2
# define HH_NORMAL   3
# define EO_RATIONAL 4
# define DD_RATIONAL 5
# define HH_RATIONAL 6

#// Fermion action filter type enum
# define F_NONE 0
# define F_HASEN 1
# define F_POLY 2
# define F_TRUNC 3

# define MTDAGMT_DD 0
# define WTDAGWT_DD 1
# define MTMUL_DD 2
# define MTDAG_DD 3

# define CG_MD      0
# define CG_MC      1
# define CG_HH      2
# define MC         0
# define AFTER_HMC  1

# undef Re
# undef Im

# define Re(z) real(z)
# define Im(z) aimag(z)

# define STRING(s) SSTRING(s)
# define SSTRING(s) #s

# define PUTSTR(unit, str) if (my_pe() == 0) write(unit,*) str
# define PUTVAL(unit, val) if (my_pe() == 0) write(unit,*) #val, ": ", val

# define DIAGSTR(str) write(UDIAG,*) str
# define DIAGVAL(val) write(UDIAG,*) #val, ": ", val

# define ASSERT(condition) if (.not. (condition)) call assertion_failed(__FILE__, __LINE__, #condition)
# define CHECK(condition) if (.not. (condition)) call check_failed(__FILE__, __LINE__, #condition)


#ifdef INTEL
# define RECL_UNIT 4
#else
# define RECL_UNIT 1
#endif

#ifdef DEBUG2
# define DEBUG2S(s)   call stderr2(s)
# define DEBUG2I(s,i) call stderr2_int(s,1,i)
# define DEBUG2R(s,r) call stderr2_real(s,1,r)
#else
# define DEBUG2S(s)
# define DEBUG2I(s,i)
# define DEBUG2R(s,r)
#endif

#ifdef WDAGW_R4
# include "w_mult_r4.h"
#endif

#endif
