#ifndef _MACROS_H
#define _MACROS_H

/* Macros common to all applications */

/* ---------------------------------------------------------- */
/* Constants */

#define SGN(a) ((a>=0) ? (1.0) : (-1.0))
#define PI 3.14159265358979323846
#define MIN(a,b) ((a>=b) ? (b) : (a))

#define MAX(x,y) ((x)>(y)? (x) :(y))
/* ---------------------------------------------------------- */
/* Conventions for defining checkerboard parity of inversions */

#define EVEN 0x02
#define ODD 0x01
#define EVENANDODD 0x03

/* ---------------------------------------------------------- */
/* Storage constants */

#define MAXFILENAME 256		/* ASCII string length for all file names */

/* ---------------------------------------------------------- */
/* Names of gauge fixing options */

#define NO_GAUGE_FIX 30
#define COULOMB_GAUGE_FIX 31
#define LANDAU_GAUGE_FIX 32

/* ---------------------------------------------------------- */
/* "field offset" and "field pointer" */

/* used when fields are arguments to subroutines */
/* Usage:  fo = F_OFFSET( field ), where "field" is the name of a field
   in lattice.
   address = F_PT( &site , fo ), where &site is the address of the
   site and fo is a field_offset.  Usually, the result will have to be
   cast to a pointer to the appropriate type. (It is naturally a char *).
 */
typedef int field_offset;
#define F_OFFSET(a) \
    ((field_offset)(((char *)&(lattice[0]. a ))-((char *)&(lattice[0])) ))
#define F_PT( site , fo )  ((char *)( site ) + (fo))

    /* ---------------------------------------------------------- */
    /* Macros for looping over directions */

#define FORALLUPDIR(dir) for(dir=XUP; dir<=TUP; dir++)

#define FORALLUPDIRBUT(direction,dir) \
    for(dir=XUP; dir<= TUP; dir++)if(dir != direction)

#define OPP_PAR(parity) (0x03 ^ parity)	/* Switches EVEN and ODD. Nulls EVENANDOdd */

    /* ---------------------------------------------------------- */
    /* printf on node zero only */
    /* #define node0_printf if(this_node==0)printf  */
    /* #define node0_fprintf if(this_node==0)fprintf   */


    /* ---------------------------------------------------------- */
#define ON 1
#define OFF 0

    /* ---------------------------------------------------------- */
    /* Macros for looping over sites on a node */

    /**********************************************************************/
    /* WARNING: FORSOMEPARITY and FORSOMEPARITYDOMAIN is redefined in some
       routines if LOOPEND is specified.  See loopend.h */
    /**********************************************************************/

#ifndef N_SUBL32
    /*--------------*/

    /* Standard red-black checkerboard */

    /* macros to loop over sites of a given parity.
       Usage:  
       int i;
       site *s;
       FOREVENSITES(i,s){
       commands, where s is a pointer to the current site and i is
       the index of the site on the node
       }
     */

#define FOREVENSITES(i,s) \
    for(i=0,s=lattice;i<even_sites_on_node;i++,s++)
#define FORODDSITES(i,s) \
    for(i=even_sites_on_node,s= &(lattice[i]);i<sites_on_node;i++,s++)
#define FORSOMEPARITY(i,s,choice) \
    for( i=((choice)==ODD ? even_sites_on_node : 0 ),  \
            s= &(lattice[i]); \
            i< ( (choice)==EVEN ? even_sites_on_node : sites_on_node); \
            i++,s++)

#define FORALLSITES(i,s) \
    for(i=0,s=lattice;i<sites_on_node;i++,s++)

    /*--------------*/
#else /* N_SUBL32 */
    /*--------------*/

    /*  32 sublattice checkerboard */

    /* macros to loop over sites in a given sublattice.
       Usage:  
       int i, subl;
       site *s;
       FORSOMESUBLATTICE(i,s,subl){
       commands, where s is a pointer to the current site and i is
       the index of the site on the node
       }
     */
#define FORALLSITES(i,s) \
    for(i=0,s=lattice;i<sites_on_node;i++,s++)
#define FORSOMESUBLATTICE(i,s,subl) \
    for( i=(subl*subl_sites_on_node), s= &(lattice[i]), \
            last_in_loop=((subl+1)*subl_sites_on_node); \
            i< last_in_loop; i++,s++)

    /*--------------*/
#endif /* N_SUBL32 */


