#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 FREE( variable, type, size ) do{ free(variable); variable=NULL; memsize-=(size)*sizeof(type); }while(0)
            

#endif /* _MACROS_H */
