HyPar  1.0
Finite-Difference Hyperbolic-Parabolic PDE Solver on Cartesian Grids
Interp1PrimFifthOrderCRWENOChar.c File Reference

Characteristic-based CRWENO5 Scheme. More...

#include <stdio.h>
#include <basic.h>
#include <arrayfunctions.h>
#include <matmult_native.h>
#include <mathfunctions.h>
#include <interpolation.h>
#include <tridiagLU.h>
#include <mpivars.h>
#include <hypar.h>

Go to the source code of this file.

Macros

#define _MINIMUM_GHOSTS_   3
 

Functions

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 More...
 

Detailed Description

Characteristic-based CRWENO5 Scheme.

Author
Debojyoti Ghosh

Definition in file Interp1PrimFifthOrderCRWENOChar.c.

Macro Definition Documentation

◆ _MINIMUM_GHOSTS_

#define _MINIMUM_GHOSTS_   3

Minimum number of ghost points required for this interpolation method.

Definition at line 25 of file Interp1PrimFifthOrderCRWENOChar.c.

Function Documentation

◆ Interp1PrimFifthOrderCRWENOChar()

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

Computes the interpolated values of the first primitive of a function \({\bf f}\left({\bf u}\right)\) at the interfaces from the cell-centered values of the function using the fifth order CRWENO scheme on a uniform grid. The first primitive is defined as a function \({\bf h}\left({\bf u}\right)\) that satisfies:

\begin{equation} {\bf f}\left({\bf u}\left(x\right)\right) = \frac{1}{\Delta x} \int_{x-\Delta x/2}^{x+\Delta x/2} {\bf h}\left({\bf u}\left(\zeta\right)\right)d\zeta, \end{equation}

where \(x\) is the spatial coordinate along the dimension of the interpolation. This function computes the 5th order CRWENO numerical approximation \(\hat{\bf f}_{j+1/2} \approx {\bf h}_{j+1/2}\) as the convex combination of three 3rd order methods:

\begin{align} &\ \omega_1\ \times\ \left[ \frac{2}{3}\hat{\alpha}^k_{j-1/2} + \frac{1}{3}\hat{\alpha}^k_{j+1/2} = \frac{1}{6} \left( f_{j-1} + 5f_j \right) \right]\\ + &\ \omega_2\ \times\ \left[ \frac{1}{3}\hat{\alpha}^k_{j-1/2}+\frac{2}{3}\hat{\alpha}^k_{j+1/2} = \frac{1}{6} \left( 5f_j + f_{j+1} \right) \right] \\ + &\ \omega_3\ \times\ \left[ \frac{2}{3}\hat{\alpha}^k_{j+1/2} + \frac{1}{3}\hat{\alpha}^k_{j+3/2} = \frac{1}{6} \left( f_j + 5f_{j+1} \right) \right] \\ \Rightarrow &\ \left(\frac{2}{3}\omega_1+\frac{1}{3}\omega_2\right)\hat{\alpha}^k_{j-1/2} + \left[\frac{1}{3}\omega_1+\frac{2}{3}(\omega_2+\omega_3)\right]\hat{\alpha}^k_{j+1/2} + \frac{1}{3}\omega_3\hat{\alpha}^k_{j+3/2} = \frac{\omega_1}{6}{\alpha}^k_{j-1} + \frac{5(\omega_1+\omega_2)+\omega_3}{6}{\alpha}^k_j + \frac{\omega_2+5\omega_3}{6}{\alpha}^k_{j+1}, \end{align}

where

\begin{equation} \alpha^k = {\bf l}_k \cdot {\bf f},\ k=1,\cdots,n \end{equation}

is the \(k\)-th characteristic quantity, and \({\bf l}_k\) is the \(k\)-th left eigenvector, \({\bf r}_k\) is the \(k\)-th right eigenvector, and \(n\) is HyPar::nvars. The nonlinear weights \(\omega_k; k=1,2,3\) are the WENO weights computed in WENOFifthOrderCalculateWeightsChar(). The resulting block tridiagonal system is solved using blocktridiagLU() (see also TridiagLU, tridiagLU.h). The final interpolated function is computed from the interpolated characteristic quantities as:

\begin{equation} \hat{\bf f}_{j+1/2} = \sum_{k=1}^n \alpha^k_{j+1/2} {\bf r}_k \end{equation}

