xref: /petsc/src/ts/tutorials/multirate/ex4.c (revision d0609ced746bc51b019815ca91d747429db24893)
184ff8c8bSHong Zhang /*
284ff8c8bSHong Zhang   Note:
384ff8c8bSHong Zhang     -hratio is the ratio between mesh size of corse grids and fine grids
484ff8c8bSHong Zhang */
584ff8c8bSHong Zhang 
684ff8c8bSHong Zhang static const char help[] = "1D periodic Finite Volume solver in slope-limiter form with semidiscrete time stepping.\n"
784ff8c8bSHong Zhang   "  advect      - Constant coefficient scalar advection\n"
884ff8c8bSHong Zhang   "                u_t       + (a*u)_x               = 0\n"
984ff8c8bSHong Zhang   "  shallow     - 1D Shallow water equations (Saint Venant System)\n"
1084ff8c8bSHong Zhang   "                h_t + (q)_x = 0 \n"
1184ff8c8bSHong Zhang   "                q_t + (\frac{q^2}{h} + g/2*h^2)_x = 0  \n"
1284ff8c8bSHong Zhang   "                where, h(x,t) denotes the height of the water and q(x,t) the momentum.\n"
1384ff8c8bSHong Zhang   "  for this toy problem, we choose different meshsizes for different sub-domains (slow-fast-slow), say\n"
1484ff8c8bSHong Zhang   "                hxs  = hratio*hxf \n"
1584ff8c8bSHong Zhang   "  where hxs and hxf are the grid spacings for coarse and fine grids respectively.\n"
1684ff8c8bSHong Zhang   "  exact       - Exact Riemann solver which usually needs to perform a Newton iteration to connect\n"
1784ff8c8bSHong Zhang   "                the states across shocks and rarefactions\n"
1884ff8c8bSHong Zhang   "  simulation  - use reference solution which is generated by smaller time step size to be true solution,\n"
1984ff8c8bSHong Zhang   "                also the reference solution should be generated by user and stored in a binary file.\n"
2084ff8c8bSHong Zhang   "  characteristic - Limit the characteristic variables, this is usually preferred (default)\n"
2184ff8c8bSHong Zhang   "  bc_type     - Boundary condition for the problem, options are: periodic, outflow, inflow "
2284ff8c8bSHong Zhang   "Several problem descriptions (initial data, physics specific features, boundary data) can be chosen with -initial N\n\n"
2384ff8c8bSHong Zhang   "The problem size should be set with -da_grid_x M\n\n";
2484ff8c8bSHong Zhang 
2584ff8c8bSHong Zhang /*
2684ff8c8bSHong Zhang   Example:
2784ff8c8bSHong Zhang      ./ex4 -da_grid_x 40 -initial 1 -hratio 1 -limit mc -ts_dt 0.01 -ts_max_time 7.0 -ts_type mprk -ts_mprk_type 2a22 -ts_monitor_draw_solution -physics shallow -bc_type outflow -xmin 0 -xmax 50 -ts_use_splitrhsfunction 0
2884ff8c8bSHong Zhang      ./ex4 -da_grid_x 40 -initial 2 -hratio 1 -limit mc -ts_dt 0.01 -ts_max_time 2.5 -ts_type mprk -ts_mprk_type 2a22 -ts_monitor_draw_solution -physics shallow -bc_type outflow -xmin 0 -xmax 50 -ts_use_splitrhsfunction 0
2984ff8c8bSHong Zhang      ./ex4 -da_grid_x 40 -initial 3 -hratio 1 -limit mc -ts_dt 0.01 -ts_max_time 4.0 -ts_type mprk -ts_mprk_type 2a22 -ts_monitor_draw_solution -physics shallow -bc_type outflow -xmin 0 -xmax 50 -ts_use_splitrhsfunction 0
3084ff8c8bSHong Zhang      ./ex4 -da_grid_x 40 -initial 4 -hratio 1 -limit koren3 -ts_dt 0.01 -ts_max_time 4.0 -ts_type mprk -ts_mprk_type 2a22 -ts_monitor_draw_solution -physics shallow -bc_type outflow -xmin 0 -xmax 50 -ts_use_splitrhsfunction 0
3184ff8c8bSHong Zhang      ./ex4 -da_grid_x 40 -initial 5 -hratio 1 -limit mc -ts_dt 0.01 -ts_max_time 5.0 -ts_type mprk -ts_mprk_type 2a22 -ts_monitor_draw_solution -physics shallow -bc_type outflow -xmin 0 -xmax 50 -ts_use_splitrhsfunction 0
3284ff8c8bSHong Zhang 
3384ff8c8bSHong Zhang   Contributed by: Aidan Hamilton <aidan@udel.edu>
3484ff8c8bSHong Zhang */
3584ff8c8bSHong Zhang 
3684ff8c8bSHong Zhang #include <petscts.h>
3784ff8c8bSHong Zhang #include <petscdm.h>
3884ff8c8bSHong Zhang #include <petscdmda.h>
3984ff8c8bSHong Zhang #include <petscdraw.h>
4084ff8c8bSHong Zhang #include "finitevolume1d.h"
4184ff8c8bSHong Zhang #include <petsc/private/kernels/blockinvert.h>
4284ff8c8bSHong Zhang 
439fbee547SJacob Faibussowitsch static inline PetscReal RangeMod(PetscReal a,PetscReal xmin,PetscReal xmax) { PetscReal range = xmax-xmin; return xmin +PetscFmodReal(range+PetscFmodReal(a,range),range); }
449fbee547SJacob Faibussowitsch static inline PetscReal MaxAbs(PetscReal a,PetscReal b) { return (PetscAbs(a) > PetscAbs(b)) ? a : b; }
4584ff8c8bSHong Zhang /* --------------------------------- Advection ----------------------------------- */
4684ff8c8bSHong Zhang typedef struct {
4784ff8c8bSHong Zhang   PetscReal a;                  /* advective velocity */
4884ff8c8bSHong Zhang } AdvectCtx;
4984ff8c8bSHong Zhang 
5084ff8c8bSHong Zhang static PetscErrorCode PhysicsRiemann_Advect(void *vctx,PetscInt m,const PetscScalar *uL,const PetscScalar *uR,PetscScalar *flux,PetscReal *maxspeed)
5184ff8c8bSHong Zhang {
5284ff8c8bSHong Zhang   AdvectCtx *ctx = (AdvectCtx*)vctx;
5384ff8c8bSHong Zhang   PetscReal speed;
5484ff8c8bSHong Zhang 
5584ff8c8bSHong Zhang   PetscFunctionBeginUser;
5684ff8c8bSHong Zhang   speed     = ctx->a;
5784ff8c8bSHong Zhang   flux[0]   = PetscMax(0,speed)*uL[0] + PetscMin(0,speed)*uR[0];
5884ff8c8bSHong Zhang   *maxspeed = speed;
5984ff8c8bSHong Zhang   PetscFunctionReturn(0);
6084ff8c8bSHong Zhang }
6184ff8c8bSHong Zhang 
6284ff8c8bSHong Zhang static PetscErrorCode PhysicsCharacteristic_Advect(void *vctx,PetscInt m,const PetscScalar *u,PetscScalar *X,PetscScalar *Xi,PetscReal *speeds)
6384ff8c8bSHong Zhang {
6484ff8c8bSHong Zhang   AdvectCtx *ctx = (AdvectCtx*)vctx;
6584ff8c8bSHong Zhang 
6684ff8c8bSHong Zhang   PetscFunctionBeginUser;
6784ff8c8bSHong Zhang   X[0]      = 1.;
6884ff8c8bSHong Zhang   Xi[0]     = 1.;
6984ff8c8bSHong Zhang   speeds[0] = ctx->a;
7084ff8c8bSHong Zhang   PetscFunctionReturn(0);
7184ff8c8bSHong Zhang }
7284ff8c8bSHong Zhang 
7384ff8c8bSHong Zhang static PetscErrorCode PhysicsSample_Advect(void *vctx,PetscInt initial,FVBCType bctype,PetscReal xmin,PetscReal xmax,PetscReal t,PetscReal x,PetscReal *u)
7484ff8c8bSHong Zhang {
7584ff8c8bSHong Zhang   AdvectCtx *ctx = (AdvectCtx*)vctx;
7684ff8c8bSHong Zhang   PetscReal a    = ctx->a,x0;
7784ff8c8bSHong Zhang 
7884ff8c8bSHong Zhang   PetscFunctionBeginUser;
7984ff8c8bSHong Zhang   switch (bctype) {
8084ff8c8bSHong Zhang     case FVBC_OUTFLOW:   x0 = x-a*t; break;
8184ff8c8bSHong Zhang     case FVBC_PERIODIC: x0 = RangeMod(x-a*t,xmin,xmax); break;
8284ff8c8bSHong Zhang     default: SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_UNKNOWN_TYPE,"unknown BCType");
8384ff8c8bSHong Zhang   }
8484ff8c8bSHong Zhang   switch (initial) {
8584ff8c8bSHong Zhang     case 0: u[0] = (x0 < 0) ? 1 : -1; break;
8684ff8c8bSHong Zhang     case 1: u[0] = (x0 < 0) ? -1 : 1; break;
8784ff8c8bSHong Zhang     case 2: u[0] = (0 < x0 && x0 < 1) ? 1 : 0; break;
8884ff8c8bSHong Zhang     case 3: u[0] = PetscSinReal(2*PETSC_PI*x0); break;
8984ff8c8bSHong Zhang     case 4: u[0] = PetscAbs(x0); break;
9084ff8c8bSHong Zhang     case 5: u[0] = (x0 < 0 || x0 > 0.5) ? 0 : PetscSqr(PetscSinReal(2*PETSC_PI*x0)); break;
9184ff8c8bSHong Zhang     case 6: u[0] = (x0 < 0) ? 0 : ((x0 < 1) ? x0 : ((x0 < 2) ? 2-x0 : 0)); break;
9284ff8c8bSHong Zhang     case 7: u[0] = PetscPowReal(PetscSinReal(PETSC_PI*x0),10.0);break;
9384ff8c8bSHong Zhang     default: SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_UNKNOWN_TYPE,"unknown initial condition");
9484ff8c8bSHong Zhang   }
9584ff8c8bSHong Zhang   PetscFunctionReturn(0);
9684ff8c8bSHong Zhang }
9784ff8c8bSHong Zhang 
9884ff8c8bSHong Zhang static PetscErrorCode PhysicsCreate_Advect(FVCtx *ctx)
9984ff8c8bSHong Zhang {
10084ff8c8bSHong Zhang   AdvectCtx      *user;
10184ff8c8bSHong Zhang 
10284ff8c8bSHong Zhang   PetscFunctionBeginUser;
1039566063dSJacob Faibussowitsch   PetscCall(PetscNew(&user));
10484ff8c8bSHong Zhang   ctx->physics2.sample2         = PhysicsSample_Advect;
10584ff8c8bSHong Zhang   ctx->physics2.riemann2        = PhysicsRiemann_Advect;
10684ff8c8bSHong Zhang   ctx->physics2.characteristic2 = PhysicsCharacteristic_Advect;
10784ff8c8bSHong Zhang   ctx->physics2.destroy         = PhysicsDestroy_SimpleFree;
10884ff8c8bSHong Zhang   ctx->physics2.user            = user;
10984ff8c8bSHong Zhang   ctx->physics2.dof             = 1;
11084ff8c8bSHong Zhang 
1119566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy("u",&ctx->physics2.fieldname[0]));
11284ff8c8bSHong Zhang   user->a = 1;
113*d0609cedSBarry Smith   PetscOptionsBegin(ctx->comm,ctx->prefix,"Options for advection","");
1149566063dSJacob Faibussowitsch     PetscCall(PetscOptionsReal("-physics_advect_a","Speed","",user->a,&user->a,NULL));
115*d0609cedSBarry Smith   PetscOptionsEnd();
11684ff8c8bSHong Zhang   PetscFunctionReturn(0);
11784ff8c8bSHong Zhang }
11884ff8c8bSHong Zhang /* --------------------------------- Shallow Water ----------------------------------- */
11984ff8c8bSHong Zhang 
12084ff8c8bSHong Zhang typedef struct {
12184ff8c8bSHong Zhang   PetscReal gravity;
12284ff8c8bSHong Zhang } ShallowCtx;
12384ff8c8bSHong Zhang 
1249fbee547SJacob Faibussowitsch static inline void ShallowFlux(ShallowCtx *phys,const PetscScalar *u,PetscScalar *f)
12584ff8c8bSHong Zhang {
12684ff8c8bSHong Zhang   f[0] = u[1];
12784ff8c8bSHong Zhang   f[1] = PetscSqr(u[1])/u[0] + 0.5*phys->gravity*PetscSqr(u[0]);
12884ff8c8bSHong Zhang }
12984ff8c8bSHong Zhang 
13084ff8c8bSHong Zhang static PetscErrorCode PhysicsRiemann_Shallow_Exact(void *vctx,PetscInt m,const PetscScalar *uL,const PetscScalar *uR,PetscScalar *flux,PetscReal *maxspeed)
13184ff8c8bSHong Zhang {
13284ff8c8bSHong Zhang   ShallowCtx                *phys = (ShallowCtx*)vctx;
13384ff8c8bSHong Zhang   PetscScalar               g    = phys->gravity,ustar[2],cL,cR,c,cstar;
13484ff8c8bSHong Zhang   struct {PetscScalar h,u;} L = {uL[0],uL[1]/uL[0]},R = {uR[0],uR[1]/uR[0]},star;
13584ff8c8bSHong Zhang   PetscInt                  i;
13684ff8c8bSHong Zhang 
13784ff8c8bSHong Zhang   PetscFunctionBeginUser;
1383c633725SBarry Smith   PetscCheck((L.h > 0 && R.h > 0),PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Reconstructed thickness is negative");
13984ff8c8bSHong Zhang   cL = PetscSqrtScalar(g*L.h);
14084ff8c8bSHong Zhang   cR = PetscSqrtScalar(g*R.h);
14184ff8c8bSHong Zhang   c  = PetscMax(cL,cR);
14284ff8c8bSHong Zhang   {
14384ff8c8bSHong Zhang     /* Solve for star state */
14484ff8c8bSHong Zhang     const PetscInt maxits = 50;
14584ff8c8bSHong Zhang     PetscScalar tmp,res,res0=0,h0,h = 0.5*(L.h + R.h); /* initial guess */
14684ff8c8bSHong Zhang     h0 = h;
14784ff8c8bSHong Zhang     for (i=0; i<maxits; i++) {
14884ff8c8bSHong Zhang       PetscScalar fr,fl,dfr,dfl;
14984ff8c8bSHong Zhang       fl = (L.h < h)
15084ff8c8bSHong Zhang         ? PetscSqrtScalar(0.5*g*(h*h - L.h*L.h)*(1/L.h - 1/h)) /* shock */
15184ff8c8bSHong Zhang         : 2*PetscSqrtScalar(g*h) - 2*PetscSqrtScalar(g*L.h);   /* rarefaction */
15284ff8c8bSHong Zhang       fr = (R.h < h)
15384ff8c8bSHong Zhang         ? PetscSqrtScalar(0.5*g*(h*h - R.h*R.h)*(1/R.h - 1/h)) /* shock */
15484ff8c8bSHong Zhang         : 2*PetscSqrtScalar(g*h) - 2*PetscSqrtScalar(g*R.h);   /* rarefaction */
15584ff8c8bSHong Zhang       res = R.u - L.u + fr + fl;
1562c71b3e2SJacob Faibussowitsch       PetscCheckFalse(PetscIsInfOrNanScalar(res),PETSC_COMM_SELF,PETSC_ERR_FP,"Infinity or Not-a-Number generated in computation");
15784ff8c8bSHong Zhang       if (PetscAbsScalar(res) < PETSC_SQRT_MACHINE_EPSILON || (i > 0 && PetscAbsScalar(h-h0) < PETSC_SQRT_MACHINE_EPSILON)) {
15884ff8c8bSHong Zhang         star.h = h;
15984ff8c8bSHong Zhang         star.u = L.u - fl;
16084ff8c8bSHong Zhang         goto converged;
16184ff8c8bSHong Zhang       } else if (i > 0 && PetscAbsScalar(res) >= PetscAbsScalar(res0)) {        /* Line search */
16284ff8c8bSHong Zhang         h = 0.8*h0 + 0.2*h;
16384ff8c8bSHong Zhang         continue;
16484ff8c8bSHong Zhang       }
16584ff8c8bSHong Zhang       /* Accept the last step and take another */
16684ff8c8bSHong Zhang       res0 = res;
16784ff8c8bSHong Zhang       h0 = h;
16884ff8c8bSHong Zhang       dfl = (L.h < h) ? 0.5/fl*0.5*g*(-L.h*L.h/(h*h) - 1 + 2*h/L.h) : PetscSqrtScalar(g/h);
16984ff8c8bSHong Zhang       dfr = (R.h < h) ? 0.5/fr*0.5*g*(-R.h*R.h/(h*h) - 1 + 2*h/R.h) : PetscSqrtScalar(g/h);
17084ff8c8bSHong Zhang       tmp = h - res/(dfr+dfl);
17184ff8c8bSHong Zhang       if (tmp <= 0) h /= 2;   /* Guard against Newton shooting off to a negative thickness */
17284ff8c8bSHong Zhang       else h = tmp;
1733c633725SBarry Smith       PetscCheck(((h > 0) && PetscIsNormalScalar(h)),PETSC_COMM_SELF,PETSC_ERR_FP,"non-normal iterate h=%g",(double)h);
17484ff8c8bSHong Zhang     }
17598921bdaSJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF,1,"Newton iteration for star.h diverged after %D iterations",i);
17684ff8c8bSHong Zhang   }
17784ff8c8bSHong Zhang converged:
17884ff8c8bSHong Zhang   cstar = PetscSqrtScalar(g*star.h);
17984ff8c8bSHong Zhang   if (L.u-cL < 0 && 0 < star.u-cstar) { /* 1-wave is sonic rarefaction */
18084ff8c8bSHong Zhang     PetscScalar ufan[2];
18184ff8c8bSHong Zhang     ufan[0] = 1/g*PetscSqr(L.u/3 + 2./3*cL);
18284ff8c8bSHong Zhang     ufan[1] = PetscSqrtScalar(g*ufan[0])*ufan[0];
18384ff8c8bSHong Zhang     ShallowFlux(phys,ufan,flux);
18484ff8c8bSHong Zhang   } else if (star.u+cstar < 0 && 0 < R.u+cR) { /* 2-wave is sonic rarefaction */
18584ff8c8bSHong Zhang     PetscScalar ufan[2];
18684ff8c8bSHong Zhang     ufan[0] = 1/g*PetscSqr(R.u/3 - 2./3*cR);
18784ff8c8bSHong Zhang     ufan[1] = -PetscSqrtScalar(g*ufan[0])*ufan[0];
18884ff8c8bSHong Zhang     ShallowFlux(phys,ufan,flux);
18984ff8c8bSHong Zhang   } else if ((L.h >= star.h && L.u-c >= 0) || (L.h<star.h && (star.h*star.u-L.h*L.u)/(star.h-L.h) > 0)) {
19084ff8c8bSHong Zhang     /* 1-wave is right-travelling shock (supersonic) */
19184ff8c8bSHong Zhang     ShallowFlux(phys,uL,flux);
19284ff8c8bSHong Zhang   } else if ((star.h <= R.h && R.u+c <= 0) || (star.h>R.h && (R.h*R.u-star.h*star.h)/(R.h-star.h) < 0)) {
19384ff8c8bSHong Zhang     /* 2-wave is left-travelling shock (supersonic) */
19484ff8c8bSHong Zhang     ShallowFlux(phys,uR,flux);
19584ff8c8bSHong Zhang   } else {
19684ff8c8bSHong Zhang     ustar[0] = star.h;
19784ff8c8bSHong Zhang     ustar[1] = star.h*star.u;
19884ff8c8bSHong Zhang     ShallowFlux(phys,ustar,flux);
19984ff8c8bSHong Zhang   }
20084ff8c8bSHong Zhang   *maxspeed = MaxAbs(MaxAbs(star.u-cstar,star.u+cstar),MaxAbs(L.u-cL,R.u+cR));
20184ff8c8bSHong Zhang   PetscFunctionReturn(0);
20284ff8c8bSHong Zhang }
20384ff8c8bSHong Zhang 
20484ff8c8bSHong Zhang static PetscErrorCode PhysicsRiemann_Shallow_Rusanov(void *vctx,PetscInt m,const PetscScalar *uL,const PetscScalar *uR,PetscScalar *flux,PetscReal *maxspeed)
20584ff8c8bSHong Zhang {
20684ff8c8bSHong Zhang   ShallowCtx                *phys = (ShallowCtx*)vctx;
20784ff8c8bSHong Zhang   PetscScalar               g = phys->gravity,fL[2],fR[2],s;
20884ff8c8bSHong Zhang   struct {PetscScalar h,u;} L = {uL[0],uL[1]/uL[0]},R = {uR[0],uR[1]/uR[0]};
20984ff8c8bSHong Zhang   PetscReal                 tol = 1e-6;
21084ff8c8bSHong Zhang 
21184ff8c8bSHong Zhang   PetscFunctionBeginUser;
21284ff8c8bSHong Zhang   /* Positivity preserving modification*/
21384ff8c8bSHong Zhang   if (L.h < tol) L.u = 0.0;
21484ff8c8bSHong Zhang   if (R.h < tol) R.u = 0.0;
21584ff8c8bSHong Zhang 
21684ff8c8bSHong Zhang   /*simple pos preserve limiter*/
21784ff8c8bSHong Zhang   if (L.h < 0) L.h = 0;
21884ff8c8bSHong Zhang   if (R.h < 0) R.h = 0;
21984ff8c8bSHong Zhang 
22084ff8c8bSHong Zhang   ShallowFlux(phys,uL,fL);
22184ff8c8bSHong Zhang   ShallowFlux(phys,uR,fR);
22284ff8c8bSHong Zhang 
22384ff8c8bSHong Zhang   s         = PetscMax(PetscAbs(L.u)+PetscSqrtScalar(g*L.h),PetscAbs(R.u)+PetscSqrtScalar(g*R.h));
22484ff8c8bSHong Zhang   flux[0]   = 0.5*(fL[0] + fR[0]) + 0.5*s*(L.h - R.h);
22584ff8c8bSHong Zhang   flux[1]   = 0.5*(fL[1] + fR[1]) + 0.5*s*(uL[1] - uR[1]);
22684ff8c8bSHong Zhang   *maxspeed = s;
22784ff8c8bSHong Zhang   PetscFunctionReturn(0);
22884ff8c8bSHong Zhang }
22984ff8c8bSHong Zhang 
23084ff8c8bSHong Zhang static PetscErrorCode PhysicsCharacteristic_Conservative(void *vctx,PetscInt m,const PetscScalar *u,PetscScalar *X,PetscScalar *Xi,PetscReal *speeds)
23184ff8c8bSHong Zhang {
23284ff8c8bSHong Zhang   PetscInt i,j;
23384ff8c8bSHong Zhang 
23484ff8c8bSHong Zhang   PetscFunctionBeginUser;
23584ff8c8bSHong Zhang   for (i=0; i<m; i++) {
23684ff8c8bSHong Zhang     for (j=0; j<m; j++) Xi[i*m+j] = X[i*m+j] = (PetscScalar)(i==j);
23784ff8c8bSHong Zhang     speeds[i] = PETSC_MAX_REAL; /* Indicates invalid */
23884ff8c8bSHong Zhang   }
23984ff8c8bSHong Zhang   PetscFunctionReturn(0);
24084ff8c8bSHong Zhang }
24184ff8c8bSHong Zhang 
24284ff8c8bSHong Zhang static PetscErrorCode PhysicsCharacteristic_Shallow(void *vctx,PetscInt m,const PetscScalar *u,PetscScalar *X,PetscScalar *Xi,PetscReal *speeds)
24384ff8c8bSHong Zhang {
24484ff8c8bSHong Zhang   ShallowCtx     *phys = (ShallowCtx*)vctx;
24584ff8c8bSHong Zhang   PetscReal      c;
24684ff8c8bSHong Zhang   PetscReal      tol = 1e-6;
24784ff8c8bSHong Zhang 
24884ff8c8bSHong Zhang   PetscFunctionBeginUser;
24984ff8c8bSHong Zhang   c           = PetscSqrtScalar(u[0]*phys->gravity);
25084ff8c8bSHong Zhang 
25184ff8c8bSHong Zhang   if (u[0] < tol) { /*Use conservative variables*/
25284ff8c8bSHong Zhang     X[0*2+0]  = 1;
25384ff8c8bSHong Zhang     X[0*2+1]  = 0;
25484ff8c8bSHong Zhang     X[1*2+0]  = 0;
25584ff8c8bSHong Zhang     X[1*2+1]  = 1;
25684ff8c8bSHong Zhang   } else {
25784ff8c8bSHong Zhang     speeds[0] = u[1]/u[0] - c;
25884ff8c8bSHong Zhang     speeds[1] = u[1]/u[0] + c;
25984ff8c8bSHong Zhang     X[0*2+0]  = 1;
26084ff8c8bSHong Zhang     X[0*2+1]  = speeds[0];
26184ff8c8bSHong Zhang     X[1*2+0]  = 1;
26284ff8c8bSHong Zhang     X[1*2+1]  = speeds[1];
26384ff8c8bSHong Zhang   }
26484ff8c8bSHong Zhang 
2659566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(Xi,X,4));
2669566063dSJacob Faibussowitsch   PetscCall(PetscKernel_A_gets_inverse_A_2(Xi,0,PETSC_FALSE,NULL));
26784ff8c8bSHong Zhang   PetscFunctionReturn(0);
26884ff8c8bSHong Zhang }
26984ff8c8bSHong Zhang 
27084ff8c8bSHong Zhang static PetscErrorCode PhysicsSample_Shallow(void *vctx,PetscInt initial,FVBCType bctype,PetscReal xmin,PetscReal xmax,PetscReal t,PetscReal x,PetscReal *u)
27184ff8c8bSHong Zhang {
27284ff8c8bSHong Zhang   PetscFunctionBeginUser;
27308401ef6SPierre Jolivet   PetscCheck(t <= 0,PETSC_COMM_SELF,PETSC_ERR_SUP,"Exact solutions not implemented for t > 0");
27484ff8c8bSHong Zhang   switch (initial) {
27584ff8c8bSHong Zhang     case 0:
27684ff8c8bSHong Zhang       u[0] = (x < 0) ? 2 : 1; /* Standard Dam Break Problem */
27784ff8c8bSHong Zhang       u[1] = (x < 0) ? 0 : 0;
27884ff8c8bSHong Zhang       break;
27984ff8c8bSHong Zhang     case 1:
28084ff8c8bSHong Zhang       u[0] = (x < 10) ?   1 : 0.1; /*The Next 5 problems are standard Riemann problem tests */
28184ff8c8bSHong Zhang       u[1] = (x < 10) ? 2.5 : 0;
28284ff8c8bSHong Zhang       break;
28384ff8c8bSHong Zhang     case 2:
28484ff8c8bSHong Zhang       u[0] = (x < 25) ?  1 : 1;
28584ff8c8bSHong Zhang       u[1] = (x < 25) ? -5 : 5;
28684ff8c8bSHong Zhang       break;
28784ff8c8bSHong Zhang     case 3:
28884ff8c8bSHong Zhang       u[0] = (x < 20) ?  1 : 1e-12;
28984ff8c8bSHong Zhang       u[1] = (x < 20) ?  0 : 0;
29084ff8c8bSHong Zhang       break;
29184ff8c8bSHong Zhang     case 4:
29284ff8c8bSHong Zhang       u[0] = (x < 30) ? 1e-12 : 1;
29384ff8c8bSHong Zhang       u[1] = (x < 30) ? 0 : 0;
29484ff8c8bSHong Zhang       break;
29584ff8c8bSHong Zhang     case 5:
29684ff8c8bSHong Zhang       u[0] = (x < 25) ?  0.1 : 0.1;
29784ff8c8bSHong Zhang       u[1] = (x < 25) ? -0.3 : 0.3;
29884ff8c8bSHong Zhang       break;
29984ff8c8bSHong Zhang     case 6:
30084ff8c8bSHong Zhang       u[0] = 1+0.5*PetscSinReal(2*PETSC_PI*x);
30184ff8c8bSHong Zhang       u[1] = 1*u[0];
30284ff8c8bSHong Zhang       break;
30384ff8c8bSHong Zhang     case 7:
30484ff8c8bSHong Zhang       if (x < -0.1) {
30584ff8c8bSHong Zhang        u[0] = 1e-9;
30684ff8c8bSHong Zhang        u[1] = 0.0;
30784ff8c8bSHong Zhang       } else if (x < 0.1) {
30884ff8c8bSHong Zhang        u[0] = 1.0;
30984ff8c8bSHong Zhang        u[1] = 0.0;
31084ff8c8bSHong Zhang       } else {
31184ff8c8bSHong Zhang        u[0] = 1e-9;
31284ff8c8bSHong Zhang        u[1] = 0.0;
31384ff8c8bSHong Zhang       }
31484ff8c8bSHong Zhang       break;
31584ff8c8bSHong Zhang     case 8:
31684ff8c8bSHong Zhang      if (x < -0.1) {
31784ff8c8bSHong Zhang        u[0] = 2;
31884ff8c8bSHong Zhang        u[1] = 0.0;
31984ff8c8bSHong Zhang       } else if (x < 0.1) {
32084ff8c8bSHong Zhang        u[0] = 3.0;
32184ff8c8bSHong Zhang        u[1] = 0.0;
32284ff8c8bSHong Zhang       } else {
32384ff8c8bSHong Zhang        u[0] = 2;
32484ff8c8bSHong Zhang        u[1] = 0.0;
32584ff8c8bSHong Zhang       }
32684ff8c8bSHong Zhang       break;
32784ff8c8bSHong Zhang     default: SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_UNKNOWN_TYPE,"unknown initial condition");
32884ff8c8bSHong Zhang   }
32984ff8c8bSHong Zhang   PetscFunctionReturn(0);
33084ff8c8bSHong Zhang }
33184ff8c8bSHong Zhang 
33284ff8c8bSHong Zhang /* Implements inflow conditions for the given initial conditions. Which conditions are actually enforced depends on
33384ff8c8bSHong Zhang    on the results of PhysicsSetInflowType_Shallow. */
33484ff8c8bSHong Zhang static PetscErrorCode PhysicsInflow_Shallow(void *vctx,PetscReal t,PetscReal x,PetscReal *u)
33584ff8c8bSHong Zhang {
33684ff8c8bSHong Zhang   FVCtx          *ctx = (FVCtx*)vctx;
33784ff8c8bSHong Zhang 
33884ff8c8bSHong Zhang   PetscFunctionBeginUser;
33984ff8c8bSHong Zhang   if (ctx->bctype == FVBC_INFLOW) {
34084ff8c8bSHong Zhang     switch (ctx->initial) {
34184ff8c8bSHong Zhang       case 0:
34284ff8c8bSHong Zhang       case 1:
34384ff8c8bSHong Zhang       case 2:
34484ff8c8bSHong Zhang       case 3:
34584ff8c8bSHong Zhang       case 4:
34684ff8c8bSHong Zhang       case 5:
34784ff8c8bSHong Zhang         u[0] = 0; u[1] = 0.0; /* Left boundary conditions */
34884ff8c8bSHong Zhang         u[2] = 0; u[3] = 0.0; /* Right boundary conditions */
34984ff8c8bSHong Zhang         break;
35084ff8c8bSHong Zhang       case 6:
35184ff8c8bSHong Zhang         u[0] = 0; u[1] = 0.0; /* Left boundary conditions */
35284ff8c8bSHong Zhang         u[2] = 0; u[3] = 0.0; /* Right boundary conditions */
35384ff8c8bSHong Zhang         break;
35484ff8c8bSHong Zhang       case 7:
35584ff8c8bSHong Zhang         u[0] = 0; u[1] = 0.0; /* Left boundary conditions */
35684ff8c8bSHong Zhang         u[2] = 0; u[3] = 0.0; /* Right boundary conditions */
35784ff8c8bSHong Zhang         break;
35884ff8c8bSHong Zhang       case 8:
35984ff8c8bSHong Zhang         u[0] = 0; u[1] = 1.0; /* Left boundary conditions */
36084ff8c8bSHong Zhang         u[2] = 0; u[3] = -1.0;/* Right boundary conditions */
36184ff8c8bSHong Zhang         break;
36284ff8c8bSHong Zhang       default: SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_UNKNOWN_TYPE,"unknown initial condition");
36384ff8c8bSHong Zhang     }
36484ff8c8bSHong Zhang   }
36584ff8c8bSHong Zhang   PetscFunctionReturn(0);
36684ff8c8bSHong Zhang }
36784ff8c8bSHong Zhang 
36884ff8c8bSHong Zhang /* Selects which boundary conditions are marked as inflow and which as outflow when FVBC_INFLOW is selected. */
36984ff8c8bSHong Zhang static PetscErrorCode PhysicsSetInflowType_Shallow(FVCtx *ctx)
37084ff8c8bSHong Zhang {
37184ff8c8bSHong Zhang   PetscFunctionBeginUser;
37284ff8c8bSHong Zhang   switch (ctx->initial) {
37384ff8c8bSHong Zhang     case 0:
37484ff8c8bSHong Zhang     case 1:
37584ff8c8bSHong Zhang     case 2:
37684ff8c8bSHong Zhang     case 3:
37784ff8c8bSHong Zhang     case 4:
37884ff8c8bSHong Zhang     case 5:
37984ff8c8bSHong Zhang     case 6:
38084ff8c8bSHong Zhang     case 7:
38184ff8c8bSHong Zhang     case 8: /* Fix left and right momentum, height is outflow */
38284ff8c8bSHong Zhang       ctx->physics2.bcinflowindex[0] = PETSC_FALSE;
38384ff8c8bSHong Zhang       ctx->physics2.bcinflowindex[1] = PETSC_TRUE;
38484ff8c8bSHong Zhang       ctx->physics2.bcinflowindex[2] = PETSC_FALSE;
38584ff8c8bSHong Zhang       ctx->physics2.bcinflowindex[3] = PETSC_TRUE;
38684ff8c8bSHong Zhang       break;
38784ff8c8bSHong Zhang     default: SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_UNKNOWN_TYPE,"unknown initial condition");
38884ff8c8bSHong Zhang   }
38984ff8c8bSHong Zhang   PetscFunctionReturn(0);
39084ff8c8bSHong Zhang }
39184ff8c8bSHong Zhang 
39284ff8c8bSHong Zhang static PetscErrorCode PhysicsCreate_Shallow(FVCtx *ctx)
39384ff8c8bSHong Zhang {
39484ff8c8bSHong Zhang   ShallowCtx        *user;
39584ff8c8bSHong Zhang   PetscFunctionList rlist = 0,rclist = 0;
39684ff8c8bSHong Zhang   char              rname[256] = "rusanov",rcname[256] = "characteristic";
39784ff8c8bSHong Zhang 
39884ff8c8bSHong Zhang   PetscFunctionBeginUser;
3999566063dSJacob Faibussowitsch   PetscCall(PetscNew(&user));
40084ff8c8bSHong Zhang   ctx->physics2.sample2         = PhysicsSample_Shallow;
40184ff8c8bSHong Zhang   ctx->physics2.inflow          = PhysicsInflow_Shallow;
40284ff8c8bSHong Zhang   ctx->physics2.destroy         = PhysicsDestroy_SimpleFree;
40384ff8c8bSHong Zhang   ctx->physics2.riemann2        = PhysicsRiemann_Shallow_Rusanov;
40484ff8c8bSHong Zhang   ctx->physics2.characteristic2 = PhysicsCharacteristic_Shallow;
40584ff8c8bSHong Zhang   ctx->physics2.user            = user;
40684ff8c8bSHong Zhang   ctx->physics2.dof             = 2;
40784ff8c8bSHong Zhang 
40884ff8c8bSHong Zhang   PetscMalloc1(2*(ctx->physics2.dof),&ctx->physics2.bcinflowindex);
40984ff8c8bSHong Zhang   PhysicsSetInflowType_Shallow(ctx);
41084ff8c8bSHong Zhang 
4119566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy("height",&ctx->physics2.fieldname[0]));
4129566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy("momentum",&ctx->physics2.fieldname[1]));
41384ff8c8bSHong Zhang 
41484ff8c8bSHong Zhang   user->gravity = 9.81;
41584ff8c8bSHong Zhang 
4169566063dSJacob Faibussowitsch   PetscCall(RiemannListAdd_2WaySplit(&rlist,"exact",  PhysicsRiemann_Shallow_Exact));
4179566063dSJacob Faibussowitsch   PetscCall(RiemannListAdd_2WaySplit(&rlist,"rusanov",PhysicsRiemann_Shallow_Rusanov));
4189566063dSJacob Faibussowitsch   PetscCall(ReconstructListAdd_2WaySplit(&rclist,"characteristic",PhysicsCharacteristic_Shallow));
4199566063dSJacob Faibussowitsch   PetscCall(ReconstructListAdd_2WaySplit(&rclist,"conservative",PhysicsCharacteristic_Conservative));
420*d0609cedSBarry Smith   PetscOptionsBegin(ctx->comm,ctx->prefix,"Options for Shallow","");
4219566063dSJacob Faibussowitsch     PetscCall(PetscOptionsReal("-physics_shallow_gravity","Gravity","",user->gravity,&user->gravity,NULL));
4229566063dSJacob Faibussowitsch     PetscCall(PetscOptionsFList("-physics_shallow_riemann","Riemann solver","",rlist,rname,rname,sizeof(rname),NULL));
4239566063dSJacob Faibussowitsch     PetscCall(PetscOptionsFList("-physics_shallow_reconstruct","Reconstruction","",rclist,rcname,rcname,sizeof(rcname),NULL));
424*d0609cedSBarry Smith   PetscOptionsEnd();
4259566063dSJacob Faibussowitsch   PetscCall(RiemannListFind_2WaySplit(rlist,rname,&ctx->physics2.riemann2));
4269566063dSJacob Faibussowitsch   PetscCall(ReconstructListFind_2WaySplit(rclist,rcname,&ctx->physics2.characteristic2));
4279566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListDestroy(&rlist));
4289566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListDestroy(&rclist));
42984ff8c8bSHong Zhang   PetscFunctionReturn(0);
43084ff8c8bSHong Zhang }
43184ff8c8bSHong Zhang 
43284ff8c8bSHong Zhang PetscErrorCode FVSample_2WaySplit(FVCtx *ctx,DM da,PetscReal time,Vec U)
43384ff8c8bSHong Zhang {
43484ff8c8bSHong Zhang   PetscScalar     *u,*uj,xj,xi;
43584ff8c8bSHong Zhang   PetscInt        i,j,k,dof,xs,xm,Mx;
43684ff8c8bSHong Zhang   const PetscInt  N = 200;
43784ff8c8bSHong Zhang   PetscReal       hs,hf;
43884ff8c8bSHong Zhang 
43984ff8c8bSHong Zhang   PetscFunctionBeginUser;
4403c633725SBarry Smith   PetscCheck(ctx->physics2.sample2,PETSC_COMM_SELF,PETSC_ERR_SUP,"Physics has not provided a sampling function");
4419566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(da,0, &Mx,0,0, 0,0,0, &dof,0,0,0,0,0));
4429566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(da,&xs,0,0,&xm,0,0));
4439566063dSJacob Faibussowitsch   PetscCall(DMDAVecGetArray(da,U,&u));
4449566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(dof,&uj));
44584ff8c8bSHong Zhang   hs   = (ctx->xmax-ctx->xmin)*3.0/8.0/ctx->sf;
44684ff8c8bSHong Zhang   hf   = (ctx->xmax-ctx->xmin)/4.0/(ctx->fs-ctx->sf);
44784ff8c8bSHong Zhang   for (i=xs; i<xs+xm; i++) {
44884ff8c8bSHong Zhang     if (i < ctx->sf) {
44984ff8c8bSHong Zhang       xi = ctx->xmin+0.5*hs+i*hs;
45084ff8c8bSHong Zhang       /* Integrate over cell i using trapezoid rule with N points. */
45184ff8c8bSHong Zhang       for (k=0; k<dof; k++) u[i*dof+k] = 0;
45284ff8c8bSHong Zhang       for (j=0; j<N+1; j++) {
45384ff8c8bSHong Zhang         xj = xi+hs*(j-N/2)/(PetscReal)N;
4549566063dSJacob Faibussowitsch         PetscCall((*ctx->physics2.sample2)(ctx->physics2.user,ctx->initial,ctx->bctype,ctx->xmin,ctx->xmax,time,xj,uj));
45584ff8c8bSHong Zhang         for (k=0; k<dof; k++) u[i*dof+k] += ((j==0 || j==N) ? 0.5 : 1.0)*uj[k]/N;
45684ff8c8bSHong Zhang       }
45784ff8c8bSHong Zhang     } else if (i < ctx->fs) {
45884ff8c8bSHong Zhang       xi = ctx->xmin+ctx->sf*hs+0.5*hf+(i-ctx->sf)*hf;
45984ff8c8bSHong Zhang       /* Integrate over cell i using trapezoid rule with N points. */
46084ff8c8bSHong Zhang       for (k=0; k<dof; k++) u[i*dof+k] = 0;
46184ff8c8bSHong Zhang       for (j=0; j<N+1; j++) {
46284ff8c8bSHong Zhang         xj = xi+hf*(j-N/2)/(PetscReal)N;
4639566063dSJacob Faibussowitsch         PetscCall((*ctx->physics2.sample2)(ctx->physics2.user,ctx->initial,ctx->bctype,ctx->xmin,ctx->xmax,time,xj,uj));
46484ff8c8bSHong Zhang         for (k=0; k<dof; k++) u[i*dof+k] += ((j==0 || j==N) ? 0.5 : 1.0)*uj[k]/N;
46584ff8c8bSHong Zhang       }
46684ff8c8bSHong Zhang     } else {
46784ff8c8bSHong Zhang       xi = ctx->xmin+ctx->sf*hs+(ctx->fs-ctx->sf)*hf+0.5*hs+(i-ctx->fs)*hs;
46884ff8c8bSHong Zhang       /* Integrate over cell i using trapezoid rule with N points. */
46984ff8c8bSHong Zhang       for (k=0; k<dof; k++) u[i*dof+k] = 0;
47084ff8c8bSHong Zhang       for (j=0; j<N+1; j++) {
47184ff8c8bSHong Zhang         xj = xi+hs*(j-N/2)/(PetscReal)N;
4729566063dSJacob Faibussowitsch         PetscCall((*ctx->physics2.sample2)(ctx->physics2.user,ctx->initial,ctx->bctype,ctx->xmin,ctx->xmax,time,xj,uj));
47384ff8c8bSHong Zhang         for (k=0; k<dof; k++) u[i*dof+k] += ((j==0 || j==N) ? 0.5 : 1.0)*uj[k]/N;
47484ff8c8bSHong Zhang       }
47584ff8c8bSHong Zhang     }
47684ff8c8bSHong Zhang   }
4779566063dSJacob Faibussowitsch   PetscCall(DMDAVecRestoreArray(da,U,&u));
4789566063dSJacob Faibussowitsch   PetscCall(PetscFree(uj));
47984ff8c8bSHong Zhang   PetscFunctionReturn(0);
48084ff8c8bSHong Zhang }
48184ff8c8bSHong Zhang 
48284ff8c8bSHong Zhang static PetscErrorCode SolutionErrorNorms_2WaySplit(FVCtx *ctx,DM da,PetscReal t,Vec X,PetscReal *nrm1)
48384ff8c8bSHong Zhang {
48484ff8c8bSHong Zhang   Vec               Y;
48584ff8c8bSHong Zhang   PetscInt          i,Mx;
48684ff8c8bSHong Zhang   const PetscScalar *ptr_X,*ptr_Y;
48784ff8c8bSHong Zhang   PetscReal         hs,hf;
48884ff8c8bSHong Zhang 
48984ff8c8bSHong Zhang   PetscFunctionBeginUser;
4909566063dSJacob Faibussowitsch   PetscCall(VecGetSize(X,&Mx));
4919566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(X,&Y));
4929566063dSJacob Faibussowitsch   PetscCall(FVSample_2WaySplit(ctx,da,t,Y));
49384ff8c8bSHong Zhang   hs   = (ctx->xmax-ctx->xmin)*3.0/8.0/ctx->sf;
49484ff8c8bSHong Zhang   hf   = (ctx->xmax-ctx->xmin)/4.0/(ctx->fs-ctx->sf);
4959566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(X,&ptr_X));
4969566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(Y,&ptr_Y));
49784ff8c8bSHong Zhang   for (i=0; i<Mx; i++) {
49884ff8c8bSHong Zhang     if (i < ctx->sf || i > ctx->fs -1) *nrm1 +=  hs*PetscAbs(ptr_X[i]-ptr_Y[i]);
49984ff8c8bSHong Zhang     else *nrm1 += hf*PetscAbs(ptr_X[i]-ptr_Y[i]);
50084ff8c8bSHong Zhang   }
5019566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(X,&ptr_X));
5029566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(Y,&ptr_Y));
5039566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&Y));
50484ff8c8bSHong Zhang   PetscFunctionReturn(0);
50584ff8c8bSHong Zhang }
50684ff8c8bSHong Zhang 
50784ff8c8bSHong Zhang PetscErrorCode FVRHSFunction_2WaySplit(TS ts,PetscReal time,Vec X,Vec F,void *vctx)
50884ff8c8bSHong Zhang {
50984ff8c8bSHong Zhang   FVCtx          *ctx = (FVCtx*)vctx;
51084ff8c8bSHong Zhang   PetscInt       i,j,k,Mx,dof,xs,xm,sf = ctx->sf,fs = ctx->fs;
51184ff8c8bSHong Zhang   PetscReal      hxf,hxs,cfl_idt = 0;
51284ff8c8bSHong Zhang   PetscScalar    *x,*f,*slope;
51384ff8c8bSHong Zhang   Vec            Xloc;
51484ff8c8bSHong Zhang   DM             da;
51584ff8c8bSHong Zhang 
51684ff8c8bSHong Zhang   PetscFunctionBeginUser;
5179566063dSJacob Faibussowitsch   PetscCall(TSGetDM(ts,&da));
5189566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(da,&Xloc));                          /* Xloc contains ghost points                                     */
5199566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(da,0, &Mx,0,0, 0,0,0, &dof,0,0,0,0,0));   /* Mx is the number of center points                              */
52084ff8c8bSHong Zhang   hxs  = (ctx->xmax-ctx->xmin)*3.0/8.0/ctx->sf;
52184ff8c8bSHong Zhang   hxf  = (ctx->xmax-ctx->xmin)/4.0/(ctx->fs-ctx->sf);
5229566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalBegin(da,X,INSERT_VALUES,Xloc));       /* X is solution vector which does not contain ghost points       */
5239566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalEnd(da,X,INSERT_VALUES,Xloc));
52484ff8c8bSHong Zhang 
5259566063dSJacob Faibussowitsch   PetscCall(VecZeroEntries(F));                                   /* F is the right hand side function corresponds to center points */
52684ff8c8bSHong Zhang 
5279566063dSJacob Faibussowitsch   PetscCall(DMDAVecGetArray(da,Xloc,&x));
5289566063dSJacob Faibussowitsch   PetscCall(DMDAVecGetArray(da,F,&f));
5299566063dSJacob Faibussowitsch   PetscCall(DMDAGetArray(da,PETSC_TRUE,&slope));                  /* contains ghost points                                           */
5309566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(da,&xs,0,0,&xm,0,0));
53184ff8c8bSHong Zhang 
53284ff8c8bSHong Zhang   if (ctx->bctype == FVBC_OUTFLOW) {
53384ff8c8bSHong Zhang     for (i=xs-2; i<0; i++) {
53484ff8c8bSHong Zhang       for (j=0; j<dof; j++) x[i*dof+j] = x[j];
53584ff8c8bSHong Zhang     }
53684ff8c8bSHong Zhang     for (i=Mx; i<xs+xm+2; i++) {
53784ff8c8bSHong Zhang       for (j=0; j<dof; j++) x[i*dof+j] = x[(xs+xm-1)*dof+j];
53884ff8c8bSHong Zhang     }
53984ff8c8bSHong Zhang   }
54084ff8c8bSHong Zhang 
54184ff8c8bSHong Zhang   if (ctx->bctype == FVBC_INFLOW) {
54284ff8c8bSHong Zhang     /* See LeVeque, R. (2002). Finite Volume Methods for Hyperbolic Problems. doi:10.1017/CBO9780511791253
54384ff8c8bSHong Zhang     pages 137-138 for the scheme. */
54484ff8c8bSHong Zhang     if (xs==0) { /* Left Boundary */
54584ff8c8bSHong Zhang       ctx->physics2.inflow(ctx,time,ctx->xmin,ctx->ub);
54684ff8c8bSHong Zhang       for (j=0; j<dof; j++) {
54784ff8c8bSHong Zhang         if (ctx->physics2.bcinflowindex[j]) {
54884ff8c8bSHong Zhang           for (i=-2; i<0; i++) x[i*dof+j] = 2.0*ctx->ub[j]-x[-(i+1)*dof+j];
54984ff8c8bSHong Zhang         } else {
55084ff8c8bSHong Zhang           for (i=-2; i<0; i++) x[i*dof+j] = x[j]; /* Outflow */
55184ff8c8bSHong Zhang         }
55284ff8c8bSHong Zhang       }
55384ff8c8bSHong Zhang     }
55484ff8c8bSHong Zhang     if (xs+xm==Mx) { /* Right Boundary */
55584ff8c8bSHong Zhang       ctx->physics2.inflow(ctx,time,ctx->xmax,ctx->ub);
55684ff8c8bSHong Zhang       for (j=0; j<dof; j++) {
55784ff8c8bSHong Zhang         if (ctx->physics2.bcinflowindex[dof+j]) {
55884ff8c8bSHong Zhang           for (i=Mx; i<Mx+2; i++) x[i*dof+j] = 2.0*ctx->ub[dof+j]-x[(2*Mx-(i+1))*dof+j];
55984ff8c8bSHong Zhang         } else {
56084ff8c8bSHong Zhang           for (i=Mx; i<Mx+2; i++) x[i*dof+j] = x[(Mx-1)*dof+j]; /* Outflow */
56184ff8c8bSHong Zhang         }
56284ff8c8bSHong Zhang       }
56384ff8c8bSHong Zhang     }
56484ff8c8bSHong Zhang   }
56584ff8c8bSHong Zhang 
56684ff8c8bSHong Zhang   for (i=xs-1; i<xs+xm+1; i++) {
56784ff8c8bSHong Zhang     struct _LimitInfo info;
56884ff8c8bSHong Zhang     PetscScalar       *cjmpL,*cjmpR;
56984ff8c8bSHong Zhang     /* Determine the right eigenvectors R, where A = R \Lambda R^{-1} */
5709566063dSJacob Faibussowitsch     PetscCall((*ctx->physics2.characteristic2)(ctx->physics2.user,dof,&x[i*dof],ctx->R,ctx->Rinv,ctx->speeds));
57184ff8c8bSHong Zhang     /* Evaluate jumps across interfaces (i-1, i) and (i, i+1), put in characteristic basis */
5729566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(ctx->cjmpLR,2*dof));
57384ff8c8bSHong Zhang     cjmpL = &ctx->cjmpLR[0];
57484ff8c8bSHong Zhang     cjmpR = &ctx->cjmpLR[dof];
57584ff8c8bSHong Zhang     for (j=0; j<dof; j++) {
57684ff8c8bSHong Zhang       PetscScalar jmpL,jmpR;
57784ff8c8bSHong Zhang       jmpL = x[(i+0)*dof+j]-x[(i-1)*dof+j];
57884ff8c8bSHong Zhang       jmpR = x[(i+1)*dof+j]-x[(i+0)*dof+j];
57984ff8c8bSHong Zhang       for (k=0; k<dof; k++) {
58084ff8c8bSHong Zhang         cjmpL[k] += ctx->Rinv[k+j*dof]*jmpL;
58184ff8c8bSHong Zhang         cjmpR[k] += ctx->Rinv[k+j*dof]*jmpR;
58284ff8c8bSHong Zhang       }
58384ff8c8bSHong Zhang     }
58484ff8c8bSHong Zhang     /* Apply limiter to the left and right characteristic jumps */
58584ff8c8bSHong Zhang     info.m  = dof;
58684ff8c8bSHong Zhang     info.hxs = hxs;
58784ff8c8bSHong Zhang     info.hxf = hxf;
58884ff8c8bSHong Zhang     (*ctx->limit2)(&info,cjmpL,cjmpR,ctx->sf,ctx->fs,i,ctx->cslope);
58984ff8c8bSHong Zhang     for (j=0; j<dof; j++) {
59084ff8c8bSHong Zhang       PetscScalar tmp = 0;
59184ff8c8bSHong Zhang       for (k=0; k<dof; k++) tmp += ctx->R[j+k*dof]*ctx->cslope[k];
59284ff8c8bSHong Zhang       slope[i*dof+j] = tmp;
59384ff8c8bSHong Zhang     }
59484ff8c8bSHong Zhang   }
59584ff8c8bSHong Zhang 
59684ff8c8bSHong Zhang   for (i=xs; i<xs+xm+1; i++) {
59784ff8c8bSHong Zhang     PetscReal   maxspeed;
59884ff8c8bSHong Zhang     PetscScalar *uL,*uR;
59984ff8c8bSHong Zhang     uL = &ctx->uLR[0];
60084ff8c8bSHong Zhang     uR = &ctx->uLR[dof];
60184ff8c8bSHong Zhang     if (i < sf) { /* slow region */
60284ff8c8bSHong Zhang       for (j=0; j<dof; j++) {
60384ff8c8bSHong Zhang         uL[j] = x[(i-1)*dof+j]+slope[(i-1)*dof+j]*hxs/2;
60484ff8c8bSHong Zhang         uR[j] = x[(i-0)*dof+j]-slope[(i-0)*dof+j]*hxs/2;
60584ff8c8bSHong Zhang       }
6069566063dSJacob Faibussowitsch       PetscCall((*ctx->physics2.riemann2)(ctx->physics2.user,dof,uL,uR,ctx->flux,&maxspeed));
60784ff8c8bSHong Zhang       if (i > xs) {
60884ff8c8bSHong Zhang         for (j=0; j<dof; j++) f[(i-1)*dof+j] -= ctx->flux[j]/hxs;
60984ff8c8bSHong Zhang       }
61084ff8c8bSHong Zhang       if (i < xs+xm) {
61184ff8c8bSHong Zhang         for (j=0; j<dof; j++) f[i*dof+j] += ctx->flux[j]/hxs;
61284ff8c8bSHong Zhang       }
61384ff8c8bSHong Zhang     } else if (i == sf) { /* interface between the slow region and the fast region */
61484ff8c8bSHong Zhang       for (j=0; j<dof; j++) {
61584ff8c8bSHong Zhang         uL[j] = x[(i-1)*dof+j]+slope[(i-1)*dof+j]*hxs/2;
61684ff8c8bSHong Zhang         uR[j] = x[(i-0)*dof+j]-slope[(i-0)*dof+j]*hxf/2;
61784ff8c8bSHong Zhang       }
6189566063dSJacob Faibussowitsch       PetscCall((*ctx->physics2.riemann2)(ctx->physics2.user,dof,uL,uR,ctx->flux,&maxspeed));
61984ff8c8bSHong Zhang       if (i > xs) {
62084ff8c8bSHong Zhang         for (j=0; j<dof; j++) f[(i-1)*dof+j] -= ctx->flux[j]/hxs;
62184ff8c8bSHong Zhang       }
62284ff8c8bSHong Zhang       if (i < xs+xm) {
62384ff8c8bSHong Zhang         for (j=0; j<dof; j++) f[i*dof+j] += ctx->flux[j]/hxf;
62484ff8c8bSHong Zhang       }
62584ff8c8bSHong Zhang     } else if (i > sf && i < fs) { /* fast region */
62684ff8c8bSHong Zhang       for (j=0; j<dof; j++) {
62784ff8c8bSHong Zhang         uL[j] = x[(i-1)*dof+j]+slope[(i-1)*dof+j]*hxf/2;
62884ff8c8bSHong Zhang         uR[j] = x[(i-0)*dof+j]-slope[(i-0)*dof+j]*hxf/2;
62984ff8c8bSHong Zhang       }
6309566063dSJacob Faibussowitsch       PetscCall((*ctx->physics2.riemann2)(ctx->physics2.user,dof,uL,uR,ctx->flux,&maxspeed));
63184ff8c8bSHong Zhang       if (i > xs) {
63284ff8c8bSHong Zhang         for (j=0; j<dof; j++) f[(i-1)*dof+j] -= ctx->flux[j]/hxf;
63384ff8c8bSHong Zhang       }
63484ff8c8bSHong Zhang       if (i < xs+xm) {
63584ff8c8bSHong Zhang         for (j=0; j<dof; j++) f[i*dof+j] += ctx->flux[j]/hxf;
63684ff8c8bSHong Zhang       }
63784ff8c8bSHong Zhang     } else if (i == fs) { /* interface between the fast region and the slow region */
63884ff8c8bSHong Zhang       for (j=0; j<dof; j++) {
63984ff8c8bSHong Zhang         uL[j] = x[(i-1)*dof+j]+slope[(i-1)*dof+j]*hxf/2;
64084ff8c8bSHong Zhang         uR[j] = x[(i-0)*dof+j]-slope[(i-0)*dof+j]*hxs/2;
64184ff8c8bSHong Zhang       }
6429566063dSJacob Faibussowitsch       PetscCall((*ctx->physics2.riemann2)(ctx->physics2.user,dof,uL,uR,ctx->flux,&maxspeed));
64384ff8c8bSHong Zhang       if (i > xs) {
64484ff8c8bSHong Zhang         for (j=0; j<dof; j++) f[(i-1)*dof+j] -= ctx->flux[j]/hxf;
64584ff8c8bSHong Zhang       }
64684ff8c8bSHong Zhang       if (i < xs+xm) {
64784ff8c8bSHong Zhang         for (j=0; j<dof; j++) f[i*dof+j] += ctx->flux[j]/hxs;
64884ff8c8bSHong Zhang       }
64984ff8c8bSHong Zhang     } else { /* slow region */
65084ff8c8bSHong Zhang       for (j=0; j<dof; j++) {
65184ff8c8bSHong Zhang         uL[j] = x[(i-1)*dof+j]+slope[(i-1)*dof+j]*hxs/2;
65284ff8c8bSHong Zhang         uR[j] = x[(i-0)*dof+j]-slope[(i-0)*dof+j]*hxs/2;
65384ff8c8bSHong Zhang       }
6549566063dSJacob Faibussowitsch       PetscCall((*ctx->physics2.riemann2)(ctx->physics2.user,dof,uL,uR,ctx->flux,&maxspeed));
65584ff8c8bSHong Zhang       cfl_idt = PetscMax(cfl_idt,PetscAbsScalar(maxspeed/hxs)); /* Max allowable value of 1/Delta t */
65684ff8c8bSHong Zhang       if (i > xs) {
65784ff8c8bSHong Zhang         for (j=0; j<dof; j++) f[(i-1)*dof+j] -= ctx->flux[j]/hxs;
65884ff8c8bSHong Zhang       }
65984ff8c8bSHong Zhang       if (i < xs+xm) {
66084ff8c8bSHong Zhang         for (j=0; j<dof; j++) f[i*dof+j] += ctx->flux[j]/hxs;
66184ff8c8bSHong Zhang       }
66284ff8c8bSHong Zhang     }
66384ff8c8bSHong Zhang   }
6649566063dSJacob Faibussowitsch   PetscCall(DMDAVecRestoreArray(da,Xloc,&x));
6659566063dSJacob Faibussowitsch   PetscCall(DMDAVecRestoreArray(da,F,&f));
6669566063dSJacob Faibussowitsch   PetscCall(DMDARestoreArray(da,PETSC_TRUE,&slope));
6679566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(da,&Xloc));
6689566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Allreduce(&cfl_idt,&ctx->cfl_idt,1,MPIU_SCALAR,MPIU_MAX,PetscObjectComm((PetscObject)da)));
66984ff8c8bSHong Zhang   if (0) {
67084ff8c8bSHong Zhang     /* We need to a way to inform the TS of a CFL constraint, this is a debugging fragment */
67184ff8c8bSHong Zhang     PetscReal dt,tnow;
6729566063dSJacob Faibussowitsch     PetscCall(TSGetTimeStep(ts,&dt));
6739566063dSJacob Faibussowitsch     PetscCall(TSGetTime(ts,&tnow));
67484ff8c8bSHong Zhang     if (dt > 0.5/ctx->cfl_idt) {
67584ff8c8bSHong Zhang       if (1) {
6769566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(ctx->comm,"Stability constraint exceeded at t=%g, dt %g > %g\n",(double)tnow,(double)dt,(double)(0.5/ctx->cfl_idt)));
67798921bdaSJacob Faibussowitsch       } else SETERRQ(PETSC_COMM_SELF,1,"Stability constraint exceeded, %g > %g",(double)dt,(double)(ctx->cfl/ctx->cfl_idt));
67884ff8c8bSHong Zhang     }
67984ff8c8bSHong Zhang   }
68084ff8c8bSHong Zhang   PetscFunctionReturn(0);
68184ff8c8bSHong Zhang }
68284ff8c8bSHong Zhang 
68384ff8c8bSHong Zhang /* --------------------------------- Finite Volume Solver for slow components ----------------------------------- */
68484ff8c8bSHong Zhang PetscErrorCode FVRHSFunctionslow_2WaySplit(TS ts,PetscReal time,Vec X,Vec F,void *vctx)
68584ff8c8bSHong Zhang {
68684ff8c8bSHong Zhang   FVCtx          *ctx = (FVCtx*)vctx;
68784ff8c8bSHong Zhang   PetscInt       i,j,k,Mx,dof,xs,xm,islow = 0,sf = ctx->sf,fs = ctx->fs,lsbwidth = ctx->lsbwidth,rsbwidth = ctx->rsbwidth;
68884ff8c8bSHong Zhang   PetscReal      hxs,hxf,cfl_idt = 0;
68984ff8c8bSHong Zhang   PetscScalar    *x,*f,*slope;
69084ff8c8bSHong Zhang   Vec            Xloc;
69184ff8c8bSHong Zhang   DM             da;
69284ff8c8bSHong Zhang 
69384ff8c8bSHong Zhang   PetscFunctionBeginUser;
6949566063dSJacob Faibussowitsch   PetscCall(TSGetDM(ts,&da));
6959566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(da,&Xloc));
6969566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(da,0, &Mx,0,0, 0,0,0, &dof,0,0,0,0,0));
69784ff8c8bSHong Zhang   hxs  = (ctx->xmax-ctx->xmin)*3.0/8.0/ctx->sf;
69884ff8c8bSHong Zhang   hxf  = (ctx->xmax-ctx->xmin)/4.0/(ctx->fs-ctx->sf);
6999566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalBegin(da,X,INSERT_VALUES,Xloc));
7009566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalEnd(da,X,INSERT_VALUES,Xloc));
7019566063dSJacob Faibussowitsch   PetscCall(VecZeroEntries(F));
7029566063dSJacob Faibussowitsch   PetscCall(DMDAVecGetArray(da,Xloc,&x));
7039566063dSJacob Faibussowitsch   PetscCall(VecGetArray(F,&f));
7049566063dSJacob Faibussowitsch   PetscCall(DMDAGetArray(da,PETSC_TRUE,&slope));
7059566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(da,&xs,0,0,&xm,0,0));
70684ff8c8bSHong Zhang 
70784ff8c8bSHong Zhang   if (ctx->bctype == FVBC_OUTFLOW) {
70884ff8c8bSHong Zhang     for (i=xs-2; i<0; i++) {
70984ff8c8bSHong Zhang       for (j=0; j<dof; j++) x[i*dof+j] = x[j];
71084ff8c8bSHong Zhang     }
71184ff8c8bSHong Zhang     for (i=Mx; i<xs+xm+2; i++) {
71284ff8c8bSHong Zhang       for (j=0; j<dof; j++) x[i*dof+j] = x[(xs+xm-1)*dof+j];
71384ff8c8bSHong Zhang     }
71484ff8c8bSHong Zhang   }
71584ff8c8bSHong Zhang   if (ctx->bctype == FVBC_INFLOW) {
71684ff8c8bSHong Zhang     /* See LeVeque, R. (2002). Finite Volume Methods for Hyperbolic Problems. doi:10.1017/CBO9780511791253
71784ff8c8bSHong Zhang     pages 137-138 for the scheme. */
71884ff8c8bSHong Zhang     if (xs==0) { /* Left Boundary */
71984ff8c8bSHong Zhang       ctx->physics2.inflow(ctx,time,ctx->xmin,ctx->ub);
72084ff8c8bSHong Zhang       for (j=0; j<dof; j++) {
72184ff8c8bSHong Zhang         if (ctx->physics2.bcinflowindex[j]==PETSC_TRUE) {
72284ff8c8bSHong Zhang           for (i=-2; i<0; i++) x[i*dof+j] = 2.0*ctx->ub[j]-x[-(i+1)*dof+j];
72384ff8c8bSHong Zhang         } else {
72484ff8c8bSHong Zhang           for (i=-2; i<0; i++) x[i*dof+j] = x[j]; /* Outflow */
72584ff8c8bSHong Zhang         }
72684ff8c8bSHong Zhang       }
72784ff8c8bSHong Zhang     }
72884ff8c8bSHong Zhang     if (xs+xm==Mx) { /* Right Boundary */
72984ff8c8bSHong Zhang       ctx->physics2.inflow(ctx,time,ctx->xmax,ctx->ub);
73084ff8c8bSHong Zhang       for (j=0; j<dof; j++) {
73184ff8c8bSHong Zhang         if (ctx->physics2.bcinflowindex[dof+j]==PETSC_TRUE) {
73284ff8c8bSHong Zhang           for (i=Mx; i<Mx+2; i++) x[i*dof+j] = 2.0*ctx->ub[dof+j]-x[(2*Mx-(i+1))*dof+j];
73384ff8c8bSHong Zhang         } else {
73484ff8c8bSHong Zhang           for (i=Mx; i<Mx+2; i++) x[i*dof+j] = x[(Mx-1)*dof+j]; /* Outflow */
73584ff8c8bSHong Zhang         }
73684ff8c8bSHong Zhang       }
73784ff8c8bSHong Zhang     }
73884ff8c8bSHong Zhang   }
73984ff8c8bSHong Zhang   for (i=xs-1; i<xs+xm+1; i++) {
74084ff8c8bSHong Zhang     struct _LimitInfo info;
74184ff8c8bSHong Zhang     PetscScalar       *cjmpL,*cjmpR;
74284ff8c8bSHong Zhang     if (i < sf-lsbwidth+1 || i > fs+rsbwidth-2) { /* slow components and the first and last fast components */
74384ff8c8bSHong Zhang       /* Determine the right eigenvectors R, where A = R \Lambda R^{-1} */
7449566063dSJacob Faibussowitsch       PetscCall((*ctx->physics2.characteristic2)(ctx->physics2.user,dof,&x[i*dof],ctx->R,ctx->Rinv,ctx->speeds));
74584ff8c8bSHong Zhang       /* Evaluate jumps across interfaces (i-1, i) and (i, i+1), put in characteristic basis */
7469566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(ctx->cjmpLR,2*dof));
74784ff8c8bSHong Zhang       cjmpL = &ctx->cjmpLR[0];
74884ff8c8bSHong Zhang       cjmpR = &ctx->cjmpLR[dof];
74984ff8c8bSHong Zhang       for (j=0; j<dof; j++) {
75084ff8c8bSHong Zhang         PetscScalar jmpL,jmpR;
75184ff8c8bSHong Zhang         jmpL = x[(i+0)*dof+j]-x[(i-1)*dof+j];
75284ff8c8bSHong Zhang         jmpR = x[(i+1)*dof+j]-x[(i+0)*dof+j];
75384ff8c8bSHong Zhang         for (k=0; k<dof; k++) {
75484ff8c8bSHong Zhang           cjmpL[k] += ctx->Rinv[k+j*dof]*jmpL;
75584ff8c8bSHong Zhang           cjmpR[k] += ctx->Rinv[k+j*dof]*jmpR;
75684ff8c8bSHong Zhang         }
75784ff8c8bSHong Zhang       }
75884ff8c8bSHong Zhang       /* Apply limiter to the left and right characteristic jumps */
75984ff8c8bSHong Zhang       info.m  = dof;
76084ff8c8bSHong Zhang       info.hxs = hxs;
76184ff8c8bSHong Zhang       info.hxf = hxf;
76284ff8c8bSHong Zhang       (*ctx->limit2)(&info,cjmpL,cjmpR,ctx->sf,ctx->fs,i,ctx->cslope);
76384ff8c8bSHong Zhang       for (j=0; j<dof; j++) {
76484ff8c8bSHong Zhang         PetscScalar tmp = 0;
76584ff8c8bSHong Zhang         for (k=0; k<dof; k++) tmp += ctx->R[j+k*dof]*ctx->cslope[k];
76684ff8c8bSHong Zhang           slope[i*dof+j] = tmp;
76784ff8c8bSHong Zhang       }
76884ff8c8bSHong Zhang     }
76984ff8c8bSHong Zhang   }
77084ff8c8bSHong Zhang 
77184ff8c8bSHong Zhang   for (i=xs; i<xs+xm+1; i++) {
77284ff8c8bSHong Zhang     PetscReal   maxspeed;
77384ff8c8bSHong Zhang     PetscScalar *uL,*uR;
77484ff8c8bSHong Zhang     uL = &ctx->uLR[0];
77584ff8c8bSHong Zhang     uR = &ctx->uLR[dof];
77684ff8c8bSHong Zhang     if (i < sf-lsbwidth) { /* slow region */
77784ff8c8bSHong Zhang       for (j=0; j<dof; j++) {
77884ff8c8bSHong Zhang         uL[j] = x[(i-1)*dof+j]+slope[(i-1)*dof+j]*hxs/2;
77984ff8c8bSHong Zhang         uR[j] = x[(i-0)*dof+j]-slope[(i-0)*dof+j]*hxs/2;
78084ff8c8bSHong Zhang       }
7819566063dSJacob Faibussowitsch       PetscCall((*ctx->physics2.riemann2)(ctx->physics2.user,dof,uL,uR,ctx->flux,&maxspeed));
78284ff8c8bSHong Zhang       cfl_idt = PetscMax(cfl_idt,PetscAbsScalar(maxspeed/hxs)); /* Max allowable value of 1/Delta t */
78384ff8c8bSHong Zhang       if (i > xs) {
78484ff8c8bSHong Zhang         for (j=0; j<dof; j++) f[(islow-1)*dof+j] -= ctx->flux[j]/hxs;
78584ff8c8bSHong Zhang       }
78684ff8c8bSHong Zhang       if (i < xs+xm) {
78784ff8c8bSHong Zhang         for (j=0; j<dof; j++) f[islow*dof+j] += ctx->flux[j]/hxs;
78884ff8c8bSHong Zhang         islow++;
78984ff8c8bSHong Zhang       }
79084ff8c8bSHong Zhang     }
79184ff8c8bSHong Zhang     if (i == sf-lsbwidth) { /* interface between the slow region and the fast region */
79284ff8c8bSHong Zhang       for (j=0; j<dof; j++) {
79384ff8c8bSHong Zhang         uL[j] = x[(i-1)*dof+j]+slope[(i-1)*dof+j]*hxs/2;
79484ff8c8bSHong Zhang         uR[j] = x[(i-0)*dof+j]-slope[(i-0)*dof+j]*hxs/2;
79584ff8c8bSHong Zhang       }
7969566063dSJacob Faibussowitsch       PetscCall((*ctx->physics2.riemann2)(ctx->physics2.user,dof,uL,uR,ctx->flux,&maxspeed));
79784ff8c8bSHong Zhang       if (i > xs) {
79884ff8c8bSHong Zhang         for (j=0; j<dof; j++) f[(islow-1)*dof+j] -= ctx->flux[j]/hxs;
79984ff8c8bSHong Zhang       }
80084ff8c8bSHong Zhang     }
80184ff8c8bSHong Zhang     if (i == fs+rsbwidth) { /* slow region */
80284ff8c8bSHong Zhang       for (j=0; j<dof; j++) {
80384ff8c8bSHong Zhang         uL[j] = x[(i-1)*dof+j]+slope[(i-1)*dof+j]*hxs/2;
80484ff8c8bSHong Zhang         uR[j] = x[(i-0)*dof+j]-slope[(i-0)*dof+j]*hxs/2;
80584ff8c8bSHong Zhang       }
8069566063dSJacob Faibussowitsch       PetscCall((*ctx->physics2.riemann2)(ctx->physics2.user,dof,uL,uR,ctx->flux,&maxspeed));
80784ff8c8bSHong Zhang       if (i < xs+xm) {
80884ff8c8bSHong Zhang         for (j=0; j<dof; j++) f[islow*dof+j] += ctx->flux[j]/hxs;
80984ff8c8bSHong Zhang         islow++;
81084ff8c8bSHong Zhang       }
81184ff8c8bSHong Zhang     }
81284ff8c8bSHong Zhang     if (i > fs+rsbwidth) { /* slow region */
81384ff8c8bSHong Zhang       for (j=0; j<dof; j++) {
81484ff8c8bSHong Zhang         uL[j] = x[(i-1)*dof+j]+slope[(i-1)*dof+j]*hxs/2;
81584ff8c8bSHong Zhang         uR[j] = x[(i-0)*dof+j]-slope[(i-0)*dof+j]*hxs/2;
81684ff8c8bSHong Zhang       }
8179566063dSJacob Faibussowitsch       PetscCall((*ctx->physics2.riemann2)(ctx->physics2.user,dof,uL,uR,ctx->flux,&maxspeed));
81884ff8c8bSHong Zhang       if (i > xs) {
81984ff8c8bSHong Zhang         for (j=0; j<dof; j++) f[(islow-1)*dof+j] -= ctx->flux[j]/hxs;
82084ff8c8bSHong Zhang       }
82184ff8c8bSHong Zhang       if (i < xs+xm) {
82284ff8c8bSHong Zhang         for (j=0; j<dof; j++) f[islow*dof+j] += ctx->flux[j]/hxs;
82384ff8c8bSHong Zhang         islow++;
82484ff8c8bSHong Zhang       }
82584ff8c8bSHong Zhang     }
82684ff8c8bSHong Zhang   }
8279566063dSJacob Faibussowitsch   PetscCall(DMDAVecRestoreArray(da,Xloc,&x));
8289566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(F,&f));
8299566063dSJacob Faibussowitsch   PetscCall(DMDARestoreArray(da,PETSC_TRUE,&slope));
8309566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(da,&Xloc));
8319566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Allreduce(&cfl_idt,&ctx->cfl_idt,1,MPIU_SCALAR,MPIU_MAX,PetscObjectComm((PetscObject)da)));
83284ff8c8bSHong Zhang   PetscFunctionReturn(0);
83384ff8c8bSHong Zhang }
83484ff8c8bSHong Zhang 
83584ff8c8bSHong Zhang PetscErrorCode FVRHSFunctionslowbuffer_2WaySplit(TS ts,PetscReal time,Vec X,Vec F,void *vctx)
83684ff8c8bSHong Zhang {
83784ff8c8bSHong Zhang   FVCtx          *ctx = (FVCtx*)vctx;
83884ff8c8bSHong Zhang   PetscInt       i,j,k,Mx,dof,xs,xm,islow = 0,sf = ctx->sf,fs = ctx->fs,lsbwidth = ctx->lsbwidth,rsbwidth = ctx->rsbwidth;
83984ff8c8bSHong Zhang   PetscReal      hxs,hxf;
84084ff8c8bSHong Zhang   PetscScalar    *x,*f,*slope;
84184ff8c8bSHong Zhang   Vec            Xloc;
84284ff8c8bSHong Zhang   DM             da;
84384ff8c8bSHong Zhang 
84484ff8c8bSHong Zhang   PetscFunctionBeginUser;
8459566063dSJacob Faibussowitsch   PetscCall(TSGetDM(ts,&da));
8469566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(da,&Xloc));
8479566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(da,0, &Mx,0,0, 0,0,0, &dof,0,0,0,0,0));
84884ff8c8bSHong Zhang   hxs  = (ctx->xmax-ctx->xmin)*3.0/8.0/ctx->sf;
84984ff8c8bSHong Zhang   hxf  = (ctx->xmax-ctx->xmin)/4.0/(ctx->fs-ctx->sf);
8509566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalBegin(da,X,INSERT_VALUES,Xloc));
8519566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalEnd(da,X,INSERT_VALUES,Xloc));
8529566063dSJacob Faibussowitsch   PetscCall(VecZeroEntries(F));
8539566063dSJacob Faibussowitsch   PetscCall(DMDAVecGetArray(da,Xloc,&x));
8549566063dSJacob Faibussowitsch   PetscCall(VecGetArray(F,&f));
8559566063dSJacob Faibussowitsch   PetscCall(DMDAGetArray(da,PETSC_TRUE,&slope));
8569566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(da,&xs,0,0,&xm,0,0));
85784ff8c8bSHong Zhang 
85884ff8c8bSHong Zhang   if (ctx->bctype == FVBC_OUTFLOW) {
85984ff8c8bSHong Zhang     for (i=xs-2; i<0; i++) {
86084ff8c8bSHong Zhang       for (j=0; j<dof; j++) x[i*dof+j] = x[j];
86184ff8c8bSHong Zhang     }
86284ff8c8bSHong Zhang     for (i=Mx; i<xs+xm+2; i++) {
86384ff8c8bSHong Zhang       for (j=0; j<dof; j++) x[i*dof+j] = x[(xs+xm-1)*dof+j];
86484ff8c8bSHong Zhang     }
86584ff8c8bSHong Zhang   }
86684ff8c8bSHong Zhang   if (ctx->bctype == FVBC_INFLOW) {
86784ff8c8bSHong Zhang     /* See LeVeque, R. (2002). Finite Volume Methods for Hyperbolic Problems. doi:10.1017/CBO9780511791253
86884ff8c8bSHong Zhang     pages 137-138 for the scheme. */
86984ff8c8bSHong Zhang     if (xs==0) { /* Left Boundary */
87084ff8c8bSHong Zhang       ctx->physics2.inflow(ctx,time,ctx->xmin,ctx->ub);
87184ff8c8bSHong Zhang       for (j=0; j<dof; j++) {
87284ff8c8bSHong Zhang         if (ctx->physics2.bcinflowindex[j]==PETSC_TRUE) {
87384ff8c8bSHong Zhang           for (i=-2; i<0; i++) x[i*dof+j] = 2.0*ctx->ub[j]-x[-(i+1)*dof+j];
87484ff8c8bSHong Zhang         } else {
87584ff8c8bSHong Zhang           for (i=-2; i<0; i++) x[i*dof+j] = x[j]; /* Outflow */
87684ff8c8bSHong Zhang         }
87784ff8c8bSHong Zhang       }
87884ff8c8bSHong Zhang     }
87984ff8c8bSHong Zhang     if (xs+xm==Mx) { /* Right Boundary */
88084ff8c8bSHong Zhang       ctx->physics2.inflow(ctx,time,ctx->xmax,ctx->ub);
88184ff8c8bSHong Zhang       for (j=0; j<dof; j++) {
88284ff8c8bSHong Zhang         if (ctx->physics2.bcinflowindex[dof+j]==PETSC_TRUE) {
88384ff8c8bSHong Zhang           for (i=Mx; i<Mx+2; i++) x[i*dof+j] = 2.0*ctx->ub[dof+j]-x[(2*Mx-(i+1))*dof+j];
88484ff8c8bSHong Zhang         } else {
88584ff8c8bSHong Zhang           for (i=Mx; i<Mx+2; i++) x[i*dof+j] = x[(Mx-1)*dof+j]; /* Outflow */
88684ff8c8bSHong Zhang         }
88784ff8c8bSHong Zhang       }
88884ff8c8bSHong Zhang     }
88984ff8c8bSHong Zhang   }
89084ff8c8bSHong Zhang   for (i=xs-1; i<xs+xm+1; i++) {
89184ff8c8bSHong Zhang     struct _LimitInfo info;
89284ff8c8bSHong Zhang     PetscScalar       *cjmpL,*cjmpR;
89384ff8c8bSHong Zhang     if ((i > sf-lsbwidth-2 && i < sf+1) || (i > fs-2 && i < fs+rsbwidth+1)) {
89484ff8c8bSHong Zhang       /* Determine the right eigenvectors R, where A = R \Lambda R^{-1} */
8959566063dSJacob Faibussowitsch       PetscCall((*ctx->physics2.characteristic2)(ctx->physics2.user,dof,&x[i*dof],ctx->R,ctx->Rinv,ctx->speeds));
89684ff8c8bSHong Zhang       /* Evaluate jumps across interfaces (i-1, i) and (i, i+1), put in characteristic basis */
8979566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(ctx->cjmpLR,2*dof));
89884ff8c8bSHong Zhang       cjmpL = &ctx->cjmpLR[0];
89984ff8c8bSHong Zhang       cjmpR = &ctx->cjmpLR[dof];
90084ff8c8bSHong Zhang       for (j=0; j<dof; j++) {
90184ff8c8bSHong Zhang         PetscScalar jmpL,jmpR;
90284ff8c8bSHong Zhang         jmpL = x[(i+0)*dof+j]-x[(i-1)*dof+j];
90384ff8c8bSHong Zhang         jmpR = x[(i+1)*dof+j]-x[(i+0)*dof+j];
90484ff8c8bSHong Zhang         for (k=0; k<dof; k++) {
90584ff8c8bSHong Zhang           cjmpL[k] += ctx->Rinv[k+j*dof]*jmpL;
90684ff8c8bSHong Zhang           cjmpR[k] += ctx->Rinv[k+j*dof]*jmpR;
90784ff8c8bSHong Zhang         }
90884ff8c8bSHong Zhang       }
90984ff8c8bSHong Zhang       /* Apply limiter to the left and right characteristic jumps */
91084ff8c8bSHong Zhang       info.m  = dof;
91184ff8c8bSHong Zhang       info.hxs = hxs;
91284ff8c8bSHong Zhang       info.hxf = hxf;
91384ff8c8bSHong Zhang       (*ctx->limit2)(&info,cjmpL,cjmpR,ctx->sf,ctx->fs,i,ctx->cslope);
91484ff8c8bSHong Zhang       for (j=0; j<dof; j++) {
91584ff8c8bSHong Zhang         PetscScalar tmp = 0;
91684ff8c8bSHong Zhang         for (k=0; k<dof; k++) tmp += ctx->R[j+k*dof]*ctx->cslope[k];
91784ff8c8bSHong Zhang           slope[i*dof+j] = tmp;
91884ff8c8bSHong Zhang       }
91984ff8c8bSHong Zhang     }
92084ff8c8bSHong Zhang   }
92184ff8c8bSHong Zhang 
92284ff8c8bSHong Zhang   for (i=xs; i<xs+xm+1; i++) {
92384ff8c8bSHong Zhang     PetscReal   maxspeed;
92484ff8c8bSHong Zhang     PetscScalar *uL,*uR;
92584ff8c8bSHong Zhang     uL = &ctx->uLR[0];
92684ff8c8bSHong Zhang     uR = &ctx->uLR[dof];
92784ff8c8bSHong Zhang     if (i == sf-lsbwidth) {
92884ff8c8bSHong Zhang       for (j=0; j<dof; j++) {
92984ff8c8bSHong Zhang         uL[j] = x[(i-1)*dof+j]+slope[(i-1)*dof+j]*hxs/2;
93084ff8c8bSHong Zhang         uR[j] = x[(i-0)*dof+j]-slope[(i-0)*dof+j]*hxs/2;
93184ff8c8bSHong Zhang       }
9329566063dSJacob Faibussowitsch       PetscCall((*ctx->physics2.riemann2)(ctx->physics2.user,dof,uL,uR,ctx->flux,&maxspeed));
93384ff8c8bSHong Zhang       if (i < xs+xm) {
93484ff8c8bSHong Zhang         for (j=0; j<dof; j++) f[islow*dof+j] += ctx->flux[j]/hxs;
93584ff8c8bSHong Zhang         islow++;
93684ff8c8bSHong Zhang       }
93784ff8c8bSHong Zhang     }
93884ff8c8bSHong Zhang     if (i > sf-lsbwidth && i < sf) {
93984ff8c8bSHong Zhang       for (j=0; j<dof; j++) {
94084ff8c8bSHong Zhang         uL[j] = x[(i-1)*dof+j]+slope[(i-1)*dof+j]*hxs/2;
94184ff8c8bSHong Zhang         uR[j] = x[(i-0)*dof+j]-slope[(i-0)*dof+j]*hxs/2;
94284ff8c8bSHong Zhang       }
9439566063dSJacob Faibussowitsch       PetscCall((*ctx->physics2.riemann2)(ctx->physics2.user,dof,uL,uR,ctx->flux,&maxspeed));
94484ff8c8bSHong Zhang       if (i > xs) {
94584ff8c8bSHong Zhang         for (j=0; j<dof; j++) f[(islow-1)*dof+j] -= ctx->flux[j]/hxs;
94684ff8c8bSHong Zhang       }
94784ff8c8bSHong Zhang       if (i < xs+xm) {
94884ff8c8bSHong Zhang         for (j=0; j<dof; j++) f[islow*dof+j] += ctx->flux[j]/hxs;
94984ff8c8bSHong Zhang         islow++;
95084ff8c8bSHong Zhang       }
95184ff8c8bSHong Zhang     }
95284ff8c8bSHong Zhang     if (i == sf) { /* interface between the slow region and the fast region */
95384ff8c8bSHong Zhang       for (j=0; j<dof; j++) {
95484ff8c8bSHong Zhang         uL[j] = x[(i-1)*dof+j]+slope[(i-1)*dof+j]*hxs/2;
95584ff8c8bSHong Zhang         uR[j] = x[(i-0)*dof+j]-slope[(i-0)*dof+j]*hxf/2;
95684ff8c8bSHong Zhang       }
9579566063dSJacob Faibussowitsch       PetscCall((*ctx->physics2.riemann2)(ctx->physics2.user,dof,uL,uR,ctx->flux,&maxspeed));
95884ff8c8bSHong Zhang       if (i > xs) {
95984ff8c8bSHong Zhang         for (j=0; j<dof; j++) f[(islow-1)*dof+j] -= ctx->flux[j]/hxs;
96084ff8c8bSHong Zhang       }
96184ff8c8bSHong Zhang     }
96284ff8c8bSHong Zhang     if (i == fs) { /* interface between the fast region and the slow region */
96384ff8c8bSHong Zhang       for (j=0; j<dof; j++) {
96484ff8c8bSHong Zhang         uL[j] = x[(i-1)*dof+j]+slope[(i-1)*dof+j]*hxf/2;
96584ff8c8bSHong Zhang         uR[j] = x[(i-0)*dof+j]-slope[(i-0)*dof+j]*hxs/2;
96684ff8c8bSHong Zhang       }
9679566063dSJacob Faibussowitsch       PetscCall((*ctx->physics2.riemann2)(ctx->physics2.user,dof,uL,uR,ctx->flux,&maxspeed));
96884ff8c8bSHong Zhang       if (i < xs+xm) {
96984ff8c8bSHong Zhang         for (j=0; j<dof; j++) f[islow*dof+j] += ctx->flux[j]/hxs;
97084ff8c8bSHong Zhang         islow++;
97184ff8c8bSHong Zhang       }
97284ff8c8bSHong Zhang     }
97384ff8c8bSHong Zhang     if (i > fs && i < fs+rsbwidth) {
97484ff8c8bSHong Zhang       for (j=0; j<dof; j++) {
97584ff8c8bSHong Zhang         uL[j] = x[(i-1)*dof+j]+slope[(i-1)*dof+j]*hxs/2;
97684ff8c8bSHong Zhang         uR[j] = x[(i-0)*dof+j]-slope[(i-0)*dof+j]*hxs/2;
97784ff8c8bSHong Zhang       }
9789566063dSJacob Faibussowitsch       PetscCall((*ctx->physics2.riemann2)(ctx->physics2.user,dof,uL,uR,ctx->flux,&maxspeed));
97984ff8c8bSHong Zhang       if (i > xs) {
98084ff8c8bSHong Zhang         for (j=0; j<dof; j++) f[(islow-1)*dof+j] -= ctx->flux[j]/hxs;
98184ff8c8bSHong Zhang       }
98284ff8c8bSHong Zhang       if (i < xs+xm) {
98384ff8c8bSHong Zhang         for (j=0; j<dof; j++) f[islow*dof+j] += ctx->flux[j]/hxs;
98484ff8c8bSHong Zhang         islow++;
98584ff8c8bSHong Zhang       }
98684ff8c8bSHong Zhang     }
98784ff8c8bSHong Zhang     if (i == fs+rsbwidth) {
98884ff8c8bSHong Zhang       for (j=0; j<dof; j++) {
98984ff8c8bSHong Zhang         uL[j] = x[(i-1)*dof+j]+slope[(i-1)*dof+j]*hxs/2;
99084ff8c8bSHong Zhang         uR[j] = x[(i-0)*dof+j]-slope[(i-0)*dof+j]*hxs/2;
99184ff8c8bSHong Zhang       }
9929566063dSJacob Faibussowitsch       PetscCall((*ctx->physics2.riemann2)(ctx->physics2.user,dof,uL,uR,ctx->flux,&maxspeed));
99384ff8c8bSHong Zhang       if (i > xs) {
99484ff8c8bSHong Zhang         for (j=0; j<dof; j++) f[(islow-1)*dof+j] -= ctx->flux[j]/hxs;
99584ff8c8bSHong Zhang       }
99684ff8c8bSHong Zhang     }
99784ff8c8bSHong Zhang   }
9989566063dSJacob Faibussowitsch   PetscCall(DMDAVecRestoreArray(da,Xloc,&x));
9999566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(F,&f));
10009566063dSJacob Faibussowitsch   PetscCall(DMDARestoreArray(da,PETSC_TRUE,&slope));
10019566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(da,&Xloc));
100284ff8c8bSHong Zhang   PetscFunctionReturn(0);
100384ff8c8bSHong Zhang }
100484ff8c8bSHong Zhang 
100584ff8c8bSHong Zhang /* --------------------------------- Finite Volume Solver for fast  parts ----------------------------------- */
100684ff8c8bSHong Zhang PetscErrorCode FVRHSFunctionfast_2WaySplit(TS ts,PetscReal time,Vec X,Vec F,void *vctx)
100784ff8c8bSHong Zhang {
100884ff8c8bSHong Zhang   FVCtx          *ctx = (FVCtx*)vctx;
100984ff8c8bSHong Zhang   PetscInt       i,j,k,Mx,dof,xs,xm,ifast = 0,sf = ctx->sf,fs = ctx->fs;
101084ff8c8bSHong Zhang   PetscReal      hxs,hxf;
101184ff8c8bSHong Zhang   PetscScalar    *x,*f,*slope;
101284ff8c8bSHong Zhang   Vec            Xloc;
101384ff8c8bSHong Zhang   DM             da;
101484ff8c8bSHong Zhang 
101584ff8c8bSHong Zhang   PetscFunctionBeginUser;
10169566063dSJacob Faibussowitsch   PetscCall(TSGetDM(ts,&da));
10179566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(da,&Xloc));
10189566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(da,0, &Mx,0,0, 0,0,0, &dof,0,0,0,0,0));
101984ff8c8bSHong Zhang   hxs  = (ctx->xmax-ctx->xmin)*3.0/8.0/ctx->sf;
102084ff8c8bSHong Zhang   hxf  = (ctx->xmax-ctx->xmin)/4.0/(ctx->fs-ctx->sf);
10219566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalBegin(da,X,INSERT_VALUES,Xloc));
10229566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalEnd(da,X,INSERT_VALUES,Xloc));
10239566063dSJacob Faibussowitsch   PetscCall(VecZeroEntries(F));
10249566063dSJacob Faibussowitsch   PetscCall(DMDAVecGetArray(da,Xloc,&x));
10259566063dSJacob Faibussowitsch   PetscCall(VecGetArray(F,&f));
10269566063dSJacob Faibussowitsch   PetscCall(DMDAGetArray(da,PETSC_TRUE,&slope));
10279566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(da,&xs,0,0,&xm,0,0));
102884ff8c8bSHong Zhang 
102984ff8c8bSHong Zhang   if (ctx->bctype == FVBC_OUTFLOW) {
103084ff8c8bSHong Zhang     for (i=xs-2; i<0; i++) {
103184ff8c8bSHong Zhang       for (j=0; j<dof; j++) x[i*dof+j] = x[j];
103284ff8c8bSHong Zhang     }
103384ff8c8bSHong Zhang     for (i=Mx; i<xs+xm+2; i++) {
103484ff8c8bSHong Zhang       for (j=0; j<dof; j++) x[i*dof+j] = x[(xs+xm-1)*dof+j];
103584ff8c8bSHong Zhang     }
103684ff8c8bSHong Zhang   }
103784ff8c8bSHong Zhang   if (ctx->bctype == FVBC_INFLOW) {
103884ff8c8bSHong Zhang     /* See LeVeque, R. (2002). Finite Volume Methods for Hyperbolic Problems. doi:10.1017/CBO9780511791253
103984ff8c8bSHong Zhang     pages 137-138 for the scheme. */
104084ff8c8bSHong Zhang     if (xs==0) { /* Left Boundary */
104184ff8c8bSHong Zhang       ctx->physics2.inflow(ctx,time,ctx->xmin,ctx->ub);
104284ff8c8bSHong Zhang       for (j=0; j<dof; j++) {
104384ff8c8bSHong Zhang         if (ctx->physics2.bcinflowindex[j]==PETSC_TRUE) {
104484ff8c8bSHong Zhang           for (i=-2; i<0; i++) x[i*dof+j] = 2.0*ctx->ub[j]-x[-(i+1)*dof+j];
104584ff8c8bSHong Zhang         } else {
104684ff8c8bSHong Zhang           for (i=-2; i<0; i++) x[i*dof+j] = x[j]; /* Outflow */
104784ff8c8bSHong Zhang         }
104884ff8c8bSHong Zhang       }
104984ff8c8bSHong Zhang     }
105084ff8c8bSHong Zhang     if (xs+xm==Mx) { /* Right Boundary */
105184ff8c8bSHong Zhang       ctx->physics2.inflow(ctx,time,ctx->xmax,ctx->ub);
105284ff8c8bSHong Zhang       for (j=0; j<dof; j++) {
105384ff8c8bSHong Zhang         if (ctx->physics2.bcinflowindex[dof+j]==PETSC_TRUE) {
105484ff8c8bSHong Zhang           for (i=Mx; i<Mx+2; i++) x[i*dof+j] = 2.0*ctx->ub[dof+j]-x[(2*Mx-(i+1))*dof+j];
105584ff8c8bSHong Zhang         } else {
105684ff8c8bSHong Zhang           for (i=Mx; i<Mx+2; i++) x[i*dof+j] = x[(Mx-1)*dof+j]; /* Outflow */
105784ff8c8bSHong Zhang         }
105884ff8c8bSHong Zhang       }
105984ff8c8bSHong Zhang     }
106084ff8c8bSHong Zhang   }
106184ff8c8bSHong Zhang   for (i=xs-1; i<xs+xm+1; i++) {
106284ff8c8bSHong Zhang     struct _LimitInfo info;
106384ff8c8bSHong Zhang     PetscScalar       *cjmpL,*cjmpR;
106484ff8c8bSHong Zhang     if (i > sf-2 && i < fs+1) {
10659566063dSJacob Faibussowitsch       PetscCall((*ctx->physics2.characteristic2)(ctx->physics2.user,dof,&x[i*dof],ctx->R,ctx->Rinv,ctx->speeds));
10669566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(ctx->cjmpLR,2*dof));
106784ff8c8bSHong Zhang       cjmpL = &ctx->cjmpLR[0];
106884ff8c8bSHong Zhang       cjmpR = &ctx->cjmpLR[dof];
106984ff8c8bSHong Zhang       for (j=0; j<dof; j++) {
107084ff8c8bSHong Zhang         PetscScalar jmpL,jmpR;
107184ff8c8bSHong Zhang         jmpL = x[(i+0)*dof+j]-x[(i-1)*dof+j];
107284ff8c8bSHong Zhang         jmpR = x[(i+1)*dof+j]-x[(i+0)*dof+j];
107384ff8c8bSHong Zhang         for (k=0; k<dof; k++) {
107484ff8c8bSHong Zhang           cjmpL[k] += ctx->Rinv[k+j*dof]*jmpL;
107584ff8c8bSHong Zhang           cjmpR[k] += ctx->Rinv[k+j*dof]*jmpR;
107684ff8c8bSHong Zhang         }
107784ff8c8bSHong Zhang       }
107884ff8c8bSHong Zhang       /* Apply limiter to the left and right characteristic jumps */
107984ff8c8bSHong Zhang       info.m  = dof;
108084ff8c8bSHong Zhang       info.hxs = hxs;
108184ff8c8bSHong Zhang       info.hxf = hxf;
108284ff8c8bSHong Zhang       (*ctx->limit2)(&info,cjmpL,cjmpR,ctx->sf,ctx->fs,i,ctx->cslope);
108384ff8c8bSHong Zhang       for (j=0; j<dof; j++) {
108484ff8c8bSHong Zhang       PetscScalar tmp = 0;
108584ff8c8bSHong Zhang       for (k=0; k<dof; k++) tmp += ctx->R[j+k*dof]*ctx->cslope[k];
108684ff8c8bSHong Zhang         slope[i*dof+j] = tmp;
108784ff8c8bSHong Zhang       }
108884ff8c8bSHong Zhang     }
108984ff8c8bSHong Zhang   }
109084ff8c8bSHong Zhang 
109184ff8c8bSHong Zhang   for (i=xs; i<xs+xm+1; i++) {
109284ff8c8bSHong Zhang     PetscReal   maxspeed;
109384ff8c8bSHong Zhang     PetscScalar *uL,*uR;
109484ff8c8bSHong Zhang     uL = &ctx->uLR[0];
109584ff8c8bSHong Zhang     uR = &ctx->uLR[dof];
109684ff8c8bSHong Zhang     if (i == sf) { /* interface between the slow region and the fast region */
109784ff8c8bSHong Zhang       for (j=0; j<dof; j++) {
109884ff8c8bSHong Zhang         uL[j] = x[(i-1)*dof+j]+slope[(i-1)*dof+j]*hxs/2;
109984ff8c8bSHong Zhang         uR[j] = x[(i-0)*dof+j]-slope[(i-0)*dof+j]*hxf/2;
110084ff8c8bSHong Zhang       }
11019566063dSJacob Faibussowitsch       PetscCall((*ctx->physics2.riemann2)(ctx->physics2.user,dof,uL,uR,ctx->flux,&maxspeed));
110284ff8c8bSHong Zhang       if (i < xs+xm) {
110384ff8c8bSHong Zhang         for (j=0; j<dof; j++) f[ifast*dof+j] += ctx->flux[j]/hxf;
110484ff8c8bSHong Zhang         ifast++;
110584ff8c8bSHong Zhang       }
110684ff8c8bSHong Zhang     }
110784ff8c8bSHong Zhang     if (i > sf && i < fs) { /* fast region */
110884ff8c8bSHong Zhang       for (j=0; j<dof; j++) {
110984ff8c8bSHong Zhang         uL[j] = x[(i-1)*dof+j]+slope[(i-1)*dof+j]*hxf/2;
111084ff8c8bSHong Zhang         uR[j] = x[(i-0)*dof+j]-slope[(i-0)*dof+j]*hxf/2;
111184ff8c8bSHong Zhang       }
11129566063dSJacob Faibussowitsch       PetscCall((*ctx->physics2.riemann2)(ctx->physics2.user,dof,uL,uR,ctx->flux,&maxspeed));
111384ff8c8bSHong Zhang       if (i > xs) {
111484ff8c8bSHong Zhang         for (j=0; j<dof; j++) f[(ifast-1)*dof+j] -= ctx->flux[j]/hxf;
111584ff8c8bSHong Zhang       }
111684ff8c8bSHong Zhang       if (i < xs+xm) {
111784ff8c8bSHong Zhang         for (j=0; j<dof; j++) f[ifast*dof+j] += ctx->flux[j]/hxf;
111884ff8c8bSHong Zhang         ifast++;
111984ff8c8bSHong Zhang       }
112084ff8c8bSHong Zhang     }
112184ff8c8bSHong Zhang     if (i == fs) { /* interface between the fast region and the slow region */
112284ff8c8bSHong Zhang       for (j=0; j<dof; j++) {
112384ff8c8bSHong Zhang         uL[j] = x[(i-1)*dof+j]+slope[(i-1)*dof+j]*hxf/2;
112484ff8c8bSHong Zhang         uR[j] = x[(i-0)*dof+j]-slope[(i-0)*dof+j]*hxs/2;
112584ff8c8bSHong Zhang       }
11269566063dSJacob Faibussowitsch       PetscCall((*ctx->physics2.riemann2)(ctx->physics2.user,dof,uL,uR,ctx->flux,&maxspeed));
112784ff8c8bSHong Zhang       if (i > xs) {
112884ff8c8bSHong Zhang         for (j=0; j<dof; j++) f[(ifast-1)*dof+j] -= ctx->flux[j]/hxf;
112984ff8c8bSHong Zhang       }
113084ff8c8bSHong Zhang     }
113184ff8c8bSHong Zhang   }
11329566063dSJacob Faibussowitsch   PetscCall(DMDAVecRestoreArray(da,Xloc,&x));
11339566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(F,&f));
11349566063dSJacob Faibussowitsch   PetscCall(DMDARestoreArray(da,PETSC_TRUE,&slope));
11359566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(da,&Xloc));
113684ff8c8bSHong Zhang   PetscFunctionReturn(0);
113784ff8c8bSHong Zhang }
113884ff8c8bSHong Zhang 
113984ff8c8bSHong Zhang int main(int argc,char *argv[])
114084ff8c8bSHong Zhang {
114184ff8c8bSHong Zhang   char              lname[256] = "mc",physname[256] = "advect",final_fname[256] = "solution.m";
114284ff8c8bSHong Zhang   PetscFunctionList limiters   = 0,physics = 0;
114384ff8c8bSHong Zhang   MPI_Comm          comm;
114484ff8c8bSHong Zhang   TS                ts;
114584ff8c8bSHong Zhang   DM                da;
114684ff8c8bSHong Zhang   Vec               X,X0,R;
114784ff8c8bSHong Zhang   FVCtx             ctx;
114884ff8c8bSHong Zhang   PetscInt          i,k,dof,xs,xm,Mx,draw = 0,count_slow,count_fast,islow = 0,ifast =0,islowbuffer = 0,*index_slow,*index_fast,*index_slowbuffer;
114984ff8c8bSHong Zhang   PetscBool         view_final = PETSC_FALSE;
115084ff8c8bSHong Zhang   PetscReal         ptime,maxtime;
115184ff8c8bSHong Zhang 
11529566063dSJacob Faibussowitsch   PetscCall(PetscInitialize(&argc,&argv,0,help));
115384ff8c8bSHong Zhang   comm = PETSC_COMM_WORLD;
11549566063dSJacob Faibussowitsch   PetscCall(PetscMemzero(&ctx,sizeof(ctx)));
115584ff8c8bSHong Zhang 
115684ff8c8bSHong Zhang   /* Register limiters to be available on the command line */
11579566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&limiters,"upwind"              ,Limit2_Upwind));
11589566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&limiters,"lax-wendroff"        ,Limit2_LaxWendroff));
11599566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&limiters,"beam-warming"        ,Limit2_BeamWarming));
11609566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&limiters,"fromm"               ,Limit2_Fromm));
11619566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&limiters,"minmod"              ,Limit2_Minmod));
11629566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&limiters,"superbee"            ,Limit2_Superbee));
11639566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&limiters,"mc"                  ,Limit2_MC));
11649566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&limiters,"koren3"              ,Limit2_Koren3));
116584ff8c8bSHong Zhang 
116684ff8c8bSHong Zhang   /* Register physical models to be available on the command line */
11679566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&physics,"shallow"         ,PhysicsCreate_Shallow));
11689566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&physics,"advect"          ,PhysicsCreate_Advect));
116984ff8c8bSHong Zhang 
117084ff8c8bSHong Zhang   ctx.comm    = comm;
117184ff8c8bSHong Zhang   ctx.cfl     = 0.9;
117284ff8c8bSHong Zhang   ctx.bctype  = FVBC_PERIODIC;
117384ff8c8bSHong Zhang   ctx.xmin    = -1.0;
117484ff8c8bSHong Zhang   ctx.xmax    = 1.0;
117584ff8c8bSHong Zhang   ctx.initial = 1;
117684ff8c8bSHong Zhang   ctx.hratio  = 2;
117784ff8c8bSHong Zhang   maxtime     = 10.0;
117884ff8c8bSHong Zhang   ctx.simulation = PETSC_FALSE;
1179*d0609cedSBarry Smith   PetscOptionsBegin(comm,NULL,"Finite Volume solver options","");
11809566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-xmin","X min","",ctx.xmin,&ctx.xmin,NULL));
11819566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-xmax","X max","",ctx.xmax,&ctx.xmax,NULL));
11829566063dSJacob Faibussowitsch   PetscCall(PetscOptionsFList("-limit","Name of flux imiter to use","",limiters,lname,lname,sizeof(lname),NULL));
11839566063dSJacob Faibussowitsch   PetscCall(PetscOptionsFList("-physics","Name of physics model to use","",physics,physname,physname,sizeof(physname),NULL));
11849566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-draw","Draw solution vector, bitwise OR of (1=initial,2=final,4=final error)","",draw,&draw,NULL));
11859566063dSJacob Faibussowitsch   PetscCall(PetscOptionsString("-view_final","Write final solution in ASCII MATLAB format to given file name","",final_fname,final_fname,sizeof(final_fname),&view_final));
11869566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-initial","Initial condition (depends on the physics)","",ctx.initial,&ctx.initial,NULL));
11879566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-exact","Compare errors with exact solution","",ctx.exact,&ctx.exact,NULL));
11889566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-simulation","Compare errors with reference solution","",ctx.simulation,&ctx.simulation,NULL));
11899566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-cfl","CFL number to time step at","",ctx.cfl,&ctx.cfl,NULL));
11909566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEnum("-bc_type","Boundary condition","",FVBCTypes,(PetscEnum)ctx.bctype,(PetscEnum*)&ctx.bctype,NULL));
11919566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-hratio","Spacing ratio","",ctx.hratio,&ctx.hratio,NULL));
1192*d0609cedSBarry Smith   PetscOptionsEnd();
119384ff8c8bSHong Zhang 
119484ff8c8bSHong Zhang   /* Choose the limiter from the list of registered limiters */
11959566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListFind(limiters,lname,&ctx.limit2));
11963c633725SBarry Smith   PetscCheck(ctx.limit2,PETSC_COMM_SELF,PETSC_ERR_ARG_UNKNOWN_TYPE,"Limiter '%s' not found",lname);
119784ff8c8bSHong Zhang 
119884ff8c8bSHong Zhang   /* Choose the physics from the list of registered models */
119984ff8c8bSHong Zhang   {
120084ff8c8bSHong Zhang     PetscErrorCode (*r)(FVCtx*);
12019566063dSJacob Faibussowitsch     PetscCall(PetscFunctionListFind(physics,physname,&r));
12023c633725SBarry Smith     PetscCheck(r,PETSC_COMM_SELF,PETSC_ERR_ARG_UNKNOWN_TYPE,"Physics '%s' not found",physname);
120384ff8c8bSHong Zhang     /* Create the physics, will set the number of fields and their names */
12049566063dSJacob Faibussowitsch     PetscCall((*r)(&ctx));
120584ff8c8bSHong Zhang   }
120684ff8c8bSHong Zhang 
120784ff8c8bSHong Zhang   /* Create a DMDA to manage the parallel grid */
12089566063dSJacob Faibussowitsch   PetscCall(DMDACreate1d(comm,DM_BOUNDARY_PERIODIC,50,ctx.physics2.dof,2,NULL,&da));
12099566063dSJacob Faibussowitsch   PetscCall(DMSetFromOptions(da));
12109566063dSJacob Faibussowitsch   PetscCall(DMSetUp(da));
121184ff8c8bSHong Zhang   /* Inform the DMDA of the field names provided by the physics. */
121284ff8c8bSHong Zhang   /* The names will be shown in the title bars when run with -ts_monitor_draw_solution */
121384ff8c8bSHong Zhang   for (i=0; i<ctx.physics2.dof; i++) {
12149566063dSJacob Faibussowitsch     PetscCall(DMDASetFieldName(da,i,ctx.physics2.fieldname[i]));
121584ff8c8bSHong Zhang   }
12169566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(da,0, &Mx,0,0, 0,0,0, &dof,0,0,0,0,0));
12179566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(da,&xs,0,0,&xm,0,0));
121884ff8c8bSHong Zhang 
121984ff8c8bSHong Zhang   /* Set coordinates of cell centers */
12209566063dSJacob Faibussowitsch   PetscCall(DMDASetUniformCoordinates(da,ctx.xmin+0.5*(ctx.xmax-ctx.xmin)/Mx,ctx.xmax+0.5*(ctx.xmax-ctx.xmin)/Mx,0,0,0,0));
122184ff8c8bSHong Zhang 
122284ff8c8bSHong Zhang   /* Allocate work space for the Finite Volume solver (so it doesn't have to be reallocated on each function evaluation) */
12239566063dSJacob Faibussowitsch   PetscCall(PetscMalloc4(dof*dof,&ctx.R,dof*dof,&ctx.Rinv,2*dof,&ctx.cjmpLR,1*dof,&ctx.cslope));
12249566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(2*dof,&ctx.uLR,dof,&ctx.flux,dof,&ctx.speeds));
12259566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(2*dof,&ctx.ub));
122684ff8c8bSHong Zhang 
122784ff8c8bSHong Zhang   /* Create a vector to store the solution and to save the initial state */
12289566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(da,&X));
12299566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(X,&X0));
12309566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(X,&R));
123184ff8c8bSHong Zhang 
123284ff8c8bSHong Zhang   /* create index for slow parts and fast parts,
123384ff8c8bSHong Zhang      count_slow + count_fast = Mx, counts_slow*hs = 0.5, counts_fast*hf = 0.5 */
123484ff8c8bSHong Zhang   count_slow = Mx/(1.0+ctx.hratio/3.0);
123508401ef6SPierre Jolivet   PetscCheck(count_slow%2 == 0,PETSC_COMM_WORLD,PETSC_ERR_USER,"Please adjust grid size Mx (-da_grid_x) and hratio (-hratio) so that Mx/(1+hratio/3) is even");
123684ff8c8bSHong Zhang   count_fast = Mx-count_slow;
123784ff8c8bSHong Zhang   ctx.sf = count_slow/2;
123884ff8c8bSHong Zhang   ctx.fs = ctx.sf+count_fast;
12399566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(xm*dof,&index_slow));
12409566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(xm*dof,&index_fast));
12419566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(8*dof,&index_slowbuffer));
124284ff8c8bSHong Zhang   ctx.lsbwidth = 4;
124384ff8c8bSHong Zhang   ctx.rsbwidth = 4;
124484ff8c8bSHong Zhang 
124584ff8c8bSHong Zhang   for (i=xs; i<xs+xm; i++) {
124684ff8c8bSHong Zhang     if (i < ctx.sf-ctx.lsbwidth || i > ctx.fs+ctx.rsbwidth-1)
124784ff8c8bSHong Zhang       for (k=0; k<dof; k++) index_slow[islow++] = i*dof+k;
124884ff8c8bSHong Zhang     else if ((i >= ctx.sf-ctx.lsbwidth && i < ctx.sf) || (i > ctx.fs-1 && i <= ctx.fs+ctx.rsbwidth-1))
124984ff8c8bSHong Zhang       for (k=0; k<dof; k++) index_slowbuffer[islowbuffer++] = i*dof+k;
125084ff8c8bSHong Zhang     else
125184ff8c8bSHong Zhang       for (k=0; k<dof; k++) index_fast[ifast++] = i*dof+k;
125284ff8c8bSHong Zhang   }
12539566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PETSC_COMM_WORLD,islow,index_slow,PETSC_COPY_VALUES,&ctx.iss));
12549566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PETSC_COMM_WORLD,ifast,index_fast,PETSC_COPY_VALUES,&ctx.isf));
12559566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PETSC_COMM_WORLD,islowbuffer,index_slowbuffer,PETSC_COPY_VALUES,&ctx.issb));
125684ff8c8bSHong Zhang 
125784ff8c8bSHong Zhang   /* Create a time-stepping object */
12589566063dSJacob Faibussowitsch   PetscCall(TSCreate(comm,&ts));
12599566063dSJacob Faibussowitsch   PetscCall(TSSetDM(ts,da));
12609566063dSJacob Faibussowitsch   PetscCall(TSSetRHSFunction(ts,R,FVRHSFunction_2WaySplit,&ctx));
12619566063dSJacob Faibussowitsch   PetscCall(TSRHSSplitSetIS(ts,"slow",ctx.iss));
12629566063dSJacob Faibussowitsch   PetscCall(TSRHSSplitSetIS(ts,"slowbuffer",ctx.issb));
12639566063dSJacob Faibussowitsch   PetscCall(TSRHSSplitSetIS(ts,"fast",ctx.isf));
12649566063dSJacob Faibussowitsch   PetscCall(TSRHSSplitSetRHSFunction(ts,"slow",NULL,FVRHSFunctionslow_2WaySplit,&ctx));
12659566063dSJacob Faibussowitsch   PetscCall(TSRHSSplitSetRHSFunction(ts,"fast",NULL,FVRHSFunctionfast_2WaySplit,&ctx));
12669566063dSJacob Faibussowitsch   PetscCall(TSRHSSplitSetRHSFunction(ts,"slowbuffer",NULL,FVRHSFunctionslowbuffer_2WaySplit,&ctx));
126784ff8c8bSHong Zhang 
12689566063dSJacob Faibussowitsch   PetscCall(TSSetType(ts,TSMPRK));
12699566063dSJacob Faibussowitsch   PetscCall(TSSetMaxTime(ts,maxtime));
12709566063dSJacob Faibussowitsch   PetscCall(TSSetExactFinalTime(ts,TS_EXACTFINALTIME_STEPOVER));
127184ff8c8bSHong Zhang 
127284ff8c8bSHong Zhang   /* Compute initial conditions and starting time step */
12739566063dSJacob Faibussowitsch   PetscCall(FVSample_2WaySplit(&ctx,da,0,X0));
12749566063dSJacob Faibussowitsch   PetscCall(FVRHSFunction_2WaySplit(ts,0,X0,X,(void*)&ctx)); /* Initial function evaluation, only used to determine max speed */
12759566063dSJacob Faibussowitsch   PetscCall(VecCopy(X0,X));                        /* The function value was not used so we set X=X0 again */
12769566063dSJacob Faibussowitsch   PetscCall(TSSetTimeStep(ts,ctx.cfl/ctx.cfl_idt));
12779566063dSJacob Faibussowitsch   PetscCall(TSSetFromOptions(ts)); /* Take runtime options */
12789566063dSJacob Faibussowitsch   PetscCall(SolutionStatsView(da,X,PETSC_VIEWER_STDOUT_WORLD));
127984ff8c8bSHong Zhang   {
128084ff8c8bSHong Zhang     PetscInt          steps;
128184ff8c8bSHong Zhang     PetscScalar       mass_initial,mass_final,mass_difference,mass_differenceg;
128284ff8c8bSHong Zhang     const PetscScalar *ptr_X,*ptr_X0;
128384ff8c8bSHong Zhang     const PetscReal   hs = (ctx.xmax-ctx.xmin)*3.0/4.0/count_slow;
128484ff8c8bSHong Zhang     const PetscReal   hf = (ctx.xmax-ctx.xmin)/4.0/count_fast;
128584ff8c8bSHong Zhang 
12869566063dSJacob Faibussowitsch     PetscCall(TSSolve(ts,X));
12879566063dSJacob Faibussowitsch     PetscCall(TSGetSolveTime(ts,&ptime));
12889566063dSJacob Faibussowitsch     PetscCall(TSGetStepNumber(ts,&steps));
128984ff8c8bSHong Zhang     /* calculate the total mass at initial time and final time */
129084ff8c8bSHong Zhang     mass_initial = 0.0;
129184ff8c8bSHong Zhang     mass_final   = 0.0;
12929566063dSJacob Faibussowitsch     PetscCall(DMDAVecGetArrayRead(da,X0,(void*)&ptr_X0));
12939566063dSJacob Faibussowitsch     PetscCall(DMDAVecGetArrayRead(da,X,(void*)&ptr_X));
129484ff8c8bSHong Zhang     for (i=xs;i<xs+xm;i++) {
129584ff8c8bSHong Zhang       if (i < ctx.sf || i > ctx.fs-1) {
129684ff8c8bSHong Zhang         for (k=0; k<dof; k++) {
129784ff8c8bSHong Zhang           mass_initial = mass_initial + hs*ptr_X0[i*dof+k];
129884ff8c8bSHong Zhang           mass_final = mass_final + hs*ptr_X[i*dof+k];
129984ff8c8bSHong Zhang         }
130084ff8c8bSHong Zhang       } else {
130184ff8c8bSHong Zhang         for (k=0; k<dof; k++) {
130284ff8c8bSHong Zhang           mass_initial = mass_initial + hf*ptr_X0[i*dof+k];
130384ff8c8bSHong Zhang           mass_final = mass_final + hf*ptr_X[i*dof+k];
130484ff8c8bSHong Zhang         }
130584ff8c8bSHong Zhang       }
130684ff8c8bSHong Zhang     }
13079566063dSJacob Faibussowitsch     PetscCall(DMDAVecRestoreArrayRead(da,X0,(void*)&ptr_X0));
13089566063dSJacob Faibussowitsch     PetscCall(DMDAVecRestoreArrayRead(da,X,(void*)&ptr_X));
130984ff8c8bSHong Zhang     mass_difference = mass_final - mass_initial;
13109566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Allreduce(&mass_difference,&mass_differenceg,1,MPIU_SCALAR,MPIU_SUM,comm));
13119566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(comm,"Mass difference %g\n",(double)mass_differenceg));
13129566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(comm,"Final time %g, steps %D\n",(double)ptime,steps));
13139566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(comm,"Maximum allowable stepsize according to CFL %g\n",(double)(1.0/ctx.cfl_idt)));
131484ff8c8bSHong Zhang     if (ctx.exact) {
131584ff8c8bSHong Zhang       PetscReal nrm1=0;
13169566063dSJacob Faibussowitsch       PetscCall(SolutionErrorNorms_2WaySplit(&ctx,da,ptime,X,&nrm1));
13179566063dSJacob Faibussowitsch       PetscCall(PetscPrintf(comm,"Error ||x-x_e||_1 %g\n",(double)nrm1));
131884ff8c8bSHong Zhang     }
131984ff8c8bSHong Zhang     if (ctx.simulation) {
132084ff8c8bSHong Zhang       PetscReal    nrm1=0;
132184ff8c8bSHong Zhang       PetscViewer  fd;
132284ff8c8bSHong Zhang       char         filename[PETSC_MAX_PATH_LEN] = "binaryoutput";
132384ff8c8bSHong Zhang       Vec          XR;
132484ff8c8bSHong Zhang       PetscBool    flg;
132584ff8c8bSHong Zhang       const PetscScalar  *ptr_XR;
13269566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetString(NULL,NULL,"-f",filename,sizeof(filename),&flg));
13273c633725SBarry Smith       PetscCheck(flg,PETSC_COMM_WORLD,PETSC_ERR_USER,"Must indicate binary file with the -f option");
13289566063dSJacob Faibussowitsch       PetscCall(PetscViewerBinaryOpen(PETSC_COMM_WORLD,filename,FILE_MODE_READ,&fd));
13299566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(X0,&XR));
13309566063dSJacob Faibussowitsch       PetscCall(VecLoad(XR,fd));
13319566063dSJacob Faibussowitsch       PetscCall(PetscViewerDestroy(&fd));
13329566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(X,&ptr_X));
13339566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(XR,&ptr_XR));
133484ff8c8bSHong Zhang       for (i=xs;i<xs+xm;i++) {
133584ff8c8bSHong Zhang         if (i < ctx.sf || i > ctx.fs-1)
133684ff8c8bSHong Zhang           for (k=0; k<dof; k++) nrm1 = nrm1 + hs*PetscAbs(ptr_X[i*dof+k]-ptr_XR[i*dof+k]);
133784ff8c8bSHong Zhang         else
133884ff8c8bSHong Zhang           for (k=0; k<dof; k++) nrm1 = nrm1 + hf*PetscAbs(ptr_X[i*dof+k]-ptr_XR[i*dof+k]);
133984ff8c8bSHong Zhang       }
13409566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(X,&ptr_X));
13419566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(XR,&ptr_XR));
13429566063dSJacob Faibussowitsch       PetscCall(PetscPrintf(comm,"Error ||x-x_e||_1 %g\n",(double)nrm1));
13439566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&XR));
134484ff8c8bSHong Zhang     }
134584ff8c8bSHong Zhang   }
134684ff8c8bSHong Zhang 
13479566063dSJacob Faibussowitsch   PetscCall(SolutionStatsView(da,X,PETSC_VIEWER_STDOUT_WORLD));
13489566063dSJacob Faibussowitsch   if (draw & 0x1) PetscCall(VecView(X0,PETSC_VIEWER_DRAW_WORLD));
13499566063dSJacob Faibussowitsch   if (draw & 0x2) PetscCall(VecView(X,PETSC_VIEWER_DRAW_WORLD));
135084ff8c8bSHong Zhang   if (draw & 0x4) {
135184ff8c8bSHong Zhang     Vec Y;
13529566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(X,&Y));
13539566063dSJacob Faibussowitsch     PetscCall(FVSample_2WaySplit(&ctx,da,ptime,Y));
13549566063dSJacob Faibussowitsch     PetscCall(VecAYPX(Y,-1,X));
13559566063dSJacob Faibussowitsch     PetscCall(VecView(Y,PETSC_VIEWER_DRAW_WORLD));
13569566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&Y));
135784ff8c8bSHong Zhang   }
135884ff8c8bSHong Zhang 
135984ff8c8bSHong Zhang   if (view_final) {
136084ff8c8bSHong Zhang     PetscViewer viewer;
13619566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIOpen(PETSC_COMM_WORLD,final_fname,&viewer));
13629566063dSJacob Faibussowitsch     PetscCall(PetscViewerPushFormat(viewer,PETSC_VIEWER_ASCII_MATLAB));
13639566063dSJacob Faibussowitsch     PetscCall(VecView(X,viewer));
13649566063dSJacob Faibussowitsch     PetscCall(PetscViewerPopFormat(viewer));
13659566063dSJacob Faibussowitsch     PetscCall(PetscViewerDestroy(&viewer));
136684ff8c8bSHong Zhang   }
136784ff8c8bSHong Zhang 
136884ff8c8bSHong Zhang   /* Clean up */
13699566063dSJacob Faibussowitsch   PetscCall((*ctx.physics2.destroy)(ctx.physics2.user));
13709566063dSJacob Faibussowitsch   for (i=0; i<ctx.physics2.dof; i++) PetscCall(PetscFree(ctx.physics2.fieldname[i]));
13719566063dSJacob Faibussowitsch   PetscCall(PetscFree(ctx.physics2.bcinflowindex));
1372*d0609cedSBarry Smith   PetscCall(PetscFree(ctx.ub));
13739566063dSJacob Faibussowitsch   PetscCall(PetscFree4(ctx.R,ctx.Rinv,ctx.cjmpLR,ctx.cslope));
13749566063dSJacob Faibussowitsch   PetscCall(PetscFree3(ctx.uLR,ctx.flux,ctx.speeds));
13759566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&X));
13769566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&X0));
13779566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&R));
13789566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&da));
13799566063dSJacob Faibussowitsch   PetscCall(TSDestroy(&ts));
13809566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&ctx.iss));
13819566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&ctx.isf));
13829566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&ctx.issb));
13839566063dSJacob Faibussowitsch   PetscCall(PetscFree(index_slow));
13849566063dSJacob Faibussowitsch   PetscCall(PetscFree(index_fast));
13859566063dSJacob Faibussowitsch   PetscCall(PetscFree(index_slowbuffer));
13869566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListDestroy(&limiters));
13879566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListDestroy(&physics));
13889566063dSJacob Faibussowitsch   PetscCall(PetscFinalize());
1389b122ec5aSJacob Faibussowitsch   return 0;
139084ff8c8bSHong Zhang }
139184ff8c8bSHong Zhang 
139284ff8c8bSHong Zhang /*TEST
139384ff8c8bSHong Zhang 
139484ff8c8bSHong Zhang     build:
139584ff8c8bSHong Zhang       requires: !complex !single
139684ff8c8bSHong Zhang       depends: finitevolume1d.c
139784ff8c8bSHong Zhang 
139884ff8c8bSHong Zhang     test:
139984ff8c8bSHong Zhang       suffix: 1
140084ff8c8bSHong Zhang       args: -da_grid_x 60 -initial 7 -xmin -1 -xmax 1 -hratio 2 -limit mc -ts_dt 0.025 -ts_max_steps 24 -ts_type mprk -ts_mprk_type 2a22
140184ff8c8bSHong Zhang       output_file: output/ex4_1.out
140284ff8c8bSHong Zhang 
140384ff8c8bSHong Zhang     test:
140484ff8c8bSHong Zhang       suffix: 2
140584ff8c8bSHong Zhang       args: -da_grid_x 60 -initial 7 -xmin -1 -xmax 1 -hratio 2 -limit mc -ts_dt 0.025 -ts_max_steps 24 -ts_type mprk -ts_mprk_type 2a22 -ts_use_splitrhsfunction 1
140684ff8c8bSHong Zhang       output_file: output/ex4_1.out
140784ff8c8bSHong Zhang 
140884ff8c8bSHong Zhang     test:
140984ff8c8bSHong Zhang       suffix: 3
141084ff8c8bSHong Zhang       args: -da_grid_x 40 -initial 1 -hratio 2 -limit mc -ts_dt 0.1 -ts_max_steps 24 -ts_max_time 7.0 -ts_type mprk -ts_mprk_type 2a22 -physics shallow -bc_type outflow -xmin 0 -xmax 50 -ts_use_splitrhsfunction 0
141184ff8c8bSHong Zhang       output_file: output/ex4_3.out
141284ff8c8bSHong Zhang 
141384ff8c8bSHong Zhang     test:
141484ff8c8bSHong Zhang       suffix: 4
141584ff8c8bSHong Zhang       nsize: 2
141684ff8c8bSHong Zhang       args: -da_grid_x 40 -initial 1 -hratio 2 -limit mc -ts_dt 0.1 -ts_max_steps 24 -ts_max_time 7.0 -ts_type mprk -ts_mprk_type 2a22 -physics shallow -bc_type outflow -xmin 0 -xmax 50 -ts_use_splitrhsfunction 1
141784ff8c8bSHong Zhang       output_file: output/ex4_3.out
141884ff8c8bSHong Zhang 
141984ff8c8bSHong Zhang     test:
142084ff8c8bSHong Zhang       suffix: 5
142184ff8c8bSHong Zhang       nsize: 4
142284ff8c8bSHong Zhang       args: args: -da_grid_x 40 -initial 1 -hratio 2 -limit mc -ts_dt 0.1 -ts_max_steps 24 -ts_max_time 7.0 -ts_type mprk -ts_mprk_type 2a22 -physics shallow -bc_type outflow -xmin 0 -xmax 50 -ts_use_splitrhsfunction 1
142384ff8c8bSHong Zhang       output_file: output/ex4_3.out
142484ff8c8bSHong Zhang TEST*/
1425