#ifndef BDEF_H
#define BDEF_H 1

/*
 * Include the system dependant and user defined stuff
 */
#include "Bconfig.h"
/*
 * ========================================================================
 *                     TYPEDEF'S USED IN THE BLACS
 * ========================================================================
 */

/*
 * Data type defining a context for the BLACS
 */
typedef struct bLaCsCoNtExT BLACSCONTEXT;
struct bLaCsCoNtExT
{
   int minID, maxID;            /* range of IDs for this context */
   int SDminID, SDmaxID;        /* point to point (pt2pt) ID range */
   int SDmyminID;		/* start of my subrange of pt2pt range */
   int IDsPerNode;		/* # of pt2pt IDs each node gets */
   int RminID, CminID, AminID;  /* minimum row, col, and all scoped ID */
   int *SDcount, *RVcount;      /* history of pt2pt communication */
   int Rcount, Ccount, Acount;  /* history of scoped communication */
   int *coord2proc;		/* maps coordinate to pid */
   int Ng, nprow, npcol;        /* # of procs in grid, row, and col */
   int vIam, myrow, mycol;	/* index in grid, and row/col in grid */
   int TopsRepeat;              /* Use only repeatable topologies? */
   int TopsCohrnt;              /* Use only coherent topologies? */
   int Nb_bs, Nr_bs;           /* for bcast general tree and multiring tops */
   int Nb_co, Nr_co;           /* for combine general tree and multiring tops */
};

/*
 *  Define the fortran 77 data types COMPLEX*8 (SCOMPLEX)
 *  and COMPLEX*16 (DCOMPLEX).
 */
typedef struct {double r, i;} DCOMPLEX;
typedef struct {float r, i;} SCOMPLEX;

typedef struct mAtInFo MATINFO;
struct mAtInFo
{
   char Uplo, Diag;
   int M, N, lda, ldb;
   char *A, *B;
};

/*
 * Pointer to the combine's matrix-vector pack/unpack (MVPK)
 * and unpack and do operation (UPKOP) functions
 */
#ifdef __STDC__
typedef void (*MVPK)(MATINFO *);
typedef void (*MVUPKOP)(MATINFO *, char *);
#else
typedef void (*MVPK)();
typedef void (*MVUPKOP)();
#endif
/*
 * ========================================================================
 *                             MACRO CONSTANTS
 * ========================================================================
 */
#define NOTINCONTEXT -1  /* Indicates node called gridmap, but not in grid */
#define MAXNCTXT 10      /* initial guess at max # of contexts */
#define IDPERC .33       /* percentage of remaining IDs given to a context */

/*
 * Error codes
 */
#define NORV 1          /* No receiver (only 1 proc in scoped op) */
#define NPOW2 2         /* Number of procs is not a power of 2 */
#define BADSCP 3        /* Scope not row, column or all */

/*
 * Data types
 */
#define INTEGER   3
#define SINGLE    4
#define DOUBLE    6
#define COMPLEX8  5
#define COMPLEX16 7

#define FULLCON 0      /* top is fully connected */

/*
 * Routine types
 */
#define RT_SD    1
#define RT_RV    2
#define RT_BS    3
#define RT_BR    4
#define RT_COMB  5

/*
 * Legal WHAT values for BLACS_SET
 */
#define SGET_SYSCONTXT    0
#define SGET_MSGIDS       1
#define SGET_DEBUGLVL     2
#define SGET_BLACSCONTXT 10
#define SGET_NR_BS       11
#define SGET_NB_BS       12
#define SGET_NR_CO       13
#define SGET_NB_CO       14
#define SGET_TOPSREPEAT  15
#define SGET_TOPSCOHRNT  16

/*
 * These are prototypes for error and warning functions -- I don't want
 * to prototype them in each routine.
 */
#ifdef __STDC__
void BlacsWarn(int ConTxt, int line, char *file, char *form, ...);
void BlacsErr(int ConTxt, int line, char *file, char *form, ...);
#else
void BlacsWarn();
void BlacsErr();
#endif

/*
 * ========================================================================
 *     PREPROCESSOR MACRO FUNCTIONS USED FOR OPTIMIZATION & CONVENIENCE
 * ========================================================================
 */

#define Mlowcase(C) ( ((C) > 64 && (C) < 91) ? (C) | 32 : (C) )

/*
 * Slightly modified gridinfo substitute
 */
