1 /*! @file ParabolicFunctionNC2Stage_GPU.cu
3 @brief Evaluate the parabolic term using a 2-stage finite difference discretization.
7 #include <arrayfunctions_gpu.h>
11 /*! Kernel for ParabolicFunctionNC2Stage_GPU() */
13 void ParabolicFunctionNC2Stage_kernel(
26 int tx = threadIdx.x + (blockDim.x * blockIdx.x);
27 if (tx < ngrid_points) {
29 int index[GPU_MAX_NDIMS];
30 double dxinv1, dxinv2;
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]);
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:
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}},
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:
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}},
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.
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.
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.
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 */
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;
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;
90 if (!solver->HFunction) return(0); /* zero parabolic terms */
93 gpuArraySetValue(par, size*nvars, 0.0);
95 int ngrid_points = 1; for (int i = 0; i < ndims; i++) ngrid_points *= dim[i];
97 for (d1 = 0; d1 < ndims; d1++) {
98 for (d2 = 0; d2 < ndims; d2++) {
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);
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
114 done = 0; _ArraySetValue_(index,ndims,0);
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);
126 if (solver->flag_ib) _ArrayBlockMultiply_(par,solver->iblank,size,nvars);