xref: /petsc/src/ts/tutorials/multirate/ex4.c (revision 48a46eb9bd028bec07ec0f396b1a3abb43f14558)
184ff8c8bSHong Zhang /*
284ff8c8bSHong Zhang   Note:
36aad120cSJose E. Roman     -hratio is the ratio between mesh size of coarse 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 
439371c9d4SSatish Balay static inline PetscReal RangeMod(PetscReal a, PetscReal xmin, PetscReal xmax) {
449371c9d4SSatish Balay   PetscReal range = xmax - xmin;
459371c9d4SSatish Balay   return xmin + PetscFmodReal(range + PetscFmodReal(a, range), range);
469371c9d4SSatish Balay }
479371c9d4SSatish Balay static inline PetscReal MaxAbs(PetscReal a, PetscReal b) {
489371c9d4SSatish Balay   return (PetscAbs(a) > PetscAbs(b)) ? a : b;
499371c9d4SSatish Balay }
5084ff8c8bSHong Zhang /* --------------------------------- Advection ----------------------------------- */
5184ff8c8bSHong Zhang typedef struct {
5284ff8c8bSHong Zhang   PetscReal a; /* advective velocity */
5384ff8c8bSHong Zhang } AdvectCtx;
5484ff8c8bSHong Zhang 
559371c9d4SSatish Balay static PetscErrorCode PhysicsRiemann_Advect(void *vctx, PetscInt m, const PetscScalar *uL, const PetscScalar *uR, PetscScalar *flux, PetscReal *maxspeed) {
5684ff8c8bSHong Zhang   AdvectCtx *ctx = (AdvectCtx *)vctx;
5784ff8c8bSHong Zhang   PetscReal  speed;
5884ff8c8bSHong Zhang 
5984ff8c8bSHong Zhang   PetscFunctionBeginUser;
6084ff8c8bSHong Zhang   speed     = ctx->a;
6184ff8c8bSHong Zhang   flux[0]   = PetscMax(0, speed) * uL[0] + PetscMin(0, speed) * uR[0];
6284ff8c8bSHong Zhang   *maxspeed = speed;
6384ff8c8bSHong Zhang   PetscFunctionReturn(0);
6484ff8c8bSHong Zhang }
6584ff8c8bSHong Zhang 
669371c9d4SSatish Balay static PetscErrorCode PhysicsCharacteristic_Advect(void *vctx, PetscInt m, const PetscScalar *u, PetscScalar *X, PetscScalar *Xi, PetscReal *speeds) {
6784ff8c8bSHong Zhang   AdvectCtx *ctx = (AdvectCtx *)vctx;
6884ff8c8bSHong Zhang 
6984ff8c8bSHong Zhang   PetscFunctionBeginUser;
7084ff8c8bSHong Zhang   X[0]      = 1.;
7184ff8c8bSHong Zhang   Xi[0]     = 1.;
7284ff8c8bSHong Zhang   speeds[0] = ctx->a;
7384ff8c8bSHong Zhang   PetscFunctionReturn(0);
7484ff8c8bSHong Zhang }
7584ff8c8bSHong Zhang 
769371c9d4SSatish Balay static PetscErrorCode PhysicsSample_Advect(void *vctx, PetscInt initial, FVBCType bctype, PetscReal xmin, PetscReal xmax, PetscReal t, PetscReal x, PetscReal *u) {
7784ff8c8bSHong Zhang   AdvectCtx *ctx = (AdvectCtx *)vctx;
7884ff8c8bSHong Zhang   PetscReal  a   = ctx->a, x0;
7984ff8c8bSHong Zhang 
8084ff8c8bSHong Zhang   PetscFunctionBeginUser;
8184ff8c8bSHong Zhang   switch (bctype) {
8284ff8c8bSHong Zhang   case FVBC_OUTFLOW: x0 = x - a * t; break;
8384ff8c8bSHong Zhang   case FVBC_PERIODIC: x0 = RangeMod(x - a * t, xmin, xmax); break;
8484ff8c8bSHong Zhang   default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "unknown BCType");
8584ff8c8bSHong Zhang   }
8684ff8c8bSHong Zhang   switch (initial) {
8784ff8c8bSHong Zhang   case 0: u[0] = (x0 < 0) ? 1 : -1; break;
8884ff8c8bSHong Zhang   case 1: u[0] = (x0 < 0) ? -1 : 1; break;
8984ff8c8bSHong Zhang   case 2: u[0] = (0 < x0 && x0 < 1) ? 1 : 0; break;
9084ff8c8bSHong Zhang   case 3: u[0] = PetscSinReal(2 * PETSC_PI * x0); break;
9184ff8c8bSHong Zhang   case 4: u[0] = PetscAbs(x0); break;
9284ff8c8bSHong Zhang   case 5: u[0] = (x0 < 0 || x0 > 0.5) ? 0 : PetscSqr(PetscSinReal(2 * PETSC_PI * x0)); break;
9384ff8c8bSHong Zhang   case 6: u[0] = (x0 < 0) ? 0 : ((x0 < 1) ? x0 : ((x0 < 2) ? 2 - x0 : 0)); break;
9484ff8c8bSHong Zhang   case 7: u[0] = PetscPowReal(PetscSinReal(PETSC_PI * x0), 10.0); break;
9584ff8c8bSHong Zhang   default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "unknown initial condition");
9684ff8c8bSHong Zhang   }
9784ff8c8bSHong Zhang   PetscFunctionReturn(0);
9884ff8c8bSHong Zhang }
9984ff8c8bSHong Zhang 
1009371c9d4SSatish Balay static PetscErrorCode PhysicsCreate_Advect(FVCtx *ctx) {
10184ff8c8bSHong Zhang   AdvectCtx *user;
10284ff8c8bSHong Zhang 
10384ff8c8bSHong Zhang   PetscFunctionBeginUser;
1049566063dSJacob Faibussowitsch   PetscCall(PetscNew(&user));
10584ff8c8bSHong Zhang   ctx->physics2.sample2         = PhysicsSample_Advect;
10684ff8c8bSHong Zhang   ctx->physics2.riemann2        = PhysicsRiemann_Advect;
10784ff8c8bSHong Zhang   ctx->physics2.characteristic2 = PhysicsCharacteristic_Advect;
10884ff8c8bSHong Zhang   ctx->physics2.destroy         = PhysicsDestroy_SimpleFree;
10984ff8c8bSHong Zhang   ctx->physics2.user            = user;
11084ff8c8bSHong Zhang   ctx->physics2.dof             = 1;
11184ff8c8bSHong Zhang 
1129566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy("u", &ctx->physics2.fieldname[0]));
11384ff8c8bSHong Zhang   user->a = 1;
114d0609cedSBarry Smith   PetscOptionsBegin(ctx->comm, ctx->prefix, "Options for advection", "");
1159566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-physics_advect_a", "Speed", "", user->a, &user->a, NULL));
116d0609cedSBarry Smith   PetscOptionsEnd();
11784ff8c8bSHong Zhang   PetscFunctionReturn(0);
11884ff8c8bSHong Zhang }
11984ff8c8bSHong Zhang /* --------------------------------- Shallow Water ----------------------------------- */
12084ff8c8bSHong Zhang 
12184ff8c8bSHong Zhang typedef struct {
12284ff8c8bSHong Zhang   PetscReal gravity;
12384ff8c8bSHong Zhang } ShallowCtx;
12484ff8c8bSHong Zhang 
1259371c9d4SSatish Balay static inline void ShallowFlux(ShallowCtx *phys, const PetscScalar *u, PetscScalar *f) {
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 
1309371c9d4SSatish Balay static PetscErrorCode PhysicsRiemann_Shallow_Exact(void *vctx, PetscInt m, const PetscScalar *uL, const PetscScalar *uR, PetscScalar *flux, PetscReal *maxspeed) {
13184ff8c8bSHong Zhang   ShallowCtx *phys = (ShallowCtx *)vctx;
13284ff8c8bSHong Zhang   PetscScalar g    = phys->gravity, ustar[2], cL, cR, c, cstar;
1339371c9d4SSatish Balay   struct {
1349371c9d4SSatish Balay     PetscScalar h, u;
1359371c9d4SSatish Balay   } L = {uL[0], uL[1] / uL[0]}, R = {uR[0], uR[1] / uR[0]}, star;
13684ff8c8bSHong Zhang   PetscInt i;
13784ff8c8bSHong Zhang 
13884ff8c8bSHong Zhang   PetscFunctionBeginUser;
1393c633725SBarry Smith   PetscCheck((L.h > 0 && R.h > 0), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Reconstructed thickness is negative");
14084ff8c8bSHong Zhang   cL = PetscSqrtScalar(g * L.h);
14184ff8c8bSHong Zhang   cR = PetscSqrtScalar(g * R.h);
14284ff8c8bSHong Zhang   c  = PetscMax(cL, cR);
14384ff8c8bSHong Zhang   {
14484ff8c8bSHong Zhang     /* Solve for star state */
14584ff8c8bSHong Zhang     const PetscInt maxits = 50;
14684ff8c8bSHong Zhang     PetscScalar    tmp, res, res0 = 0, h0, h = 0.5 * (L.h + R.h); /* initial guess */
14784ff8c8bSHong Zhang     h0 = h;
14884ff8c8bSHong Zhang     for (i = 0; i < maxits; i++) {
14984ff8c8bSHong Zhang       PetscScalar fr, fl, dfr, dfl;
1509371c9d4SSatish Balay       fl  = (L.h < h) ? 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 */
1529371c9d4SSatish Balay       fr  = (R.h < h) ? PetscSqrtScalar(0.5 * g * (h * h - R.h * R.h) * (1 / R.h - 1 / h)) /* shock */
15384ff8c8bSHong Zhang                       : 2 * PetscSqrtScalar(g * h) - 2 * PetscSqrtScalar(g * R.h);         /* rarefaction */
15484ff8c8bSHong Zhang       res = R.u - L.u + fr + fl;
155cad9d221SBarry Smith       PetscCheck(!PetscIsInfOrNanScalar(res), PETSC_COMM_SELF, PETSC_ERR_FP, "Infinity or Not-a-Number generated in computation");
15684ff8c8bSHong Zhang       if (PetscAbsScalar(res) < PETSC_SQRT_MACHINE_EPSILON || (i > 0 && PetscAbsScalar(h - h0) < PETSC_SQRT_MACHINE_EPSILON)) {
15784ff8c8bSHong Zhang         star.h = h;
15884ff8c8bSHong Zhang         star.u = L.u - fl;
15984ff8c8bSHong Zhang         goto converged;
16084ff8c8bSHong Zhang       } else if (i > 0 && PetscAbsScalar(res) >= PetscAbsScalar(res0)) { /* Line search */
16184ff8c8bSHong Zhang         h = 0.8 * h0 + 0.2 * h;
16284ff8c8bSHong Zhang         continue;
16384ff8c8bSHong Zhang       }
16484ff8c8bSHong Zhang       /* Accept the last step and take another */
16584ff8c8bSHong Zhang       res0 = res;
16684ff8c8bSHong Zhang       h0   = h;
16784ff8c8bSHong 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);
16884ff8c8bSHong 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);
16984ff8c8bSHong Zhang       tmp  = h - res / (dfr + dfl);
17084ff8c8bSHong Zhang       if (tmp <= 0) h /= 2; /* Guard against Newton shooting off to a negative thickness */
17184ff8c8bSHong Zhang       else h = tmp;
1723c633725SBarry Smith       PetscCheck(((h > 0) && PetscIsNormalScalar(h)), PETSC_COMM_SELF, PETSC_ERR_FP, "non-normal iterate h=%g", (double)h);
17384ff8c8bSHong Zhang     }
17463a3b9bcSJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF, 1, "Newton iteration for star.h diverged after %" PetscInt_FMT " iterations", i);
17584ff8c8bSHong Zhang   }
17684ff8c8bSHong Zhang converged:
17784ff8c8bSHong Zhang   cstar = PetscSqrtScalar(g * star.h);
17884ff8c8bSHong Zhang   if (L.u - cL < 0 && 0 < star.u - cstar) { /* 1-wave is sonic rarefaction */
17984ff8c8bSHong Zhang     PetscScalar ufan[2];
18084ff8c8bSHong Zhang     ufan[0] = 1 / g * PetscSqr(L.u / 3 + 2. / 3 * cL);
18184ff8c8bSHong Zhang     ufan[1] = PetscSqrtScalar(g * ufan[0]) * ufan[0];
18284ff8c8bSHong Zhang     ShallowFlux(phys, ufan, flux);
18384ff8c8bSHong Zhang   } else if (star.u + cstar < 0 && 0 < R.u + cR) { /* 2-wave is sonic rarefaction */
18484ff8c8bSHong Zhang     PetscScalar ufan[2];
18584ff8c8bSHong Zhang     ufan[0] = 1 / g * PetscSqr(R.u / 3 - 2. / 3 * cR);
18684ff8c8bSHong Zhang     ufan[1] = -PetscSqrtScalar(g * ufan[0]) * ufan[0];
18784ff8c8bSHong Zhang     ShallowFlux(phys, ufan, flux);
18884ff8c8bSHong 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)) {
18984ff8c8bSHong Zhang     /* 1-wave is right-travelling shock (supersonic) */
19084ff8c8bSHong Zhang     ShallowFlux(phys, uL, flux);
19184ff8c8bSHong 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)) {
19284ff8c8bSHong Zhang     /* 2-wave is left-travelling shock (supersonic) */
19384ff8c8bSHong Zhang     ShallowFlux(phys, uR, flux);
19484ff8c8bSHong Zhang   } else {
19584ff8c8bSHong Zhang     ustar[0] = star.h;
19684ff8c8bSHong Zhang     ustar[1] = star.h * star.u;
19784ff8c8bSHong Zhang     ShallowFlux(phys, ustar, flux);
19884ff8c8bSHong Zhang   }
19984ff8c8bSHong Zhang   *maxspeed = MaxAbs(MaxAbs(star.u - cstar, star.u + cstar), MaxAbs(L.u - cL, R.u + cR));
20084ff8c8bSHong Zhang   PetscFunctionReturn(0);
20184ff8c8bSHong Zhang }
20284ff8c8bSHong Zhang 
2039371c9d4SSatish Balay static PetscErrorCode PhysicsRiemann_Shallow_Rusanov(void *vctx, PetscInt m, const PetscScalar *uL, const PetscScalar *uR, PetscScalar *flux, PetscReal *maxspeed) {
20484ff8c8bSHong Zhang   ShallowCtx *phys = (ShallowCtx *)vctx;
20584ff8c8bSHong Zhang   PetscScalar g    = phys->gravity, fL[2], fR[2], s;
2069371c9d4SSatish Balay   struct {
2079371c9d4SSatish Balay     PetscScalar h, u;
2089371c9d4SSatish Balay   } 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 
2309371c9d4SSatish Balay static PetscErrorCode PhysicsCharacteristic_Conservative(void *vctx, PetscInt m, const PetscScalar *u, PetscScalar *X, PetscScalar *Xi, PetscReal *speeds) {
23184ff8c8bSHong Zhang   PetscInt i, j;
23284ff8c8bSHong Zhang 
23384ff8c8bSHong Zhang   PetscFunctionBeginUser;
23484ff8c8bSHong Zhang   for (i = 0; i < m; i++) {
23584ff8c8bSHong Zhang     for (j = 0; j < m; j++) Xi[i * m + j] = X[i * m + j] = (PetscScalar)(i == j);
23684ff8c8bSHong Zhang     speeds[i] = PETSC_MAX_REAL; /* Indicates invalid */
23784ff8c8bSHong Zhang   }
23884ff8c8bSHong Zhang   PetscFunctionReturn(0);
23984ff8c8bSHong Zhang }
24084ff8c8bSHong Zhang 
2419371c9d4SSatish Balay static PetscErrorCode PhysicsCharacteristic_Shallow(void *vctx, PetscInt m, const PetscScalar *u, PetscScalar *X, PetscScalar *Xi, PetscReal *speeds) {
24284ff8c8bSHong Zhang   ShallowCtx *phys = (ShallowCtx *)vctx;
24384ff8c8bSHong Zhang   PetscReal   c;
24484ff8c8bSHong Zhang   PetscReal   tol = 1e-6;
24584ff8c8bSHong Zhang 
24684ff8c8bSHong Zhang   PetscFunctionBeginUser;
24784ff8c8bSHong Zhang   c = PetscSqrtScalar(u[0] * phys->gravity);
24884ff8c8bSHong Zhang 
24984ff8c8bSHong Zhang   if (u[0] < tol) { /*Use conservative variables*/
25084ff8c8bSHong Zhang     X[0 * 2 + 0] = 1;
25184ff8c8bSHong Zhang     X[0 * 2 + 1] = 0;
25284ff8c8bSHong Zhang     X[1 * 2 + 0] = 0;
25384ff8c8bSHong Zhang     X[1 * 2 + 1] = 1;
25484ff8c8bSHong Zhang   } else {
25584ff8c8bSHong Zhang     speeds[0]    = u[1] / u[0] - c;
25684ff8c8bSHong Zhang     speeds[1]    = u[1] / u[0] + c;
25784ff8c8bSHong Zhang     X[0 * 2 + 0] = 1;
25884ff8c8bSHong Zhang     X[0 * 2 + 1] = speeds[0];
25984ff8c8bSHong Zhang     X[1 * 2 + 0] = 1;
26084ff8c8bSHong Zhang     X[1 * 2 + 1] = speeds[1];
26184ff8c8bSHong Zhang   }
26284ff8c8bSHong Zhang 
2639566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(Xi, X, 4));
2649566063dSJacob Faibussowitsch   PetscCall(PetscKernel_A_gets_inverse_A_2(Xi, 0, PETSC_FALSE, NULL));
26584ff8c8bSHong Zhang   PetscFunctionReturn(0);
26684ff8c8bSHong Zhang }
26784ff8c8bSHong Zhang 
2689371c9d4SSatish Balay static PetscErrorCode PhysicsSample_Shallow(void *vctx, PetscInt initial, FVBCType bctype, PetscReal xmin, PetscReal xmax, PetscReal t, PetscReal x, PetscReal *u) {
26984ff8c8bSHong Zhang   PetscFunctionBeginUser;
27008401ef6SPierre Jolivet   PetscCheck(t <= 0, PETSC_COMM_SELF, PETSC_ERR_SUP, "Exact solutions not implemented for t > 0");
27184ff8c8bSHong Zhang   switch (initial) {
27284ff8c8bSHong Zhang   case 0:
27384ff8c8bSHong Zhang     u[0] = (x < 0) ? 2 : 1; /* Standard Dam Break Problem */
27484ff8c8bSHong Zhang     u[1] = (x < 0) ? 0 : 0;
27584ff8c8bSHong Zhang     break;
27684ff8c8bSHong Zhang   case 1:
27784ff8c8bSHong Zhang     u[0] = (x < 10) ? 1 : 0.1; /*The Next 5 problems are standard Riemann problem tests */
27884ff8c8bSHong Zhang     u[1] = (x < 10) ? 2.5 : 0;
27984ff8c8bSHong Zhang     break;
28084ff8c8bSHong Zhang   case 2:
28184ff8c8bSHong Zhang     u[0] = (x < 25) ? 1 : 1;
28284ff8c8bSHong Zhang     u[1] = (x < 25) ? -5 : 5;
28384ff8c8bSHong Zhang     break;
28484ff8c8bSHong Zhang   case 3:
28584ff8c8bSHong Zhang     u[0] = (x < 20) ? 1 : 1e-12;
28684ff8c8bSHong Zhang     u[1] = (x < 20) ? 0 : 0;
28784ff8c8bSHong Zhang     break;
28884ff8c8bSHong Zhang   case 4:
28984ff8c8bSHong Zhang     u[0] = (x < 30) ? 1e-12 : 1;
29084ff8c8bSHong Zhang     u[1] = (x < 30) ? 0 : 0;
29184ff8c8bSHong Zhang     break;
29284ff8c8bSHong Zhang   case 5:
29384ff8c8bSHong Zhang     u[0] = (x < 25) ? 0.1 : 0.1;
29484ff8c8bSHong Zhang     u[1] = (x < 25) ? -0.3 : 0.3;
29584ff8c8bSHong Zhang     break;
29684ff8c8bSHong Zhang   case 6:
29784ff8c8bSHong Zhang     u[0] = 1 + 0.5 * PetscSinReal(2 * PETSC_PI * x);
29884ff8c8bSHong Zhang     u[1] = 1 * u[0];
29984ff8c8bSHong Zhang     break;
30084ff8c8bSHong Zhang   case 7:
30184ff8c8bSHong Zhang     if (x < -0.1) {
30284ff8c8bSHong Zhang       u[0] = 1e-9;
30384ff8c8bSHong Zhang       u[1] = 0.0;
30484ff8c8bSHong Zhang     } else if (x < 0.1) {
30584ff8c8bSHong Zhang       u[0] = 1.0;
30684ff8c8bSHong Zhang       u[1] = 0.0;
30784ff8c8bSHong Zhang     } else {
30884ff8c8bSHong Zhang       u[0] = 1e-9;
30984ff8c8bSHong Zhang       u[1] = 0.0;
31084ff8c8bSHong Zhang     }
31184ff8c8bSHong Zhang     break;
31284ff8c8bSHong Zhang   case 8:
31384ff8c8bSHong Zhang     if (x < -0.1) {
31484ff8c8bSHong Zhang       u[0] = 2;
31584ff8c8bSHong Zhang       u[1] = 0.0;
31684ff8c8bSHong Zhang     } else if (x < 0.1) {
31784ff8c8bSHong Zhang       u[0] = 3.0;
31884ff8c8bSHong Zhang       u[1] = 0.0;
31984ff8c8bSHong Zhang     } else {
32084ff8c8bSHong Zhang       u[0] = 2;
32184ff8c8bSHong Zhang       u[1] = 0.0;
32284ff8c8bSHong Zhang     }
32384ff8c8bSHong Zhang     break;
32484ff8c8bSHong Zhang   default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "unknown initial condition");
32584ff8c8bSHong Zhang   }
32684ff8c8bSHong Zhang   PetscFunctionReturn(0);
32784ff8c8bSHong Zhang }
32884ff8c8bSHong Zhang 
32984ff8c8bSHong Zhang /* Implements inflow conditions for the given initial conditions. Which conditions are actually enforced depends on
33084ff8c8bSHong Zhang    on the results of PhysicsSetInflowType_Shallow. */
3319371c9d4SSatish Balay static PetscErrorCode PhysicsInflow_Shallow(void *vctx, PetscReal t, PetscReal x, PetscReal *u) {
33284ff8c8bSHong Zhang   FVCtx *ctx = (FVCtx *)vctx;
33384ff8c8bSHong Zhang 
33484ff8c8bSHong Zhang   PetscFunctionBeginUser;
33584ff8c8bSHong Zhang   if (ctx->bctype == FVBC_INFLOW) {
33684ff8c8bSHong Zhang     switch (ctx->initial) {
33784ff8c8bSHong Zhang     case 0:
33884ff8c8bSHong Zhang     case 1:
33984ff8c8bSHong Zhang     case 2:
34084ff8c8bSHong Zhang     case 3:
34184ff8c8bSHong Zhang     case 4:
34284ff8c8bSHong Zhang     case 5:
3439371c9d4SSatish Balay       u[0] = 0;
3449371c9d4SSatish Balay       u[1] = 0.0; /* Left boundary conditions */
3459371c9d4SSatish Balay       u[2] = 0;
3469371c9d4SSatish Balay       u[3] = 0.0; /* Right boundary conditions */
34784ff8c8bSHong Zhang       break;
34884ff8c8bSHong Zhang     case 6:
3499371c9d4SSatish Balay       u[0] = 0;
3509371c9d4SSatish Balay       u[1] = 0.0; /* Left boundary conditions */
3519371c9d4SSatish Balay       u[2] = 0;
3529371c9d4SSatish Balay       u[3] = 0.0; /* Right boundary conditions */
35384ff8c8bSHong Zhang       break;
35484ff8c8bSHong Zhang     case 7:
3559371c9d4SSatish Balay       u[0] = 0;
3569371c9d4SSatish Balay       u[1] = 0.0; /* Left boundary conditions */
3579371c9d4SSatish Balay       u[2] = 0;
3589371c9d4SSatish Balay       u[3] = 0.0; /* Right boundary conditions */
35984ff8c8bSHong Zhang       break;
36084ff8c8bSHong Zhang     case 8:
3619371c9d4SSatish Balay       u[0] = 0;
3629371c9d4SSatish Balay       u[1] = 1.0; /* Left boundary conditions */
3639371c9d4SSatish Balay       u[2] = 0;
3649371c9d4SSatish Balay       u[3] = -1.0; /* Right boundary conditions */
36584ff8c8bSHong Zhang       break;
36684ff8c8bSHong Zhang     default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "unknown initial condition");
36784ff8c8bSHong Zhang     }
36884ff8c8bSHong Zhang   }
36984ff8c8bSHong Zhang   PetscFunctionReturn(0);
37084ff8c8bSHong Zhang }
37184ff8c8bSHong Zhang 
37284ff8c8bSHong Zhang /* Selects which boundary conditions are marked as inflow and which as outflow when FVBC_INFLOW is selected. */
3739371c9d4SSatish Balay static PetscErrorCode PhysicsSetInflowType_Shallow(FVCtx *ctx) {
37484ff8c8bSHong Zhang   PetscFunctionBeginUser;
37584ff8c8bSHong Zhang   switch (ctx->initial) {
37684ff8c8bSHong Zhang   case 0:
37784ff8c8bSHong Zhang   case 1:
37884ff8c8bSHong Zhang   case 2:
37984ff8c8bSHong Zhang   case 3:
38084ff8c8bSHong Zhang   case 4:
38184ff8c8bSHong Zhang   case 5:
38284ff8c8bSHong Zhang   case 6:
38384ff8c8bSHong Zhang   case 7:
38484ff8c8bSHong Zhang   case 8: /* Fix left and right momentum, height is outflow */
38584ff8c8bSHong Zhang     ctx->physics2.bcinflowindex[0] = PETSC_FALSE;
38684ff8c8bSHong Zhang     ctx->physics2.bcinflowindex[1] = PETSC_TRUE;
38784ff8c8bSHong Zhang     ctx->physics2.bcinflowindex[2] = PETSC_FALSE;
38884ff8c8bSHong Zhang     ctx->physics2.bcinflowindex[3] = PETSC_TRUE;
38984ff8c8bSHong Zhang     break;
39084ff8c8bSHong Zhang   default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "unknown initial condition");
39184ff8c8bSHong Zhang   }
39284ff8c8bSHong Zhang   PetscFunctionReturn(0);
39384ff8c8bSHong Zhang }
39484ff8c8bSHong Zhang 
3959371c9d4SSatish Balay static PetscErrorCode PhysicsCreate_Shallow(FVCtx *ctx) {
39684ff8c8bSHong Zhang   ShallowCtx       *user;
39784ff8c8bSHong Zhang   PetscFunctionList rlist = 0, rclist = 0;
39884ff8c8bSHong Zhang   char              rname[256] = "rusanov", rcname[256] = "characteristic";
39984ff8c8bSHong Zhang 
40084ff8c8bSHong Zhang   PetscFunctionBeginUser;
4019566063dSJacob Faibussowitsch   PetscCall(PetscNew(&user));
40284ff8c8bSHong Zhang   ctx->physics2.sample2         = PhysicsSample_Shallow;
40384ff8c8bSHong Zhang   ctx->physics2.inflow          = PhysicsInflow_Shallow;
40484ff8c8bSHong Zhang   ctx->physics2.destroy         = PhysicsDestroy_SimpleFree;
40584ff8c8bSHong Zhang   ctx->physics2.riemann2        = PhysicsRiemann_Shallow_Rusanov;
40684ff8c8bSHong Zhang   ctx->physics2.characteristic2 = PhysicsCharacteristic_Shallow;
40784ff8c8bSHong Zhang   ctx->physics2.user            = user;
40884ff8c8bSHong Zhang   ctx->physics2.dof             = 2;
40984ff8c8bSHong Zhang 
41084ff8c8bSHong Zhang   PetscMalloc1(2 * (ctx->physics2.dof), &ctx->physics2.bcinflowindex);
41184ff8c8bSHong Zhang   PhysicsSetInflowType_Shallow(ctx);
41284ff8c8bSHong Zhang 
4139566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy("height", &ctx->physics2.fieldname[0]));
4149566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy("momentum", &ctx->physics2.fieldname[1]));
41584ff8c8bSHong Zhang 
41684ff8c8bSHong Zhang   user->gravity = 9.81;
41784ff8c8bSHong Zhang 
4189566063dSJacob Faibussowitsch   PetscCall(RiemannListAdd_2WaySplit(&rlist, "exact", PhysicsRiemann_Shallow_Exact));
4199566063dSJacob Faibussowitsch   PetscCall(RiemannListAdd_2WaySplit(&rlist, "rusanov", PhysicsRiemann_Shallow_Rusanov));
4209566063dSJacob Faibussowitsch   PetscCall(ReconstructListAdd_2WaySplit(&rclist, "characteristic", PhysicsCharacteristic_Shallow));
4219566063dSJacob Faibussowitsch   PetscCall(ReconstructListAdd_2WaySplit(&rclist, "conservative", PhysicsCharacteristic_Conservative));
422d0609cedSBarry Smith   PetscOptionsBegin(ctx->comm, ctx->prefix, "Options for Shallow", "");
4239566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-physics_shallow_gravity", "Gravity", "", user->gravity, &user->gravity, NULL));
4249566063dSJacob Faibussowitsch   PetscCall(PetscOptionsFList("-physics_shallow_riemann", "Riemann solver", "", rlist, rname, rname, sizeof(rname), NULL));
4259566063dSJacob Faibussowitsch   PetscCall(PetscOptionsFList("-physics_shallow_reconstruct", "Reconstruction", "", rclist, rcname, rcname, sizeof(rcname), NULL));
426d0609cedSBarry Smith   PetscOptionsEnd();
4279566063dSJacob Faibussowitsch   PetscCall(RiemannListFind_2WaySplit(rlist, rname, &ctx->physics2.riemann2));
4289566063dSJacob Faibussowitsch   PetscCall(ReconstructListFind_2WaySplit(rclist, rcname, &ctx->physics2.characteristic2));
4299566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListDestroy(&rlist));
4309566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListDestroy(&rclist));
43184ff8c8bSHong Zhang   PetscFunctionReturn(0);
43284ff8c8bSHong Zhang }
43384ff8c8bSHong Zhang 
4349371c9d4SSatish Balay PetscErrorCode FVSample_2WaySplit(FVCtx *ctx, DM da, PetscReal time, Vec U) {
43584ff8c8bSHong Zhang   PetscScalar   *u, *uj, xj, xi;
43684ff8c8bSHong Zhang   PetscInt       i, j, k, dof, xs, xm, Mx;
43784ff8c8bSHong Zhang   const PetscInt N = 200;
43884ff8c8bSHong Zhang   PetscReal      hs, hf;
43984ff8c8bSHong Zhang 
44084ff8c8bSHong Zhang   PetscFunctionBeginUser;
4413c633725SBarry Smith   PetscCheck(ctx->physics2.sample2, PETSC_COMM_SELF, PETSC_ERR_SUP, "Physics has not provided a sampling function");
4429566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(da, 0, &Mx, 0, 0, 0, 0, 0, &dof, 0, 0, 0, 0, 0));
4439566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(da, &xs, 0, 0, &xm, 0, 0));
4449566063dSJacob Faibussowitsch   PetscCall(DMDAVecGetArray(da, U, &u));
4459566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(dof, &uj));
44684ff8c8bSHong Zhang   hs = (ctx->xmax - ctx->xmin) * 3.0 / 8.0 / ctx->sf;
44784ff8c8bSHong Zhang   hf = (ctx->xmax - ctx->xmin) / 4.0 / (ctx->fs - ctx->sf);
44884ff8c8bSHong Zhang   for (i = xs; i < xs + xm; i++) {
44984ff8c8bSHong Zhang     if (i < ctx->sf) {
45084ff8c8bSHong Zhang       xi = ctx->xmin + 0.5 * hs + i * hs;
45184ff8c8bSHong Zhang       /* Integrate over cell i using trapezoid rule with N points. */
45284ff8c8bSHong Zhang       for (k = 0; k < dof; k++) u[i * dof + k] = 0;
45384ff8c8bSHong Zhang       for (j = 0; j < N + 1; j++) {
45484ff8c8bSHong Zhang         xj = xi + hs * (j - N / 2) / (PetscReal)N;
4559566063dSJacob Faibussowitsch         PetscCall((*ctx->physics2.sample2)(ctx->physics2.user, ctx->initial, ctx->bctype, ctx->xmin, ctx->xmax, time, xj, uj));
45684ff8c8bSHong Zhang         for (k = 0; k < dof; k++) u[i * dof + k] += ((j == 0 || j == N) ? 0.5 : 1.0) * uj[k] / N;
45784ff8c8bSHong Zhang       }
45884ff8c8bSHong Zhang     } else if (i < ctx->fs) {
45984ff8c8bSHong Zhang       xi = ctx->xmin + ctx->sf * hs + 0.5 * hf + (i - ctx->sf) * hf;
46084ff8c8bSHong Zhang       /* Integrate over cell i using trapezoid rule with N points. */
46184ff8c8bSHong Zhang       for (k = 0; k < dof; k++) u[i * dof + k] = 0;
46284ff8c8bSHong Zhang       for (j = 0; j < N + 1; j++) {
46384ff8c8bSHong Zhang         xj = xi + hf * (j - N / 2) / (PetscReal)N;
4649566063dSJacob Faibussowitsch         PetscCall((*ctx->physics2.sample2)(ctx->physics2.user, ctx->initial, ctx->bctype, ctx->xmin, ctx->xmax, time, xj, uj));
46584ff8c8bSHong Zhang         for (k = 0; k < dof; k++) u[i * dof + k] += ((j == 0 || j == N) ? 0.5 : 1.0) * uj[k] / N;
46684ff8c8bSHong Zhang       }
46784ff8c8bSHong Zhang     } else {
46884ff8c8bSHong Zhang       xi = ctx->xmin + ctx->sf * hs + (ctx->fs - ctx->sf) * hf + 0.5 * hs + (i - ctx->fs) * hs;
46984ff8c8bSHong Zhang       /* Integrate over cell i using trapezoid rule with N points. */
47084ff8c8bSHong Zhang       for (k = 0; k < dof; k++) u[i * dof + k] = 0;
47184ff8c8bSHong Zhang       for (j = 0; j < N + 1; j++) {
47284ff8c8bSHong Zhang         xj = xi + hs * (j - N / 2) / (PetscReal)N;
4739566063dSJacob Faibussowitsch         PetscCall((*ctx->physics2.sample2)(ctx->physics2.user, ctx->initial, ctx->bctype, ctx->xmin, ctx->xmax, time, xj, uj));
47484ff8c8bSHong Zhang         for (k = 0; k < dof; k++) u[i * dof + k] += ((j == 0 || j == N) ? 0.5 : 1.0) * uj[k] / N;
47584ff8c8bSHong Zhang       }
47684ff8c8bSHong Zhang     }
47784ff8c8bSHong Zhang   }
4789566063dSJacob Faibussowitsch   PetscCall(DMDAVecRestoreArray(da, U, &u));
4799566063dSJacob Faibussowitsch   PetscCall(PetscFree(uj));
48084ff8c8bSHong Zhang   PetscFunctionReturn(0);
48184ff8c8bSHong Zhang }
48284ff8c8bSHong Zhang 
4839371c9d4SSatish Balay static PetscErrorCode SolutionErrorNorms_2WaySplit(FVCtx *ctx, DM da, PetscReal t, Vec X, PetscReal *nrm1) {
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 
5079371c9d4SSatish Balay PetscErrorCode FVRHSFunction_2WaySplit(TS ts, PetscReal time, Vec X, Vec F, void *vctx) {
50884ff8c8bSHong Zhang   FVCtx       *ctx = (FVCtx *)vctx;
50984ff8c8bSHong Zhang   PetscInt     i, j, k, Mx, dof, xs, xm, sf = ctx->sf, fs = ctx->fs;
51084ff8c8bSHong Zhang   PetscReal    hxf, hxs, cfl_idt = 0;
51184ff8c8bSHong Zhang   PetscScalar *x, *f, *slope;
51284ff8c8bSHong Zhang   Vec          Xloc;
51384ff8c8bSHong Zhang   DM           da;
51484ff8c8bSHong Zhang 
51584ff8c8bSHong Zhang   PetscFunctionBeginUser;
5169566063dSJacob Faibussowitsch   PetscCall(TSGetDM(ts, &da));
5179566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(da, &Xloc));                                 /* Xloc contains ghost points                                     */
5189566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(da, 0, &Mx, 0, 0, 0, 0, 0, &dof, 0, 0, 0, 0, 0)); /* Mx is the number of center points                              */
51984ff8c8bSHong Zhang   hxs = (ctx->xmax - ctx->xmin) * 3.0 / 8.0 / ctx->sf;
52084ff8c8bSHong Zhang   hxf = (ctx->xmax - ctx->xmin) / 4.0 / (ctx->fs - ctx->sf);
5219566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalBegin(da, X, INSERT_VALUES, Xloc)); /* X is solution vector which does not contain ghost points       */
5229566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalEnd(da, X, INSERT_VALUES, Xloc));
52384ff8c8bSHong Zhang 
5249566063dSJacob Faibussowitsch   PetscCall(VecZeroEntries(F)); /* F is the right hand side function corresponds to center points */
52584ff8c8bSHong Zhang 
5269566063dSJacob Faibussowitsch   PetscCall(DMDAVecGetArray(da, Xloc, &x));
5279566063dSJacob Faibussowitsch   PetscCall(DMDAVecGetArray(da, F, &f));
5289566063dSJacob Faibussowitsch   PetscCall(DMDAGetArray(da, PETSC_TRUE, &slope)); /* contains ghost points                                           */
5299566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(da, &xs, 0, 0, &xm, 0, 0));
53084ff8c8bSHong Zhang 
53184ff8c8bSHong Zhang   if (ctx->bctype == FVBC_OUTFLOW) {
53284ff8c8bSHong Zhang     for (i = xs - 2; i < 0; i++) {
53384ff8c8bSHong Zhang       for (j = 0; j < dof; j++) x[i * dof + j] = x[j];
53484ff8c8bSHong Zhang     }
53584ff8c8bSHong Zhang     for (i = Mx; i < xs + xm + 2; i++) {
53684ff8c8bSHong Zhang       for (j = 0; j < dof; j++) x[i * dof + j] = x[(xs + xm - 1) * dof + j];
53784ff8c8bSHong Zhang     }
53884ff8c8bSHong Zhang   }
53984ff8c8bSHong Zhang 
54084ff8c8bSHong Zhang   if (ctx->bctype == FVBC_INFLOW) {
54184ff8c8bSHong Zhang     /* See LeVeque, R. (2002). Finite Volume Methods for Hyperbolic Problems. doi:10.1017/CBO9780511791253
54284ff8c8bSHong Zhang     pages 137-138 for the scheme. */
54384ff8c8bSHong Zhang     if (xs == 0) { /* Left Boundary */
54484ff8c8bSHong Zhang       ctx->physics2.inflow(ctx, time, ctx->xmin, ctx->ub);
54584ff8c8bSHong Zhang       for (j = 0; j < dof; j++) {
54684ff8c8bSHong Zhang         if (ctx->physics2.bcinflowindex[j]) {
54784ff8c8bSHong Zhang           for (i = -2; i < 0; i++) x[i * dof + j] = 2.0 * ctx->ub[j] - x[-(i + 1) * dof + j];
54884ff8c8bSHong Zhang         } else {
54984ff8c8bSHong Zhang           for (i = -2; i < 0; i++) x[i * dof + j] = x[j]; /* Outflow */
55084ff8c8bSHong Zhang         }
55184ff8c8bSHong Zhang       }
55284ff8c8bSHong Zhang     }
55384ff8c8bSHong Zhang     if (xs + xm == Mx) { /* Right Boundary */
55484ff8c8bSHong Zhang       ctx->physics2.inflow(ctx, time, ctx->xmax, ctx->ub);
55584ff8c8bSHong Zhang       for (j = 0; j < dof; j++) {
55684ff8c8bSHong Zhang         if (ctx->physics2.bcinflowindex[dof + j]) {
55784ff8c8bSHong 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];
55884ff8c8bSHong Zhang         } else {
55984ff8c8bSHong Zhang           for (i = Mx; i < Mx + 2; i++) x[i * dof + j] = x[(Mx - 1) * dof + j]; /* Outflow */
56084ff8c8bSHong Zhang         }
56184ff8c8bSHong Zhang       }
56284ff8c8bSHong Zhang     }
56384ff8c8bSHong Zhang   }
56484ff8c8bSHong Zhang 
56584ff8c8bSHong Zhang   for (i = xs - 1; i < xs + xm + 1; i++) {
56684ff8c8bSHong Zhang     struct _LimitInfo info;
56784ff8c8bSHong Zhang     PetscScalar      *cjmpL, *cjmpR;
56884ff8c8bSHong Zhang     /* Determine the right eigenvectors R, where A = R \Lambda R^{-1} */
5699566063dSJacob Faibussowitsch     PetscCall((*ctx->physics2.characteristic2)(ctx->physics2.user, dof, &x[i * dof], ctx->R, ctx->Rinv, ctx->speeds));
57084ff8c8bSHong Zhang     /* Evaluate jumps across interfaces (i-1, i) and (i, i+1), put in characteristic basis */
5719566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(ctx->cjmpLR, 2 * dof));
57284ff8c8bSHong Zhang     cjmpL = &ctx->cjmpLR[0];
57384ff8c8bSHong Zhang     cjmpR = &ctx->cjmpLR[dof];
57484ff8c8bSHong Zhang     for (j = 0; j < dof; j++) {
57584ff8c8bSHong Zhang       PetscScalar jmpL, jmpR;
57684ff8c8bSHong Zhang       jmpL = x[(i + 0) * dof + j] - x[(i - 1) * dof + j];
57784ff8c8bSHong Zhang       jmpR = x[(i + 1) * dof + j] - x[(i + 0) * dof + j];
57884ff8c8bSHong Zhang       for (k = 0; k < dof; k++) {
57984ff8c8bSHong Zhang         cjmpL[k] += ctx->Rinv[k + j * dof] * jmpL;
58084ff8c8bSHong Zhang         cjmpR[k] += ctx->Rinv[k + j * dof] * jmpR;
58184ff8c8bSHong Zhang       }
58284ff8c8bSHong Zhang     }
58384ff8c8bSHong Zhang     /* Apply limiter to the left and right characteristic jumps */
58484ff8c8bSHong Zhang     info.m   = dof;
58584ff8c8bSHong Zhang     info.hxs = hxs;
58684ff8c8bSHong Zhang     info.hxf = hxf;
58784ff8c8bSHong Zhang     (*ctx->limit2)(&info, cjmpL, cjmpR, ctx->sf, ctx->fs, i, ctx->cslope);
58884ff8c8bSHong Zhang     for (j = 0; j < dof; j++) {
58984ff8c8bSHong Zhang       PetscScalar tmp = 0;
59084ff8c8bSHong Zhang       for (k = 0; k < dof; k++) tmp += ctx->R[j + k * dof] * ctx->cslope[k];
59184ff8c8bSHong Zhang       slope[i * dof + j] = tmp;
59284ff8c8bSHong Zhang     }
59384ff8c8bSHong Zhang   }
59484ff8c8bSHong Zhang 
59584ff8c8bSHong Zhang   for (i = xs; i < xs + xm + 1; i++) {
59684ff8c8bSHong Zhang     PetscReal    maxspeed;
59784ff8c8bSHong Zhang     PetscScalar *uL, *uR;
59884ff8c8bSHong Zhang     uL = &ctx->uLR[0];
59984ff8c8bSHong Zhang     uR = &ctx->uLR[dof];
60084ff8c8bSHong Zhang     if (i < sf) { /* slow region */
60184ff8c8bSHong Zhang       for (j = 0; j < dof; j++) {
60284ff8c8bSHong Zhang         uL[j] = x[(i - 1) * dof + j] + slope[(i - 1) * dof + j] * hxs / 2;
60384ff8c8bSHong Zhang         uR[j] = x[(i - 0) * dof + j] - slope[(i - 0) * dof + j] * hxs / 2;
60484ff8c8bSHong Zhang       }
6059566063dSJacob Faibussowitsch       PetscCall((*ctx->physics2.riemann2)(ctx->physics2.user, dof, uL, uR, ctx->flux, &maxspeed));
60684ff8c8bSHong Zhang       if (i > xs) {
60784ff8c8bSHong Zhang         for (j = 0; j < dof; j++) f[(i - 1) * dof + j] -= ctx->flux[j] / hxs;
60884ff8c8bSHong Zhang       }
60984ff8c8bSHong Zhang       if (i < xs + xm) {
61084ff8c8bSHong Zhang         for (j = 0; j < dof; j++) f[i * dof + j] += ctx->flux[j] / hxs;
61184ff8c8bSHong Zhang       }
61284ff8c8bSHong Zhang     } else if (i == sf) { /* interface between the slow region and the fast region */
61384ff8c8bSHong Zhang       for (j = 0; j < dof; j++) {
61484ff8c8bSHong Zhang         uL[j] = x[(i - 1) * dof + j] + slope[(i - 1) * dof + j] * hxs / 2;
61584ff8c8bSHong Zhang         uR[j] = x[(i - 0) * dof + j] - slope[(i - 0) * dof + j] * hxf / 2;
61684ff8c8bSHong Zhang       }
6179566063dSJacob Faibussowitsch       PetscCall((*ctx->physics2.riemann2)(ctx->physics2.user, dof, uL, uR, ctx->flux, &maxspeed));
61884ff8c8bSHong Zhang       if (i > xs) {
61984ff8c8bSHong Zhang         for (j = 0; j < dof; j++) f[(i - 1) * dof + j] -= ctx->flux[j] / hxs;
62084ff8c8bSHong Zhang       }
62184ff8c8bSHong Zhang       if (i < xs + xm) {
62284ff8c8bSHong Zhang         for (j = 0; j < dof; j++) f[i * dof + j] += ctx->flux[j] / hxf;
62384ff8c8bSHong Zhang       }
62484ff8c8bSHong Zhang     } else if (i > sf && i < fs) { /* fast region */
62584ff8c8bSHong Zhang       for (j = 0; j < dof; j++) {
62684ff8c8bSHong Zhang         uL[j] = x[(i - 1) * dof + j] + slope[(i - 1) * dof + j] * hxf / 2;
62784ff8c8bSHong Zhang         uR[j] = x[(i - 0) * dof + j] - slope[(i - 0) * dof + j] * hxf / 2;
62884ff8c8bSHong Zhang       }
6299566063dSJacob Faibussowitsch       PetscCall((*ctx->physics2.riemann2)(ctx->physics2.user, dof, uL, uR, ctx->flux, &maxspeed));
63084ff8c8bSHong Zhang       if (i > xs) {
63184ff8c8bSHong Zhang         for (j = 0; j < dof; j++) f[(i - 1) * dof + j] -= ctx->flux[j] / hxf;
63284ff8c8bSHong Zhang       }
63384ff8c8bSHong Zhang       if (i < xs + xm) {
63484ff8c8bSHong Zhang         for (j = 0; j < dof; j++) f[i * dof + j] += ctx->flux[j] / hxf;
63584ff8c8bSHong Zhang       }
63684ff8c8bSHong Zhang     } else if (i == fs) { /* interface between the fast region and the slow region */
63784ff8c8bSHong Zhang       for (j = 0; j < dof; j++) {
63884ff8c8bSHong Zhang         uL[j] = x[(i - 1) * dof + j] + slope[(i - 1) * dof + j] * hxf / 2;
63984ff8c8bSHong Zhang         uR[j] = x[(i - 0) * dof + j] - slope[(i - 0) * dof + j] * hxs / 2;
64084ff8c8bSHong Zhang       }
6419566063dSJacob Faibussowitsch       PetscCall((*ctx->physics2.riemann2)(ctx->physics2.user, dof, uL, uR, ctx->flux, &maxspeed));
64284ff8c8bSHong Zhang       if (i > xs) {
64384ff8c8bSHong Zhang         for (j = 0; j < dof; j++) f[(i - 1) * dof + j] -= ctx->flux[j] / hxf;
64484ff8c8bSHong Zhang       }
64584ff8c8bSHong Zhang       if (i < xs + xm) {
64684ff8c8bSHong Zhang         for (j = 0; j < dof; j++) f[i * dof + j] += ctx->flux[j] / hxs;
64784ff8c8bSHong Zhang       }
64884ff8c8bSHong Zhang     } else { /* slow region */
64984ff8c8bSHong Zhang       for (j = 0; j < dof; j++) {
65084ff8c8bSHong Zhang         uL[j] = x[(i - 1) * dof + j] + slope[(i - 1) * dof + j] * hxs / 2;
65184ff8c8bSHong Zhang         uR[j] = x[(i - 0) * dof + j] - slope[(i - 0) * dof + j] * hxs / 2;
65284ff8c8bSHong Zhang       }
6539566063dSJacob Faibussowitsch       PetscCall((*ctx->physics2.riemann2)(ctx->physics2.user, dof, uL, uR, ctx->flux, &maxspeed));
65484ff8c8bSHong Zhang       cfl_idt = PetscMax(cfl_idt, PetscAbsScalar(maxspeed / hxs)); /* Max allowable value of 1/Delta t */
65584ff8c8bSHong Zhang       if (i > xs) {
65684ff8c8bSHong Zhang         for (j = 0; j < dof; j++) f[(i - 1) * dof + j] -= ctx->flux[j] / hxs;
65784ff8c8bSHong Zhang       }
65884ff8c8bSHong Zhang       if (i < xs + xm) {
65984ff8c8bSHong Zhang         for (j = 0; j < dof; j++) f[i * dof + j] += ctx->flux[j] / hxs;
66084ff8c8bSHong Zhang       }
66184ff8c8bSHong Zhang     }
66284ff8c8bSHong Zhang   }
6639566063dSJacob Faibussowitsch   PetscCall(DMDAVecRestoreArray(da, Xloc, &x));
6649566063dSJacob Faibussowitsch   PetscCall(DMDAVecRestoreArray(da, F, &f));
6659566063dSJacob Faibussowitsch   PetscCall(DMDARestoreArray(da, PETSC_TRUE, &slope));
6669566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(da, &Xloc));
6679566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Allreduce(&cfl_idt, &ctx->cfl_idt, 1, MPIU_SCALAR, MPIU_MAX, PetscObjectComm((PetscObject)da)));
66884ff8c8bSHong Zhang   if (0) {
66984ff8c8bSHong Zhang     /* We need to a way to inform the TS of a CFL constraint, this is a debugging fragment */
67084ff8c8bSHong Zhang     PetscReal dt, tnow;
6719566063dSJacob Faibussowitsch     PetscCall(TSGetTimeStep(ts, &dt));
6729566063dSJacob Faibussowitsch     PetscCall(TSGetTime(ts, &tnow));
67384ff8c8bSHong Zhang     if (dt > 0.5 / ctx->cfl_idt) {
67484ff8c8bSHong Zhang       if (1) {
6759566063dSJacob 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)));
67698921bdaSJacob Faibussowitsch       } else SETERRQ(PETSC_COMM_SELF, 1, "Stability constraint exceeded, %g > %g", (double)dt, (double)(ctx->cfl / ctx->cfl_idt));
67784ff8c8bSHong Zhang     }
67884ff8c8bSHong Zhang   }
67984ff8c8bSHong Zhang   PetscFunctionReturn(0);
68084ff8c8bSHong Zhang }
68184ff8c8bSHong Zhang 
68284ff8c8bSHong Zhang /* --------------------------------- Finite Volume Solver for slow components ----------------------------------- */
6839371c9d4SSatish Balay PetscErrorCode FVRHSFunctionslow_2WaySplit(TS ts, PetscReal time, Vec X, Vec F, void *vctx) {
68484ff8c8bSHong Zhang   FVCtx       *ctx = (FVCtx *)vctx;
68584ff8c8bSHong Zhang   PetscInt     i, j, k, Mx, dof, xs, xm, islow = 0, sf = ctx->sf, fs = ctx->fs, lsbwidth = ctx->lsbwidth, rsbwidth = ctx->rsbwidth;
68684ff8c8bSHong Zhang   PetscReal    hxs, hxf, cfl_idt = 0;
68784ff8c8bSHong Zhang   PetscScalar *x, *f, *slope;
68884ff8c8bSHong Zhang   Vec          Xloc;
68984ff8c8bSHong Zhang   DM           da;
69084ff8c8bSHong Zhang 
69184ff8c8bSHong Zhang   PetscFunctionBeginUser;
6929566063dSJacob Faibussowitsch   PetscCall(TSGetDM(ts, &da));
6939566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(da, &Xloc));
6949566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(da, 0, &Mx, 0, 0, 0, 0, 0, &dof, 0, 0, 0, 0, 0));
69584ff8c8bSHong Zhang   hxs = (ctx->xmax - ctx->xmin) * 3.0 / 8.0 / ctx->sf;
69684ff8c8bSHong Zhang   hxf = (ctx->xmax - ctx->xmin) / 4.0 / (ctx->fs - ctx->sf);
6979566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalBegin(da, X, INSERT_VALUES, Xloc));
6989566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalEnd(da, X, INSERT_VALUES, Xloc));
6999566063dSJacob Faibussowitsch   PetscCall(VecZeroEntries(F));
7009566063dSJacob Faibussowitsch   PetscCall(DMDAVecGetArray(da, Xloc, &x));
7019566063dSJacob Faibussowitsch   PetscCall(VecGetArray(F, &f));
7029566063dSJacob Faibussowitsch   PetscCall(DMDAGetArray(da, PETSC_TRUE, &slope));
7039566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(da, &xs, 0, 0, &xm, 0, 0));
70484ff8c8bSHong Zhang 
70584ff8c8bSHong Zhang   if (ctx->bctype == FVBC_OUTFLOW) {
70684ff8c8bSHong Zhang     for (i = xs - 2; i < 0; i++) {
70784ff8c8bSHong Zhang       for (j = 0; j < dof; j++) x[i * dof + j] = x[j];
70884ff8c8bSHong Zhang     }
70984ff8c8bSHong Zhang     for (i = Mx; i < xs + xm + 2; i++) {
71084ff8c8bSHong Zhang       for (j = 0; j < dof; j++) x[i * dof + j] = x[(xs + xm - 1) * dof + j];
71184ff8c8bSHong Zhang     }
71284ff8c8bSHong Zhang   }
71384ff8c8bSHong Zhang   if (ctx->bctype == FVBC_INFLOW) {
71484ff8c8bSHong Zhang     /* See LeVeque, R. (2002). Finite Volume Methods for Hyperbolic Problems. doi:10.1017/CBO9780511791253
71584ff8c8bSHong Zhang     pages 137-138 for the scheme. */
71684ff8c8bSHong Zhang     if (xs == 0) { /* Left Boundary */
71784ff8c8bSHong Zhang       ctx->physics2.inflow(ctx, time, ctx->xmin, ctx->ub);
71884ff8c8bSHong Zhang       for (j = 0; j < dof; j++) {
71984ff8c8bSHong Zhang         if (ctx->physics2.bcinflowindex[j] == PETSC_TRUE) {
72084ff8c8bSHong Zhang           for (i = -2; i < 0; i++) x[i * dof + j] = 2.0 * ctx->ub[j] - x[-(i + 1) * dof + j];
72184ff8c8bSHong Zhang         } else {
72284ff8c8bSHong Zhang           for (i = -2; i < 0; i++) x[i * dof + j] = x[j]; /* Outflow */
72384ff8c8bSHong Zhang         }
72484ff8c8bSHong Zhang       }
72584ff8c8bSHong Zhang     }
72684ff8c8bSHong Zhang     if (xs + xm == Mx) { /* Right Boundary */
72784ff8c8bSHong Zhang       ctx->physics2.inflow(ctx, time, ctx->xmax, ctx->ub);
72884ff8c8bSHong Zhang       for (j = 0; j < dof; j++) {
72984ff8c8bSHong Zhang         if (ctx->physics2.bcinflowindex[dof + j] == PETSC_TRUE) {
73084ff8c8bSHong 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];
73184ff8c8bSHong Zhang         } else {
73284ff8c8bSHong Zhang           for (i = Mx; i < Mx + 2; i++) x[i * dof + j] = x[(Mx - 1) * dof + j]; /* Outflow */
73384ff8c8bSHong Zhang         }
73484ff8c8bSHong Zhang       }
73584ff8c8bSHong Zhang     }
73684ff8c8bSHong Zhang   }
73784ff8c8bSHong Zhang   for (i = xs - 1; i < xs + xm + 1; i++) {
73884ff8c8bSHong Zhang     struct _LimitInfo info;
73984ff8c8bSHong Zhang     PetscScalar      *cjmpL, *cjmpR;
74084ff8c8bSHong Zhang     if (i < sf - lsbwidth + 1 || i > fs + rsbwidth - 2) { /* slow components and the first and last fast components */
74184ff8c8bSHong Zhang       /* Determine the right eigenvectors R, where A = R \Lambda R^{-1} */
7429566063dSJacob Faibussowitsch       PetscCall((*ctx->physics2.characteristic2)(ctx->physics2.user, dof, &x[i * dof], ctx->R, ctx->Rinv, ctx->speeds));
74384ff8c8bSHong Zhang       /* Evaluate jumps across interfaces (i-1, i) and (i, i+1), put in characteristic basis */
7449566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(ctx->cjmpLR, 2 * dof));
74584ff8c8bSHong Zhang       cjmpL = &ctx->cjmpLR[0];
74684ff8c8bSHong Zhang       cjmpR = &ctx->cjmpLR[dof];
74784ff8c8bSHong Zhang       for (j = 0; j < dof; j++) {
74884ff8c8bSHong Zhang         PetscScalar jmpL, jmpR;
74984ff8c8bSHong Zhang         jmpL = x[(i + 0) * dof + j] - x[(i - 1) * dof + j];
75084ff8c8bSHong Zhang         jmpR = x[(i + 1) * dof + j] - x[(i + 0) * dof + j];
75184ff8c8bSHong Zhang         for (k = 0; k < dof; k++) {
75284ff8c8bSHong Zhang           cjmpL[k] += ctx->Rinv[k + j * dof] * jmpL;
75384ff8c8bSHong Zhang           cjmpR[k] += ctx->Rinv[k + j * dof] * jmpR;
75484ff8c8bSHong Zhang         }
75584ff8c8bSHong Zhang       }
75684ff8c8bSHong Zhang       /* Apply limiter to the left and right characteristic jumps */
75784ff8c8bSHong Zhang       info.m   = dof;
75884ff8c8bSHong Zhang       info.hxs = hxs;
75984ff8c8bSHong Zhang       info.hxf = hxf;
76084ff8c8bSHong Zhang       (*ctx->limit2)(&info, cjmpL, cjmpR, ctx->sf, ctx->fs, i, ctx->cslope);
76184ff8c8bSHong Zhang       for (j = 0; j < dof; j++) {
76284ff8c8bSHong Zhang         PetscScalar tmp = 0;
76384ff8c8bSHong Zhang         for (k = 0; k < dof; k++) tmp += ctx->R[j + k * dof] * ctx->cslope[k];
76484ff8c8bSHong Zhang         slope[i * dof + j] = tmp;
76584ff8c8bSHong Zhang       }
76684ff8c8bSHong Zhang     }
76784ff8c8bSHong Zhang   }
76884ff8c8bSHong Zhang 
76984ff8c8bSHong Zhang   for (i = xs; i < xs + xm + 1; i++) {
77084ff8c8bSHong Zhang     PetscReal    maxspeed;
77184ff8c8bSHong Zhang     PetscScalar *uL, *uR;
77284ff8c8bSHong Zhang     uL = &ctx->uLR[0];
77384ff8c8bSHong Zhang     uR = &ctx->uLR[dof];
77484ff8c8bSHong Zhang     if (i < sf - lsbwidth) { /* slow region */
77584ff8c8bSHong Zhang       for (j = 0; j < dof; j++) {
77684ff8c8bSHong Zhang         uL[j] = x[(i - 1) * dof + j] + slope[(i - 1) * dof + j] * hxs / 2;
77784ff8c8bSHong Zhang         uR[j] = x[(i - 0) * dof + j] - slope[(i - 0) * dof + j] * hxs / 2;
77884ff8c8bSHong Zhang       }
7799566063dSJacob Faibussowitsch       PetscCall((*ctx->physics2.riemann2)(ctx->physics2.user, dof, uL, uR, ctx->flux, &maxspeed));
78084ff8c8bSHong Zhang       cfl_idt = PetscMax(cfl_idt, PetscAbsScalar(maxspeed / hxs)); /* Max allowable value of 1/Delta t */
78184ff8c8bSHong Zhang       if (i > xs) {
78284ff8c8bSHong Zhang         for (j = 0; j < dof; j++) f[(islow - 1) * dof + j] -= ctx->flux[j] / hxs;
78384ff8c8bSHong Zhang       }
78484ff8c8bSHong Zhang       if (i < xs + xm) {
78584ff8c8bSHong Zhang         for (j = 0; j < dof; j++) f[islow * dof + j] += ctx->flux[j] / hxs;
78684ff8c8bSHong Zhang         islow++;
78784ff8c8bSHong Zhang       }
78884ff8c8bSHong Zhang     }
78984ff8c8bSHong Zhang     if (i == sf - lsbwidth) { /* interface between the slow region and the fast region */
79084ff8c8bSHong Zhang       for (j = 0; j < dof; j++) {
79184ff8c8bSHong Zhang         uL[j] = x[(i - 1) * dof + j] + slope[(i - 1) * dof + j] * hxs / 2;
79284ff8c8bSHong Zhang         uR[j] = x[(i - 0) * dof + j] - slope[(i - 0) * dof + j] * hxs / 2;
79384ff8c8bSHong Zhang       }
7949566063dSJacob Faibussowitsch       PetscCall((*ctx->physics2.riemann2)(ctx->physics2.user, dof, uL, uR, ctx->flux, &maxspeed));
79584ff8c8bSHong Zhang       if (i > xs) {
79684ff8c8bSHong Zhang         for (j = 0; j < dof; j++) f[(islow - 1) * dof + j] -= ctx->flux[j] / hxs;
79784ff8c8bSHong Zhang       }
79884ff8c8bSHong Zhang     }
79984ff8c8bSHong Zhang     if (i == fs + rsbwidth) { /* slow region */
80084ff8c8bSHong Zhang       for (j = 0; j < dof; j++) {
80184ff8c8bSHong Zhang         uL[j] = x[(i - 1) * dof + j] + slope[(i - 1) * dof + j] * hxs / 2;
80284ff8c8bSHong Zhang         uR[j] = x[(i - 0) * dof + j] - slope[(i - 0) * dof + j] * hxs / 2;
80384ff8c8bSHong Zhang       }
8049566063dSJacob Faibussowitsch       PetscCall((*ctx->physics2.riemann2)(ctx->physics2.user, dof, uL, uR, ctx->flux, &maxspeed));
80584ff8c8bSHong Zhang       if (i < xs + xm) {
80684ff8c8bSHong Zhang         for (j = 0; j < dof; j++) f[islow * dof + j] += ctx->flux[j] / hxs;
80784ff8c8bSHong Zhang         islow++;
80884ff8c8bSHong Zhang       }
80984ff8c8bSHong Zhang     }
81084ff8c8bSHong Zhang     if (i > fs + rsbwidth) { /* slow region */
81184ff8c8bSHong Zhang       for (j = 0; j < dof; j++) {
81284ff8c8bSHong Zhang         uL[j] = x[(i - 1) * dof + j] + slope[(i - 1) * dof + j] * hxs / 2;
81384ff8c8bSHong Zhang         uR[j] = x[(i - 0) * dof + j] - slope[(i - 0) * dof + j] * hxs / 2;
81484ff8c8bSHong Zhang       }
8159566063dSJacob Faibussowitsch       PetscCall((*ctx->physics2.riemann2)(ctx->physics2.user, dof, uL, uR, ctx->flux, &maxspeed));
81684ff8c8bSHong Zhang       if (i > xs) {
81784ff8c8bSHong Zhang         for (j = 0; j < dof; j++) f[(islow - 1) * dof + j] -= ctx->flux[j] / hxs;
81884ff8c8bSHong Zhang       }
81984ff8c8bSHong Zhang       if (i < xs + xm) {
82084ff8c8bSHong Zhang         for (j = 0; j < dof; j++) f[islow * dof + j] += ctx->flux[j] / hxs;
82184ff8c8bSHong Zhang         islow++;
82284ff8c8bSHong Zhang       }
82384ff8c8bSHong Zhang     }
82484ff8c8bSHong Zhang   }
8259566063dSJacob Faibussowitsch   PetscCall(DMDAVecRestoreArray(da, Xloc, &x));
8269566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(F, &f));
8279566063dSJacob Faibussowitsch   PetscCall(DMDARestoreArray(da, PETSC_TRUE, &slope));
8289566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(da, &Xloc));
8299566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Allreduce(&cfl_idt, &ctx->cfl_idt, 1, MPIU_SCALAR, MPIU_MAX, PetscObjectComm((PetscObject)da)));
83084ff8c8bSHong Zhang   PetscFunctionReturn(0);
83184ff8c8bSHong Zhang }
83284ff8c8bSHong Zhang 
8339371c9d4SSatish Balay PetscErrorCode FVRHSFunctionslowbuffer_2WaySplit(TS ts, PetscReal time, Vec X, Vec F, void *vctx) {
83484ff8c8bSHong Zhang   FVCtx       *ctx = (FVCtx *)vctx;
83584ff8c8bSHong Zhang   PetscInt     i, j, k, Mx, dof, xs, xm, islow = 0, sf = ctx->sf, fs = ctx->fs, lsbwidth = ctx->lsbwidth, rsbwidth = ctx->rsbwidth;
83684ff8c8bSHong Zhang   PetscReal    hxs, hxf;
83784ff8c8bSHong Zhang   PetscScalar *x, *f, *slope;
83884ff8c8bSHong Zhang   Vec          Xloc;
83984ff8c8bSHong Zhang   DM           da;
84084ff8c8bSHong Zhang 
84184ff8c8bSHong Zhang   PetscFunctionBeginUser;
8429566063dSJacob Faibussowitsch   PetscCall(TSGetDM(ts, &da));
8439566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(da, &Xloc));
8449566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(da, 0, &Mx, 0, 0, 0, 0, 0, &dof, 0, 0, 0, 0, 0));
84584ff8c8bSHong Zhang   hxs = (ctx->xmax - ctx->xmin) * 3.0 / 8.0 / ctx->sf;
84684ff8c8bSHong Zhang   hxf = (ctx->xmax - ctx->xmin) / 4.0 / (ctx->fs - ctx->sf);
8479566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalBegin(da, X, INSERT_VALUES, Xloc));
8489566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalEnd(da, X, INSERT_VALUES, Xloc));
8499566063dSJacob Faibussowitsch   PetscCall(VecZeroEntries(F));
8509566063dSJacob Faibussowitsch   PetscCall(DMDAVecGetArray(da, Xloc, &x));
8519566063dSJacob Faibussowitsch   PetscCall(VecGetArray(F, &f));
8529566063dSJacob Faibussowitsch   PetscCall(DMDAGetArray(da, PETSC_TRUE, &slope));
8539566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(da, &xs, 0, 0, &xm, 0, 0));
85484ff8c8bSHong Zhang 
85584ff8c8bSHong Zhang   if (ctx->bctype == FVBC_OUTFLOW) {
85684ff8c8bSHong Zhang     for (i = xs - 2; i < 0; i++) {
85784ff8c8bSHong Zhang       for (j = 0; j < dof; j++) x[i * dof + j] = x[j];
85884ff8c8bSHong Zhang     }
85984ff8c8bSHong Zhang     for (i = Mx; i < xs + xm + 2; i++) {
86084ff8c8bSHong Zhang       for (j = 0; j < dof; j++) x[i * dof + j] = x[(xs + xm - 1) * dof + j];
86184ff8c8bSHong Zhang     }
86284ff8c8bSHong Zhang   }
86384ff8c8bSHong Zhang   if (ctx->bctype == FVBC_INFLOW) {
86484ff8c8bSHong Zhang     /* See LeVeque, R. (2002). Finite Volume Methods for Hyperbolic Problems. doi:10.1017/CBO9780511791253
86584ff8c8bSHong Zhang     pages 137-138 for the scheme. */
86684ff8c8bSHong Zhang     if (xs == 0) { /* Left Boundary */
86784ff8c8bSHong Zhang       ctx->physics2.inflow(ctx, time, ctx->xmin, ctx->ub);
86884ff8c8bSHong Zhang       for (j = 0; j < dof; j++) {
86984ff8c8bSHong Zhang         if (ctx->physics2.bcinflowindex[j] == PETSC_TRUE) {
87084ff8c8bSHong Zhang           for (i = -2; i < 0; i++) x[i * dof + j] = 2.0 * ctx->ub[j] - x[-(i + 1) * dof + j];
87184ff8c8bSHong Zhang         } else {
87284ff8c8bSHong Zhang           for (i = -2; i < 0; i++) x[i * dof + j] = x[j]; /* Outflow */
87384ff8c8bSHong Zhang         }
87484ff8c8bSHong Zhang       }
87584ff8c8bSHong Zhang     }
87684ff8c8bSHong Zhang     if (xs + xm == Mx) { /* Right Boundary */
87784ff8c8bSHong Zhang       ctx->physics2.inflow(ctx, time, ctx->xmax, ctx->ub);
87884ff8c8bSHong Zhang       for (j = 0; j < dof; j++) {
87984ff8c8bSHong Zhang         if (ctx->physics2.bcinflowindex[dof + j] == PETSC_TRUE) {
88084ff8c8bSHong 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];
88184ff8c8bSHong Zhang         } else {
88284ff8c8bSHong Zhang           for (i = Mx; i < Mx + 2; i++) x[i * dof + j] = x[(Mx - 1) * dof + j]; /* Outflow */
88384ff8c8bSHong Zhang         }
88484ff8c8bSHong Zhang       }
88584ff8c8bSHong Zhang     }
88684ff8c8bSHong Zhang   }
88784ff8c8bSHong Zhang   for (i = xs - 1; i < xs + xm + 1; i++) {
88884ff8c8bSHong Zhang     struct _LimitInfo info;
88984ff8c8bSHong Zhang     PetscScalar      *cjmpL, *cjmpR;
89084ff8c8bSHong Zhang     if ((i > sf - lsbwidth - 2 && i < sf + 1) || (i > fs - 2 && i < fs + rsbwidth + 1)) {
89184ff8c8bSHong Zhang       /* Determine the right eigenvectors R, where A = R \Lambda R^{-1} */
8929566063dSJacob Faibussowitsch       PetscCall((*ctx->physics2.characteristic2)(ctx->physics2.user, dof, &x[i * dof], ctx->R, ctx->Rinv, ctx->speeds));
89384ff8c8bSHong Zhang       /* Evaluate jumps across interfaces (i-1, i) and (i, i+1), put in characteristic basis */
8949566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(ctx->cjmpLR, 2 * dof));
89584ff8c8bSHong Zhang       cjmpL = &ctx->cjmpLR[0];
89684ff8c8bSHong Zhang       cjmpR = &ctx->cjmpLR[dof];
89784ff8c8bSHong Zhang       for (j = 0; j < dof; j++) {
89884ff8c8bSHong Zhang         PetscScalar jmpL, jmpR;
89984ff8c8bSHong Zhang         jmpL = x[(i + 0) * dof + j] - x[(i - 1) * dof + j];
90084ff8c8bSHong Zhang         jmpR = x[(i + 1) * dof + j] - x[(i + 0) * dof + j];
90184ff8c8bSHong Zhang         for (k = 0; k < dof; k++) {
90284ff8c8bSHong Zhang           cjmpL[k] += ctx->Rinv[k + j * dof] * jmpL;
90384ff8c8bSHong Zhang           cjmpR[k] += ctx->Rinv[k + j * dof] * jmpR;
90484ff8c8bSHong Zhang         }
90584ff8c8bSHong Zhang       }
90684ff8c8bSHong Zhang       /* Apply limiter to the left and right characteristic jumps */
90784ff8c8bSHong Zhang       info.m   = dof;
90884ff8c8bSHong Zhang       info.hxs = hxs;
90984ff8c8bSHong Zhang       info.hxf = hxf;
91084ff8c8bSHong Zhang       (*ctx->limit2)(&info, cjmpL, cjmpR, ctx->sf, ctx->fs, i, ctx->cslope);
91184ff8c8bSHong Zhang       for (j = 0; j < dof; j++) {
91284ff8c8bSHong Zhang         PetscScalar tmp = 0;
91384ff8c8bSHong Zhang         for (k = 0; k < dof; k++) tmp += ctx->R[j + k * dof] * ctx->cslope[k];
91484ff8c8bSHong Zhang         slope[i * dof + j] = tmp;
91584ff8c8bSHong Zhang       }
91684ff8c8bSHong Zhang     }
91784ff8c8bSHong Zhang   }
91884ff8c8bSHong Zhang 
91984ff8c8bSHong Zhang   for (i = xs; i < xs + xm + 1; i++) {
92084ff8c8bSHong Zhang     PetscReal    maxspeed;
92184ff8c8bSHong Zhang     PetscScalar *uL, *uR;
92284ff8c8bSHong Zhang     uL = &ctx->uLR[0];
92384ff8c8bSHong Zhang     uR = &ctx->uLR[dof];
92484ff8c8bSHong Zhang     if (i == sf - lsbwidth) {
92584ff8c8bSHong Zhang       for (j = 0; j < dof; j++) {
92684ff8c8bSHong Zhang         uL[j] = x[(i - 1) * dof + j] + slope[(i - 1) * dof + j] * hxs / 2;
92784ff8c8bSHong Zhang         uR[j] = x[(i - 0) * dof + j] - slope[(i - 0) * dof + j] * hxs / 2;
92884ff8c8bSHong Zhang       }
9299566063dSJacob Faibussowitsch       PetscCall((*ctx->physics2.riemann2)(ctx->physics2.user, dof, uL, uR, ctx->flux, &maxspeed));
93084ff8c8bSHong Zhang       if (i < xs + xm) {
93184ff8c8bSHong Zhang         for (j = 0; j < dof; j++) f[islow * dof + j] += ctx->flux[j] / hxs;
93284ff8c8bSHong Zhang         islow++;
93384ff8c8bSHong Zhang       }
93484ff8c8bSHong Zhang     }
93584ff8c8bSHong Zhang     if (i > sf - lsbwidth && i < sf) {
93684ff8c8bSHong Zhang       for (j = 0; j < dof; j++) {
93784ff8c8bSHong Zhang         uL[j] = x[(i - 1) * dof + j] + slope[(i - 1) * dof + j] * hxs / 2;
93884ff8c8bSHong Zhang         uR[j] = x[(i - 0) * dof + j] - slope[(i - 0) * dof + j] * hxs / 2;
93984ff8c8bSHong Zhang       }
9409566063dSJacob Faibussowitsch       PetscCall((*ctx->physics2.riemann2)(ctx->physics2.user, dof, uL, uR, ctx->flux, &maxspeed));
94184ff8c8bSHong Zhang       if (i > xs) {
94284ff8c8bSHong Zhang         for (j = 0; j < dof; j++) f[(islow - 1) * dof + j] -= ctx->flux[j] / hxs;
94384ff8c8bSHong Zhang       }
94484ff8c8bSHong Zhang       if (i < xs + xm) {
94584ff8c8bSHong Zhang         for (j = 0; j < dof; j++) f[islow * dof + j] += ctx->flux[j] / hxs;
94684ff8c8bSHong Zhang         islow++;
94784ff8c8bSHong Zhang       }
94884ff8c8bSHong Zhang     }
94984ff8c8bSHong Zhang     if (i == sf) { /* interface between the slow region and the fast region */
95084ff8c8bSHong Zhang       for (j = 0; j < dof; j++) {
95184ff8c8bSHong Zhang         uL[j] = x[(i - 1) * dof + j] + slope[(i - 1) * dof + j] * hxs / 2;
95284ff8c8bSHong Zhang         uR[j] = x[(i - 0) * dof + j] - slope[(i - 0) * dof + j] * hxf / 2;
95384ff8c8bSHong Zhang       }
9549566063dSJacob Faibussowitsch       PetscCall((*ctx->physics2.riemann2)(ctx->physics2.user, dof, uL, uR, ctx->flux, &maxspeed));
95584ff8c8bSHong Zhang       if (i > xs) {
95684ff8c8bSHong Zhang         for (j = 0; j < dof; j++) f[(islow - 1) * dof + j] -= ctx->flux[j] / hxs;
95784ff8c8bSHong Zhang       }
95884ff8c8bSHong Zhang     }
95984ff8c8bSHong Zhang     if (i == fs) { /* interface between the fast region and the slow region */
96084ff8c8bSHong Zhang       for (j = 0; j < dof; j++) {
96184ff8c8bSHong Zhang         uL[j] = x[(i - 1) * dof + j] + slope[(i - 1) * dof + j] * hxf / 2;
96284ff8c8bSHong Zhang         uR[j] = x[(i - 0) * dof + j] - slope[(i - 0) * dof + j] * hxs / 2;
96384ff8c8bSHong Zhang       }
9649566063dSJacob Faibussowitsch       PetscCall((*ctx->physics2.riemann2)(ctx->physics2.user, dof, uL, uR, ctx->flux, &maxspeed));
96584ff8c8bSHong Zhang       if (i < xs + xm) {
96684ff8c8bSHong Zhang         for (j = 0; j < dof; j++) f[islow * dof + j] += ctx->flux[j] / hxs;
96784ff8c8bSHong Zhang         islow++;
96884ff8c8bSHong Zhang       }
96984ff8c8bSHong Zhang     }
97084ff8c8bSHong Zhang     if (i > fs && i < fs + rsbwidth) {
97184ff8c8bSHong Zhang       for (j = 0; j < dof; j++) {
97284ff8c8bSHong Zhang         uL[j] = x[(i - 1) * dof + j] + slope[(i - 1) * dof + j] * hxs / 2;
97384ff8c8bSHong Zhang         uR[j] = x[(i - 0) * dof + j] - slope[(i - 0) * dof + j] * hxs / 2;
97484ff8c8bSHong Zhang       }
9759566063dSJacob Faibussowitsch       PetscCall((*ctx->physics2.riemann2)(ctx->physics2.user, dof, uL, uR, ctx->flux, &maxspeed));
97684ff8c8bSHong Zhang       if (i > xs) {
97784ff8c8bSHong Zhang         for (j = 0; j < dof; j++) f[(islow - 1) * dof + j] -= ctx->flux[j] / hxs;
97884ff8c8bSHong Zhang       }
97984ff8c8bSHong Zhang       if (i < xs + xm) {
98084ff8c8bSHong Zhang         for (j = 0; j < dof; j++) f[islow * dof + j] += ctx->flux[j] / hxs;
98184ff8c8bSHong Zhang         islow++;
98284ff8c8bSHong Zhang       }
98384ff8c8bSHong Zhang     }
98484ff8c8bSHong Zhang     if (i == fs + rsbwidth) {
98584ff8c8bSHong Zhang       for (j = 0; j < dof; j++) {
98684ff8c8bSHong Zhang         uL[j] = x[(i - 1) * dof + j] + slope[(i - 1) * dof + j] * hxs / 2;
98784ff8c8bSHong Zhang         uR[j] = x[(i - 0) * dof + j] - slope[(i - 0) * dof + j] * hxs / 2;
98884ff8c8bSHong Zhang       }
9899566063dSJacob Faibussowitsch       PetscCall((*ctx->physics2.riemann2)(ctx->physics2.user, dof, uL, uR, ctx->flux, &maxspeed));
99084ff8c8bSHong Zhang       if (i > xs) {
99184ff8c8bSHong Zhang         for (j = 0; j < dof; j++) f[(islow - 1) * dof + j] -= ctx->flux[j] / hxs;
99284ff8c8bSHong Zhang       }
99384ff8c8bSHong Zhang     }
99484ff8c8bSHong Zhang   }
9959566063dSJacob Faibussowitsch   PetscCall(DMDAVecRestoreArray(da, Xloc, &x));
9969566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(F, &f));
9979566063dSJacob Faibussowitsch   PetscCall(DMDARestoreArray(da, PETSC_TRUE, &slope));
9989566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(da, &Xloc));
99984ff8c8bSHong Zhang   PetscFunctionReturn(0);
100084ff8c8bSHong Zhang }
100184ff8c8bSHong Zhang 
100284ff8c8bSHong Zhang /* --------------------------------- Finite Volume Solver for fast  parts ----------------------------------- */
10039371c9d4SSatish Balay PetscErrorCode FVRHSFunctionfast_2WaySplit(TS ts, PetscReal time, Vec X, Vec F, void *vctx) {
100484ff8c8bSHong Zhang   FVCtx       *ctx = (FVCtx *)vctx;
100584ff8c8bSHong Zhang   PetscInt     i, j, k, Mx, dof, xs, xm, ifast = 0, sf = ctx->sf, fs = ctx->fs;
100684ff8c8bSHong Zhang   PetscReal    hxs, hxf;
100784ff8c8bSHong Zhang   PetscScalar *x, *f, *slope;
100884ff8c8bSHong Zhang   Vec          Xloc;
100984ff8c8bSHong Zhang   DM           da;
101084ff8c8bSHong Zhang 
101184ff8c8bSHong Zhang   PetscFunctionBeginUser;
10129566063dSJacob Faibussowitsch   PetscCall(TSGetDM(ts, &da));
10139566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(da, &Xloc));
10149566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(da, 0, &Mx, 0, 0, 0, 0, 0, &dof, 0, 0, 0, 0, 0));
101584ff8c8bSHong Zhang   hxs = (ctx->xmax - ctx->xmin) * 3.0 / 8.0 / ctx->sf;
101684ff8c8bSHong Zhang   hxf = (ctx->xmax - ctx->xmin) / 4.0 / (ctx->fs - ctx->sf);
10179566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalBegin(da, X, INSERT_VALUES, Xloc));
10189566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalEnd(da, X, INSERT_VALUES, Xloc));
10199566063dSJacob Faibussowitsch   PetscCall(VecZeroEntries(F));
10209566063dSJacob Faibussowitsch   PetscCall(DMDAVecGetArray(da, Xloc, &x));
10219566063dSJacob Faibussowitsch   PetscCall(VecGetArray(F, &f));
10229566063dSJacob Faibussowitsch   PetscCall(DMDAGetArray(da, PETSC_TRUE, &slope));
10239566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(da, &xs, 0, 0, &xm, 0, 0));
102484ff8c8bSHong Zhang 
102584ff8c8bSHong Zhang   if (ctx->bctype == FVBC_OUTFLOW) {
102684ff8c8bSHong Zhang     for (i = xs - 2; i < 0; i++) {
102784ff8c8bSHong Zhang       for (j = 0; j < dof; j++) x[i * dof + j] = x[j];
102884ff8c8bSHong Zhang     }
102984ff8c8bSHong Zhang     for (i = Mx; i < xs + xm + 2; i++) {
103084ff8c8bSHong Zhang       for (j = 0; j < dof; j++) x[i * dof + j] = x[(xs + xm - 1) * dof + j];
103184ff8c8bSHong Zhang     }
103284ff8c8bSHong Zhang   }
103384ff8c8bSHong Zhang   if (ctx->bctype == FVBC_INFLOW) {
103484ff8c8bSHong Zhang     /* See LeVeque, R. (2002). Finite Volume Methods for Hyperbolic Problems. doi:10.1017/CBO9780511791253
103584ff8c8bSHong Zhang     pages 137-138 for the scheme. */
103684ff8c8bSHong Zhang     if (xs == 0) { /* Left Boundary */
103784ff8c8bSHong Zhang       ctx->physics2.inflow(ctx, time, ctx->xmin, ctx->ub);
103884ff8c8bSHong Zhang       for (j = 0; j < dof; j++) {
103984ff8c8bSHong Zhang         if (ctx->physics2.bcinflowindex[j] == PETSC_TRUE) {
104084ff8c8bSHong Zhang           for (i = -2; i < 0; i++) x[i * dof + j] = 2.0 * ctx->ub[j] - x[-(i + 1) * dof + j];
104184ff8c8bSHong Zhang         } else {
104284ff8c8bSHong Zhang           for (i = -2; i < 0; i++) x[i * dof + j] = x[j]; /* Outflow */
104384ff8c8bSHong Zhang         }
104484ff8c8bSHong Zhang       }
104584ff8c8bSHong Zhang     }
104684ff8c8bSHong Zhang     if (xs + xm == Mx) { /* Right Boundary */
104784ff8c8bSHong Zhang       ctx->physics2.inflow(ctx, time, ctx->xmax, ctx->ub);
104884ff8c8bSHong Zhang       for (j = 0; j < dof; j++) {
104984ff8c8bSHong Zhang         if (ctx->physics2.bcinflowindex[dof + j] == PETSC_TRUE) {
105084ff8c8bSHong 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];
105184ff8c8bSHong Zhang         } else {
105284ff8c8bSHong Zhang           for (i = Mx; i < Mx + 2; i++) x[i * dof + j] = x[(Mx - 1) * dof + j]; /* Outflow */
105384ff8c8bSHong Zhang         }
105484ff8c8bSHong Zhang       }
105584ff8c8bSHong Zhang     }
105684ff8c8bSHong Zhang   }
105784ff8c8bSHong Zhang   for (i = xs - 1; i < xs + xm + 1; i++) {
105884ff8c8bSHong Zhang     struct _LimitInfo info;
105984ff8c8bSHong Zhang     PetscScalar      *cjmpL, *cjmpR;
106084ff8c8bSHong Zhang     if (i > sf - 2 && i < fs + 1) {
10619566063dSJacob Faibussowitsch       PetscCall((*ctx->physics2.characteristic2)(ctx->physics2.user, dof, &x[i * dof], ctx->R, ctx->Rinv, ctx->speeds));
10629566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(ctx->cjmpLR, 2 * dof));
106384ff8c8bSHong Zhang       cjmpL = &ctx->cjmpLR[0];
106484ff8c8bSHong Zhang       cjmpR = &ctx->cjmpLR[dof];
106584ff8c8bSHong Zhang       for (j = 0; j < dof; j++) {
106684ff8c8bSHong Zhang         PetscScalar jmpL, jmpR;
106784ff8c8bSHong Zhang         jmpL = x[(i + 0) * dof + j] - x[(i - 1) * dof + j];
106884ff8c8bSHong Zhang         jmpR = x[(i + 1) * dof + j] - x[(i + 0) * dof + j];
106984ff8c8bSHong Zhang         for (k = 0; k < dof; k++) {
107084ff8c8bSHong Zhang           cjmpL[k] += ctx->Rinv[k + j * dof] * jmpL;
107184ff8c8bSHong Zhang           cjmpR[k] += ctx->Rinv[k + j * dof] * jmpR;
107284ff8c8bSHong Zhang         }
107384ff8c8bSHong Zhang       }
107484ff8c8bSHong Zhang       /* Apply limiter to the left and right characteristic jumps */
107584ff8c8bSHong Zhang       info.m   = dof;
107684ff8c8bSHong Zhang       info.hxs = hxs;
107784ff8c8bSHong Zhang       info.hxf = hxf;
107884ff8c8bSHong Zhang       (*ctx->limit2)(&info, cjmpL, cjmpR, ctx->sf, ctx->fs, i, ctx->cslope);
107984ff8c8bSHong Zhang       for (j = 0; j < dof; j++) {
108084ff8c8bSHong Zhang         PetscScalar tmp = 0;
108184ff8c8bSHong Zhang         for (k = 0; k < dof; k++) tmp += ctx->R[j + k * dof] * ctx->cslope[k];
108284ff8c8bSHong Zhang         slope[i * dof + j] = tmp;
108384ff8c8bSHong Zhang       }
108484ff8c8bSHong Zhang     }
108584ff8c8bSHong Zhang   }
108684ff8c8bSHong Zhang 
108784ff8c8bSHong Zhang   for (i = xs; i < xs + xm + 1; i++) {
108884ff8c8bSHong Zhang     PetscReal    maxspeed;
108984ff8c8bSHong Zhang     PetscScalar *uL, *uR;
109084ff8c8bSHong Zhang     uL = &ctx->uLR[0];
109184ff8c8bSHong Zhang     uR = &ctx->uLR[dof];
109284ff8c8bSHong Zhang     if (i == sf) { /* interface between the slow region and the fast region */
109384ff8c8bSHong Zhang       for (j = 0; j < dof; j++) {
109484ff8c8bSHong Zhang         uL[j] = x[(i - 1) * dof + j] + slope[(i - 1) * dof + j] * hxs / 2;
109584ff8c8bSHong Zhang         uR[j] = x[(i - 0) * dof + j] - slope[(i - 0) * dof + j] * hxf / 2;
109684ff8c8bSHong Zhang       }
10979566063dSJacob Faibussowitsch       PetscCall((*ctx->physics2.riemann2)(ctx->physics2.user, dof, uL, uR, ctx->flux, &maxspeed));
109884ff8c8bSHong Zhang       if (i < xs + xm) {
109984ff8c8bSHong Zhang         for (j = 0; j < dof; j++) f[ifast * dof + j] += ctx->flux[j] / hxf;
110084ff8c8bSHong Zhang         ifast++;
110184ff8c8bSHong Zhang       }
110284ff8c8bSHong Zhang     }
110384ff8c8bSHong Zhang     if (i > sf && i < fs) { /* fast region */
110484ff8c8bSHong Zhang       for (j = 0; j < dof; j++) {
110584ff8c8bSHong Zhang         uL[j] = x[(i - 1) * dof + j] + slope[(i - 1) * dof + j] * hxf / 2;
110684ff8c8bSHong Zhang         uR[j] = x[(i - 0) * dof + j] - slope[(i - 0) * dof + j] * hxf / 2;
110784ff8c8bSHong Zhang       }
11089566063dSJacob Faibussowitsch       PetscCall((*ctx->physics2.riemann2)(ctx->physics2.user, dof, uL, uR, ctx->flux, &maxspeed));
110984ff8c8bSHong Zhang       if (i > xs) {
111084ff8c8bSHong Zhang         for (j = 0; j < dof; j++) f[(ifast - 1) * dof + j] -= ctx->flux[j] / hxf;
111184ff8c8bSHong Zhang       }
111284ff8c8bSHong Zhang       if (i < xs + xm) {
111384ff8c8bSHong Zhang         for (j = 0; j < dof; j++) f[ifast * dof + j] += ctx->flux[j] / hxf;
111484ff8c8bSHong Zhang         ifast++;
111584ff8c8bSHong Zhang       }
111684ff8c8bSHong Zhang     }
111784ff8c8bSHong Zhang     if (i == fs) { /* interface between the fast region and the slow region */
111884ff8c8bSHong Zhang       for (j = 0; j < dof; j++) {
111984ff8c8bSHong Zhang         uL[j] = x[(i - 1) * dof + j] + slope[(i - 1) * dof + j] * hxf / 2;
112084ff8c8bSHong Zhang         uR[j] = x[(i - 0) * dof + j] - slope[(i - 0) * dof + j] * hxs / 2;
112184ff8c8bSHong Zhang       }
11229566063dSJacob Faibussowitsch       PetscCall((*ctx->physics2.riemann2)(ctx->physics2.user, dof, uL, uR, ctx->flux, &maxspeed));
112384ff8c8bSHong Zhang       if (i > xs) {
112484ff8c8bSHong Zhang         for (j = 0; j < dof; j++) f[(ifast - 1) * dof + j] -= ctx->flux[j] / hxf;
112584ff8c8bSHong Zhang       }
112684ff8c8bSHong Zhang     }
112784ff8c8bSHong Zhang   }
11289566063dSJacob Faibussowitsch   PetscCall(DMDAVecRestoreArray(da, Xloc, &x));
11299566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(F, &f));
11309566063dSJacob Faibussowitsch   PetscCall(DMDARestoreArray(da, PETSC_TRUE, &slope));
11319566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(da, &Xloc));
113284ff8c8bSHong Zhang   PetscFunctionReturn(0);
113384ff8c8bSHong Zhang }
113484ff8c8bSHong Zhang 
11359371c9d4SSatish Balay int main(int argc, char *argv[]) {
113684ff8c8bSHong Zhang   char              lname[256] = "mc", physname[256] = "advect", final_fname[256] = "solution.m";
113784ff8c8bSHong Zhang   PetscFunctionList limiters = 0, physics = 0;
113884ff8c8bSHong Zhang   MPI_Comm          comm;
113984ff8c8bSHong Zhang   TS                ts;
114084ff8c8bSHong Zhang   DM                da;
114184ff8c8bSHong Zhang   Vec               X, X0, R;
114284ff8c8bSHong Zhang   FVCtx             ctx;
114384ff8c8bSHong 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;
114484ff8c8bSHong Zhang   PetscBool         view_final = PETSC_FALSE;
114584ff8c8bSHong Zhang   PetscReal         ptime, maxtime;
114684ff8c8bSHong Zhang 
1147327415f7SBarry Smith   PetscFunctionBeginUser;
11489566063dSJacob Faibussowitsch   PetscCall(PetscInitialize(&argc, &argv, 0, help));
114984ff8c8bSHong Zhang   comm = PETSC_COMM_WORLD;
11509566063dSJacob Faibussowitsch   PetscCall(PetscMemzero(&ctx, sizeof(ctx)));
115184ff8c8bSHong Zhang 
115284ff8c8bSHong Zhang   /* Register limiters to be available on the command line */
11539566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&limiters, "upwind", Limit2_Upwind));
11549566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&limiters, "lax-wendroff", Limit2_LaxWendroff));
11559566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&limiters, "beam-warming", Limit2_BeamWarming));
11569566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&limiters, "fromm", Limit2_Fromm));
11579566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&limiters, "minmod", Limit2_Minmod));
11589566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&limiters, "superbee", Limit2_Superbee));
11599566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&limiters, "mc", Limit2_MC));
11609566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&limiters, "koren3", Limit2_Koren3));
116184ff8c8bSHong Zhang 
116284ff8c8bSHong Zhang   /* Register physical models to be available on the command line */
11639566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&physics, "shallow", PhysicsCreate_Shallow));
11649566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&physics, "advect", PhysicsCreate_Advect));
116584ff8c8bSHong Zhang 
116684ff8c8bSHong Zhang   ctx.comm       = comm;
116784ff8c8bSHong Zhang   ctx.cfl        = 0.9;
116884ff8c8bSHong Zhang   ctx.bctype     = FVBC_PERIODIC;
116984ff8c8bSHong Zhang   ctx.xmin       = -1.0;
117084ff8c8bSHong Zhang   ctx.xmax       = 1.0;
117184ff8c8bSHong Zhang   ctx.initial    = 1;
117284ff8c8bSHong Zhang   ctx.hratio     = 2;
117384ff8c8bSHong Zhang   maxtime        = 10.0;
117484ff8c8bSHong Zhang   ctx.simulation = PETSC_FALSE;
1175d0609cedSBarry Smith   PetscOptionsBegin(comm, NULL, "Finite Volume solver options", "");
11769566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-xmin", "X min", "", ctx.xmin, &ctx.xmin, NULL));
11779566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-xmax", "X max", "", ctx.xmax, &ctx.xmax, NULL));
11789566063dSJacob Faibussowitsch   PetscCall(PetscOptionsFList("-limit", "Name of flux imiter to use", "", limiters, lname, lname, sizeof(lname), NULL));
11799566063dSJacob Faibussowitsch   PetscCall(PetscOptionsFList("-physics", "Name of physics model to use", "", physics, physname, physname, sizeof(physname), NULL));
11809566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-draw", "Draw solution vector, bitwise OR of (1=initial,2=final,4=final error)", "", draw, &draw, NULL));
11819566063dSJacob 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));
11829566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-initial", "Initial condition (depends on the physics)", "", ctx.initial, &ctx.initial, NULL));
11839566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-exact", "Compare errors with exact solution", "", ctx.exact, &ctx.exact, NULL));
11849566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-simulation", "Compare errors with reference solution", "", ctx.simulation, &ctx.simulation, NULL));
11859566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-cfl", "CFL number to time step at", "", ctx.cfl, &ctx.cfl, NULL));
11869566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEnum("-bc_type", "Boundary condition", "", FVBCTypes, (PetscEnum)ctx.bctype, (PetscEnum *)&ctx.bctype, NULL));
11879566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-hratio", "Spacing ratio", "", ctx.hratio, &ctx.hratio, NULL));
1188d0609cedSBarry Smith   PetscOptionsEnd();
118984ff8c8bSHong Zhang 
119084ff8c8bSHong Zhang   /* Choose the limiter from the list of registered limiters */
11919566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListFind(limiters, lname, &ctx.limit2));
11923c633725SBarry Smith   PetscCheck(ctx.limit2, PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "Limiter '%s' not found", lname);
119384ff8c8bSHong Zhang 
119484ff8c8bSHong Zhang   /* Choose the physics from the list of registered models */
119584ff8c8bSHong Zhang   {
119684ff8c8bSHong Zhang     PetscErrorCode (*r)(FVCtx *);
11979566063dSJacob Faibussowitsch     PetscCall(PetscFunctionListFind(physics, physname, &r));
11983c633725SBarry Smith     PetscCheck(r, PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "Physics '%s' not found", physname);
119984ff8c8bSHong Zhang     /* Create the physics, will set the number of fields and their names */
12009566063dSJacob Faibussowitsch     PetscCall((*r)(&ctx));
120184ff8c8bSHong Zhang   }
120284ff8c8bSHong Zhang 
120384ff8c8bSHong Zhang   /* Create a DMDA to manage the parallel grid */
12049566063dSJacob Faibussowitsch   PetscCall(DMDACreate1d(comm, DM_BOUNDARY_PERIODIC, 50, ctx.physics2.dof, 2, NULL, &da));
12059566063dSJacob Faibussowitsch   PetscCall(DMSetFromOptions(da));
12069566063dSJacob Faibussowitsch   PetscCall(DMSetUp(da));
120784ff8c8bSHong Zhang   /* Inform the DMDA of the field names provided by the physics. */
120884ff8c8bSHong Zhang   /* The names will be shown in the title bars when run with -ts_monitor_draw_solution */
1209*48a46eb9SPierre Jolivet   for (i = 0; i < ctx.physics2.dof; i++) PetscCall(DMDASetFieldName(da, i, ctx.physics2.fieldname[i]));
12109566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(da, 0, &Mx, 0, 0, 0, 0, 0, &dof, 0, 0, 0, 0, 0));
12119566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(da, &xs, 0, 0, &xm, 0, 0));
121284ff8c8bSHong Zhang 
121384ff8c8bSHong Zhang   /* Set coordinates of cell centers */
12149566063dSJacob 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));
121584ff8c8bSHong Zhang 
121684ff8c8bSHong Zhang   /* Allocate work space for the Finite Volume solver (so it doesn't have to be reallocated on each function evaluation) */
12179566063dSJacob Faibussowitsch   PetscCall(PetscMalloc4(dof * dof, &ctx.R, dof * dof, &ctx.Rinv, 2 * dof, &ctx.cjmpLR, 1 * dof, &ctx.cslope));
12189566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(2 * dof, &ctx.uLR, dof, &ctx.flux, dof, &ctx.speeds));
12199566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(2 * dof, &ctx.ub));
122084ff8c8bSHong Zhang 
122184ff8c8bSHong Zhang   /* Create a vector to store the solution and to save the initial state */
12229566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(da, &X));
12239566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(X, &X0));
12249566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(X, &R));
122584ff8c8bSHong Zhang 
122684ff8c8bSHong Zhang   /* create index for slow parts and fast parts,
122784ff8c8bSHong Zhang      count_slow + count_fast = Mx, counts_slow*hs = 0.5, counts_fast*hf = 0.5 */
122884ff8c8bSHong Zhang   count_slow = Mx / (1.0 + ctx.hratio / 3.0);
122908401ef6SPierre 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");
123084ff8c8bSHong Zhang   count_fast = Mx - count_slow;
123184ff8c8bSHong Zhang   ctx.sf     = count_slow / 2;
123284ff8c8bSHong Zhang   ctx.fs     = ctx.sf + count_fast;
12339566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(xm * dof, &index_slow));
12349566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(xm * dof, &index_fast));
12359566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(8 * dof, &index_slowbuffer));
123684ff8c8bSHong Zhang   ctx.lsbwidth = 4;
123784ff8c8bSHong Zhang   ctx.rsbwidth = 4;
123884ff8c8bSHong Zhang 
123984ff8c8bSHong Zhang   for (i = xs; i < xs + xm; i++) {
124084ff8c8bSHong Zhang     if (i < ctx.sf - ctx.lsbwidth || i > ctx.fs + ctx.rsbwidth - 1)
124184ff8c8bSHong Zhang       for (k = 0; k < dof; k++) index_slow[islow++] = i * dof + k;
124284ff8c8bSHong Zhang     else if ((i >= ctx.sf - ctx.lsbwidth && i < ctx.sf) || (i > ctx.fs - 1 && i <= ctx.fs + ctx.rsbwidth - 1))
124384ff8c8bSHong Zhang       for (k = 0; k < dof; k++) index_slowbuffer[islowbuffer++] = i * dof + k;
124484ff8c8bSHong Zhang     else
124584ff8c8bSHong Zhang       for (k = 0; k < dof; k++) index_fast[ifast++] = i * dof + k;
124684ff8c8bSHong Zhang   }
12479566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PETSC_COMM_WORLD, islow, index_slow, PETSC_COPY_VALUES, &ctx.iss));
12489566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PETSC_COMM_WORLD, ifast, index_fast, PETSC_COPY_VALUES, &ctx.isf));
12499566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PETSC_COMM_WORLD, islowbuffer, index_slowbuffer, PETSC_COPY_VALUES, &ctx.issb));
125084ff8c8bSHong Zhang 
125184ff8c8bSHong Zhang   /* Create a time-stepping object */
12529566063dSJacob Faibussowitsch   PetscCall(TSCreate(comm, &ts));
12539566063dSJacob Faibussowitsch   PetscCall(TSSetDM(ts, da));
12549566063dSJacob Faibussowitsch   PetscCall(TSSetRHSFunction(ts, R, FVRHSFunction_2WaySplit, &ctx));
12559566063dSJacob Faibussowitsch   PetscCall(TSRHSSplitSetIS(ts, "slow", ctx.iss));
12569566063dSJacob Faibussowitsch   PetscCall(TSRHSSplitSetIS(ts, "slowbuffer", ctx.issb));
12579566063dSJacob Faibussowitsch   PetscCall(TSRHSSplitSetIS(ts, "fast", ctx.isf));
12589566063dSJacob Faibussowitsch   PetscCall(TSRHSSplitSetRHSFunction(ts, "slow", NULL, FVRHSFunctionslow_2WaySplit, &ctx));
12599566063dSJacob Faibussowitsch   PetscCall(TSRHSSplitSetRHSFunction(ts, "fast", NULL, FVRHSFunctionfast_2WaySplit, &ctx));
12609566063dSJacob Faibussowitsch   PetscCall(TSRHSSplitSetRHSFunction(ts, "slowbuffer", NULL, FVRHSFunctionslowbuffer_2WaySplit, &ctx));
126184ff8c8bSHong Zhang 
12629566063dSJacob Faibussowitsch   PetscCall(TSSetType(ts, TSMPRK));
12639566063dSJacob Faibussowitsch   PetscCall(TSSetMaxTime(ts, maxtime));
12649566063dSJacob Faibussowitsch   PetscCall(TSSetExactFinalTime(ts, TS_EXACTFINALTIME_STEPOVER));
126584ff8c8bSHong Zhang 
126684ff8c8bSHong Zhang   /* Compute initial conditions and starting time step */
12679566063dSJacob Faibussowitsch   PetscCall(FVSample_2WaySplit(&ctx, da, 0, X0));
12689566063dSJacob Faibussowitsch   PetscCall(FVRHSFunction_2WaySplit(ts, 0, X0, X, (void *)&ctx)); /* Initial function evaluation, only used to determine max speed */
12699566063dSJacob Faibussowitsch   PetscCall(VecCopy(X0, X));                                      /* The function value was not used so we set X=X0 again */
12709566063dSJacob Faibussowitsch   PetscCall(TSSetTimeStep(ts, ctx.cfl / ctx.cfl_idt));
12719566063dSJacob Faibussowitsch   PetscCall(TSSetFromOptions(ts)); /* Take runtime options */
12729566063dSJacob Faibussowitsch   PetscCall(SolutionStatsView(da, X, PETSC_VIEWER_STDOUT_WORLD));
127384ff8c8bSHong Zhang   {
127484ff8c8bSHong Zhang     PetscInt           steps;
127584ff8c8bSHong Zhang     PetscScalar        mass_initial, mass_final, mass_difference, mass_differenceg;
127684ff8c8bSHong Zhang     const PetscScalar *ptr_X, *ptr_X0;
127784ff8c8bSHong Zhang     const PetscReal    hs = (ctx.xmax - ctx.xmin) * 3.0 / 4.0 / count_slow;
127884ff8c8bSHong Zhang     const PetscReal    hf = (ctx.xmax - ctx.xmin) / 4.0 / count_fast;
127984ff8c8bSHong Zhang 
12809566063dSJacob Faibussowitsch     PetscCall(TSSolve(ts, X));
12819566063dSJacob Faibussowitsch     PetscCall(TSGetSolveTime(ts, &ptime));
12829566063dSJacob Faibussowitsch     PetscCall(TSGetStepNumber(ts, &steps));
128384ff8c8bSHong Zhang     /* calculate the total mass at initial time and final time */
128484ff8c8bSHong Zhang     mass_initial = 0.0;
128584ff8c8bSHong Zhang     mass_final   = 0.0;
12869566063dSJacob Faibussowitsch     PetscCall(DMDAVecGetArrayRead(da, X0, (void *)&ptr_X0));
12879566063dSJacob Faibussowitsch     PetscCall(DMDAVecGetArrayRead(da, X, (void *)&ptr_X));
128884ff8c8bSHong Zhang     for (i = xs; i < xs + xm; i++) {
128984ff8c8bSHong Zhang       if (i < ctx.sf || i > ctx.fs - 1) {
129084ff8c8bSHong Zhang         for (k = 0; k < dof; k++) {
129184ff8c8bSHong Zhang           mass_initial = mass_initial + hs * ptr_X0[i * dof + k];
129284ff8c8bSHong Zhang           mass_final   = mass_final + hs * ptr_X[i * dof + k];
129384ff8c8bSHong Zhang         }
129484ff8c8bSHong Zhang       } else {
129584ff8c8bSHong Zhang         for (k = 0; k < dof; k++) {
129684ff8c8bSHong Zhang           mass_initial = mass_initial + hf * ptr_X0[i * dof + k];
129784ff8c8bSHong Zhang           mass_final   = mass_final + hf * ptr_X[i * dof + k];
129884ff8c8bSHong Zhang         }
129984ff8c8bSHong Zhang       }
130084ff8c8bSHong Zhang     }
13019566063dSJacob Faibussowitsch     PetscCall(DMDAVecRestoreArrayRead(da, X0, (void *)&ptr_X0));
13029566063dSJacob Faibussowitsch     PetscCall(DMDAVecRestoreArrayRead(da, X, (void *)&ptr_X));
130384ff8c8bSHong Zhang     mass_difference = mass_final - mass_initial;
13049566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Allreduce(&mass_difference, &mass_differenceg, 1, MPIU_SCALAR, MPIU_SUM, comm));
13059566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(comm, "Mass difference %g\n", (double)mass_differenceg));
130663a3b9bcSJacob Faibussowitsch     PetscCall(PetscPrintf(comm, "Final time %g, steps %" PetscInt_FMT "\n", (double)ptime, steps));
13079566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(comm, "Maximum allowable stepsize according to CFL %g\n", (double)(1.0 / ctx.cfl_idt)));
130884ff8c8bSHong Zhang     if (ctx.exact) {
130984ff8c8bSHong Zhang       PetscReal nrm1 = 0;
13109566063dSJacob Faibussowitsch       PetscCall(SolutionErrorNorms_2WaySplit(&ctx, da, ptime, X, &nrm1));
13119566063dSJacob Faibussowitsch       PetscCall(PetscPrintf(comm, "Error ||x-x_e||_1 %g\n", (double)nrm1));
131284ff8c8bSHong Zhang     }
131384ff8c8bSHong Zhang     if (ctx.simulation) {
131484ff8c8bSHong Zhang       PetscReal          nrm1 = 0;
131584ff8c8bSHong Zhang       PetscViewer        fd;
131684ff8c8bSHong Zhang       char               filename[PETSC_MAX_PATH_LEN] = "binaryoutput";
131784ff8c8bSHong Zhang       Vec                XR;
131884ff8c8bSHong Zhang       PetscBool          flg;
131984ff8c8bSHong Zhang       const PetscScalar *ptr_XR;
13209566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetString(NULL, NULL, "-f", filename, sizeof(filename), &flg));
13213c633725SBarry Smith       PetscCheck(flg, PETSC_COMM_WORLD, PETSC_ERR_USER, "Must indicate binary file with the -f option");
13229566063dSJacob Faibussowitsch       PetscCall(PetscViewerBinaryOpen(PETSC_COMM_WORLD, filename, FILE_MODE_READ, &fd));
13239566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(X0, &XR));
13249566063dSJacob Faibussowitsch       PetscCall(VecLoad(XR, fd));
13259566063dSJacob Faibussowitsch       PetscCall(PetscViewerDestroy(&fd));
13269566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(X, &ptr_X));
13279566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(XR, &ptr_XR));
132884ff8c8bSHong Zhang       for (i = xs; i < xs + xm; i++) {
132984ff8c8bSHong Zhang         if (i < ctx.sf || i > ctx.fs - 1)
133084ff8c8bSHong Zhang           for (k = 0; k < dof; k++) nrm1 = nrm1 + hs * PetscAbs(ptr_X[i * dof + k] - ptr_XR[i * dof + k]);
133184ff8c8bSHong Zhang         else
133284ff8c8bSHong Zhang           for (k = 0; k < dof; k++) nrm1 = nrm1 + hf * PetscAbs(ptr_X[i * dof + k] - ptr_XR[i * dof + k]);
133384ff8c8bSHong Zhang       }
13349566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(X, &ptr_X));
13359566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(XR, &ptr_XR));
13369566063dSJacob Faibussowitsch       PetscCall(PetscPrintf(comm, "Error ||x-x_e||_1 %g\n", (double)nrm1));
13379566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&XR));
133884ff8c8bSHong Zhang     }
133984ff8c8bSHong Zhang   }
134084ff8c8bSHong Zhang 
13419566063dSJacob Faibussowitsch   PetscCall(SolutionStatsView(da, X, PETSC_VIEWER_STDOUT_WORLD));
13429566063dSJacob Faibussowitsch   if (draw & 0x1) PetscCall(VecView(X0, PETSC_VIEWER_DRAW_WORLD));
13439566063dSJacob Faibussowitsch   if (draw & 0x2) PetscCall(VecView(X, PETSC_VIEWER_DRAW_WORLD));
134484ff8c8bSHong Zhang   if (draw & 0x4) {
134584ff8c8bSHong Zhang     Vec Y;
13469566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(X, &Y));
13479566063dSJacob Faibussowitsch     PetscCall(FVSample_2WaySplit(&ctx, da, ptime, Y));
13489566063dSJacob Faibussowitsch     PetscCall(VecAYPX(Y, -1, X));
13499566063dSJacob Faibussowitsch     PetscCall(VecView(Y, PETSC_VIEWER_DRAW_WORLD));
13509566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&Y));
135184ff8c8bSHong Zhang   }
135284ff8c8bSHong Zhang 
135384ff8c8bSHong Zhang   if (view_final) {
135484ff8c8bSHong Zhang     PetscViewer viewer;
13559566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIOpen(PETSC_COMM_WORLD, final_fname, &viewer));
13569566063dSJacob Faibussowitsch     PetscCall(PetscViewerPushFormat(viewer, PETSC_VIEWER_ASCII_MATLAB));
13579566063dSJacob Faibussowitsch     PetscCall(VecView(X, viewer));
13589566063dSJacob Faibussowitsch     PetscCall(PetscViewerPopFormat(viewer));
13599566063dSJacob Faibussowitsch     PetscCall(PetscViewerDestroy(&viewer));
136084ff8c8bSHong Zhang   }
136184ff8c8bSHong Zhang 
136284ff8c8bSHong Zhang   /* Clean up */
13639566063dSJacob Faibussowitsch   PetscCall((*ctx.physics2.destroy)(ctx.physics2.user));
13649566063dSJacob Faibussowitsch   for (i = 0; i < ctx.physics2.dof; i++) PetscCall(PetscFree(ctx.physics2.fieldname[i]));
13659566063dSJacob Faibussowitsch   PetscCall(PetscFree(ctx.physics2.bcinflowindex));
1366d0609cedSBarry Smith   PetscCall(PetscFree(ctx.ub));
13679566063dSJacob Faibussowitsch   PetscCall(PetscFree4(ctx.R, ctx.Rinv, ctx.cjmpLR, ctx.cslope));
13689566063dSJacob Faibussowitsch   PetscCall(PetscFree3(ctx.uLR, ctx.flux, ctx.speeds));
13699566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&X));
13709566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&X0));
13719566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&R));
13729566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&da));
13739566063dSJacob Faibussowitsch   PetscCall(TSDestroy(&ts));
13749566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&ctx.iss));
13759566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&ctx.isf));
13769566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&ctx.issb));
13779566063dSJacob Faibussowitsch   PetscCall(PetscFree(index_slow));
13789566063dSJacob Faibussowitsch   PetscCall(PetscFree(index_fast));
13799566063dSJacob Faibussowitsch   PetscCall(PetscFree(index_slowbuffer));
13809566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListDestroy(&limiters));
13819566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListDestroy(&physics));
13829566063dSJacob Faibussowitsch   PetscCall(PetscFinalize());
1383b122ec5aSJacob Faibussowitsch   return 0;
138484ff8c8bSHong Zhang }
138584ff8c8bSHong Zhang 
138684ff8c8bSHong Zhang /*TEST
138784ff8c8bSHong Zhang 
138884ff8c8bSHong Zhang     build:
138984ff8c8bSHong Zhang       requires: !complex !single
139084ff8c8bSHong Zhang       depends: finitevolume1d.c
139184ff8c8bSHong Zhang 
139284ff8c8bSHong Zhang     test:
139384ff8c8bSHong Zhang       suffix: 1
139484ff8c8bSHong 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
139584ff8c8bSHong Zhang       output_file: output/ex4_1.out
139684ff8c8bSHong Zhang 
139784ff8c8bSHong Zhang     test:
139884ff8c8bSHong Zhang       suffix: 2
139984ff8c8bSHong 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
140084ff8c8bSHong Zhang       output_file: output/ex4_1.out
140184ff8c8bSHong Zhang 
140284ff8c8bSHong Zhang     test:
140384ff8c8bSHong Zhang       suffix: 3
140484ff8c8bSHong 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
140584ff8c8bSHong Zhang       output_file: output/ex4_3.out
140684ff8c8bSHong Zhang 
140784ff8c8bSHong Zhang     test:
140884ff8c8bSHong Zhang       suffix: 4
140984ff8c8bSHong Zhang       nsize: 2
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 1
141184ff8c8bSHong Zhang       output_file: output/ex4_3.out
141284ff8c8bSHong Zhang 
141384ff8c8bSHong Zhang     test:
141484ff8c8bSHong Zhang       suffix: 5
141584ff8c8bSHong Zhang       nsize: 4
1416660278c0SBarry Smith       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 TEST*/
1419