#define Mgridinfo(ctxt, Ng0, nprow0, npcol0, myrow0, mycol0)\
{\
   (Ng0) = (ctxt)->Ng;\
   (nprow0) = (ctxt)->nprow;\
   (npcol0) = (ctxt)->npcol;\
   (myrow0) = (ctxt)->myrow;\
   (mycol0) = (ctxt)->mycol;\
}

/*
 * These routines return coordinates based on nodes number, or node number
 * based on coordinates.  Those routines with v after the M return virtual
 * nodes numbers (i.e., in respect to the grid, not physical node numbers)
 * based on grid coordinates, or grid coordinates based on virtual node numbers.
 */
#define Mpcoord(ctxt, node, prow, pcol)\
{\
   int MMi;\
   for (MMi=0; ( (MMi < (ctxt)->Ng) && ((ctxt)->coord2proc[MMi] != (node)) );\
        MMi++);\
   if (MMi < (ctxt)->Ng)\
   {\
      (prow) = MMi / (ctxt)->npcol;\
      (pcol) = MMi % (ctxt)->npcol;\
   }\
   else (prow) = (pcol) = -1;\
}
#define Mvpcoord(ctxt, vnode, prow, pcol)\
{\
   (prow) = (vnode) / (ctxt)->npcol;\
   (pcol) = (vnode) % (ctxt)->npcol;\
}
#define Mkpnum(ctxt, prow, pcol) (ctxt)->coord2proc[(prow)*(ctxt)->npcol+(pcol)]
#define Mvkpnum(ctxt, prow, pcol) ( (prow)*(ctxt)->npcol+(pcol) )

/*
 * These macros return point to point message ID's.
 */
#define Msdid(ctxt, vdest) (ctxt)->SDmyminID + (ctxt)->SDcount[(vdest)]; \
   if (++((ctxt)->SDcount[(vdest)]) >= (ctxt)->IDsPerNode) \
      (ctxt)->SDcount[(vdest)] = 0
#define Mrvid(ctxt, vsrc) \
   (ctxt)->IDsPerNode * (vsrc) + (ctxt)->RVcount[(vsrc)] + (ctxt)->SDminID;\
   if (++((ctxt)->RVcount[(vsrc)]) >= (ctxt)->IDsPerNode) \
      (ctxt)->RVcount[(vsrc)] = 0

/*
 * These macros return scoped message ID's.
 */
#define Mrid(ctxt) (ctxt)->Rcount; \
   if (++(ctxt)->Rcount == (ctxt)->CminID) (ctxt)->Rcount = (ctxt)->RminID;
#define Mcid(ctxt) (ctxt)->Ccount; \
   if (++(ctxt)->Ccount == (ctxt)->AminID) (ctxt)->Ccount = (ctxt)->CminID;
#define Maid(ctxt) (ctxt)->Acount; \
   if (++(ctxt)->Acount == (ctxt)->maxID) (ctxt)->Acount = (ctxt)->AminID;

/*
 *  Get context, and check for validity if debug level is high
 */
#if (BlacsDebugLvl > 0)
#define MGetConTxt(Context, ctxtptr)\
{\
   extern BLACSCONTEXT **MyConTxts00;\
   extern int MaxNCtxt00;\
   if ( ((Context) >= MaxNCtxt00) || ((Context) < 0) )\
      BlacsErr(-1, __LINE__, __FILE__, "Invalid context handle");\
   else if (MyConTxts00[(Context)] == NULL)\
      BlacsErr(-1, __LINE__, __FILE__, "Invalid context");\
   (ctxtptr) = MyConTxts00[(Context)];\
}
#else
#define MGetConTxt(Context, ctxtptr)\
{\
   extern BLACSCONTEXT **MyConTxts00;\
   (ctxtptr) = MyConTxts00[(Context)];\
}
#endif
#if(BlacsDebugLvl > 0)
#define Mpvmerror(info, rout, Line, File) \
{\
   extern int *pvmtids00, Iam00;\
   if ( (info) < 0 )\
   {\
      fprintf(stderr,"%x: PVM ERROR #%d on call to %s on line %d of file %s.\n",\
              pvmtids00[Iam00], (info), (rout), (Line), (File));\
      exit((info));\
   }\
}
#else
#define Mpvmerror(info, rout, Line, File)
#endif

#define Minitsend(info, line)\
{\
   (info) = pvm_initsend(PvmDataDefault);\
   Mpvmerror((info), "pvm_initsend", (line), __FILE__);\
}
/*
 *  These macros allow for accessing values and addresses of parameters, which
 *  will be pointers if we're using fortran, and values if we're using C.
 */