#ifdef SCHROED_FUN
#define FOREVENSITESDOMAIN(i,s) \
FOREVENSITES(i,s) if(s->t > 0)
#define FORODDSITESDOMAIN(i,s) \
FORODDSITES(i,s) if(s->t > 0)
#define FORALLSITESDOMAIN(i,s) \
FORALLSITES(i,s) if(s->t > 0)
#define FORSOMEPARITYDOMAIN(i,s,parity) \
FORSOMEPARITY(i,s,parity) if(s->t > 0)
#else
#define FOREVENSITESDOMAIN FOREVENSITES
#define FORODDSITESDOMAIN FORODDSITES
#define FORALLSITESDOMAIN FORALLSITES
#define FORSOMEPARITYDOMAIN FORSOMEPARITY
#endif

#ifdef DEBUG
#define node0_debug() do {node0_printf("DEBUG: %s:%d in %s()\n",__FILE__,__LINE__,__FUNCTION__);}while(0)
#define debug() do {printf("DEBUG: node= %d %s:%d in %s()\n",mynode_KE(),__FILE__,__LINE__,__FUNCTION__); fflush(0);} while(0)
#else
#define node0_debug() do{ }while(0)
#define debug() do{ }while(0)
#endif

/* #ifdef POSIX_MEMALIGN */
/* #define MEMALIGN( variable, type, size ) do{ posix_memalign( (void**) &variable, 16, (size) * sizeof( type ) ); if( (variable) == NULL ) { printf( "ERROR node= %d memory allocation failed\n",this_node );  exit(1);}; memsize+=(size)*sizeof(type); }while(0) */
/* #else */
/* #define MEMALIGN( variable, type, size ) do{ (variable) = ( type * ) memalign( 16, (size) * sizeof( type ) ); if( (variable) == NULL ) { printf( "ERROR node= %d memory allocation failed\n",this_node );  exit(1);}; memsize+=(size)*sizeof(type); }while(0) */
/* #endif */

#define MEMALIGN( variable, type, size ) do{ (variable) = ( type * ) malloc((size) * sizeof( type ) ); if( (variable) == NULL ) { printf( "ERROR node= %d memory allocation failed\n",this_node );  exit(1);}; memsize+=(size)*sizeof(type); }while(0)
        
#define FREE( variable, type, size ) do{ free(variable); variable=NULL; memsize-=(size)*sizeof(type); }while(0)
            

//targetDP


#define REPART 0
#define IMPART 1



//data access macros

//generic macros with variable "chunk size" cs
//wilson vector
#define WVI_(site,colour,spin,reim,cs)					\
(((site)/(cs))*3*4*2*(cs) + (colour)*4*2*(cs) + (spin)*2*(cs) + (reim)*(cs) + ((site)-((site)/(cs))*(cs)))

//half wilson vector
#define HWVI_(site,colour,spin,reim,cs)					\
(((site)/(cs))*3*2*2*(cs) + (colour)*2*2*(cs) + (spin)*2*(cs) + (reim)*(cs) + ((site)-((site)/(cs))*(cs)))

//su3 matrix
#define SU3MI_(site,colour1,colour2,dir,reim,cs)				\
(((site)/(cs))*4*3*3*2*(cs) + (dir)*3*3*2*(cs) + (colour1)*3*2*(cs) + (colour2)*2*(cs) + (reim)*(cs) + ((site)-((site)/(cs))*(cs)))


#ifdef AoS //set chunk size to 1
#define CINT 1
#define CIN 1
#else

#ifdef SoA //set chunk size to size of local lattice

#define CINT t_sites_on_node
#define CIN sites_on_node

#else //default AoSoA - set chunk size to VVL

#define CINT VVL
#define CIN VVL

#endif

#endif



#define WVI(site,colour,spin,reim)  WVI_(site,colour,spin,reim,CINT)	
#define WVIH(site,colour,spin,reim)  WVI_(site,colour,spin,reim,CIN)	
#define HWVI(site,colour,spin,reim) HWVI_(site,colour,spin,reim,CINT)
#define HWVIH(site,colour,spin,reim) HWVI_(site,colour,spin,reim,CIN)
#define SU3MI(site,colour1,colour2,dir,reim) SU3MI_(site,colour1,colour2,dir,reim,CINT)			    
#define SU3MIH(site,colour1,colour2,dir,reim) SU3MI_(site,colour1,colour2,dir,reim,CIN)		       		


#define HWVLI(site,colour,spin,reim) ((colour)*2*2*VVL+(spin)*2*VVL+(reim)*VVL+(site))

//#endif



#define COM_BIT 0x40000000

#endif /* _MACROS_H */
