HyPar  1.0
Finite-Difference Hyperbolic-Parabolic PDE Solver on Cartesian Grids
ParabolicFunctionNC2Stage_GPU.cu
Go to the documentation of this file.
1 /*! @file ParabolicFunctionNC2Stage_GPU.cu
2  @author Youngdae Kim
3  @brief Evaluate the parabolic term using a 2-stage finite difference discretization.
4 */
5 
6 #include <basic_gpu.h>
7 #include <arrayfunctions_gpu.h>
8 #include <mpivars.h>
9 #include <hypar.h>
10 
11 /*! Kernel for ParabolicFunctionNC2Stage_GPU() */
12 __global__
13 void ParabolicFunctionNC2Stage_kernel(
14  int ngrid_points,
15  int ghosts,
16  int d1,
17  int d2,
18  int ndims,
19  int nvars,
20  const int *dim,
21  const double *dxinv,
22  const double *Deriv2,
23  double *par
24 )
25 {
26  int tx = threadIdx.x + (blockDim.x * blockIdx.x);
27  if (tx < ngrid_points) {
28  int p, v;
29  int index[GPU_MAX_NDIMS];
30  double dxinv1, dxinv2;
31 
32  _ArrayIndexnD_(ndims,tx,dim,index,0);
33  _ArrayIndex1D_(ndims,dim,index,ghosts,p);
34  _GetCoordinate_(d1,index[d1],dim,ghosts,dxinv,dxinv1);
35  _GetCoordinate_(d2,index[d2],dim,ghosts,dxinv,dxinv2);
36  for (v=0; v<nvars; v++) par[nvars*p+v] += (dxinv1*dxinv2 * Deriv2[nvars*p+v]);
37  }
38 
39  return;
40 }
41 
42 /*! Evaluate the parabolic term using a "1.5"-stage finite-difference spatial discretization:
43  The parabolic term is assumed to be of the form:
44  \f{equation}{
45  {\bf P}\left({\bf u}\right) = \sum_{d1=0}^{D-1}\sum_{d2=0}^{D-1} \frac {\partial^2 h_{d1,d2}\left(\bf u\right)} {\partial x_{d1} \partial x_{d2}},
46  \f}
47  where \f$d1\f$ and \f$d2\f$ are spatial dimension indices, and \f$D\f$ is the total number of spatial dimensions (#HyPar::ndims). This term is
48  discretized at a grid point as:
49  \f{equation}{
50  \left.{\bf P}\left({\bf u}\right)\right|_j = \sum_{d1=0}^{D-1} \sum_{d2=0}^{D-1} \frac { \mathcal{D}_{d1}\mathcal{D}_{d2} \left[ {\bf h}_{d1,d2} \right] } {\Delta x_{d1} \Delta x_{d2}},
51  \f}
52  where \f$\mathcal{D}\f$ denotes the finite-difference approximation to the first derivative. Each of the first derivative approximations are \f$\mathcal{D}_{d1}\f$ and \f$\mathcal{D}_{d2}\f$ are computed separately, and thus the cross-derivative is evaluated in two steps using #HyPar::FirstDerivativePar.
53 
54  \b Notes:
55  + This form of the parabolic term \b does \b allow for cross-derivatives (\f$ d1 \ne d2 \f$).
56  + A \f$n\f$-th order central approximation to the second derivative can be expressed as a
57  conjugation of two \f$(n-1)\f$-th order approximations to the first
58  derivative, one forward and one backward. Computing it this way avoids
59  odd-even decoupling. Thus, where possible #HyPar::FirstDerivativePar should
60  point to the function computing \f$(n-1)\f$-th order first derivative where \f$n\f$
61  is the desired order. Currently, this is implemented only for \f$n=2\f$. For other values
62  of \f$n\f$, the first derivative is also computed with a \f$n\f$-th order approximation.
63 
64  To use this form of the parabolic term:
65  + specify \b "par_space_type" in solver.inp as \b "nonconservative-2stage" (#HyPar::spatial_type_par).
66  + the physical model must specify \f${\bf h}_{d1,d2}\left({\bf u}\right)\f$ through #HyPar::HFunction.
67 */
68 int ParabolicFunctionNC2Stage_GPU(
69  double *par, /*!< array to hold the computed parabolic term */
70  double *u, /*!< solution */
71  void *s, /*!< Solver object of type #HyPar */
72  void *m, /*!< MPI object of type #MPIVariables */
73  double t /*!< Current simulation time */
74 )
75 {
76  HyPar *solver = (HyPar*) s;
77  MPIVariables *mpi = (MPIVariables*) m;
78  double *Func = solver->fluxC;
79  double *Deriv1 = solver->Deriv1;
80  double *Deriv2 = solver->Deriv2;
81  int d1, d2;
82  _DECLARE_IERR_;
83 
84  int ndims = solver->ndims;
85  int nvars = solver->nvars;
86  int ghosts = solver->ghosts;
87  int *dim = solver->dim_local;
88  int size = solver->npoints_local_wghosts;
89 
90  if (!solver->HFunction) return(0); /* zero parabolic terms */
91  solver->count_par++;
92 
93  gpuArraySetValue(par, size*nvars, 0.0);
94 
95  int ngrid_points = 1; for (int i = 0; i < ndims; i++) ngrid_points *= dim[i];
96 
97  for (d1 = 0; d1 < ndims; d1++) {
98  for (d2 = 0; d2 < ndims; d2++) {
99 
100  /* calculate the diffusion function */
101  solver->HFunction(Func,u,d1,d2,solver,t);
102  solver->FirstDerivativePar(Deriv1,Func ,d1, 1,solver,mpi);
103  MPIExchangeBoundariesnD(ndims,nvars,dim,ghosts,mpi,Deriv1);
104  solver->FirstDerivativePar(Deriv2,Deriv1,d2,-1,solver,mpi);
105 
106  /* calculate the final term - second derivative of the diffusion function */
107  int nblocks = (ngrid_points - 1) / GPU_THREADS_PER_BLOCK + 1;
108  ParabolicFunctionNC2Stage_kernel<<<nblocks, GPU_THREADS_PER_BLOCK>>>(
109  ghosts, d1, d2, ndims, nvars, ngrid_points,
110  solver->gpu_dim_local, solver->gpu_dxinv, solver->Deriv2, par
111  );
112 
113  /*
114  done = 0; _ArraySetValue_(index,ndims,0);
115  while (!done) {
116  _ArrayIndex1D_(ndims,dim,index,ghosts,p);
117  _GetCoordinate_(d1,index[d1],dim,ghosts,dxinv,dxinv1);
118  _GetCoordinate_(d2,index[d2],dim,ghosts,dxinv,dxinv2);
119  for (v=0; v<nvars; v++) par[nvars*p+v] += (dxinv1*dxinv2 * Deriv2[nvars*p+v]);
120  _ArrayIncrementIndex_(ndims,dim,index,done);
121  }
122  */
123  }
124  }
125 
126  if (solver->flag_ib) _ArrayBlockMultiply_(par,solver->iblank,size,nvars);
127  return(0);
128 }