#if (INTFACE == C_CALL)
#define Mpval(para) (para)
#define Mpaddress(para) (&(para))
#define Mwalltime Cdwalltime00
#else
#define Mpval(para) (*(para))
#define Mpaddress(para) (para)
#define Mwalltime dwalltime00_
#endif

/*
 * Real and complex absolute values
 */
#define Rabs(x) ( (x) < 0 ? (x) * -1 : (x) )
#define Cabs(z) ( (((z).i) < 0 ? ((z).i) * -1 : ((z).i)) + (((z).r) < 0 ? ((z).r) * -1 : ((z).r)) )

#define imvcopy(m, n, A, lda, buff) \
        mvcopy4((m), (n), (int *) (A), (lda), (int *) (buff))
#define ivmcopy(m, n, A, lda, buff) \
        vmcopy4((m), (n), (int *) (A), (lda), (int *) (buff))
#define itvcopy(uplo, diag, m, n, A, lda, v) \
        tvcopy4((uplo), (diag), (m), (n), (int*) (A), (lda), (int*) (v))
#define ivtcopy(uplo, diag, m, n, A, lda, v) \
        vtcopy4((uplo), (diag), (m), (n), (int*) (A), (lda), (int*) (v))
#define smvcopy(m, n, A, lda, buff) \
        mvcopy4((m), (n), (int *) (A), (lda), (int *) (buff))
#define svmcopy(m, n, A, lda, buff) \
        vmcopy4((m), (n), (int *) (A), (lda), (int *) (buff))
#define stvcopy(uplo, diag, m, n, A, lda, v) \
        tvcopy4((uplo), (diag), (m), (n), (int*) (A), (lda), (int*) (v))
#define svtcopy(uplo, diag, m, n, A, lda, v) \
        vtcopy4((uplo), (diag), (m), (n), (int*) (A), (lda), (int*) (v))
#define dmvcopy(m, n, A, lda, buff) \
        mvcopy8((m), (n), (double *) (A), (lda), (double *) (buff))
#define dvmcopy(m, n, A, lda, buff) \
        vmcopy8((m), (n), (double *) (A), (lda), (double *) (buff))
#define dtvcopy(uplo, diag, m, n, A, lda, v) \
        tvcopy8((uplo), (diag), (m), (n), (double*) (A), (lda), (double*) (v))
#define dvtcopy(uplo, diag, m, n, A, lda, v) \
        vtcopy8((uplo), (diag), (m), (n), (double*) (A), (lda), (double*) (v))
#define cmvcopy(m, n, A, lda, buff) \
        mvcopy8((m), (n), (double *) (A), (lda), (double *) (buff))
#define cvmcopy(m, n, A, lda, buff) \
        vmcopy8((m), (n), (double *) (A), (lda), (double *) (buff))
#define ctvcopy(uplo, diag, m, n, A, lda, v) \
        tvcopy8((uplo), (diag), (m), (n), (double*) (A), (lda), (double*) (v))
#define cvtcopy(uplo, diag, m, n, A, lda, v) \
        vtcopy8((uplo), (diag), (m), (n), (double*) (A), (lda), (double*) (v))
#define zmvcopy(m, n, A, lda, buff) \
        mvcopy8(2*(m), (n), (double *) (A), 2*(lda), (double *) (buff))
#define zvmcopy(m, n, A, lda, buff) \
        vmcopy8(2*(m), (n), (double *) (A), 2*(lda), (double *) (buff))
#define ztvcopy(uplo, diag, m, n, A, lda, v) \
        tvcopy16((uplo), (diag), (m), (n), (double*) (A), (lda), (double*) (v))
#define zvtcopy(uplo, diag, m, n, A, lda, v) \
        vtcopy16((uplo), (diag), (m), (n), (double*) (A), (lda), (double*) (v))

#if (F77_CALL_C == ADD_)
/*
 * These defines set up the naming scheme required to have a fortran 77
 * routine call a C routine (which is what the BLACS are written in).
 * No redefinition necessary to have following Fortran to C interface:
 *           FORTRAN CALL               C DECLARATION
 *           call dgebs2d(...)          void dgebs2d_(...)
 */
#endif

