// oth_cuda.h
#ifndef _OTH_CUDA_H_
#define _OTH_CUDA_H_

#include <cuComplex.h>

#ifdef MAIN
#define EXTERN
#else
#define EXTERN extern
#endif

#define BLOCK_X (16)
#define BLOCK_Y (16)
#define PBC_BLOCK_X (16)
#define PBC_BLOCK_Y (16)
#define BLAS_GRID_SIZE  (128)
#define BLAS_BLOCK_SIZE (128)

#define CEIL(n,d) (((n) + (d) - 1) / (d))

// parameter
typedef struct {
int      Nx, Ny, Nz;
int64_t  NEXI, NEXJ, NEXK, NEX0;
int64_t  NEYI, NEYJ, NEYK, NEY0;
int64_t  NEZI, NEZJ, NEZK, NEZ0;
int64_t  NHXI, NHXJ, NHXK, NHX0;
int64_t  NHYI, NHYJ, NHYK, NHY0;
int64_t  NHZI, NHZJ, NHZK, NHZ0;
int      NMaterial;
int      SCALING, MATRIX;
int      NFeed;
int      IPlanewave, Planewave_isemi;
int      Abc, Lpml, Xpbc, Ypbc, Zpbc;
cuDoubleComplex pbc_fx, pbc_fy, pbc_fz;
} param_t;

#define nEX(p,i,j,k) ((p)->NEXI*(i)+(p)->NEXJ*(j)+(p)->NEXK*(k)+(p)->NEX0)
#define nEY(p,i,j,k) ((p)->NEYI*(i)+(p)->NEYJ*(j)+(p)->NEYK*(k)+(p)->NEY0)
#define nEZ(p,i,j,k) ((p)->NEZI*(i)+(p)->NEZJ*(j)+(p)->NEZK*(k)+(p)->NEZ0)

#define nHX(p,i,j,k) ((p)->NHXI*(i)+(p)->NHXJ*(j)+(p)->NHXK*(k)+(p)->NHX0)
#define nHY(p,i,j,k) ((p)->NHYI*(i)+(p)->NHYJ*(j)+(p)->NHYK*(k)+(p)->NHY0)
#define nHZ(p,i,j,k) ((p)->NHZI*(i)+(p)->NHZJ*(j)+(p)->NHZK*(k)+(p)->NHZ0)

#define mEX(p,i,j,k) me[nEX(p,i,j,k)]
#define mEY(p,i,j,k) me[nEY(p,i,j,k)]
#define mEZ(p,i,j,k) me[nEZ(p,i,j,k)]

#define mHX(p,i,j,k) mh[nHX(p,i,j,k)]
#define mHY(p,i,j,k) mh[nHY(p,i,j,k)]
#define mHZ(p,i,j,k) mh[nHZ(p,i,j,k)]

EXTERN int     GPU;
EXTERN int     UM;

// constant memory
EXTERN param_t h_Param;
__constant__ param_t d_Param;

// device memory
EXTERN double   *d_DXn, *d_DYn, *d_DZn;
EXTERN double   *d_DXc, *d_DYc, *d_DZc;
EXTERN double   *d_KRXn, *d_KRYn, *d_KRZn;
EXTERN double   *d_KRXc, *d_KRYc, *d_KRZc;
EXTERN double   *d_KDXn, *d_KDYn, *d_KDZn;
EXTERN double   *d_KDXc, *d_KDYc, *d_KDZc;
EXTERN double   *d_KRXp, *d_KRYp, *d_KRZp;
EXTERN double   *d_KRXm, *d_KRYm, *d_KRZm;

EXTERN int      *d_mE, *d_mH;

EXTERN cuDoubleComplex *d_Acg;
EXTERN cuDoubleComplex *d_Ecg, *d_Bcg, *d_Rcg, *d_Pcg, *d_Qcg, *d_Tcg, *d_Ucg, *d_R0cg;
EXTERN cuDoubleComplex *h_Wblas, *d_Wblas;

EXTERN material_t *d_Material;

EXTERN double   *d_Fxpml, *d_Fypml, *d_Fzpml;

#endif		// _OTH_CUDA_H_