Implementation Notes:

  • This method assumes a uniform grid in the spatial dimension corresponding to the interpolation.
  • The method described above corresponds to a left-biased interpolation. The corresponding right-biased interpolation can be obtained by reflecting the equations about interface j+1/2.
  • The left and right eigenvectors are computed at an averaged quantity at j+1/2. Thus, this function requires functions to compute the average state, and the left and right eigenvectors. These are provided by the physical model through

    If these functions are not provided by the physical model, then a characteristic-based interpolation cannot be used.

  • The function computes the interpolant for the entire grid in one call. It loops over all the grid lines along the interpolation direction and carries out the 1D interpolation along these grid lines.
  • Location of cell-centers and cell interfaces along the spatial dimension of the interpolation is shown in the following figure:
    chap1_1Ddomain.png

Function arguments:

Argument Type Explanation ------—
fI double* Array to hold the computed interpolant at the grid interfaces. This array must have the same layout as the solution, but with no ghost points. Its size should be the same as u in all dimensions, except dir (the dimension along which to interpolate) along which it should be larger by 1 (number of interfaces is 1 more than the number of interior cell centers).
fC double* Array with the cell-centered values of the flux function \({\bf f}\left({\bf u}\right)\). This array must have the same layout and size as the solution, with ghost points.
u double* The solution array \({\bf u}\) (with ghost points). If the interpolation is characteristic based, this is needed to compute the eigendecomposition. For a multidimensional problem, the layout is as follows: u is a contiguous 1D array of size (nvars*dim[0]*dim[1]*...*dim[D-1]) corresponding to the multi-dimensional solution, with the following ordering - nvars, dim[0], dim[1], ..., dim[D-1], where nvars is the number of solution components (HyPar::nvars), dim is the local size (HyPar::dim_local), D is the number of spatial dimensions.
x double* The grid array (with ghost points). This is used only by non-uniform-grid interpolation methods. For multidimensional problems, the layout is as follows: x is a contiguous 1D array of size (dim[0]+dim[1]+...+dim[D-1]), with the spatial coordinates along dim[0] stored from 0,...,dim[0]-1, the spatial coordinates along dim[1] stored along dim[0],...,dim[0]+dim[1]-1, and so forth.
upw int Upwinding direction: if positive, a left-biased interpolant will be computed; if negative, a right-biased interpolant will be computed. If the interpolation method is central, then this has no effect.
dir int Spatial dimension along which to interpolate (eg: 0 for 1D; 0 or 1 for 2D; 0,1 or 2 for 3D)
s void* Solver object of type HyPar: the following variables are needed - HyPar::ghosts, HyPar::ndims, HyPar::nvars, HyPar::dim_local.
m void* MPI object of type MPIVariables: this is needed only by compact interpolation method that need to solve a global implicit system across MPI ranks.
uflag int A flag indicating if the function being interpolated \({\bf f}\) is the solution itself \({\bf u}\) (if 1, \({\bf f}\left({\bf u}\right) \equiv {\bf u}\)).

Reference:

  • Ghosh, D., Baeder, J. D., Compact Reconstruction Schemes with Weighted ENO Limiting for Hyperbolic Conservation Laws, SIAM Journal on Scientific Computing, 34 (3), 2012, A1678–A1706, http://dx.doi.org/10.1137/110857659
  • Ghosh, D., Constantinescu, E. M., Brown, J., Efficient Implementation of Nonlinear Compact Schemes on Massively Parallel Platforms, SIAM Journal on Scientific Computing, 37 (3), 2015, C354–C383, http://dx.doi.org/10.1137/140989261
Parameters
fIArray of interpolated function values at the interfaces
fCArray of cell-centered values of the function \({\bf f}\left({\bf u}\right)\)
uArray of cell-centered values of the solution \({\bf u}\)
xGrid coordinates
upwUpwind direction (left or right biased)
dirSpatial dimension along which to interpolation
sObject of type HyPar containing solver-related variables
mObject of type MPIVariables containing MPI-related variables
uflagFlag to indicate if \(f(u) \equiv u\), i.e, if the solution is being reconstructed

Definition at line 93 of file Interp1PrimFifthOrderCRWENOChar.c.

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
#define CHECKERR(ierr)
Definition: basic.h:18
int(* AveragingFunction)(double *, double *, double *, void *)
Definition: hypar.h:354
#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
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
Structure of MPI-related variables.
#define _DECLARE_IERR_
Definition: basic.h:17
#define _ArrayCopy1D_(x, y, size)
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