#if (F77_CALL_C == NOCHANGE)
/*
 * These defines set up the naming scheme required to have a fortran 77
 * routine call a C routine (which is what the BLACS are written in)
 * for the following Fortran to C interface:
 *           FORTRAN CALL               C DECLARATION
 *           call dgebs2d(...)          void dgebs2d(...)
 */
#define igesd2d_ igesd2d
#define igerv2d_ igerv2d
#define igebs2d_ igebs2d
#define igebr2d_ igebr2d
#define itrsd2d_ itrsd2d
#define itrrv2d_ itrrv2d
#define itrbs2d_ itrbs2d
#define itrbr2d_ itrbr2d

#define igsum2d_ igsum2d
#define igamx2d_ igamx2d
#define igamn2d_ igamn2d

#define sgesd2d_ sgesd2d
#define sgerv2d_ sgerv2d
#define sgebs2d_ sgebs2d
#define sgebr2d_ sgebr2d
#define strsd2d_ strsd2d
#define strrv2d_ strrv2d
#define strbs2d_ strbs2d
#define strbr2d_ strbr2d

#define sgsum2d_ sgsum2d
#define sgamx2d_ sgamx2d
#define sgamn2d_ sgamn2d

#define dgesd2d_ dgesd2d
#define dgerv2d_ dgerv2d
#define dgebs2d_ dgebs2d
#define dgebr2d_ dgebr2d
#define dtrsd2d_ dtrsd2d
#define dtrrv2d_ dtrrv2d
#define dtrbs2d_ dtrbs2d
#define dtrbr2d_ dtrbr2d

#define dgsum2d_ dgsum2d
#define dgamx2d_ dgamx2d
#define dgamn2d_ dgamn2d

#define cgesd2d_ cgesd2d
#define cgerv2d_ cgerv2d
#define cgebs2d_ cgebs2d
#define cgebr2d_ cgebr2d
#define ctrsd2d_ ctrsd2d
#define ctrrv2d_ ctrrv2d
#define ctrbs2d_ ctrbs2d
#define ctrbr2d_ ctrbr2d

#define cgsum2d_ cgsum2d
#define cgamx2d_ cgamx2d
#define cgamn2d_ cgamn2d

#define zgesd2d_ zgesd2d
#define zgerv2d_ zgerv2d
#define zgebs2d_ zgebs2d
#define zgebr2d_ zgebr2d
#define ztrsd2d_ ztrsd2d
#define ztrrv2d_ ztrrv2d
#define ztrbs2d_ ztrbs2d
#define ztrbr2d_ ztrbr2d

#define zgsum2d_ zgsum2d
#define zgamx2d_ zgamx2d
#define zgamn2d_ zgamn2d

/*
 * Initialization routines
 */
#define blacs_pinfo_    blacs_pinfo
#define blacs_setup_    blacs_setup
#define setpvmtids_     setpvmtids
#define blacs_set_      blacs_set
#define blacs_get_      blacs_get
#define blacs_gridinit_ blacs_gridinit
#define blacs_gridmap_  blacs_gridmap
/*
 * ID generation
 */
#define ksendid_ ksendid
#define krecvid_ krecvid
#define kbsid_   kbsid
#define kbrid_   kbrid
/*
 * Destruction routines
 */
#define blacs_freebuff_ blacs_freebuff
#define blacs_gridexit_ blacs_gridexit
#define blacs_abort_    blacs_abort
#define blacs_exit_     blacs_exit
/*
 * Informational & misc.
 */
#define blacs_gridinfo_ blacs_gridinfo
#define blacs_pnum_     blacs_pnum
#define blacs_pcoord_   blacs_pcoord
#define dcputime00_     dcputime00
#define dwalltime00_    dwalltime00
#define blacs_barrier_  blacs_barrier
#endif

#if (F77_CALL_C == UPCASE)
/*
 * These defines set up the naming scheme required to have a fortran 77
 * routine call a C routine (which is what the BLACS are written in)
 * for the following Fortran to C interface:
 *           FORTRAN CALL               C DECLARATION
 *           call dgebs2d(...)          void DGEBS2D(...)
 */
#define igesd2d_ IGESD2D
#define igerv2d_ IGERV2D
#define igebs2d_ IGEBS2D
#define igebr2d_ IGEBR2D
#define itrsd2d_ ITRSD2D
#define itrrv2d_ ITRRV2D
#define itrbs2d_ ITRBS2D
#define itrbr2d_ ITRBR2D

