HyPar  1.0
Finite-Difference Hyperbolic-Parabolic PDE Solver on Cartesian Grids
Interp1PrimFifthOrderCRWENOChar.c
Go to the documentation of this file.
1 
6 #include <stdio.h>
7 #include <basic.h>
8 #include <arrayfunctions.h>
9 #include <matmult_native.h>
10 #include <mathfunctions.h>
11 #include <interpolation.h>
12 #include <tridiagLU.h>
13 #include <mpivars.h>
14 #include <hypar.h>
15 
16 #ifdef with_omp
17 #include <omp.h>
18 #endif
19 
20 #undef _MINIMUM_GHOSTS_
21 
25 #define _MINIMUM_GHOSTS_ 3
26 
94  double *fI,
95  double *fC,
96  double *u,
97  double *x,
98  int upw,
99  int dir,
100  void *s,
101  void *m,
102  int uflag
103  )
104 {
105  HyPar *solver = (HyPar*) s;
106  MPIVariables *mpi = (MPIVariables*) m;
107  CompactScheme *compact= (CompactScheme*) solver->compact;
108  WENOParameters *weno = (WENOParameters*) solver->interp;
109  TridiagLU *lu = (TridiagLU*) solver->lusolver;
110  int sys,Nsys,d,v,k;
112 
113  int ghosts = solver->ghosts;
114  int ndims = solver->ndims;
115  int nvars = solver->nvars;
116  int *dim = solver->dim_local;
117 
118  /* define some constants */
119  static const double one_third = 1.0/3.0;
120  static const double one_sixth = 1.0/6.0;
121 
122  double *ww1, *ww2, *ww3;
123  ww1 = weno->w1 + (upw < 0 ? 2*weno->size : 0) + (uflag ? weno->size : 0) + weno->offset[dir];
124  ww2 = weno->w2 + (upw < 0 ? 2*weno->size : 0) + (uflag ? weno->size : 0) + weno->offset[dir];
125  ww3 = weno->w3 + (upw < 0 ? 2*weno->size : 0) + (uflag ? weno->size : 0) + weno->offset[dir];
126 
127  /* create index and bounds for the outer loop, i.e., to loop over all 1D lines along
128  dimension "dir" */
129  int indexC[ndims], indexI[ndims], index_outer[ndims], bounds_outer[ndims], bounds_inter[ndims];
130  _ArrayCopy1D_(dim,bounds_outer,ndims); bounds_outer[dir] = 1;
131  _ArrayCopy1D_(dim,bounds_inter,ndims); bounds_inter[dir] += 1;
132 
133  /* calculate total number of block tridiagonal systems to solve */
134  _ArrayProduct1D_(bounds_outer,ndims,Nsys);
135 
136  /* allocate arrays for the averaged state, eigenvectors and characteristic interpolated f */
137  double R[nvars*nvars], L[nvars*nvars], uavg[nvars];
138 
139  /* Allocate arrays for tridiagonal system */
140  double *A = compact->A;
141  double *B = compact->B;
142  double *C = compact->C;
143  double *F = compact->R;
144 
145 #pragma omp parallel for schedule(auto) default(shared) private(sys,d,v,k,R,L,uavg,index_outer,indexC,indexI)
146  for (sys=0; sys<Nsys; sys++) {
147  _ArrayIndexnD_(ndims,sys,bounds_outer,index_outer,0);
148  _ArrayCopy1D_(index_outer,indexC,ndims);
149  _ArrayCopy1D_(index_outer,indexI,ndims);
150  for (indexI[dir] = 0; indexI[dir] < dim[dir]+1; indexI[dir]++) {
151  int qm1,qm2,qm3,qp1,qp2;
152  if (upw > 0) {
153  indexC[dir] = indexI[dir]-3; _ArrayIndex1D_(ndims,dim,indexC,ghosts,qm3);
154  indexC[dir] = indexI[dir]-2; _ArrayIndex1D_(ndims,dim,indexC,ghosts,qm2);
155  indexC[dir] = indexI[dir]-1; _ArrayIndex1D_(ndims,dim,indexC,ghosts,qm1);
156  indexC[dir] = indexI[dir] ; _ArrayIndex1D_(ndims,dim,indexC,ghosts,qp1);
157  indexC[dir] = indexI[dir]+1; _ArrayIndex1D_(ndims,dim,indexC,ghosts,qp2);
158  } else {
159  indexC[dir] = indexI[dir]+2; _ArrayIndex1D_(ndims,dim,indexC,ghosts,qm3);
160  indexC[dir] = indexI[dir]+1; _ArrayIndex1D_(ndims,dim,indexC,ghosts,qm2);
161  indexC[dir] = indexI[dir] ; _ArrayIndex1D_(ndims,dim,indexC,ghosts,qm1);
162  indexC[dir] = indexI[dir]-1; _ArrayIndex1D_(ndims,dim,indexC,ghosts,qp1);
163  indexC[dir] = indexI[dir]-2; _ArrayIndex1D_(ndims,dim,indexC,ghosts,qp2);
164  }
165 
166  int p; /* 1D index of the interface */
167  _ArrayIndex1D_(ndims,bounds_inter,indexI,0,p);
168 
169  /* find averaged state at this interface */
170  IERR solver->AveragingFunction(uavg,&u[nvars*qm1],&u[nvars*qp1],solver->physics); CHECKERR(ierr);
171 
172  /* Get the left and right eigenvectors */
173  IERR solver->GetLeftEigenvectors (uavg,L,solver->physics,dir); CHECKERR(ierr);
174  IERR solver->GetRightEigenvectors (uavg,R,solver->physics,dir); CHECKERR(ierr);
175 
176  for (v=0; v<nvars; v++) {
177 
178  /* calculate the characteristic flux components along this characteristic */
179  double fm3, fm2, fm1, fp1, fp2;
180  fm3 = fm2 = fm1 = fp1 = fp2 = 0;
181  for (k = 0; k < nvars; k++) {
182  fm3 += L[v*nvars+k] * fC[qm3*nvars+k];
183  fm2 += L[v*nvars+k] * fC[qm2*nvars+k];
184  fm1 += L[v*nvars+k] * fC[qm1*nvars+k];
185  fp1 += L[v*nvars+k] * fC[qp1*nvars+k];
186  fp2 += L[v*nvars+k] * fC[qp2*nvars+k];
187  }
188 
189  /* Candidate stencils and their optimal weights*/
190  double f1, f2, f3;
191  if ( ((mpi->ip[dir] == 0 ) && (indexI[dir] == 0 ))
192  || ((mpi->ip[dir] == mpi->iproc[dir]-1) && (indexI[dir] == dim[dir])) ) {
193  /* Use WENO5 at the physical boundaries */
194  f1 = (2*one_sixth)*fm3 - (7.0*one_sixth)*fm2 + (11.0*one_sixth)*fm1;
195  f2 = (-one_sixth)*fm2 + (5.0*one_sixth)*fm1 + (2*one_sixth)*fp1;
196  f3 = (2*one_sixth)*fm1 + (5*one_sixth)*fp1 - (one_sixth)*fp2;
197  } else {
198  /* CRWENO5 at the interior points */
199  f1 = (one_sixth) * (fm2 + 5*fm1);
200  f2 = (one_sixth) * (5*fm1 + fp1);
201  f3 = (one_sixth) * (fm1 + 5*fp1);
202  }
203 
204  /* calculate WENO weights */
205  double w1,w2,w3;
206  w1 = *(ww1+p*nvars+v);
207  w2 = *(ww2+p*nvars+v);
208  w3 = *(ww3+p*nvars+v);
209 
210  if ( ((mpi->ip[dir] == 0 ) && (indexI[dir] == 0 ))
211  || ((mpi->ip[dir] == mpi->iproc[dir]-1) && (indexI[dir] == dim[dir])) ) {
212  for (k=0; k<nvars; k++) {
213  A[(Nsys*indexI[dir]+sys)*nvars*nvars+v*nvars+k] = 0.0;
214  C[(Nsys*indexI[dir]+sys)*nvars*nvars+v*nvars+k] = 0.0;
215  B[(Nsys*indexI[dir]+sys)*nvars*nvars+v*nvars+k] = L[v*nvars+k];
216  }
217  } else {
218  if (upw > 0) {
219  for (k=0; k<nvars; k++) {
220  A[(Nsys*indexI[dir]+sys)*nvars*nvars+v*nvars+k] = ((2*one_third)*w1 + (one_third)*w2) * L[v*nvars+k];
221  B[(Nsys*indexI[dir]+sys)*nvars*nvars+v*nvars+k] = ((one_third)*w1 + (2*one_third)*(w2+w3)) * L[v*nvars+k];
222  C[(Nsys*indexI[dir]+sys)*nvars*nvars+v*nvars+k] = ((one_third)*w3) * L[v*nvars+k];
223  }
224  } else {
225  for (k=0; k<nvars; k++) {
226  C[(Nsys*indexI[dir]+sys)*nvars*nvars+v*nvars+k] = ((2*one_third)*w1 + (one_third)*w2) * L[v*nvars+k];
227  B[(Nsys*indexI[dir]+sys)*nvars*nvars+v*nvars+k] = ((one_third)*w1 + (2*one_third)*(w2+w3)) * L[v*nvars+k];
228  A[(Nsys*indexI[dir]+sys)*nvars*nvars+v*nvars+k] = ((one_third)*w3) * L[v*nvars+k];
229  }
230  }
231  }
232  F[(Nsys*indexI[dir]+sys)*nvars+v] = w1*f1 + w2*f2 + w3*f3;
233  }
234  }
235  }
236 
237 #ifdef serial
238 
239  /* Solve the tridiagonal system */
240  IERR blocktridiagLU(A,B,C,F,dim[dir]+1,Nsys,nvars,lu,NULL); CHECKERR(ierr);
241 
242 #else
243 
244  /* Solve the tridiagonal system */
245  /* all processes except the last will solve without the last interface to avoid overlap */
246  if (mpi->ip[dir] != mpi->iproc[dir]-1) {
247  IERR blocktridiagLU(A,B,C,F,dim[dir] ,Nsys,nvars,lu,&mpi->comm[dir]); CHECKERR(ierr);
248  } else {
249  IERR blocktridiagLU(A,B,C,F,dim[dir]+1,Nsys,nvars,lu,&mpi->comm[dir]); CHECKERR(ierr);
250  }
251 
252  /* Now get the solution to the last interface from the next proc */
253  double *sendbuf = compact->sendbuf;
254  double *recvbuf = compact->recvbuf;
255  MPI_Request req[2] = {MPI_REQUEST_NULL,MPI_REQUEST_NULL};
256  if (mpi->ip[dir]) for (d=0; d<Nsys*nvars; d++) sendbuf[d] = F[d];
257  if (mpi->ip[dir] != mpi->iproc[dir]-1) MPI_Irecv(recvbuf,Nsys*nvars,MPI_DOUBLE,mpi->ip[dir]+1,214,mpi->comm[dir],&req[0]);
258  if (mpi->ip[dir]) MPI_Isend(sendbuf,Nsys*nvars,MPI_DOUBLE,mpi->ip[dir]-1,214,mpi->comm[dir],&req[1]);
259  MPI_Status status_arr[2];
260  MPI_Waitall(2,&req[0],status_arr);
261  if (mpi->ip[dir] != mpi->iproc[dir]-1) for (d=0; d<Nsys*nvars; d++) F[d+Nsys*nvars*dim[dir]] = recvbuf[d];
262 
263 #endif
264 
265  /* save the solution to fI */
266 #pragma omp parallel for schedule(auto) default(shared) private(sys,d,v,k,R,L,uavg,index_outer,indexC,indexI)
267  for (sys=0; sys<Nsys; sys++) {
268  _ArrayIndexnD_(ndims,sys,bounds_outer,index_outer,0);
269  _ArrayCopy1D_(index_outer,indexI,ndims);
270  for (indexI[dir] = 0; indexI[dir] < dim[dir]+1; indexI[dir]++) {
271  int p; _ArrayIndex1D_(ndims,bounds_inter,indexI,0,p);
272  _ArrayCopy1D_((F+sys*nvars+Nsys*nvars*indexI[dir]),(fI+nvars*p),nvars);
273  }
274  }
275 
276  return(0);
277 }
int nvars
Definition: hypar.h:29
#define IERR
Definition: basic.h:16
MPI related function definitions.
#define CHECKERR(ierr)
Definition: basic.h:18
Contains function definitions for common mathematical functions.
Header file for TridiagLU.
int(* AveragingFunction)(double *, double *, double *, void *)
Definition: hypar.h:354
int Interp1PrimFifthOrderCRWENOChar(double *fI, double *fC, double *u, double *x, int upw, int dir, void *s, void *m, int uflag)
5th order CRWENO reconstruction (characteristic-based) on a uniform grid
Some basic definitions and macros.
#define _ArrayIndexnD_(N, index, imax, i, ghost)
int ndims
Definition: hypar.h:26
int blocktridiagLU(double *, double *, double *, double *, int, int, int, void *, void *)
Structure containing all solver-specific variables and functions.
Definition: hypar.h:23
Contains structure definition for hypar.
MPI_Comm * comm
#define _ArrayIndex1D_(N, imax, i, ghost, index)
void * lusolver
Definition: hypar.h:368
double * recvbuf
Structure of variables/parameters needed by the WENO-type scheme.
Structure of variables/parameters needed by the compact schemes.
int * dim_local
Definition: hypar.h:37
void * interp
Definition: hypar.h:362
void * physics
Definition: hypar.h:266
int ghosts
Definition: hypar.h:52
Contains macros and function definitions for common matrix multiplication.
Structure of MPI-related variables.
Definitions for the functions computing the interpolated value of the primitive at the cell interface...
#define _DECLARE_IERR_
Definition: basic.h:17
#define _ArrayCopy1D_(x, y, size)
Contains macros and function definitions for common array operations.
int(* GetRightEigenvectors)(double *, double *, void *, int)
Definition: hypar.h:359
#define _ArrayProduct1D_(x, size, p)
int(* GetLeftEigenvectors)(double *, double *, void *, int)
Definition: hypar.h:357
void * compact
Definition: hypar.h:364
double * sendbuf