#define igsum2d_ IGSUM2D
#define igamx2d_ IGAMX2D
#define igamn2d_ IGAMN2D

#define sgesd2d_ SGESD2D
#define sgerv2d_ SGERV2D
#define sgebs2d_ SGEBS2D
#define sgebr2d_ SGEBR2D
#define strsd2d_ STRSD2D
#define strrv2d_ STRRV2D
#define strbs2d_ STRBS2D
#define strbr2d_ STRBR2D

#define sgsum2d_ SGSUM2D
#define sgamx2d_ SGAMX2D
#define sgamn2d_ SGAMN2D

#define dgesd2d_ DGESD2D
#define dgerv2d_ DGERV2D
#define dgebs2d_ DGEBS2D
#define dgebr2d_ DGEBR2D
#define dtrsd2d_ DTRSD2D
#define dtrrv2d_ DTRRV2D
#define dtrbs2d_ DTRBS2D
#define dtrbr2d_ DTRBR2D

#define dgsum2d_ DGSUM2D
#define dgamx2d_ DGAMX2D
#define dgamn2d_ DGAMN2D

#define cgesd2d_ CGESD2D
#define cgerv2d_ CGERV2D
#define cgebs2d_ CGEBS2D
#define cgebr2d_ CGEBR2D
#define ctrsd2d_ CTRSD2D
#define ctrrv2d_ CTRRV2D
#define ctrbs2d_ CTRBS2D
#define ctrbr2d_ CTRBR2D

#define cgsum2d_ CGSUM2D
#define cgamx2d_ CGAMX2D
#define cgamn2d_ CGAMN2D

#define zgesd2d_ ZGESD2D
#define zgerv2d_ ZGERV2D
#define zgebs2d_ ZGEBS2D
#define zgebr2d_ ZGEBR2D
#define ztrsd2d_ ZTRSD2D
#define ztrrv2d_ ZTRRV2D
#define ztrbs2d_ ZTRBS2D
#define ztrbr2d_ ZTRBR2D

#define zgsum2d_ ZGSUM2D
#define zgamx2d_ ZGAMX2D
#define zgamn2d_ ZGAMN2D

/*
 * Initialization routines
 */
#define blacs_pinfo_    BLACS_PINFO
#define blacs_setup_    BLACS_SETUP
#define setpvmtids_     SETPVMTIDS
#define blacs_gridinit_ BLACS_GRIDINIT
#define blacs_gridmap_  BLACS_GRIDMAP
#define blacs_set_      BLACS_SET
#define blacs_get_      BLACS_GET
/*
 * ID generation
 */
#define ksendid_ KSENDID
#define krecvid_ KRECVID
#define kbsid_   KBSID
#define kbrid_   KBRID
/*
 * Destruction
 */
#define blacs_freebuff_ BLACS_FREEBUFF
#define blacs_gridexit_ BLACS_GRIDEXIT
#define blacs_abort_    BLACS_ABORT
#define blacs_exit_     BLACS_EXIT
/*
 * Informational & misc.
 */
#define blacs_gridinfo_ BLACS_GRIDINFO
#define blacs_pnum_     BLACS_PNUM
#define blacs_pcoord_   BLACS_PCOORD
#define dcputime00_     DCPUTIME00
#define dwalltime00_    DWALLTIME00
#define blacs_barrier_  BLACS_BARRIER
#endif

#if (F77_CALL_C == F77ISF2C)
/*
 * These defines set up the naming scheme required to have a fortran 77
 * routine call a C routine (which is what the BLACS are written in)
 * for systems where the fortran "compiler" is actually f2c (a fortran
 * to C conversion utility).
 */
/*
 * Initialization routines
 */
#define blacs_pinfo_    blacs_pinfo__
#define blacs_setup_    blacs_setup__
#define blacs_set_      blacs_set__
#define blacs_get_      blacs_get__
#define blacs_gridinit_ blacs_gridinit__
#define blacs_gridmap_  blacs_gridmap__
/*
 * Destruction routines
 */
#define blacs_freebuff_ blacs_freebuff__
#define blacs_gridexit_ blacs_gridexit__
#define blacs_abort_    blacs_abort__
#define blacs_exit_     blacs_exit__
/*
 * Informational & misc.
 */
#define blacs_gridinfo_ blacs_gridinfo__
#define blacs_pnum_     blacs_pnum__
#define blacs_pcoord_   blacs_pcoord__
#define blacs_barrier_  blacs_barrier__
#endif

#endif
