xref: /petsc/src/ts/tutorials/ex9.c (revision 834855d6effb0d027771461c8e947ee1ce5a1e17)
1c4762a1bSJed Brown static const char help[] = "1D periodic Finite Volume solver in slope-limiter form with semidiscrete time stepping.\n"
2c4762a1bSJed Brown                            "Solves scalar and vector problems, choose the physical model with -physics\n"
3c4762a1bSJed Brown                            "  advection   - Constant coefficient scalar advection\n"
4c4762a1bSJed Brown                            "                u_t       + (a*u)_x               = 0\n"
5c4762a1bSJed Brown                            "  burgers     - Burgers equation\n"
6c4762a1bSJed Brown                            "                u_t       + (u^2/2)_x             = 0\n"
7c4762a1bSJed Brown                            "  traffic     - Traffic equation\n"
8c4762a1bSJed Brown                            "                u_t       + (u*(1-u))_x           = 0\n"
9c4762a1bSJed Brown                            "  acoustics   - Acoustic wave propagation\n"
10c4762a1bSJed Brown                            "                u_t       + (c*z*v)_x             = 0\n"
11c4762a1bSJed Brown                            "                v_t       + (c/z*u)_x             = 0\n"
12c4762a1bSJed Brown                            "  isogas      - Isothermal gas dynamics\n"
13c4762a1bSJed Brown                            "                rho_t     + (rho*u)_x             = 0\n"
14c4762a1bSJed Brown                            "                (rho*u)_t + (rho*u^2 + c^2*rho)_x = 0\n"
15c4762a1bSJed Brown                            "  shallow     - Shallow water equations\n"
16c4762a1bSJed Brown                            "                h_t       + (h*u)_x               = 0\n"
17c4762a1bSJed Brown                            "                (h*u)_t   + (h*u^2 + g*h^2/2)_x   = 0\n"
18c4762a1bSJed Brown                            "Some of these physical models have multiple Riemann solvers, select these with -physics_xxx_riemann\n"
19c4762a1bSJed Brown                            "  exact       - Exact Riemann solver which usually needs to perform a Newton iteration to connect\n"
20c4762a1bSJed Brown                            "                the states across shocks and rarefactions\n"
21c4762a1bSJed Brown                            "  roe         - Linearized scheme, usually with an entropy fix inside sonic rarefactions\n"
22c4762a1bSJed Brown                            "The systems provide a choice of reconstructions with -physics_xxx_reconstruct\n"
23c4762a1bSJed Brown                            "  characteristic - Limit the characteristic variables, this is usually preferred (default)\n"
24c4762a1bSJed Brown                            "  conservative   - Limit the conservative variables directly, can cause undesired interaction of waves\n\n"
25c4762a1bSJed Brown                            "A variety of limiters for high-resolution TVD limiters are available with -limit\n"
26c4762a1bSJed Brown                            "  upwind,minmod,superbee,mc,vanleer,vanalbada,koren,cada-torillhon (last two are nominally third order)\n"
27c4762a1bSJed Brown                            "  and non-TVD schemes lax-wendroff,beam-warming,fromm\n\n"
28c4762a1bSJed Brown                            "To preserve the TVD property, one should time step with a strong stability preserving method.\n"
29c4762a1bSJed Brown                            "The optimal high order explicit Runge-Kutta methods in TSSSP are recommended for non-stiff problems.\n\n"
30c4762a1bSJed Brown                            "Several initial conditions can be chosen with -initial N\n\n"
31c4762a1bSJed Brown                            "The problem size should be set with -da_grid_x M\n\n";
32c4762a1bSJed Brown 
33c4762a1bSJed Brown #include <petscts.h>
34c4762a1bSJed Brown #include <petscdm.h>
35c4762a1bSJed Brown #include <petscdmda.h>
36c4762a1bSJed Brown #include <petscdraw.h>
37c4762a1bSJed Brown 
38c4762a1bSJed Brown #include <petsc/private/kernels/blockinvert.h> /* For the Kernel_*_gets_* stuff for BAIJ */
39c4762a1bSJed Brown 
Sgn(PetscReal a)40d71ae5a4SJacob Faibussowitsch static inline PetscReal Sgn(PetscReal a)
41d71ae5a4SJacob Faibussowitsch {
429371c9d4SSatish Balay   return (a < 0) ? -1 : 1;
439371c9d4SSatish Balay }
Abs(PetscReal a)44d71ae5a4SJacob Faibussowitsch static inline PetscReal Abs(PetscReal a)
45d71ae5a4SJacob Faibussowitsch {
469371c9d4SSatish Balay   return (a < 0) ? 0 : a;
479371c9d4SSatish Balay }
Sqr(PetscReal a)48d71ae5a4SJacob Faibussowitsch static inline PetscReal Sqr(PetscReal a)
49d71ae5a4SJacob Faibussowitsch {
509371c9d4SSatish Balay   return a * a;
519371c9d4SSatish Balay }
MaxAbs(PetscReal a,PetscReal b)52d71ae5a4SJacob Faibussowitsch static inline PetscReal MaxAbs(PetscReal a, PetscReal b)
53d71ae5a4SJacob Faibussowitsch {
549371c9d4SSatish Balay   return (PetscAbs(a) > PetscAbs(b)) ? a : b;
559371c9d4SSatish Balay }
MinAbs(PetscReal a,PetscReal b)56d71ae5a4SJacob Faibussowitsch PETSC_UNUSED static inline PetscReal MinAbs(PetscReal a, PetscReal b)
57d71ae5a4SJacob Faibussowitsch {
589371c9d4SSatish Balay   return (PetscAbs(a) < PetscAbs(b)) ? a : b;
599371c9d4SSatish Balay }
MinMod2(PetscReal a,PetscReal b)60d71ae5a4SJacob Faibussowitsch static inline PetscReal MinMod2(PetscReal a, PetscReal b)
61d71ae5a4SJacob Faibussowitsch {
629371c9d4SSatish Balay   return (a * b < 0) ? 0 : Sgn(a) * PetscMin(PetscAbs(a), PetscAbs(b));
639371c9d4SSatish Balay }
MaxMod2(PetscReal a,PetscReal b)64d71ae5a4SJacob Faibussowitsch static inline PetscReal MaxMod2(PetscReal a, PetscReal b)
65d71ae5a4SJacob Faibussowitsch {
669371c9d4SSatish Balay   return (a * b < 0) ? 0 : Sgn(a) * PetscMax(PetscAbs(a), PetscAbs(b));
679371c9d4SSatish Balay }
MinMod3(PetscReal a,PetscReal b,PetscReal c)68d71ae5a4SJacob Faibussowitsch static inline PetscReal MinMod3(PetscReal a, PetscReal b, PetscReal c)
69d71ae5a4SJacob Faibussowitsch {
709371c9d4SSatish Balay   return (a * b < 0 || a * c < 0) ? 0 : Sgn(a) * PetscMin(PetscAbs(a), PetscMin(PetscAbs(b), PetscAbs(c)));
719371c9d4SSatish Balay }
72c4762a1bSJed Brown 
RangeMod(PetscReal a,PetscReal xmin,PetscReal xmax)73d71ae5a4SJacob Faibussowitsch static inline PetscReal RangeMod(PetscReal a, PetscReal xmin, PetscReal xmax)
74d71ae5a4SJacob Faibussowitsch {
759371c9d4SSatish Balay   PetscReal range = xmax - xmin;
769371c9d4SSatish Balay   return xmin + PetscFmodReal(range + PetscFmodReal(a, range), range);
779371c9d4SSatish Balay }
78c4762a1bSJed Brown 
79c4762a1bSJed Brown /* ----------------------- Lots of limiters, these could go in a separate library ------------------------- */
80c4762a1bSJed Brown typedef struct _LimitInfo {
81c4762a1bSJed Brown   PetscReal hx;
82c4762a1bSJed Brown   PetscInt  m;
83c4762a1bSJed Brown }          *LimitInfo;
Limit_Upwind(LimitInfo info,const PetscScalar * jL,const PetscScalar * jR,PetscScalar * lmt)84d71ae5a4SJacob Faibussowitsch static void Limit_Upwind(LimitInfo info, const PetscScalar *jL, const PetscScalar *jR, PetscScalar *lmt)
85d71ae5a4SJacob Faibussowitsch {
86c4762a1bSJed Brown   PetscInt i;
87c4762a1bSJed Brown   for (i = 0; i < info->m; i++) lmt[i] = 0;
88c4762a1bSJed Brown }
Limit_LaxWendroff(LimitInfo info,const PetscScalar * jL,const PetscScalar * jR,PetscScalar * lmt)89d71ae5a4SJacob Faibussowitsch static void Limit_LaxWendroff(LimitInfo info, const PetscScalar *jL, const PetscScalar *jR, PetscScalar *lmt)
90d71ae5a4SJacob Faibussowitsch {
91c4762a1bSJed Brown   PetscInt i;
92c4762a1bSJed Brown   for (i = 0; i < info->m; i++) lmt[i] = jR[i];
93c4762a1bSJed Brown }
Limit_BeamWarming(LimitInfo info,const PetscScalar * jL,const PetscScalar * jR,PetscScalar * lmt)94d71ae5a4SJacob Faibussowitsch static void Limit_BeamWarming(LimitInfo info, const PetscScalar *jL, const PetscScalar *jR, PetscScalar *lmt)
95d71ae5a4SJacob Faibussowitsch {
96c4762a1bSJed Brown   PetscInt i;
97c4762a1bSJed Brown   for (i = 0; i < info->m; i++) lmt[i] = jL[i];
98c4762a1bSJed Brown }
Limit_Fromm(LimitInfo info,const PetscScalar * jL,const PetscScalar * jR,PetscScalar * lmt)99d71ae5a4SJacob Faibussowitsch static void Limit_Fromm(LimitInfo info, const PetscScalar *jL, const PetscScalar *jR, PetscScalar *lmt)
100d71ae5a4SJacob Faibussowitsch {
101c4762a1bSJed Brown   PetscInt i;
102c4762a1bSJed Brown   for (i = 0; i < info->m; i++) lmt[i] = 0.5 * (jL[i] + jR[i]);
103c4762a1bSJed Brown }
Limit_Minmod(LimitInfo info,const PetscScalar * jL,const PetscScalar * jR,PetscScalar * lmt)104d71ae5a4SJacob Faibussowitsch static void Limit_Minmod(LimitInfo info, const PetscScalar *jL, const PetscScalar *jR, PetscScalar *lmt)
105d71ae5a4SJacob Faibussowitsch {
106c4762a1bSJed Brown   PetscInt i;
107c4762a1bSJed Brown   for (i = 0; i < info->m; i++) lmt[i] = MinMod2(jL[i], jR[i]);
108c4762a1bSJed Brown }
Limit_Superbee(LimitInfo info,const PetscScalar * jL,const PetscScalar * jR,PetscScalar * lmt)109d71ae5a4SJacob Faibussowitsch static void Limit_Superbee(LimitInfo info, const PetscScalar *jL, const PetscScalar *jR, PetscScalar *lmt)
110d71ae5a4SJacob Faibussowitsch {
111c4762a1bSJed Brown   PetscInt i;
112c4762a1bSJed Brown   for (i = 0; i < info->m; i++) lmt[i] = MaxMod2(MinMod2(jL[i], 2 * jR[i]), MinMod2(2 * jL[i], jR[i]));
113c4762a1bSJed Brown }
Limit_MC(LimitInfo info,const PetscScalar * jL,const PetscScalar * jR,PetscScalar * lmt)114d71ae5a4SJacob Faibussowitsch static void Limit_MC(LimitInfo info, const PetscScalar *jL, const PetscScalar *jR, PetscScalar *lmt)
115d71ae5a4SJacob Faibussowitsch {
116c4762a1bSJed Brown   PetscInt i;
117c4762a1bSJed Brown   for (i = 0; i < info->m; i++) lmt[i] = MinMod3(2 * jL[i], 0.5 * (jL[i] + jR[i]), 2 * jR[i]);
118c4762a1bSJed Brown }
Limit_VanLeer(LimitInfo info,const PetscScalar * jL,const PetscScalar * jR,PetscScalar * lmt)119d71ae5a4SJacob Faibussowitsch static void Limit_VanLeer(LimitInfo info, const PetscScalar *jL, const PetscScalar *jR, PetscScalar *lmt)
120d71ae5a4SJacob Faibussowitsch { /* phi = (t + abs(t)) / (1 + abs(t)) */
121c4762a1bSJed Brown   PetscInt i;
122c4762a1bSJed Brown   for (i = 0; i < info->m; i++) lmt[i] = (jL[i] * Abs(jR[i]) + Abs(jL[i]) * jR[i]) / (Abs(jL[i]) + Abs(jR[i]) + 1e-15);
123c4762a1bSJed Brown }
Limit_VanAlbada(LimitInfo info,const PetscScalar * jL,const PetscScalar * jR,PetscScalar * lmt)124c4762a1bSJed Brown static void Limit_VanAlbada(LimitInfo info, const PetscScalar *jL, const PetscScalar *jR, PetscScalar *lmt) /* differentiable */
125c4762a1bSJed Brown {                                                                                                           /* phi = (t + t^2) / (1 + t^2) */
126c4762a1bSJed Brown   PetscInt i;
127c4762a1bSJed Brown   for (i = 0; i < info->m; i++) lmt[i] = (jL[i] * Sqr(jR[i]) + Sqr(jL[i]) * jR[i]) / (Sqr(jL[i]) + Sqr(jR[i]) + 1e-15);
128c4762a1bSJed Brown }
Limit_VanAlbadaTVD(LimitInfo info,const PetscScalar * jL,const PetscScalar * jR,PetscScalar * lmt)129d71ae5a4SJacob Faibussowitsch static void Limit_VanAlbadaTVD(LimitInfo info, const PetscScalar *jL, const PetscScalar *jR, PetscScalar *lmt)
130d71ae5a4SJacob Faibussowitsch { /* phi = (t + t^2) / (1 + t^2) */
131c4762a1bSJed Brown   PetscInt i;
132c4762a1bSJed Brown   for (i = 0; i < info->m; i++) lmt[i] = (jL[i] * jR[i] < 0) ? 0 : (jL[i] * Sqr(jR[i]) + Sqr(jL[i]) * jR[i]) / (Sqr(jL[i]) + Sqr(jR[i]) + 1e-15);
133c4762a1bSJed Brown }
Limit_Koren(LimitInfo info,const PetscScalar * jL,const PetscScalar * jR,PetscScalar * lmt)134c4762a1bSJed Brown static void Limit_Koren(LimitInfo info, const PetscScalar *jL, const PetscScalar *jR, PetscScalar *lmt) /* differentiable */
135c4762a1bSJed Brown {                                                                                                       /* phi = (t + 2*t^2) / (2 - t + 2*t^2) */
136c4762a1bSJed Brown   PetscInt i;
137c4762a1bSJed Brown   for (i = 0; i < info->m; i++) lmt[i] = ((jL[i] * Sqr(jR[i]) + 2 * Sqr(jL[i]) * jR[i]) / (2 * Sqr(jL[i]) - jL[i] * jR[i] + 2 * Sqr(jR[i]) + 1e-15));
138c4762a1bSJed Brown }
Limit_KorenSym(LimitInfo info,const PetscScalar * jL,const PetscScalar * jR,PetscScalar * lmt)139c4762a1bSJed Brown static void Limit_KorenSym(LimitInfo info, const PetscScalar *jL, const PetscScalar *jR, PetscScalar *lmt) /* differentiable */
140c4762a1bSJed Brown {                                                                                                          /* Symmetric version of above */
141c4762a1bSJed Brown   PetscInt i;
142c4762a1bSJed Brown   for (i = 0; i < info->m; i++) lmt[i] = (1.5 * (jL[i] * Sqr(jR[i]) + Sqr(jL[i]) * jR[i]) / (2 * Sqr(jL[i]) - jL[i] * jR[i] + 2 * Sqr(jR[i]) + 1e-15));
143c4762a1bSJed Brown }
Limit_Koren3(LimitInfo info,const PetscScalar * jL,const PetscScalar * jR,PetscScalar * lmt)144d71ae5a4SJacob Faibussowitsch static void Limit_Koren3(LimitInfo info, const PetscScalar *jL, const PetscScalar *jR, PetscScalar *lmt)
145d71ae5a4SJacob Faibussowitsch { /* Eq 11 of Cada-Torrilhon 2009 */
146c4762a1bSJed Brown   PetscInt i;
147c4762a1bSJed Brown   for (i = 0; i < info->m; i++) lmt[i] = MinMod3(2 * jL[i], (jL[i] + 2 * jR[i]) / 3, 2 * jR[i]);
148c4762a1bSJed Brown }
CadaTorrilhonPhiHatR_Eq13(PetscReal L,PetscReal R)149d71ae5a4SJacob Faibussowitsch static PetscReal CadaTorrilhonPhiHatR_Eq13(PetscReal L, PetscReal R)
150d71ae5a4SJacob Faibussowitsch {
151c4762a1bSJed Brown   return PetscMax(0, PetscMin((L + 2 * R) / 3, PetscMax(-0.5 * L, PetscMin(2 * L, PetscMin((L + 2 * R) / 3, 1.6 * R)))));
152c4762a1bSJed Brown }
Limit_CadaTorrilhon2(LimitInfo info,const PetscScalar * jL,const PetscScalar * jR,PetscScalar * lmt)153d71ae5a4SJacob Faibussowitsch static void Limit_CadaTorrilhon2(LimitInfo info, const PetscScalar *jL, const PetscScalar *jR, PetscScalar *lmt)
154d71ae5a4SJacob Faibussowitsch { /* Cada-Torrilhon 2009, Eq 13 */
155c4762a1bSJed Brown   PetscInt i;
156c4762a1bSJed Brown   for (i = 0; i < info->m; i++) lmt[i] = CadaTorrilhonPhiHatR_Eq13(jL[i], jR[i]);
157c4762a1bSJed Brown }
Limit_CadaTorrilhon3R(PetscReal r,LimitInfo info,const PetscScalar * jL,const PetscScalar * jR,PetscScalar * lmt)158d71ae5a4SJacob Faibussowitsch static void Limit_CadaTorrilhon3R(PetscReal r, LimitInfo info, const PetscScalar *jL, const PetscScalar *jR, PetscScalar *lmt)
159d71ae5a4SJacob Faibussowitsch { /* Cada-Torrilhon 2009, Eq 22 */
160c4762a1bSJed Brown   /* They recommend 0.001 < r < 1, but larger values are more accurate in smooth regions */
161c4762a1bSJed Brown   const PetscReal eps = 1e-7, hx = info->hx;
162c4762a1bSJed Brown   PetscInt        i;
163c4762a1bSJed Brown   for (i = 0; i < info->m; i++) {
164c4762a1bSJed Brown     const PetscReal eta = (Sqr(jL[i]) + Sqr(jR[i])) / Sqr(r * hx);
165c4762a1bSJed Brown     lmt[i] = ((eta < 1 - eps) ? (jL[i] + 2 * jR[i]) / 3 : ((eta > 1 + eps) ? CadaTorrilhonPhiHatR_Eq13(jL[i], jR[i]) : 0.5 * ((1 - (eta - 1) / eps) * (jL[i] + 2 * jR[i]) / 3 + (1 + (eta + 1) / eps) * CadaTorrilhonPhiHatR_Eq13(jL[i], jR[i]))));
166c4762a1bSJed Brown   }
167c4762a1bSJed Brown }
Limit_CadaTorrilhon3R0p1(LimitInfo info,const PetscScalar * jL,const PetscScalar * jR,PetscScalar * lmt)168d71ae5a4SJacob Faibussowitsch static void Limit_CadaTorrilhon3R0p1(LimitInfo info, const PetscScalar *jL, const PetscScalar *jR, PetscScalar *lmt)
169d71ae5a4SJacob Faibussowitsch {
170c4762a1bSJed Brown   Limit_CadaTorrilhon3R(0.1, info, jL, jR, lmt);
171c4762a1bSJed Brown }
Limit_CadaTorrilhon3R1(LimitInfo info,const PetscScalar * jL,const PetscScalar * jR,PetscScalar * lmt)172d71ae5a4SJacob Faibussowitsch static void Limit_CadaTorrilhon3R1(LimitInfo info, const PetscScalar *jL, const PetscScalar *jR, PetscScalar *lmt)
173d71ae5a4SJacob Faibussowitsch {
174c4762a1bSJed Brown   Limit_CadaTorrilhon3R(1, info, jL, jR, lmt);
175c4762a1bSJed Brown }
Limit_CadaTorrilhon3R10(LimitInfo info,const PetscScalar * jL,const PetscScalar * jR,PetscScalar * lmt)176d71ae5a4SJacob Faibussowitsch static void Limit_CadaTorrilhon3R10(LimitInfo info, const PetscScalar *jL, const PetscScalar *jR, PetscScalar *lmt)
177d71ae5a4SJacob Faibussowitsch {
178c4762a1bSJed Brown   Limit_CadaTorrilhon3R(10, info, jL, jR, lmt);
179c4762a1bSJed Brown }
Limit_CadaTorrilhon3R100(LimitInfo info,const PetscScalar * jL,const PetscScalar * jR,PetscScalar * lmt)180d71ae5a4SJacob Faibussowitsch static void Limit_CadaTorrilhon3R100(LimitInfo info, const PetscScalar *jL, const PetscScalar *jR, PetscScalar *lmt)
181d71ae5a4SJacob Faibussowitsch {
182c4762a1bSJed Brown   Limit_CadaTorrilhon3R(100, info, jL, jR, lmt);
183c4762a1bSJed Brown }
184c4762a1bSJed Brown 
185c4762a1bSJed Brown /* --------------------------------- Finite Volume data structures ----------------------------------- */
186c4762a1bSJed Brown 
1879371c9d4SSatish Balay typedef enum {
1889371c9d4SSatish Balay   FVBC_PERIODIC,
1899371c9d4SSatish Balay   FVBC_OUTFLOW
1909371c9d4SSatish Balay } FVBCType;
191c4762a1bSJed Brown static const char *FVBCTypes[] = {"PERIODIC", "OUTFLOW", "FVBCType", "FVBC_", 0};
192c4762a1bSJed Brown typedef PetscErrorCode (*RiemannFunction)(void *, PetscInt, const PetscScalar *, const PetscScalar *, PetscScalar *, PetscReal *);
193c4762a1bSJed Brown typedef PetscErrorCode (*ReconstructFunction)(void *, PetscInt, const PetscScalar *, PetscScalar *, PetscScalar *, PetscReal *);
194c4762a1bSJed Brown 
195c4762a1bSJed Brown typedef struct {
196c4762a1bSJed Brown   PetscErrorCode (*sample)(void *, PetscInt, FVBCType, PetscReal, PetscReal, PetscReal, PetscReal, PetscReal *);
197c4762a1bSJed Brown   RiemannFunction     riemann;
198c4762a1bSJed Brown   ReconstructFunction characteristic;
199c4762a1bSJed Brown   PetscErrorCode (*destroy)(void *);
200c4762a1bSJed Brown   void    *user;
201c4762a1bSJed Brown   PetscInt dof;
202c4762a1bSJed Brown   char    *fieldname[16];
203c4762a1bSJed Brown } PhysicsCtx;
204c4762a1bSJed Brown 
205c4762a1bSJed Brown typedef struct {
206c4762a1bSJed Brown   void (*limit)(LimitInfo, const PetscScalar *, const PetscScalar *, PetscScalar *);
207c4762a1bSJed Brown   PhysicsCtx physics;
208c4762a1bSJed Brown   MPI_Comm   comm;
209c4762a1bSJed Brown   char       prefix[256];
210c4762a1bSJed Brown 
211c4762a1bSJed Brown   /* Local work arrays */
212c4762a1bSJed Brown   PetscScalar *R, *Rinv; /* Characteristic basis, and it's inverse.  COLUMN-MAJOR */
213c4762a1bSJed Brown   PetscScalar *cjmpLR;   /* Jumps at left and right edge of cell, in characteristic basis, len=2*dof */
214c4762a1bSJed Brown   PetscScalar *cslope;   /* Limited slope, written in characteristic basis */
215c4762a1bSJed Brown   PetscScalar *uLR;      /* Solution at left and right of interface, conservative variables, len=2*dof */
216c4762a1bSJed Brown   PetscScalar *flux;     /* Flux across interface */
217c4762a1bSJed Brown   PetscReal   *speeds;   /* Speeds of each wave */
218c4762a1bSJed Brown 
219c4762a1bSJed Brown   PetscReal cfl_idt; /* Max allowable value of 1/Delta t */
220c4762a1bSJed Brown   PetscReal cfl;
221c4762a1bSJed Brown   PetscReal xmin, xmax;
222c4762a1bSJed Brown   PetscInt  initial;
223c4762a1bSJed Brown   PetscBool exact;
224c4762a1bSJed Brown   FVBCType  bctype;
225c4762a1bSJed Brown } FVCtx;
226c4762a1bSJed Brown 
RiemannListAdd(PetscFunctionList * flist,const char * name,RiemannFunction rsolve)227d71ae5a4SJacob Faibussowitsch PetscErrorCode RiemannListAdd(PetscFunctionList *flist, const char *name, RiemannFunction rsolve)
228d71ae5a4SJacob Faibussowitsch {
229c4762a1bSJed Brown   PetscFunctionBeginUser;
2309566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(flist, name, rsolve));
2313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
232c4762a1bSJed Brown }
233c4762a1bSJed Brown 
RiemannListFind(PetscFunctionList flist,const char * name,RiemannFunction * rsolve)234d71ae5a4SJacob Faibussowitsch PetscErrorCode RiemannListFind(PetscFunctionList flist, const char *name, RiemannFunction *rsolve)
235d71ae5a4SJacob Faibussowitsch {
236c4762a1bSJed Brown   PetscFunctionBeginUser;
2379566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListFind(flist, name, rsolve));
2383c633725SBarry Smith   PetscCheck(*rsolve, PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "Riemann solver \"%s\" could not be found", name);
2393ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
240c4762a1bSJed Brown }
241c4762a1bSJed Brown 
ReconstructListAdd(PetscFunctionList * flist,const char * name,ReconstructFunction r)242d71ae5a4SJacob Faibussowitsch PetscErrorCode ReconstructListAdd(PetscFunctionList *flist, const char *name, ReconstructFunction r)
243d71ae5a4SJacob Faibussowitsch {
244c4762a1bSJed Brown   PetscFunctionBeginUser;
2459566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(flist, name, r));
2463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
247c4762a1bSJed Brown }
248c4762a1bSJed Brown 
ReconstructListFind(PetscFunctionList flist,const char * name,ReconstructFunction * r)249d71ae5a4SJacob Faibussowitsch PetscErrorCode ReconstructListFind(PetscFunctionList flist, const char *name, ReconstructFunction *r)
250d71ae5a4SJacob Faibussowitsch {
251c4762a1bSJed Brown   PetscFunctionBeginUser;
2529566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListFind(flist, name, r));
2533c633725SBarry Smith   PetscCheck(*r, PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "Reconstruction \"%s\" could not be found", name);
2543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
255c4762a1bSJed Brown }
256c4762a1bSJed Brown 
257c4762a1bSJed Brown /* --------------------------------- Physics ----------------------------------- */
2580e3d61c9SBarry Smith /*
2590e3d61c9SBarry Smith   Each physical model consists of Riemann solver and a function to determine the basis to use for reconstruction.  These
2600e3d61c9SBarry Smith   are set with the PhysicsCreate_XXX function which allocates private storage and sets these methods as well as the
2610e3d61c9SBarry Smith   number of fields and their names, and a function to deallocate private storage.
2620e3d61c9SBarry Smith */
263c4762a1bSJed Brown 
264c4762a1bSJed Brown /* First a few functions useful to several different physics */
PhysicsCharacteristic_Conservative(void * vctx,PetscInt m,const PetscScalar * u,PetscScalar * X,PetscScalar * Xi,PetscReal * speeds)265d71ae5a4SJacob Faibussowitsch static PetscErrorCode PhysicsCharacteristic_Conservative(void *vctx, PetscInt m, const PetscScalar *u, PetscScalar *X, PetscScalar *Xi, PetscReal *speeds)
266d71ae5a4SJacob Faibussowitsch {
267c4762a1bSJed Brown   PetscInt i, j;
268c4762a1bSJed Brown 
269c4762a1bSJed Brown   PetscFunctionBeginUser;
270c4762a1bSJed Brown   for (i = 0; i < m; i++) {
271c4762a1bSJed Brown     for (j = 0; j < m; j++) Xi[i * m + j] = X[i * m + j] = (PetscScalar)(i == j);
272c4762a1bSJed Brown     speeds[i] = PETSC_MAX_REAL; /* Indicates invalid */
273c4762a1bSJed Brown   }
2743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
275c4762a1bSJed Brown }
276c4762a1bSJed Brown 
PhysicsDestroy_SimpleFree(void * vctx)277d71ae5a4SJacob Faibussowitsch static PetscErrorCode PhysicsDestroy_SimpleFree(void *vctx)
278d71ae5a4SJacob Faibussowitsch {
279c4762a1bSJed Brown   PetscFunctionBeginUser;
2809566063dSJacob Faibussowitsch   PetscCall(PetscFree(vctx));
2813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
282c4762a1bSJed Brown }
283c4762a1bSJed Brown 
284c4762a1bSJed Brown /* --------------------------------- Advection ----------------------------------- */
285c4762a1bSJed Brown 
286c4762a1bSJed Brown typedef struct {
287c4762a1bSJed Brown   PetscReal a; /* advective velocity */
288c4762a1bSJed Brown } AdvectCtx;
289c4762a1bSJed Brown 
PhysicsRiemann_Advect(void * vctx,PetscInt m,const PetscScalar * uL,const PetscScalar * uR,PetscScalar * flux,PetscReal * maxspeed)290d71ae5a4SJacob Faibussowitsch static PetscErrorCode PhysicsRiemann_Advect(void *vctx, PetscInt m, const PetscScalar *uL, const PetscScalar *uR, PetscScalar *flux, PetscReal *maxspeed)
291d71ae5a4SJacob Faibussowitsch {
292c4762a1bSJed Brown   AdvectCtx *ctx = (AdvectCtx *)vctx;
293c4762a1bSJed Brown   PetscReal  speed;
294c4762a1bSJed Brown 
295c4762a1bSJed Brown   PetscFunctionBeginUser;
296c4762a1bSJed Brown   speed     = ctx->a;
297c4762a1bSJed Brown   flux[0]   = PetscMax(0, speed) * uL[0] + PetscMin(0, speed) * uR[0];
298c4762a1bSJed Brown   *maxspeed = speed;
2993ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
300c4762a1bSJed Brown }
301c4762a1bSJed Brown 
PhysicsCharacteristic_Advect(void * vctx,PetscInt m,const PetscScalar * u,PetscScalar * X,PetscScalar * Xi,PetscReal * speeds)302d71ae5a4SJacob Faibussowitsch static PetscErrorCode PhysicsCharacteristic_Advect(void *vctx, PetscInt m, const PetscScalar *u, PetscScalar *X, PetscScalar *Xi, PetscReal *speeds)
303d71ae5a4SJacob Faibussowitsch {
304c4762a1bSJed Brown   AdvectCtx *ctx = (AdvectCtx *)vctx;
305c4762a1bSJed Brown 
306c4762a1bSJed Brown   PetscFunctionBeginUser;
307c4762a1bSJed Brown   X[0]      = 1.;
308c4762a1bSJed Brown   Xi[0]     = 1.;
309c4762a1bSJed Brown   speeds[0] = ctx->a;
3103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
311c4762a1bSJed Brown }
312c4762a1bSJed Brown 
PhysicsSample_Advect(void * vctx,PetscInt initial,FVBCType bctype,PetscReal xmin,PetscReal xmax,PetscReal t,PetscReal x,PetscReal * u)313d71ae5a4SJacob Faibussowitsch static PetscErrorCode PhysicsSample_Advect(void *vctx, PetscInt initial, FVBCType bctype, PetscReal xmin, PetscReal xmax, PetscReal t, PetscReal x, PetscReal *u)
314d71ae5a4SJacob Faibussowitsch {
315c4762a1bSJed Brown   AdvectCtx *ctx = (AdvectCtx *)vctx;
316c4762a1bSJed Brown   PetscReal  a   = ctx->a, x0;
317c4762a1bSJed Brown 
318c4762a1bSJed Brown   PetscFunctionBeginUser;
319c4762a1bSJed Brown   switch (bctype) {
320d71ae5a4SJacob Faibussowitsch   case FVBC_OUTFLOW:
321d71ae5a4SJacob Faibussowitsch     x0 = x - a * t;
322d71ae5a4SJacob Faibussowitsch     break;
323d71ae5a4SJacob Faibussowitsch   case FVBC_PERIODIC:
324d71ae5a4SJacob Faibussowitsch     x0 = RangeMod(x - a * t, xmin, xmax);
325d71ae5a4SJacob Faibussowitsch     break;
326d71ae5a4SJacob Faibussowitsch   default:
327d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "unknown BCType");
328c4762a1bSJed Brown   }
329c4762a1bSJed Brown   switch (initial) {
330d71ae5a4SJacob Faibussowitsch   case 0:
331d71ae5a4SJacob Faibussowitsch     u[0] = (x0 < 0) ? 1 : -1;
332d71ae5a4SJacob Faibussowitsch     break;
333d71ae5a4SJacob Faibussowitsch   case 1:
334d71ae5a4SJacob Faibussowitsch     u[0] = (x0 < 0) ? -1 : 1;
335d71ae5a4SJacob Faibussowitsch     break;
336d71ae5a4SJacob Faibussowitsch   case 2:
337d71ae5a4SJacob Faibussowitsch     u[0] = (0 < x0 && x0 < 1) ? 1 : 0;
338d71ae5a4SJacob Faibussowitsch     break;
339d71ae5a4SJacob Faibussowitsch   case 3:
340d71ae5a4SJacob Faibussowitsch     u[0] = PetscSinReal(2 * PETSC_PI * x0);
341d71ae5a4SJacob Faibussowitsch     break;
342d71ae5a4SJacob Faibussowitsch   case 4:
343d71ae5a4SJacob Faibussowitsch     u[0] = PetscAbs(x0);
344d71ae5a4SJacob Faibussowitsch     break;
345d71ae5a4SJacob Faibussowitsch   case 5:
346d71ae5a4SJacob Faibussowitsch     u[0] = (x0 < 0 || x0 > 0.5) ? 0 : PetscSqr(PetscSinReal(2 * PETSC_PI * x0));
347d71ae5a4SJacob Faibussowitsch     break;
348d71ae5a4SJacob Faibussowitsch   case 6:
349d71ae5a4SJacob Faibussowitsch     u[0] = (x0 < 0) ? 0 : ((x0 < 1) ? x0 : ((x0 < 2) ? 2 - x0 : 0));
350d71ae5a4SJacob Faibussowitsch     break;
351d71ae5a4SJacob Faibussowitsch   case 7:
352d71ae5a4SJacob Faibussowitsch     u[0] = PetscPowReal(PetscSinReal(PETSC_PI * x0), 10.0);
353d71ae5a4SJacob Faibussowitsch     break;
354d71ae5a4SJacob Faibussowitsch   default:
355d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "unknown initial condition");
356c4762a1bSJed Brown   }
3573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
358c4762a1bSJed Brown }
359c4762a1bSJed Brown 
PhysicsCreate_Advect(FVCtx * ctx)360d71ae5a4SJacob Faibussowitsch static PetscErrorCode PhysicsCreate_Advect(FVCtx *ctx)
361d71ae5a4SJacob Faibussowitsch {
362c4762a1bSJed Brown   AdvectCtx *user;
363c4762a1bSJed Brown 
364c4762a1bSJed Brown   PetscFunctionBeginUser;
3659566063dSJacob Faibussowitsch   PetscCall(PetscNew(&user));
366c4762a1bSJed Brown   ctx->physics.sample         = PhysicsSample_Advect;
367c4762a1bSJed Brown   ctx->physics.riemann        = PhysicsRiemann_Advect;
368c4762a1bSJed Brown   ctx->physics.characteristic = PhysicsCharacteristic_Advect;
369c4762a1bSJed Brown   ctx->physics.destroy        = PhysicsDestroy_SimpleFree;
370c4762a1bSJed Brown   ctx->physics.user           = user;
371c4762a1bSJed Brown   ctx->physics.dof            = 1;
3729566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy("u", &ctx->physics.fieldname[0]));
373c4762a1bSJed Brown   user->a = 1;
374d0609cedSBarry Smith   PetscOptionsBegin(ctx->comm, ctx->prefix, "Options for advection", "");
375d71ae5a4SJacob Faibussowitsch   {
376d71ae5a4SJacob Faibussowitsch     PetscCall(PetscOptionsReal("-physics_advect_a", "Speed", "", user->a, &user->a, NULL));
377d71ae5a4SJacob Faibussowitsch   }
378d0609cedSBarry Smith   PetscOptionsEnd();
3793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
380c4762a1bSJed Brown }
381c4762a1bSJed Brown 
382c4762a1bSJed Brown /* --------------------------------- Burgers ----------------------------------- */
383c4762a1bSJed Brown 
384c4762a1bSJed Brown typedef struct {
385c4762a1bSJed Brown   PetscReal lxf_speed;
386c4762a1bSJed Brown } BurgersCtx;
387c4762a1bSJed Brown 
PhysicsSample_Burgers(void * vctx,PetscInt initial,FVBCType bctype,PetscReal xmin,PetscReal xmax,PetscReal t,PetscReal x,PetscReal * u)388d71ae5a4SJacob Faibussowitsch static PetscErrorCode PhysicsSample_Burgers(void *vctx, PetscInt initial, FVBCType bctype, PetscReal xmin, PetscReal xmax, PetscReal t, PetscReal x, PetscReal *u)
389d71ae5a4SJacob Faibussowitsch {
390c4762a1bSJed Brown   PetscFunctionBeginUser;
3913c633725SBarry Smith   PetscCheck(bctype != FVBC_PERIODIC || t <= 0, PETSC_COMM_SELF, PETSC_ERR_SUP, "Exact solution not implemented for periodic");
392c4762a1bSJed Brown   switch (initial) {
393d71ae5a4SJacob Faibussowitsch   case 0:
394d71ae5a4SJacob Faibussowitsch     u[0] = (x < 0) ? 1 : -1;
395d71ae5a4SJacob Faibussowitsch     break;
396c4762a1bSJed Brown   case 1:
397c4762a1bSJed Brown     if (x < -t) u[0] = -1;
398c4762a1bSJed Brown     else if (x < t) u[0] = x / t;
399c4762a1bSJed Brown     else u[0] = 1;
400c4762a1bSJed Brown     break;
401c4762a1bSJed Brown   case 2:
4020912c85aSBarry Smith     if (x <= 0) u[0] = 0;
4030912c85aSBarry Smith     else if (x < t) u[0] = x / t;
404c4762a1bSJed Brown     else if (x < 1 + 0.5 * t) u[0] = 1;
405c4762a1bSJed Brown     else u[0] = 0;
406c4762a1bSJed Brown     break;
407c4762a1bSJed Brown   case 3:
408c4762a1bSJed Brown     if (x < 0.2 * t) u[0] = 0.2;
409c4762a1bSJed Brown     else if (x < t) u[0] = x / t;
410c4762a1bSJed Brown     else u[0] = 1;
411c4762a1bSJed Brown     break;
412c4762a1bSJed Brown   case 4:
4133c633725SBarry Smith     PetscCheck(t <= 0, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only initial condition available");
414c4762a1bSJed Brown     u[0] = 0.7 + 0.3 * PetscSinReal(2 * PETSC_PI * ((x - xmin) / (xmax - xmin)));
415c4762a1bSJed Brown     break;
416c4762a1bSJed Brown   case 5: /* Pure shock solution */
417c4762a1bSJed Brown     if (x < 0.5 * t) u[0] = 1;
418c4762a1bSJed Brown     else u[0] = 0;
419c4762a1bSJed Brown     break;
420d71ae5a4SJacob Faibussowitsch   default:
421d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "unknown initial condition");
422c4762a1bSJed Brown   }
4233ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
424c4762a1bSJed Brown }
425c4762a1bSJed Brown 
PhysicsRiemann_Burgers_Exact(void * vctx,PetscInt m,const PetscScalar * uL,const PetscScalar * uR,PetscScalar * flux,PetscReal * maxspeed)426d71ae5a4SJacob Faibussowitsch static PetscErrorCode PhysicsRiemann_Burgers_Exact(void *vctx, PetscInt m, const PetscScalar *uL, const PetscScalar *uR, PetscScalar *flux, PetscReal *maxspeed)
427d71ae5a4SJacob Faibussowitsch {
428c4762a1bSJed Brown   PetscFunctionBeginUser;
429c4762a1bSJed Brown   if (uL[0] < uR[0]) {                /* rarefaction */
4309371c9d4SSatish Balay     flux[0] = (uL[0] * uR[0] < 0) ? 0 /* sonic rarefaction */
431c4762a1bSJed Brown                                   : 0.5 * PetscMin(PetscSqr(uL[0]), PetscSqr(uR[0]));
432c4762a1bSJed Brown   } else { /* shock */
433c4762a1bSJed Brown     flux[0] = 0.5 * PetscMax(PetscSqr(uL[0]), PetscSqr(uR[0]));
434c4762a1bSJed Brown   }
435c4762a1bSJed Brown   *maxspeed = (PetscAbs(uL[0]) > PetscAbs(uR[0])) ? uL[0] : uR[0];
4363ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
437c4762a1bSJed Brown }
438c4762a1bSJed Brown 
PhysicsRiemann_Burgers_Roe(void * vctx,PetscInt m,const PetscScalar * uL,const PetscScalar * uR,PetscScalar * flux,PetscReal * maxspeed)439d71ae5a4SJacob Faibussowitsch static PetscErrorCode PhysicsRiemann_Burgers_Roe(void *vctx, PetscInt m, const PetscScalar *uL, const PetscScalar *uR, PetscScalar *flux, PetscReal *maxspeed)
440d71ae5a4SJacob Faibussowitsch {
441c4762a1bSJed Brown   PetscReal speed;
442c4762a1bSJed Brown 
443c4762a1bSJed Brown   PetscFunctionBeginUser;
444c4762a1bSJed Brown   speed   = 0.5 * (uL[0] + uR[0]);
445c4762a1bSJed Brown   flux[0] = 0.25 * (PetscSqr(uL[0]) + PetscSqr(uR[0])) - 0.5 * PetscAbs(speed) * (uR[0] - uL[0]);
446c4762a1bSJed Brown   if (uL[0] <= 0 && 0 <= uR[0]) flux[0] = 0; /* Entropy fix for sonic rarefaction */
447c4762a1bSJed Brown   *maxspeed = speed;
4483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
449c4762a1bSJed Brown }
450c4762a1bSJed Brown 
PhysicsRiemann_Burgers_LxF(void * vctx,PetscInt m,const PetscScalar * uL,const PetscScalar * uR,PetscScalar * flux,PetscReal * maxspeed)451d71ae5a4SJacob Faibussowitsch static PetscErrorCode PhysicsRiemann_Burgers_LxF(void *vctx, PetscInt m, const PetscScalar *uL, const PetscScalar *uR, PetscScalar *flux, PetscReal *maxspeed)
452d71ae5a4SJacob Faibussowitsch {
453c4762a1bSJed Brown   PetscReal   c;
454c4762a1bSJed Brown   PetscScalar fL, fR;
455c4762a1bSJed Brown 
456c4762a1bSJed Brown   PetscFunctionBeginUser;
457c4762a1bSJed Brown   c         = ((BurgersCtx *)vctx)->lxf_speed;
458c4762a1bSJed Brown   fL        = 0.5 * PetscSqr(uL[0]);
459c4762a1bSJed Brown   fR        = 0.5 * PetscSqr(uR[0]);
460c4762a1bSJed Brown   flux[0]   = 0.5 * (fL + fR) - 0.5 * c * (uR[0] - uL[0]);
461c4762a1bSJed Brown   *maxspeed = c;
4623ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
463c4762a1bSJed Brown }
464c4762a1bSJed Brown 
PhysicsRiemann_Burgers_Rusanov(void * vctx,PetscInt m,const PetscScalar * uL,const PetscScalar * uR,PetscScalar * flux,PetscReal * maxspeed)465d71ae5a4SJacob Faibussowitsch static PetscErrorCode PhysicsRiemann_Burgers_Rusanov(void *vctx, PetscInt m, const PetscScalar *uL, const PetscScalar *uR, PetscScalar *flux, PetscReal *maxspeed)
466d71ae5a4SJacob Faibussowitsch {
467c4762a1bSJed Brown   PetscReal   c;
468c4762a1bSJed Brown   PetscScalar fL, fR;
469c4762a1bSJed Brown 
470c4762a1bSJed Brown   PetscFunctionBeginUser;
471c4762a1bSJed Brown   c         = PetscMax(PetscAbs(uL[0]), PetscAbs(uR[0]));
472c4762a1bSJed Brown   fL        = 0.5 * PetscSqr(uL[0]);
473c4762a1bSJed Brown   fR        = 0.5 * PetscSqr(uR[0]);
474c4762a1bSJed Brown   flux[0]   = 0.5 * (fL + fR) - 0.5 * c * (uR[0] - uL[0]);
475c4762a1bSJed Brown   *maxspeed = c;
4763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
477c4762a1bSJed Brown }
478c4762a1bSJed Brown 
PhysicsCreate_Burgers(FVCtx * ctx)479d71ae5a4SJacob Faibussowitsch static PetscErrorCode PhysicsCreate_Burgers(FVCtx *ctx)
480d71ae5a4SJacob Faibussowitsch {
481c4762a1bSJed Brown   BurgersCtx       *user;
482c4762a1bSJed Brown   RiemannFunction   r;
483c4762a1bSJed Brown   PetscFunctionList rlist      = 0;
484c4762a1bSJed Brown   char              rname[256] = "exact";
485c4762a1bSJed Brown 
486c4762a1bSJed Brown   PetscFunctionBeginUser;
4879566063dSJacob Faibussowitsch   PetscCall(PetscNew(&user));
488c4762a1bSJed Brown 
489c4762a1bSJed Brown   ctx->physics.sample         = PhysicsSample_Burgers;
490c4762a1bSJed Brown   ctx->physics.characteristic = PhysicsCharacteristic_Conservative;
491c4762a1bSJed Brown   ctx->physics.destroy        = PhysicsDestroy_SimpleFree;
492c4762a1bSJed Brown   ctx->physics.user           = user;
493c4762a1bSJed Brown   ctx->physics.dof            = 1;
494c4762a1bSJed Brown 
4959566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy("u", &ctx->physics.fieldname[0]));
4969566063dSJacob Faibussowitsch   PetscCall(RiemannListAdd(&rlist, "exact", PhysicsRiemann_Burgers_Exact));
4979566063dSJacob Faibussowitsch   PetscCall(RiemannListAdd(&rlist, "roe", PhysicsRiemann_Burgers_Roe));
4989566063dSJacob Faibussowitsch   PetscCall(RiemannListAdd(&rlist, "lxf", PhysicsRiemann_Burgers_LxF));
4999566063dSJacob Faibussowitsch   PetscCall(RiemannListAdd(&rlist, "rusanov", PhysicsRiemann_Burgers_Rusanov));
500d0609cedSBarry Smith   PetscOptionsBegin(ctx->comm, ctx->prefix, "Options for advection", "");
501d71ae5a4SJacob Faibussowitsch   {
502d71ae5a4SJacob Faibussowitsch     PetscCall(PetscOptionsFList("-physics_burgers_riemann", "Riemann solver", "", rlist, rname, rname, sizeof(rname), NULL));
503d71ae5a4SJacob Faibussowitsch   }
504d0609cedSBarry Smith   PetscOptionsEnd();
5059566063dSJacob Faibussowitsch   PetscCall(RiemannListFind(rlist, rname, &r));
5069566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListDestroy(&rlist));
507c4762a1bSJed Brown   ctx->physics.riemann = r;
508c4762a1bSJed Brown 
509c4762a1bSJed Brown   /* *
510c4762a1bSJed Brown   * Hack to deal with LxF in semi-discrete form
511c4762a1bSJed Brown   * max speed is 1 for the basic initial conditions (where |u| <= 1)
512c4762a1bSJed Brown   * */
513c4762a1bSJed Brown   if (r == PhysicsRiemann_Burgers_LxF) user->lxf_speed = 1;
5143ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
515c4762a1bSJed Brown }
516c4762a1bSJed Brown 
517c4762a1bSJed Brown /* --------------------------------- Traffic ----------------------------------- */
518c4762a1bSJed Brown 
519c4762a1bSJed Brown typedef struct {
520c4762a1bSJed Brown   PetscReal lxf_speed;
521c4762a1bSJed Brown   PetscReal a;
522c4762a1bSJed Brown } TrafficCtx;
523c4762a1bSJed Brown 
TrafficFlux(PetscScalar a,PetscScalar u)524d71ae5a4SJacob Faibussowitsch static inline PetscScalar TrafficFlux(PetscScalar a, PetscScalar u)
525d71ae5a4SJacob Faibussowitsch {
5269371c9d4SSatish Balay   return a * u * (1 - u);
5279371c9d4SSatish Balay }
528c4762a1bSJed Brown 
PhysicsSample_Traffic(void * vctx,PetscInt initial,FVBCType bctype,PetscReal xmin,PetscReal xmax,PetscReal t,PetscReal x,PetscReal * u)529d71ae5a4SJacob Faibussowitsch static PetscErrorCode PhysicsSample_Traffic(void *vctx, PetscInt initial, FVBCType bctype, PetscReal xmin, PetscReal xmax, PetscReal t, PetscReal x, PetscReal *u)
530d71ae5a4SJacob Faibussowitsch {
531c4762a1bSJed Brown   PetscReal a = ((TrafficCtx *)vctx)->a;
532c4762a1bSJed Brown 
533c4762a1bSJed Brown   PetscFunctionBeginUser;
5343c633725SBarry Smith   PetscCheck(bctype != FVBC_PERIODIC || t <= 0, PETSC_COMM_SELF, PETSC_ERR_SUP, "Exact solution not implemented for periodic");
535c4762a1bSJed Brown   switch (initial) {
536d71ae5a4SJacob Faibussowitsch   case 0:
537d71ae5a4SJacob Faibussowitsch     u[0] = (-a * t < x) ? 2 : 0;
538d71ae5a4SJacob Faibussowitsch     break;
539c4762a1bSJed Brown   case 1:
540c4762a1bSJed Brown     if (x < PetscMin(2 * a * t, 0.5 + a * t)) u[0] = -1;
541c4762a1bSJed Brown     else if (x < 1) u[0] = 0;
542c4762a1bSJed Brown     else u[0] = 1;
543c4762a1bSJed Brown     break;
544c4762a1bSJed Brown   case 2:
5453c633725SBarry Smith     PetscCheck(t <= 0, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only initial condition available");
546c4762a1bSJed Brown     u[0] = 0.7 + 0.3 * PetscSinReal(2 * PETSC_PI * ((x - xmin) / (xmax - xmin)));
547c4762a1bSJed Brown     break;
548d71ae5a4SJacob Faibussowitsch   default:
549d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "unknown initial condition");
550c4762a1bSJed Brown   }
5513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
552c4762a1bSJed Brown }
553c4762a1bSJed Brown 
PhysicsRiemann_Traffic_Exact(void * vctx,PetscInt m,const PetscScalar * uL,const PetscScalar * uR,PetscScalar * flux,PetscReal * maxspeed)554d71ae5a4SJacob Faibussowitsch static PetscErrorCode PhysicsRiemann_Traffic_Exact(void *vctx, PetscInt m, const PetscScalar *uL, const PetscScalar *uR, PetscScalar *flux, PetscReal *maxspeed)
555d71ae5a4SJacob Faibussowitsch {
556c4762a1bSJed Brown   PetscReal a = ((TrafficCtx *)vctx)->a;
557c4762a1bSJed Brown 
558c4762a1bSJed Brown   PetscFunctionBeginUser;
559c4762a1bSJed Brown   if (uL[0] < uR[0]) {
560c4762a1bSJed Brown     flux[0] = PetscMin(TrafficFlux(a, uL[0]), TrafficFlux(a, uR[0]));
561c4762a1bSJed Brown   } else {
562c4762a1bSJed Brown     flux[0] = (uR[0] < 0.5 && 0.5 < uL[0]) ? TrafficFlux(a, 0.5) : PetscMax(TrafficFlux(a, uL[0]), TrafficFlux(a, uR[0]));
563c4762a1bSJed Brown   }
564c4762a1bSJed Brown   *maxspeed = a * MaxAbs(1 - 2 * uL[0], 1 - 2 * uR[0]);
5653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
566c4762a1bSJed Brown }
567c4762a1bSJed Brown 
PhysicsRiemann_Traffic_Roe(void * vctx,PetscInt m,const PetscScalar * uL,const PetscScalar * uR,PetscScalar * flux,PetscReal * maxspeed)568d71ae5a4SJacob Faibussowitsch static PetscErrorCode PhysicsRiemann_Traffic_Roe(void *vctx, PetscInt m, const PetscScalar *uL, const PetscScalar *uR, PetscScalar *flux, PetscReal *maxspeed)
569d71ae5a4SJacob Faibussowitsch {
570c4762a1bSJed Brown   PetscReal a = ((TrafficCtx *)vctx)->a;
571c4762a1bSJed Brown   PetscReal speed;
572c4762a1bSJed Brown 
573c4762a1bSJed Brown   PetscFunctionBeginUser;
574c4762a1bSJed Brown   speed     = a * (1 - (uL[0] + uR[0]));
575c4762a1bSJed Brown   flux[0]   = 0.5 * (TrafficFlux(a, uL[0]) + TrafficFlux(a, uR[0])) - 0.5 * PetscAbs(speed) * (uR[0] - uL[0]);
576c4762a1bSJed Brown   *maxspeed = speed;
5773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
578c4762a1bSJed Brown }
579c4762a1bSJed Brown 
PhysicsRiemann_Traffic_LxF(void * vctx,PetscInt m,const PetscScalar * uL,const PetscScalar * uR,PetscScalar * flux,PetscReal * maxspeed)580d71ae5a4SJacob Faibussowitsch static PetscErrorCode PhysicsRiemann_Traffic_LxF(void *vctx, PetscInt m, const PetscScalar *uL, const PetscScalar *uR, PetscScalar *flux, PetscReal *maxspeed)
581d71ae5a4SJacob Faibussowitsch {
582c4762a1bSJed Brown   TrafficCtx *phys = (TrafficCtx *)vctx;
583c4762a1bSJed Brown   PetscReal   a    = phys->a;
584c4762a1bSJed Brown   PetscReal   speed;
585c4762a1bSJed Brown 
586c4762a1bSJed Brown   PetscFunctionBeginUser;
587c4762a1bSJed Brown   speed     = a * (1 - (uL[0] + uR[0]));
588c4762a1bSJed Brown   flux[0]   = 0.5 * (TrafficFlux(a, uL[0]) + TrafficFlux(a, uR[0])) - 0.5 * phys->lxf_speed * (uR[0] - uL[0]);
589c4762a1bSJed Brown   *maxspeed = speed;
5903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
591c4762a1bSJed Brown }
592c4762a1bSJed Brown 
PhysicsRiemann_Traffic_Rusanov(void * vctx,PetscInt m,const PetscScalar * uL,const PetscScalar * uR,PetscScalar * flux,PetscReal * maxspeed)593d71ae5a4SJacob Faibussowitsch static PetscErrorCode PhysicsRiemann_Traffic_Rusanov(void *vctx, PetscInt m, const PetscScalar *uL, const PetscScalar *uR, PetscScalar *flux, PetscReal *maxspeed)
594d71ae5a4SJacob Faibussowitsch {
595c4762a1bSJed Brown   PetscReal a = ((TrafficCtx *)vctx)->a;
596c4762a1bSJed Brown   PetscReal speed;
597c4762a1bSJed Brown 
598c4762a1bSJed Brown   PetscFunctionBeginUser;
599c4762a1bSJed Brown   speed     = a * PetscMax(PetscAbs(1 - 2 * uL[0]), PetscAbs(1 - 2 * uR[0]));
600c4762a1bSJed Brown   flux[0]   = 0.5 * (TrafficFlux(a, uL[0]) + TrafficFlux(a, uR[0])) - 0.5 * speed * (uR[0] - uL[0]);
601c4762a1bSJed Brown   *maxspeed = speed;
6023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
603c4762a1bSJed Brown }
604c4762a1bSJed Brown 
PhysicsCreate_Traffic(FVCtx * ctx)605d71ae5a4SJacob Faibussowitsch static PetscErrorCode PhysicsCreate_Traffic(FVCtx *ctx)
606d71ae5a4SJacob Faibussowitsch {
607c4762a1bSJed Brown   TrafficCtx       *user;
608c4762a1bSJed Brown   RiemannFunction   r;
609c4762a1bSJed Brown   PetscFunctionList rlist      = 0;
610c4762a1bSJed Brown   char              rname[256] = "exact";
611c4762a1bSJed Brown 
612c4762a1bSJed Brown   PetscFunctionBeginUser;
6139566063dSJacob Faibussowitsch   PetscCall(PetscNew(&user));
614c4762a1bSJed Brown   ctx->physics.sample         = PhysicsSample_Traffic;
615c4762a1bSJed Brown   ctx->physics.characteristic = PhysicsCharacteristic_Conservative;
616c4762a1bSJed Brown   ctx->physics.destroy        = PhysicsDestroy_SimpleFree;
617c4762a1bSJed Brown   ctx->physics.user           = user;
618c4762a1bSJed Brown   ctx->physics.dof            = 1;
619c4762a1bSJed Brown 
6209566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy("density", &ctx->physics.fieldname[0]));
621c4762a1bSJed Brown   user->a = 0.5;
6229566063dSJacob Faibussowitsch   PetscCall(RiemannListAdd(&rlist, "exact", PhysicsRiemann_Traffic_Exact));
6239566063dSJacob Faibussowitsch   PetscCall(RiemannListAdd(&rlist, "roe", PhysicsRiemann_Traffic_Roe));
6249566063dSJacob Faibussowitsch   PetscCall(RiemannListAdd(&rlist, "lxf", PhysicsRiemann_Traffic_LxF));
6259566063dSJacob Faibussowitsch   PetscCall(RiemannListAdd(&rlist, "rusanov", PhysicsRiemann_Traffic_Rusanov));
626d0609cedSBarry Smith   PetscOptionsBegin(ctx->comm, ctx->prefix, "Options for Traffic", "");
6279566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-physics_traffic_a", "Flux = a*u*(1-u)", "", user->a, &user->a, NULL));
6289566063dSJacob Faibussowitsch   PetscCall(PetscOptionsFList("-physics_traffic_riemann", "Riemann solver", "", rlist, rname, rname, sizeof(rname), NULL));
629d0609cedSBarry Smith   PetscOptionsEnd();
630c4762a1bSJed Brown 
6319566063dSJacob Faibussowitsch   PetscCall(RiemannListFind(rlist, rname, &r));
6329566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListDestroy(&rlist));
633c4762a1bSJed Brown 
634c4762a1bSJed Brown   ctx->physics.riemann = r;
635c4762a1bSJed Brown 
636c4762a1bSJed Brown   /* *
637c4762a1bSJed Brown   * Hack to deal with LxF in semi-discrete form
638c4762a1bSJed Brown   * max speed is 3*a for the basic initial conditions (-1 <= u <= 2)
639c4762a1bSJed Brown   * */
640c4762a1bSJed Brown   if (r == PhysicsRiemann_Traffic_LxF) user->lxf_speed = 3 * user->a;
6413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
642c4762a1bSJed Brown }
643c4762a1bSJed Brown 
644c4762a1bSJed Brown /* --------------------------------- Linear Acoustics ----------------------------------- */
645c4762a1bSJed Brown 
646c4762a1bSJed Brown /* Flux: u_t + (A u)_x
647c4762a1bSJed Brown  * z = sqrt(rho*bulk), c = sqrt(rho/bulk)
648c4762a1bSJed Brown  * Spectral decomposition: A = R * D * Rinv
649c4762a1bSJed Brown  * [    cz] = [-z   z] [-c    ] [-1/2z  1/2]
650c4762a1bSJed Brown  * [c/z   ] = [ 1   1] [     c] [ 1/2z  1/2]
651c4762a1bSJed Brown  *
652c4762a1bSJed Brown  * We decompose this into the left-traveling waves Al = R * D^- Rinv
653c4762a1bSJed Brown  * and the right-traveling waves Ar = R * D^+ * Rinv
654c4762a1bSJed Brown  * Multiplying out these expressions produces the following two matrices
655c4762a1bSJed Brown  */
656c4762a1bSJed Brown 
657c4762a1bSJed Brown typedef struct {
658c4762a1bSJed Brown   PetscReal c; /* speed of sound: c = sqrt(bulk/rho) */
659da81f932SPierre Jolivet   PetscReal z; /* impedance: z = sqrt(rho*bulk) */
660c4762a1bSJed Brown } AcousticsCtx;
661c4762a1bSJed Brown 
AcousticsFlux(AcousticsCtx * ctx,const PetscScalar * u,PetscScalar * f)662d71ae5a4SJacob Faibussowitsch PETSC_UNUSED static inline void AcousticsFlux(AcousticsCtx *ctx, const PetscScalar *u, PetscScalar *f)
663d71ae5a4SJacob Faibussowitsch {
664c4762a1bSJed Brown   f[0] = ctx->c * ctx->z * u[1];
665c4762a1bSJed Brown   f[1] = ctx->c / ctx->z * u[0];
666c4762a1bSJed Brown }
667c4762a1bSJed Brown 
PhysicsCharacteristic_Acoustics(void * vctx,PetscInt m,const PetscScalar * u,PetscScalar * X,PetscScalar * Xi,PetscReal * speeds)668d71ae5a4SJacob Faibussowitsch static PetscErrorCode PhysicsCharacteristic_Acoustics(void *vctx, PetscInt m, const PetscScalar *u, PetscScalar *X, PetscScalar *Xi, PetscReal *speeds)
669d71ae5a4SJacob Faibussowitsch {
670c4762a1bSJed Brown   AcousticsCtx *phys = (AcousticsCtx *)vctx;
671c4762a1bSJed Brown   PetscReal     z = phys->z, c = phys->c;
672c4762a1bSJed Brown 
673c4762a1bSJed Brown   PetscFunctionBeginUser;
674c4762a1bSJed Brown   X[0 * 2 + 0]  = -z;
675c4762a1bSJed Brown   X[0 * 2 + 1]  = z;
676c4762a1bSJed Brown   X[1 * 2 + 0]  = 1;
677c4762a1bSJed Brown   X[1 * 2 + 1]  = 1;
678c4762a1bSJed Brown   Xi[0 * 2 + 0] = -1. / (2 * z);
679c4762a1bSJed Brown   Xi[0 * 2 + 1] = 1. / 2;
680c4762a1bSJed Brown   Xi[1 * 2 + 0] = 1. / (2 * z);
681c4762a1bSJed Brown   Xi[1 * 2 + 1] = 1. / 2;
682c4762a1bSJed Brown   speeds[0]     = -c;
683c4762a1bSJed Brown   speeds[1]     = c;
6843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
685c4762a1bSJed Brown }
686c4762a1bSJed Brown 
PhysicsSample_Acoustics_Initial(AcousticsCtx * phys,PetscInt initial,PetscReal xmin,PetscReal xmax,PetscReal x,PetscReal * u)687d71ae5a4SJacob Faibussowitsch static PetscErrorCode PhysicsSample_Acoustics_Initial(AcousticsCtx *phys, PetscInt initial, PetscReal xmin, PetscReal xmax, PetscReal x, PetscReal *u)
688d71ae5a4SJacob Faibussowitsch {
689c4762a1bSJed Brown   PetscFunctionBeginUser;
690c4762a1bSJed Brown   switch (initial) {
691c4762a1bSJed Brown   case 0:
692c4762a1bSJed Brown     u[0] = (PetscAbs((x - xmin) / (xmax - xmin) - 0.2) < 0.1) ? 1 : 0.5;
693c4762a1bSJed Brown     u[1] = (PetscAbs((x - xmin) / (xmax - xmin) - 0.7) < 0.1) ? 1 : -0.5;
694c4762a1bSJed Brown     break;
695c4762a1bSJed Brown   case 1:
696c4762a1bSJed Brown     u[0] = PetscCosReal(3 * 2 * PETSC_PI * x / (xmax - xmin));
697c4762a1bSJed Brown     u[1] = PetscExpReal(-PetscSqr(x - (xmax + xmin) / 2) / (2 * PetscSqr(0.2 * (xmax - xmin)))) - 0.5;
698c4762a1bSJed Brown     break;
699d71ae5a4SJacob Faibussowitsch   default:
700d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "unknown initial condition");
701c4762a1bSJed Brown   }
7023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
703c4762a1bSJed Brown }
704c4762a1bSJed Brown 
PhysicsSample_Acoustics(void * vctx,PetscInt initial,FVBCType bctype,PetscReal xmin,PetscReal xmax,PetscReal t,PetscReal x,PetscReal * u)705d71ae5a4SJacob Faibussowitsch static PetscErrorCode PhysicsSample_Acoustics(void *vctx, PetscInt initial, FVBCType bctype, PetscReal xmin, PetscReal xmax, PetscReal t, PetscReal x, PetscReal *u)
706d71ae5a4SJacob Faibussowitsch {
707c4762a1bSJed Brown   AcousticsCtx *phys = (AcousticsCtx *)vctx;
708c4762a1bSJed Brown   PetscReal     c    = phys->c;
709c4762a1bSJed Brown   PetscReal     x0a, x0b, u0a[2], u0b[2], tmp[2];
710c4762a1bSJed Brown   PetscReal     X[2][2], Xi[2][2], dummy[2];
711c4762a1bSJed Brown 
712c4762a1bSJed Brown   PetscFunctionBeginUser;
713c4762a1bSJed Brown   switch (bctype) {
714c4762a1bSJed Brown   case FVBC_OUTFLOW:
715c4762a1bSJed Brown     x0a = x + c * t;
716c4762a1bSJed Brown     x0b = x - c * t;
717c4762a1bSJed Brown     break;
718c4762a1bSJed Brown   case FVBC_PERIODIC:
719c4762a1bSJed Brown     x0a = RangeMod(x + c * t, xmin, xmax);
720c4762a1bSJed Brown     x0b = RangeMod(x - c * t, xmin, xmax);
721c4762a1bSJed Brown     break;
722d71ae5a4SJacob Faibussowitsch   default:
723d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "unknown BCType");
724c4762a1bSJed Brown   }
7259566063dSJacob Faibussowitsch   PetscCall(PhysicsSample_Acoustics_Initial(phys, initial, xmin, xmax, x0a, u0a));
7269566063dSJacob Faibussowitsch   PetscCall(PhysicsSample_Acoustics_Initial(phys, initial, xmin, xmax, x0b, u0b));
7279566063dSJacob Faibussowitsch   PetscCall(PhysicsCharacteristic_Acoustics(vctx, 2, u, &X[0][0], &Xi[0][0], dummy));
728c4762a1bSJed Brown   tmp[0] = Xi[0][0] * u0a[0] + Xi[0][1] * u0a[1];
729c4762a1bSJed Brown   tmp[1] = Xi[1][0] * u0b[0] + Xi[1][1] * u0b[1];
730c4762a1bSJed Brown   u[0]   = X[0][0] * tmp[0] + X[0][1] * tmp[1];
731c4762a1bSJed Brown   u[1]   = X[1][0] * tmp[0] + X[1][1] * tmp[1];
7323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
733c4762a1bSJed Brown }
734c4762a1bSJed Brown 
PhysicsRiemann_Acoustics_Exact(void * vctx,PetscInt m,const PetscScalar * uL,const PetscScalar * uR,PetscScalar * flux,PetscReal * maxspeed)735d71ae5a4SJacob Faibussowitsch static PetscErrorCode PhysicsRiemann_Acoustics_Exact(void *vctx, PetscInt m, const PetscScalar *uL, const PetscScalar *uR, PetscScalar *flux, PetscReal *maxspeed)
736d71ae5a4SJacob Faibussowitsch {
737c4762a1bSJed Brown   AcousticsCtx *phys = (AcousticsCtx *)vctx;
738c4762a1bSJed Brown   PetscReal     c = phys->c, z = phys->z;
7399371c9d4SSatish Balay   PetscReal     Al[2][2] =
7409371c9d4SSatish Balay     {
7419371c9d4SSatish Balay       {-c / 2,      c * z / 2},
7429371c9d4SSatish Balay       {c / (2 * z), -c / 2   }
7439371c9d4SSatish Balay   },         /* Left traveling waves */
7449371c9d4SSatish Balay     Ar[2][2] = {{c / 2, c * z / 2}, {c / (2 * z), c / 2}}; /* Right traveling waves */
745c4762a1bSJed Brown 
746c4762a1bSJed Brown   PetscFunctionBeginUser;
747c4762a1bSJed Brown   flux[0]   = Al[0][0] * uR[0] + Al[0][1] * uR[1] + Ar[0][0] * uL[0] + Ar[0][1] * uL[1];
748c4762a1bSJed Brown   flux[1]   = Al[1][0] * uR[0] + Al[1][1] * uR[1] + Ar[1][0] * uL[0] + Ar[1][1] * uL[1];
749c4762a1bSJed Brown   *maxspeed = c;
7503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
751c4762a1bSJed Brown }
752c4762a1bSJed Brown 
PhysicsCreate_Acoustics(FVCtx * ctx)753d71ae5a4SJacob Faibussowitsch static PetscErrorCode PhysicsCreate_Acoustics(FVCtx *ctx)
754d71ae5a4SJacob Faibussowitsch {
755c4762a1bSJed Brown   AcousticsCtx     *user;
756c4762a1bSJed Brown   PetscFunctionList rlist = 0, rclist = 0;
757c4762a1bSJed Brown   char              rname[256] = "exact", rcname[256] = "characteristic";
758c4762a1bSJed Brown 
759c4762a1bSJed Brown   PetscFunctionBeginUser;
7609566063dSJacob Faibussowitsch   PetscCall(PetscNew(&user));
761c4762a1bSJed Brown   ctx->physics.sample  = PhysicsSample_Acoustics;
762c4762a1bSJed Brown   ctx->physics.destroy = PhysicsDestroy_SimpleFree;
763c4762a1bSJed Brown   ctx->physics.user    = user;
764c4762a1bSJed Brown   ctx->physics.dof     = 2;
765c4762a1bSJed Brown 
7669566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy("u", &ctx->physics.fieldname[0]));
7679566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy("v", &ctx->physics.fieldname[1]));
768c4762a1bSJed Brown 
769c4762a1bSJed Brown   user->c = 1;
770c4762a1bSJed Brown   user->z = 1;
771c4762a1bSJed Brown 
7729566063dSJacob Faibussowitsch   PetscCall(RiemannListAdd(&rlist, "exact", PhysicsRiemann_Acoustics_Exact));
7739566063dSJacob Faibussowitsch   PetscCall(ReconstructListAdd(&rclist, "characteristic", PhysicsCharacteristic_Acoustics));
7749566063dSJacob Faibussowitsch   PetscCall(ReconstructListAdd(&rclist, "conservative", PhysicsCharacteristic_Conservative));
775d0609cedSBarry Smith   PetscOptionsBegin(ctx->comm, ctx->prefix, "Options for linear Acoustics", "");
776c4762a1bSJed Brown   {
7779566063dSJacob Faibussowitsch     PetscCall(PetscOptionsReal("-physics_acoustics_c", "c = sqrt(bulk/rho)", "", user->c, &user->c, NULL));
7789566063dSJacob Faibussowitsch     PetscCall(PetscOptionsReal("-physics_acoustics_z", "z = sqrt(bulk*rho)", "", user->z, &user->z, NULL));
7799566063dSJacob Faibussowitsch     PetscCall(PetscOptionsFList("-physics_acoustics_riemann", "Riemann solver", "", rlist, rname, rname, sizeof(rname), NULL));
7809566063dSJacob Faibussowitsch     PetscCall(PetscOptionsFList("-physics_acoustics_reconstruct", "Reconstruction", "", rclist, rcname, rcname, sizeof(rcname), NULL));
781c4762a1bSJed Brown   }
782d0609cedSBarry Smith   PetscOptionsEnd();
7839566063dSJacob Faibussowitsch   PetscCall(RiemannListFind(rlist, rname, &ctx->physics.riemann));
7849566063dSJacob Faibussowitsch   PetscCall(ReconstructListFind(rclist, rcname, &ctx->physics.characteristic));
7859566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListDestroy(&rlist));
7869566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListDestroy(&rclist));
7873ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
788c4762a1bSJed Brown }
789c4762a1bSJed Brown 
790c4762a1bSJed Brown /* --------------------------------- Isothermal Gas Dynamics ----------------------------------- */
791c4762a1bSJed Brown 
792c4762a1bSJed Brown typedef struct {
793c4762a1bSJed Brown   PetscReal acoustic_speed;
794c4762a1bSJed Brown } IsoGasCtx;
795c4762a1bSJed Brown 
IsoGasFlux(PetscReal c,const PetscScalar * u,PetscScalar * f)796d71ae5a4SJacob Faibussowitsch static inline void IsoGasFlux(PetscReal c, const PetscScalar *u, PetscScalar *f)
797d71ae5a4SJacob Faibussowitsch {
798c4762a1bSJed Brown   f[0] = u[1];
799c4762a1bSJed Brown   f[1] = PetscSqr(u[1]) / u[0] + c * c * u[0];
800c4762a1bSJed Brown }
801c4762a1bSJed Brown 
PhysicsSample_IsoGas(void * vctx,PetscInt initial,FVBCType bctype,PetscReal xmin,PetscReal xmax,PetscReal t,PetscReal x,PetscReal * u)802d71ae5a4SJacob Faibussowitsch static PetscErrorCode PhysicsSample_IsoGas(void *vctx, PetscInt initial, FVBCType bctype, PetscReal xmin, PetscReal xmax, PetscReal t, PetscReal x, PetscReal *u)
803d71ae5a4SJacob Faibussowitsch {
804c4762a1bSJed Brown   PetscFunctionBeginUser;
8053c633725SBarry Smith   PetscCheck(t <= 0, PETSC_COMM_SELF, PETSC_ERR_SUP, "Exact solutions not implemented for t > 0");
806c4762a1bSJed Brown   switch (initial) {
807c4762a1bSJed Brown   case 0:
808c4762a1bSJed Brown     u[0] = (x < 0) ? 1 : 0.5;
809c4762a1bSJed Brown     u[1] = (x < 0) ? 1 : 0.7;
810c4762a1bSJed Brown     break;
811c4762a1bSJed Brown   case 1:
812c4762a1bSJed Brown     u[0] = 1 + 0.5 * PetscSinReal(2 * PETSC_PI * x);
813c4762a1bSJed Brown     u[1] = 1 * u[0];
814c4762a1bSJed Brown     break;
815d71ae5a4SJacob Faibussowitsch   default:
816d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "unknown initial condition");
817c4762a1bSJed Brown   }
8183ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
819c4762a1bSJed Brown }
820c4762a1bSJed Brown 
PhysicsRiemann_IsoGas_Roe(void * vctx,PetscInt m,const PetscScalar * uL,const PetscScalar * uR,PetscScalar * flux,PetscReal * maxspeed)821d71ae5a4SJacob Faibussowitsch static PetscErrorCode PhysicsRiemann_IsoGas_Roe(void *vctx, PetscInt m, const PetscScalar *uL, const PetscScalar *uR, PetscScalar *flux, PetscReal *maxspeed)
822d71ae5a4SJacob Faibussowitsch {
823c4762a1bSJed Brown   IsoGasCtx  *phys = (IsoGasCtx *)vctx;
824c4762a1bSJed Brown   PetscReal   c    = phys->acoustic_speed;
825c4762a1bSJed Brown   PetscScalar ubar, du[2], a[2], fL[2], fR[2], lam[2], ustar[2], R[2][2];
826c4762a1bSJed Brown   PetscInt    i;
827c4762a1bSJed Brown 
828c4762a1bSJed Brown   PetscFunctionBeginUser;
829c4762a1bSJed Brown   ubar = (uL[1] / PetscSqrtScalar(uL[0]) + uR[1] / PetscSqrtScalar(uR[0])) / (PetscSqrtScalar(uL[0]) + PetscSqrtScalar(uR[0]));
830c4762a1bSJed Brown   /* write fluxuations in characteristic basis */
831c4762a1bSJed Brown   du[0] = uR[0] - uL[0];
832c4762a1bSJed Brown   du[1] = uR[1] - uL[1];
833c4762a1bSJed Brown   a[0]  = (1 / (2 * c)) * ((ubar + c) * du[0] - du[1]);
834c4762a1bSJed Brown   a[1]  = (1 / (2 * c)) * ((-ubar + c) * du[0] + du[1]);
835c4762a1bSJed Brown   /* wave speeds */
836c4762a1bSJed Brown   lam[0] = ubar - c;
837c4762a1bSJed Brown   lam[1] = ubar + c;
838c4762a1bSJed Brown   /* Right eigenvectors */
8399371c9d4SSatish Balay   R[0][0] = 1;
8409371c9d4SSatish Balay   R[0][1] = ubar - c;
8419371c9d4SSatish Balay   R[1][0] = 1;
8429371c9d4SSatish Balay   R[1][1] = ubar + c;
843c4762a1bSJed Brown   /* Compute state in star region (between the 1-wave and 2-wave) */
844c4762a1bSJed Brown   for (i = 0; i < 2; i++) ustar[i] = uL[i] + a[0] * R[0][i];
845c4762a1bSJed Brown   if (uL[1] / uL[0] < c && c < ustar[1] / ustar[0]) { /* 1-wave is sonic rarefaction */
846c4762a1bSJed Brown     PetscScalar ufan[2];
847c4762a1bSJed Brown     ufan[0] = uL[0] * PetscExpScalar(uL[1] / (uL[0] * c) - 1);
848c4762a1bSJed Brown     ufan[1] = c * ufan[0];
849c4762a1bSJed Brown     IsoGasFlux(c, ufan, flux);
850c4762a1bSJed Brown   } else if (ustar[1] / ustar[0] < -c && -c < uR[1] / uR[0]) { /* 2-wave is sonic rarefaction */
851c4762a1bSJed Brown     PetscScalar ufan[2];
852c4762a1bSJed Brown     ufan[0] = uR[0] * PetscExpScalar(-uR[1] / (uR[0] * c) - 1);
853c4762a1bSJed Brown     ufan[1] = -c * ufan[0];
854c4762a1bSJed Brown     IsoGasFlux(c, ufan, flux);
855c4762a1bSJed Brown   } else { /* Centered form */
856c4762a1bSJed Brown     IsoGasFlux(c, uL, fL);
857c4762a1bSJed Brown     IsoGasFlux(c, uR, fR);
858c4762a1bSJed Brown     for (i = 0; i < 2; i++) {
859c4762a1bSJed Brown       PetscScalar absdu = PetscAbsScalar(lam[0]) * a[0] * R[0][i] + PetscAbsScalar(lam[1]) * a[1] * R[1][i];
860c4762a1bSJed Brown       flux[i]           = 0.5 * (fL[i] + fR[i]) - 0.5 * absdu;
861c4762a1bSJed Brown     }
862c4762a1bSJed Brown   }
863c4762a1bSJed Brown   *maxspeed = MaxAbs(lam[0], lam[1]);
8643ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
865c4762a1bSJed Brown }
866c4762a1bSJed Brown 
PhysicsRiemann_IsoGas_Exact(void * vctx,PetscInt m,const PetscScalar * uL,const PetscScalar * uR,PetscScalar * flux,PetscReal * maxspeed)867d71ae5a4SJacob Faibussowitsch static PetscErrorCode PhysicsRiemann_IsoGas_Exact(void *vctx, PetscInt m, const PetscScalar *uL, const PetscScalar *uR, PetscScalar *flux, PetscReal *maxspeed)
868d71ae5a4SJacob Faibussowitsch {
869c4762a1bSJed Brown   IsoGasCtx  *phys = (IsoGasCtx *)vctx;
870c4762a1bSJed Brown   PetscReal   c    = phys->acoustic_speed;
871c4762a1bSJed Brown   PetscScalar ustar[2];
8729371c9d4SSatish Balay   struct {
8739371c9d4SSatish Balay     PetscScalar rho, u;
8749371c9d4SSatish Balay   } L = {uL[0], uL[1] / uL[0]}, R = {uR[0], uR[1] / uR[0]}, star;
875c4762a1bSJed Brown   PetscInt i;
876c4762a1bSJed Brown 
877c4762a1bSJed Brown   PetscFunctionBeginUser;
87857508eceSPierre Jolivet   PetscCheck(L.rho > 0 && R.rho > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Reconstructed density is negative");
879c4762a1bSJed Brown   {
880c4762a1bSJed Brown     /* Solve for star state */
881c4762a1bSJed Brown     PetscScalar res, tmp, rho = 0.5 * (L.rho + R.rho); /* initial guess */
882c4762a1bSJed Brown     for (i = 0; i < 20; i++) {
883c4762a1bSJed Brown       PetscScalar fr, fl, dfr, dfl;
8849371c9d4SSatish Balay       fl  = (L.rho < rho) ? (rho - L.rho) / PetscSqrtScalar(L.rho * rho) /* shock */
885c4762a1bSJed Brown                           : PetscLogScalar(rho) - PetscLogScalar(L.rho); /* rarefaction */
8869371c9d4SSatish Balay       fr  = (R.rho < rho) ? (rho - R.rho) / PetscSqrtScalar(R.rho * rho) /* shock */
887c4762a1bSJed Brown                           : PetscLogScalar(rho) - PetscLogScalar(R.rho); /* rarefaction */
888c4762a1bSJed Brown       res = R.u - L.u + c * (fr + fl);
8893c633725SBarry Smith       PetscCheck(!PetscIsInfOrNanScalar(res), PETSC_COMM_SELF, PETSC_ERR_FP, "Infinity or Not-a-Number generated in computation");
890c4762a1bSJed Brown       if (PetscAbsScalar(res) < 1e-10) {
891c4762a1bSJed Brown         star.rho = rho;
892c4762a1bSJed Brown         star.u   = L.u - c * fl;
893c4762a1bSJed Brown         goto converged;
894c4762a1bSJed Brown       }
895c4762a1bSJed Brown       dfl = (L.rho < rho) ? 1 / PetscSqrtScalar(L.rho * rho) * (1 - 0.5 * (rho - L.rho) / rho) : 1 / rho;
896c4762a1bSJed Brown       dfr = (R.rho < rho) ? 1 / PetscSqrtScalar(R.rho * rho) * (1 - 0.5 * (rho - R.rho) / rho) : 1 / rho;
897c4762a1bSJed Brown       tmp = rho - res / (c * (dfr + dfl));
898c4762a1bSJed Brown       if (tmp <= 0) rho /= 2; /* Guard against Newton shooting off to a negative density */
899c4762a1bSJed Brown       else rho = tmp;
90057508eceSPierre Jolivet       PetscCheck((rho > 0) && PetscIsNormalScalar(rho), PETSC_COMM_SELF, PETSC_ERR_FP, "non-normal iterate rho=%g", (double)PetscRealPart(rho));
901c4762a1bSJed Brown     }
90263a3b9bcSJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_CONV_FAILED, "Newton iteration for star.rho diverged after %" PetscInt_FMT " iterations", i);
903c4762a1bSJed Brown   }
904c4762a1bSJed Brown converged:
905c4762a1bSJed Brown   if (L.u - c < 0 && 0 < star.u - c) { /* 1-wave is sonic rarefaction */
906c4762a1bSJed Brown     PetscScalar ufan[2];
907c4762a1bSJed Brown     ufan[0] = L.rho * PetscExpScalar(L.u / c - 1);
908c4762a1bSJed Brown     ufan[1] = c * ufan[0];
909c4762a1bSJed Brown     IsoGasFlux(c, ufan, flux);
910c4762a1bSJed Brown   } else if (star.u + c < 0 && 0 < R.u + c) { /* 2-wave is sonic rarefaction */
911c4762a1bSJed Brown     PetscScalar ufan[2];
912c4762a1bSJed Brown     ufan[0] = R.rho * PetscExpScalar(-R.u / c - 1);
913c4762a1bSJed Brown     ufan[1] = -c * ufan[0];
914c4762a1bSJed Brown     IsoGasFlux(c, ufan, flux);
915c4762a1bSJed Brown   } else if ((L.rho >= star.rho && L.u - c >= 0) || (L.rho < star.rho && (star.rho * star.u - L.rho * L.u) / (star.rho - L.rho) > 0)) {
916c4762a1bSJed Brown     /* 1-wave is supersonic rarefaction, or supersonic shock */
917c4762a1bSJed Brown     IsoGasFlux(c, uL, flux);
918c4762a1bSJed Brown   } else if ((star.rho <= R.rho && R.u + c <= 0) || (star.rho > R.rho && (R.rho * R.u - star.rho * star.u) / (R.rho - star.rho) < 0)) {
919c4762a1bSJed Brown     /* 2-wave is supersonic rarefaction or supersonic shock */
920c4762a1bSJed Brown     IsoGasFlux(c, uR, flux);
921c4762a1bSJed Brown   } else {
922c4762a1bSJed Brown     ustar[0] = star.rho;
923c4762a1bSJed Brown     ustar[1] = star.rho * star.u;
924c4762a1bSJed Brown     IsoGasFlux(c, ustar, flux);
925c4762a1bSJed Brown   }
926c4762a1bSJed Brown   *maxspeed = MaxAbs(MaxAbs(star.u - c, star.u + c), MaxAbs(L.u - c, R.u + c));
9273ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
928c4762a1bSJed Brown }
929c4762a1bSJed Brown 
PhysicsRiemann_IsoGas_Rusanov(void * vctx,PetscInt m,const PetscScalar * uL,const PetscScalar * uR,PetscScalar * flux,PetscReal * maxspeed)930d71ae5a4SJacob Faibussowitsch static PetscErrorCode PhysicsRiemann_IsoGas_Rusanov(void *vctx, PetscInt m, const PetscScalar *uL, const PetscScalar *uR, PetscScalar *flux, PetscReal *maxspeed)
931d71ae5a4SJacob Faibussowitsch {
932c4762a1bSJed Brown   IsoGasCtx  *phys = (IsoGasCtx *)vctx;
933c4762a1bSJed Brown   PetscScalar c    = phys->acoustic_speed, fL[2], fR[2], s;
9349371c9d4SSatish Balay   struct {
9359371c9d4SSatish Balay     PetscScalar rho, u;
9369371c9d4SSatish Balay   } L = {uL[0], uL[1] / uL[0]}, R = {uR[0], uR[1] / uR[0]};
937c4762a1bSJed Brown 
938c4762a1bSJed Brown   PetscFunctionBeginUser;
93957508eceSPierre Jolivet   PetscCheck(L.rho > 0 && R.rho > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Reconstructed density is negative");
940c4762a1bSJed Brown   IsoGasFlux(c, uL, fL);
941c4762a1bSJed Brown   IsoGasFlux(c, uR, fR);
942c4762a1bSJed Brown   s         = PetscMax(PetscAbs(L.u), PetscAbs(R.u)) + c;
943c4762a1bSJed Brown   flux[0]   = 0.5 * (fL[0] + fR[0]) + 0.5 * s * (uL[0] - uR[0]);
944c4762a1bSJed Brown   flux[1]   = 0.5 * (fL[1] + fR[1]) + 0.5 * s * (uL[1] - uR[1]);
945c4762a1bSJed Brown   *maxspeed = s;
9463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
947c4762a1bSJed Brown }
948c4762a1bSJed Brown 
PhysicsCharacteristic_IsoGas(void * vctx,PetscInt m,const PetscScalar * u,PetscScalar * X,PetscScalar * Xi,PetscReal * speeds)949d71ae5a4SJacob Faibussowitsch static PetscErrorCode PhysicsCharacteristic_IsoGas(void *vctx, PetscInt m, const PetscScalar *u, PetscScalar *X, PetscScalar *Xi, PetscReal *speeds)
950d71ae5a4SJacob Faibussowitsch {
951c4762a1bSJed Brown   IsoGasCtx *phys = (IsoGasCtx *)vctx;
952c4762a1bSJed Brown   PetscReal  c    = phys->acoustic_speed;
953c4762a1bSJed Brown 
954c4762a1bSJed Brown   PetscFunctionBeginUser;
955c4762a1bSJed Brown   speeds[0]    = u[1] / u[0] - c;
956c4762a1bSJed Brown   speeds[1]    = u[1] / u[0] + c;
957c4762a1bSJed Brown   X[0 * 2 + 0] = 1;
958c4762a1bSJed Brown   X[0 * 2 + 1] = speeds[0];
959c4762a1bSJed Brown   X[1 * 2 + 0] = 1;
960c4762a1bSJed Brown   X[1 * 2 + 1] = speeds[1];
9619566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(Xi, X, 4));
9629566063dSJacob Faibussowitsch   PetscCall(PetscKernel_A_gets_inverse_A_2(Xi, 0, PETSC_FALSE, NULL));
9633ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
964c4762a1bSJed Brown }
965c4762a1bSJed Brown 
PhysicsCreate_IsoGas(FVCtx * ctx)966d71ae5a4SJacob Faibussowitsch static PetscErrorCode PhysicsCreate_IsoGas(FVCtx *ctx)
967d71ae5a4SJacob Faibussowitsch {
968c4762a1bSJed Brown   IsoGasCtx        *user;
969c4762a1bSJed Brown   PetscFunctionList rlist = 0, rclist = 0;
970c4762a1bSJed Brown   char              rname[256] = "exact", rcname[256] = "characteristic";
971c4762a1bSJed Brown 
972c4762a1bSJed Brown   PetscFunctionBeginUser;
9739566063dSJacob Faibussowitsch   PetscCall(PetscNew(&user));
974c4762a1bSJed Brown   ctx->physics.sample  = PhysicsSample_IsoGas;
975c4762a1bSJed Brown   ctx->physics.destroy = PhysicsDestroy_SimpleFree;
976c4762a1bSJed Brown   ctx->physics.user    = user;
977c4762a1bSJed Brown   ctx->physics.dof     = 2;
978c4762a1bSJed Brown 
9799566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy("density", &ctx->physics.fieldname[0]));
9809566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy("momentum", &ctx->physics.fieldname[1]));
981c4762a1bSJed Brown 
982c4762a1bSJed Brown   user->acoustic_speed = 1;
983c4762a1bSJed Brown 
9849566063dSJacob Faibussowitsch   PetscCall(RiemannListAdd(&rlist, "exact", PhysicsRiemann_IsoGas_Exact));
9859566063dSJacob Faibussowitsch   PetscCall(RiemannListAdd(&rlist, "roe", PhysicsRiemann_IsoGas_Roe));
9869566063dSJacob Faibussowitsch   PetscCall(RiemannListAdd(&rlist, "rusanov", PhysicsRiemann_IsoGas_Rusanov));
9879566063dSJacob Faibussowitsch   PetscCall(ReconstructListAdd(&rclist, "characteristic", PhysicsCharacteristic_IsoGas));
9889566063dSJacob Faibussowitsch   PetscCall(ReconstructListAdd(&rclist, "conservative", PhysicsCharacteristic_Conservative));
989d0609cedSBarry Smith   PetscOptionsBegin(ctx->comm, ctx->prefix, "Options for IsoGas", "");
9909566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-physics_isogas_acoustic_speed", "Acoustic speed", "", user->acoustic_speed, &user->acoustic_speed, NULL));
9919566063dSJacob Faibussowitsch   PetscCall(PetscOptionsFList("-physics_isogas_riemann", "Riemann solver", "", rlist, rname, rname, sizeof(rname), NULL));
9929566063dSJacob Faibussowitsch   PetscCall(PetscOptionsFList("-physics_isogas_reconstruct", "Reconstruction", "", rclist, rcname, rcname, sizeof(rcname), NULL));
993d0609cedSBarry Smith   PetscOptionsEnd();
9949566063dSJacob Faibussowitsch   PetscCall(RiemannListFind(rlist, rname, &ctx->physics.riemann));
9959566063dSJacob Faibussowitsch   PetscCall(ReconstructListFind(rclist, rcname, &ctx->physics.characteristic));
9969566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListDestroy(&rlist));
9979566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListDestroy(&rclist));
9983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
999c4762a1bSJed Brown }
1000c4762a1bSJed Brown 
1001c4762a1bSJed Brown /* --------------------------------- Shallow Water ----------------------------------- */
1002c4762a1bSJed Brown typedef struct {
1003c4762a1bSJed Brown   PetscReal gravity;
1004c4762a1bSJed Brown } ShallowCtx;
1005c4762a1bSJed Brown 
ShallowFlux(ShallowCtx * phys,const PetscScalar * u,PetscScalar * f)1006d71ae5a4SJacob Faibussowitsch static inline void ShallowFlux(ShallowCtx *phys, const PetscScalar *u, PetscScalar *f)
1007d71ae5a4SJacob Faibussowitsch {
1008c4762a1bSJed Brown   f[0] = u[1];
1009c4762a1bSJed Brown   f[1] = PetscSqr(u[1]) / u[0] + 0.5 * phys->gravity * PetscSqr(u[0]);
1010c4762a1bSJed Brown }
1011c4762a1bSJed Brown 
PhysicsRiemann_Shallow_Exact(void * vctx,PetscInt m,const PetscScalar * uL,const PetscScalar * uR,PetscScalar * flux,PetscReal * maxspeed)1012d71ae5a4SJacob Faibussowitsch static PetscErrorCode PhysicsRiemann_Shallow_Exact(void *vctx, PetscInt m, const PetscScalar *uL, const PetscScalar *uR, PetscScalar *flux, PetscReal *maxspeed)
1013d71ae5a4SJacob Faibussowitsch {
1014c4762a1bSJed Brown   ShallowCtx *phys = (ShallowCtx *)vctx;
1015c4762a1bSJed Brown   PetscScalar g    = phys->gravity, ustar[2], cL, cR, c, cstar;
10169371c9d4SSatish Balay   struct {
10179371c9d4SSatish Balay     PetscScalar h, u;
10189371c9d4SSatish Balay   } L = {uL[0], uL[1] / uL[0]}, R = {uR[0], uR[1] / uR[0]}, star;
1019c4762a1bSJed Brown   PetscInt i;
1020c4762a1bSJed Brown 
1021c4762a1bSJed Brown   PetscFunctionBeginUser;
102257508eceSPierre Jolivet   PetscCheck(L.h > 0 && R.h > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Reconstructed thickness is negative");
1023c4762a1bSJed Brown   cL = PetscSqrtScalar(g * L.h);
1024c4762a1bSJed Brown   cR = PetscSqrtScalar(g * R.h);
1025c4762a1bSJed Brown   c  = PetscMax(cL, cR);
1026c4762a1bSJed Brown   {
1027c4762a1bSJed Brown     /* Solve for star state */
1028c4762a1bSJed Brown     const PetscInt maxits = 50;
1029c4762a1bSJed Brown     PetscScalar    tmp, res, res0 = 0, h0, h = 0.5 * (L.h + R.h); /* initial guess */
1030c4762a1bSJed Brown     h0 = h;
1031c4762a1bSJed Brown     for (i = 0; i < maxits; i++) {
1032c4762a1bSJed Brown       PetscScalar fr, fl, dfr, dfl;
10339371c9d4SSatish Balay       fl  = (L.h < h) ? PetscSqrtScalar(0.5 * g * (h * h - L.h * L.h) * (1 / L.h - 1 / h)) /* shock */
1034c4762a1bSJed Brown                       : 2 * PetscSqrtScalar(g * h) - 2 * PetscSqrtScalar(g * L.h);         /* rarefaction */
10359371c9d4SSatish Balay       fr  = (R.h < h) ? PetscSqrtScalar(0.5 * g * (h * h - R.h * R.h) * (1 / R.h - 1 / h)) /* shock */
1036c4762a1bSJed Brown                       : 2 * PetscSqrtScalar(g * h) - 2 * PetscSqrtScalar(g * R.h);         /* rarefaction */
1037c4762a1bSJed Brown       res = R.u - L.u + fr + fl;
10383c633725SBarry Smith       PetscCheck(!PetscIsInfOrNanScalar(res), PETSC_COMM_SELF, PETSC_ERR_FP, "Infinity or Not-a-Number generated in computation");
1039c4762a1bSJed Brown       if (PetscAbsScalar(res) < 1e-8 || (i > 0 && PetscAbsScalar(h - h0) < 1e-8)) {
1040c4762a1bSJed Brown         star.h = h;
1041c4762a1bSJed Brown         star.u = L.u - fl;
1042c4762a1bSJed Brown         goto converged;
1043c4762a1bSJed Brown       } else if (i > 0 && PetscAbsScalar(res) >= PetscAbsScalar(res0)) { /* Line search */
1044c4762a1bSJed Brown         h = 0.8 * h0 + 0.2 * h;
1045c4762a1bSJed Brown         continue;
1046c4762a1bSJed Brown       }
1047c4762a1bSJed Brown       /* Accept the last step and take another */
1048c4762a1bSJed Brown       res0 = res;
1049c4762a1bSJed Brown       h0   = h;
1050c4762a1bSJed Brown       dfl  = (L.h < h) ? 0.5 / fl * 0.5 * g * (-L.h * L.h / (h * h) - 1 + 2 * h / L.h) : PetscSqrtScalar(g / h);
1051c4762a1bSJed Brown       dfr  = (R.h < h) ? 0.5 / fr * 0.5 * g * (-R.h * R.h / (h * h) - 1 + 2 * h / R.h) : PetscSqrtScalar(g / h);
1052c4762a1bSJed Brown       tmp  = h - res / (dfr + dfl);
1053c4762a1bSJed Brown       if (tmp <= 0) h /= 2; /* Guard against Newton shooting off to a negative thickness */
1054c4762a1bSJed Brown       else h = tmp;
105557508eceSPierre Jolivet       PetscCheck((h > 0) && PetscIsNormalScalar(h), PETSC_COMM_SELF, PETSC_ERR_FP, "non-normal iterate h=%g", (double)h);
1056c4762a1bSJed Brown     }
105763a3b9bcSJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_CONV_FAILED, "Newton iteration for star.h diverged after %" PetscInt_FMT " iterations", i);
1058c4762a1bSJed Brown   }
1059c4762a1bSJed Brown converged:
1060c4762a1bSJed Brown   cstar = PetscSqrtScalar(g * star.h);
1061c4762a1bSJed Brown   if (L.u - cL < 0 && 0 < star.u - cstar) { /* 1-wave is sonic rarefaction */
1062c4762a1bSJed Brown     PetscScalar ufan[2];
1063c4762a1bSJed Brown     ufan[0] = 1 / g * PetscSqr(L.u / 3 + 2. / 3 * cL);
1064c4762a1bSJed Brown     ufan[1] = PetscSqrtScalar(g * ufan[0]) * ufan[0];
1065c4762a1bSJed Brown     ShallowFlux(phys, ufan, flux);
1066c4762a1bSJed Brown   } else if (star.u + cstar < 0 && 0 < R.u + cR) { /* 2-wave is sonic rarefaction */
1067c4762a1bSJed Brown     PetscScalar ufan[2];
1068c4762a1bSJed Brown     ufan[0] = 1 / g * PetscSqr(R.u / 3 - 2. / 3 * cR);
1069c4762a1bSJed Brown     ufan[1] = -PetscSqrtScalar(g * ufan[0]) * ufan[0];
1070c4762a1bSJed Brown     ShallowFlux(phys, ufan, flux);
1071c4762a1bSJed Brown   } 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)) {
1072c4762a1bSJed Brown     /* 1-wave is right-travelling shock (supersonic) */
1073c4762a1bSJed Brown     ShallowFlux(phys, uL, flux);
1074c4762a1bSJed Brown   } 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)) {
1075c4762a1bSJed Brown     /* 2-wave is left-travelling shock (supersonic) */
1076c4762a1bSJed Brown     ShallowFlux(phys, uR, flux);
1077c4762a1bSJed Brown   } else {
1078c4762a1bSJed Brown     ustar[0] = star.h;
1079c4762a1bSJed Brown     ustar[1] = star.h * star.u;
1080c4762a1bSJed Brown     ShallowFlux(phys, ustar, flux);
1081c4762a1bSJed Brown   }
1082c4762a1bSJed Brown   *maxspeed = MaxAbs(MaxAbs(star.u - cstar, star.u + cstar), MaxAbs(L.u - cL, R.u + cR));
10833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1084c4762a1bSJed Brown }
1085c4762a1bSJed Brown 
PhysicsRiemann_Shallow_Rusanov(void * vctx,PetscInt m,const PetscScalar * uL,const PetscScalar * uR,PetscScalar * flux,PetscReal * maxspeed)1086d71ae5a4SJacob Faibussowitsch static PetscErrorCode PhysicsRiemann_Shallow_Rusanov(void *vctx, PetscInt m, const PetscScalar *uL, const PetscScalar *uR, PetscScalar *flux, PetscReal *maxspeed)
1087d71ae5a4SJacob Faibussowitsch {
1088c4762a1bSJed Brown   ShallowCtx *phys = (ShallowCtx *)vctx;
1089c4762a1bSJed Brown   PetscScalar g    = phys->gravity, fL[2], fR[2], s;
10909371c9d4SSatish Balay   struct {
10919371c9d4SSatish Balay     PetscScalar h, u;
10929371c9d4SSatish Balay   } L = {uL[0], uL[1] / uL[0]}, R = {uR[0], uR[1] / uR[0]};
1093c4762a1bSJed Brown 
1094c4762a1bSJed Brown   PetscFunctionBeginUser;
109557508eceSPierre Jolivet   PetscCheck(L.h > 0 && R.h > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Reconstructed thickness is negative");
1096c4762a1bSJed Brown   ShallowFlux(phys, uL, fL);
1097c4762a1bSJed Brown   ShallowFlux(phys, uR, fR);
1098c4762a1bSJed Brown   s         = PetscMax(PetscAbs(L.u) + PetscSqrtScalar(g * L.h), PetscAbs(R.u) + PetscSqrtScalar(g * R.h));
1099c4762a1bSJed Brown   flux[0]   = 0.5 * (fL[0] + fR[0]) + 0.5 * s * (uL[0] - uR[0]);
1100c4762a1bSJed Brown   flux[1]   = 0.5 * (fL[1] + fR[1]) + 0.5 * s * (uL[1] - uR[1]);
1101c4762a1bSJed Brown   *maxspeed = s;
11023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1103c4762a1bSJed Brown }
1104c4762a1bSJed Brown 
PhysicsCharacteristic_Shallow(void * vctx,PetscInt m,const PetscScalar * u,PetscScalar * X,PetscScalar * Xi,PetscReal * speeds)1105d71ae5a4SJacob Faibussowitsch static PetscErrorCode PhysicsCharacteristic_Shallow(void *vctx, PetscInt m, const PetscScalar *u, PetscScalar *X, PetscScalar *Xi, PetscReal *speeds)
1106d71ae5a4SJacob Faibussowitsch {
1107c4762a1bSJed Brown   ShallowCtx *phys = (ShallowCtx *)vctx;
1108c4762a1bSJed Brown   PetscReal   c;
1109c4762a1bSJed Brown 
1110c4762a1bSJed Brown   PetscFunctionBeginUser;
1111c4762a1bSJed Brown   c            = PetscSqrtScalar(u[0] * phys->gravity);
1112c4762a1bSJed Brown   speeds[0]    = u[1] / u[0] - c;
1113c4762a1bSJed Brown   speeds[1]    = u[1] / u[0] + c;
1114c4762a1bSJed Brown   X[0 * 2 + 0] = 1;
1115c4762a1bSJed Brown   X[0 * 2 + 1] = speeds[0];
1116c4762a1bSJed Brown   X[1 * 2 + 0] = 1;
1117c4762a1bSJed Brown   X[1 * 2 + 1] = speeds[1];
11189566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(Xi, X, 4));
11199566063dSJacob Faibussowitsch   PetscCall(PetscKernel_A_gets_inverse_A_2(Xi, 0, PETSC_FALSE, NULL));
11203ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1121c4762a1bSJed Brown }
1122c4762a1bSJed Brown 
PhysicsCreate_Shallow(FVCtx * ctx)1123d71ae5a4SJacob Faibussowitsch static PetscErrorCode PhysicsCreate_Shallow(FVCtx *ctx)
1124d71ae5a4SJacob Faibussowitsch {
1125c4762a1bSJed Brown   ShallowCtx       *user;
1126c4762a1bSJed Brown   PetscFunctionList rlist = 0, rclist = 0;
1127c4762a1bSJed Brown   char              rname[256] = "exact", rcname[256] = "characteristic";
1128c4762a1bSJed Brown 
1129c4762a1bSJed Brown   PetscFunctionBeginUser;
11309566063dSJacob Faibussowitsch   PetscCall(PetscNew(&user));
1131c4762a1bSJed Brown   /* Shallow water and Isothermal Gas dynamics are similar so we reuse initial conditions for now */
1132c4762a1bSJed Brown   ctx->physics.sample  = PhysicsSample_IsoGas;
1133c4762a1bSJed Brown   ctx->physics.destroy = PhysicsDestroy_SimpleFree;
1134c4762a1bSJed Brown   ctx->physics.user    = user;
1135c4762a1bSJed Brown   ctx->physics.dof     = 2;
1136c4762a1bSJed Brown 
11379566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy("density", &ctx->physics.fieldname[0]));
11389566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy("momentum", &ctx->physics.fieldname[1]));
1139c4762a1bSJed Brown 
1140c4762a1bSJed Brown   user->gravity = 1;
1141c4762a1bSJed Brown 
11429566063dSJacob Faibussowitsch   PetscCall(RiemannListAdd(&rlist, "exact", PhysicsRiemann_Shallow_Exact));
11439566063dSJacob Faibussowitsch   PetscCall(RiemannListAdd(&rlist, "rusanov", PhysicsRiemann_Shallow_Rusanov));
11449566063dSJacob Faibussowitsch   PetscCall(ReconstructListAdd(&rclist, "characteristic", PhysicsCharacteristic_Shallow));
11459566063dSJacob Faibussowitsch   PetscCall(ReconstructListAdd(&rclist, "conservative", PhysicsCharacteristic_Conservative));
1146d0609cedSBarry Smith   PetscOptionsBegin(ctx->comm, ctx->prefix, "Options for Shallow", "");
11479566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-physics_shallow_gravity", "Gravity", "", user->gravity, &user->gravity, NULL));
11489566063dSJacob Faibussowitsch   PetscCall(PetscOptionsFList("-physics_shallow_riemann", "Riemann solver", "", rlist, rname, rname, sizeof(rname), NULL));
11499566063dSJacob Faibussowitsch   PetscCall(PetscOptionsFList("-physics_shallow_reconstruct", "Reconstruction", "", rclist, rcname, rcname, sizeof(rcname), NULL));
1150d0609cedSBarry Smith   PetscOptionsEnd();
11519566063dSJacob Faibussowitsch   PetscCall(RiemannListFind(rlist, rname, &ctx->physics.riemann));
11529566063dSJacob Faibussowitsch   PetscCall(ReconstructListFind(rclist, rcname, &ctx->physics.characteristic));
11539566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListDestroy(&rlist));
11549566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListDestroy(&rclist));
11553ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1156c4762a1bSJed Brown }
1157c4762a1bSJed Brown 
1158c4762a1bSJed Brown /* --------------------------------- Finite Volume Solver ----------------------------------- */
1159c4762a1bSJed Brown 
FVRHSFunction(TS ts,PetscReal time,Vec X,Vec F,void * vctx)1160d71ae5a4SJacob Faibussowitsch static PetscErrorCode FVRHSFunction(TS ts, PetscReal time, Vec X, Vec F, void *vctx)
1161d71ae5a4SJacob Faibussowitsch {
1162c4762a1bSJed Brown   FVCtx       *ctx = (FVCtx *)vctx;
1163c4762a1bSJed Brown   PetscInt     i, j, k, Mx, dof, xs, xm;
1164c4762a1bSJed Brown   PetscReal    hx, cfl_idt = 0;
1165c4762a1bSJed Brown   PetscScalar *x, *f, *slope;
1166c4762a1bSJed Brown   Vec          Xloc;
1167c4762a1bSJed Brown   DM           da;
1168c4762a1bSJed Brown 
1169c4762a1bSJed Brown   PetscFunctionBeginUser;
11709566063dSJacob Faibussowitsch   PetscCall(TSGetDM(ts, &da));
11719566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(da, &Xloc));
11729566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(da, 0, &Mx, 0, 0, 0, 0, 0, &dof, 0, 0, 0, 0, 0));
1173c4762a1bSJed Brown   hx = (ctx->xmax - ctx->xmin) / Mx;
11749566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalBegin(da, X, INSERT_VALUES, Xloc));
11759566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalEnd(da, X, INSERT_VALUES, Xloc));
1176c4762a1bSJed Brown 
11779566063dSJacob Faibussowitsch   PetscCall(VecZeroEntries(F));
1178c4762a1bSJed Brown 
11799566063dSJacob Faibussowitsch   PetscCall(DMDAVecGetArray(da, Xloc, &x));
11809566063dSJacob Faibussowitsch   PetscCall(DMDAVecGetArray(da, F, &f));
11819566063dSJacob Faibussowitsch   PetscCall(DMDAGetArray(da, PETSC_TRUE, &slope));
1182c4762a1bSJed Brown 
11839566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(da, &xs, 0, 0, &xm, 0, 0));
1184c4762a1bSJed Brown 
1185c4762a1bSJed Brown   if (ctx->bctype == FVBC_OUTFLOW) {
1186c4762a1bSJed Brown     for (i = xs - 2; i < 0; i++) {
1187c4762a1bSJed Brown       for (j = 0; j < dof; j++) x[i * dof + j] = x[j];
1188c4762a1bSJed Brown     }
1189c4762a1bSJed Brown     for (i = Mx; i < xs + xm + 2; i++) {
1190c4762a1bSJed Brown       for (j = 0; j < dof; j++) x[i * dof + j] = x[(xs + xm - 1) * dof + j];
1191c4762a1bSJed Brown     }
1192c4762a1bSJed Brown   }
1193c4762a1bSJed Brown   for (i = xs - 1; i < xs + xm + 1; i++) {
1194c4762a1bSJed Brown     struct _LimitInfo info;
1195c4762a1bSJed Brown     PetscScalar      *cjmpL, *cjmpR;
1196c4762a1bSJed Brown     /* Determine the right eigenvectors R, where A = R \Lambda R^{-1} */
11979566063dSJacob Faibussowitsch     PetscCall((*ctx->physics.characteristic)(ctx->physics.user, dof, &x[i * dof], ctx->R, ctx->Rinv, ctx->speeds));
1198c4762a1bSJed Brown     /* Evaluate jumps across interfaces (i-1, i) and (i, i+1), put in characteristic basis */
11999566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(ctx->cjmpLR, 2 * dof));
1200c4762a1bSJed Brown     cjmpL = &ctx->cjmpLR[0];
1201c4762a1bSJed Brown     cjmpR = &ctx->cjmpLR[dof];
1202c4762a1bSJed Brown     for (j = 0; j < dof; j++) {
1203c4762a1bSJed Brown       PetscScalar jmpL, jmpR;
1204c4762a1bSJed Brown       jmpL = x[(i + 0) * dof + j] - x[(i - 1) * dof + j];
1205c4762a1bSJed Brown       jmpR = x[(i + 1) * dof + j] - x[(i + 0) * dof + j];
1206c4762a1bSJed Brown       for (k = 0; k < dof; k++) {
1207c4762a1bSJed Brown         cjmpL[k] += ctx->Rinv[k + j * dof] * jmpL;
1208c4762a1bSJed Brown         cjmpR[k] += ctx->Rinv[k + j * dof] * jmpR;
1209c4762a1bSJed Brown       }
1210c4762a1bSJed Brown     }
1211c4762a1bSJed Brown     /* Apply limiter to the left and right characteristic jumps */
1212c4762a1bSJed Brown     info.m  = dof;
1213c4762a1bSJed Brown     info.hx = hx;
1214c4762a1bSJed Brown     (*ctx->limit)(&info, cjmpL, cjmpR, ctx->cslope);
1215c4762a1bSJed Brown     for (j = 0; j < dof; j++) ctx->cslope[j] /= hx; /* rescale to a slope */
1216c4762a1bSJed Brown     for (j = 0; j < dof; j++) {
1217c4762a1bSJed Brown       PetscScalar tmp = 0;
1218c4762a1bSJed Brown       for (k = 0; k < dof; k++) tmp += ctx->R[j + k * dof] * ctx->cslope[k];
1219c4762a1bSJed Brown       slope[i * dof + j] = tmp;
1220c4762a1bSJed Brown     }
1221c4762a1bSJed Brown   }
1222c4762a1bSJed Brown 
1223c4762a1bSJed Brown   for (i = xs; i < xs + xm + 1; i++) {
1224c4762a1bSJed Brown     PetscReal    maxspeed;
1225c4762a1bSJed Brown     PetscScalar *uL, *uR;
1226c4762a1bSJed Brown     uL = &ctx->uLR[0];
1227c4762a1bSJed Brown     uR = &ctx->uLR[dof];
1228c4762a1bSJed Brown     for (j = 0; j < dof; j++) {
1229c4762a1bSJed Brown       uL[j] = x[(i - 1) * dof + j] + slope[(i - 1) * dof + j] * hx / 2;
1230c4762a1bSJed Brown       uR[j] = x[(i - 0) * dof + j] - slope[(i - 0) * dof + j] * hx / 2;
1231c4762a1bSJed Brown     }
12329566063dSJacob Faibussowitsch     PetscCall((*ctx->physics.riemann)(ctx->physics.user, dof, uL, uR, ctx->flux, &maxspeed));
1233c4762a1bSJed Brown     cfl_idt = PetscMax(cfl_idt, PetscAbsScalar(maxspeed / hx)); /* Max allowable value of 1/Delta t */
1234c4762a1bSJed Brown 
1235c4762a1bSJed Brown     if (i > xs) {
1236c4762a1bSJed Brown       for (j = 0; j < dof; j++) f[(i - 1) * dof + j] -= ctx->flux[j] / hx;
1237c4762a1bSJed Brown     }
1238c4762a1bSJed Brown     if (i < xs + xm) {
1239c4762a1bSJed Brown       for (j = 0; j < dof; j++) f[i * dof + j] += ctx->flux[j] / hx;
1240c4762a1bSJed Brown     }
1241c4762a1bSJed Brown   }
1242c4762a1bSJed Brown 
12439566063dSJacob Faibussowitsch   PetscCall(DMDAVecRestoreArray(da, Xloc, &x));
12449566063dSJacob Faibussowitsch   PetscCall(DMDAVecRestoreArray(da, F, &f));
12459566063dSJacob Faibussowitsch   PetscCall(DMDARestoreArray(da, PETSC_TRUE, &slope));
12469566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(da, &Xloc));
1247c4762a1bSJed Brown 
1248462c564dSBarry Smith   PetscCallMPI(MPIU_Allreduce(&cfl_idt, &ctx->cfl_idt, 1, MPIU_REAL, MPIU_MAX, PetscObjectComm((PetscObject)da)));
1249c4762a1bSJed Brown   if (0) {
1250c4762a1bSJed Brown     /* We need to a way to inform the TS of a CFL constraint, this is a debugging fragment */
1251c4762a1bSJed Brown     PetscReal dt, tnow;
12529566063dSJacob Faibussowitsch     PetscCall(TSGetTimeStep(ts, &dt));
12539566063dSJacob Faibussowitsch     PetscCall(TSGetTime(ts, &tnow));
125448a46eb9SPierre Jolivet     if (dt > 0.5 / ctx->cfl_idt) PetscCall(PetscPrintf(ctx->comm, "Stability constraint exceeded at t=%g, dt %g > %g\n", (double)tnow, (double)dt, (double)(0.5 / ctx->cfl_idt)));
1255c4762a1bSJed Brown   }
12563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1257c4762a1bSJed Brown }
1258c4762a1bSJed Brown 
SmallMatMultADB(PetscScalar * C,PetscInt bs,const PetscScalar * A,const PetscReal * D,const PetscScalar * B)1259d71ae5a4SJacob Faibussowitsch static PetscErrorCode SmallMatMultADB(PetscScalar *C, PetscInt bs, const PetscScalar *A, const PetscReal *D, const PetscScalar *B)
1260d71ae5a4SJacob Faibussowitsch {
1261c4762a1bSJed Brown   PetscInt i, j, k;
1262c4762a1bSJed Brown 
1263c4762a1bSJed Brown   PetscFunctionBeginUser;
1264c4762a1bSJed Brown   for (i = 0; i < bs; i++) {
1265c4762a1bSJed Brown     for (j = 0; j < bs; j++) {
1266c4762a1bSJed Brown       PetscScalar tmp = 0;
1267c4762a1bSJed Brown       for (k = 0; k < bs; k++) tmp += A[i * bs + k] * D[k] * B[k * bs + j];
1268c4762a1bSJed Brown       C[i * bs + j] = tmp;
1269c4762a1bSJed Brown     }
1270c4762a1bSJed Brown   }
12713ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1272c4762a1bSJed Brown }
1273c4762a1bSJed Brown 
FVIJacobian(TS ts,PetscReal t,Vec X,Vec Xdot,PetscReal shift,Mat A,Mat B,void * vctx)1274d71ae5a4SJacob Faibussowitsch static PetscErrorCode FVIJacobian(TS ts, PetscReal t, Vec X, Vec Xdot, PetscReal shift, Mat A, Mat B, void *vctx)
1275d71ae5a4SJacob Faibussowitsch {
1276c4762a1bSJed Brown   FVCtx             *ctx = (FVCtx *)vctx;
1277c4762a1bSJed Brown   PetscInt           i, j, dof = ctx->physics.dof;
1278c4762a1bSJed Brown   PetscScalar       *J;
1279c4762a1bSJed Brown   const PetscScalar *x;
1280c4762a1bSJed Brown   PetscReal          hx;
1281c4762a1bSJed Brown   DM                 da;
1282c4762a1bSJed Brown   DMDALocalInfo      dainfo;
1283c4762a1bSJed Brown 
1284c4762a1bSJed Brown   PetscFunctionBeginUser;
12859566063dSJacob Faibussowitsch   PetscCall(TSGetDM(ts, &da));
12869566063dSJacob Faibussowitsch   PetscCall(DMDAVecGetArrayRead(da, X, (void *)&x));
12879566063dSJacob Faibussowitsch   PetscCall(DMDAGetLocalInfo(da, &dainfo));
1288c4762a1bSJed Brown   hx = (ctx->xmax - ctx->xmin) / dainfo.mx;
12899566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(dof * dof, &J));
1290c4762a1bSJed Brown   for (i = dainfo.xs; i < dainfo.xs + dainfo.xm; i++) {
12919566063dSJacob Faibussowitsch     PetscCall((*ctx->physics.characteristic)(ctx->physics.user, dof, &x[i * dof], ctx->R, ctx->Rinv, ctx->speeds));
1292c4762a1bSJed Brown     for (j = 0; j < dof; j++) ctx->speeds[j] = PetscAbs(ctx->speeds[j]);
12939566063dSJacob Faibussowitsch     PetscCall(SmallMatMultADB(J, dof, ctx->R, ctx->speeds, ctx->Rinv));
1294c4762a1bSJed Brown     for (j = 0; j < dof * dof; j++) J[j] = J[j] / hx + shift * (j / dof == j % dof);
12959566063dSJacob Faibussowitsch     PetscCall(MatSetValuesBlocked(B, 1, &i, 1, &i, J, INSERT_VALUES));
1296c4762a1bSJed Brown   }
12979566063dSJacob Faibussowitsch   PetscCall(PetscFree(J));
12989566063dSJacob Faibussowitsch   PetscCall(DMDAVecRestoreArrayRead(da, X, (void *)&x));
1299c4762a1bSJed Brown 
13009566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
13019566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
1302c4762a1bSJed Brown   if (A != B) {
13039566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
13049566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
1305c4762a1bSJed Brown   }
13063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1307c4762a1bSJed Brown }
1308c4762a1bSJed Brown 
FVSample(FVCtx * ctx,DM da,PetscReal time,Vec U)1309d71ae5a4SJacob Faibussowitsch static PetscErrorCode FVSample(FVCtx *ctx, DM da, PetscReal time, Vec U)
1310d71ae5a4SJacob Faibussowitsch {
1311c4762a1bSJed Brown   PetscScalar *u, *uj;
1312c4762a1bSJed Brown   PetscInt     i, j, k, dof, xs, xm, Mx;
1313c4762a1bSJed Brown 
1314c4762a1bSJed Brown   PetscFunctionBeginUser;
13153c633725SBarry Smith   PetscCheck(ctx->physics.sample, PETSC_COMM_SELF, PETSC_ERR_SUP, "Physics has not provided a sampling function");
13169566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(da, 0, &Mx, 0, 0, 0, 0, 0, &dof, 0, 0, 0, 0, 0));
13179566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(da, &xs, 0, 0, &xm, 0, 0));
13189566063dSJacob Faibussowitsch   PetscCall(DMDAVecGetArray(da, U, &u));
13199566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(dof, &uj));
1320c4762a1bSJed Brown   for (i = xs; i < xs + xm; i++) {
1321c4762a1bSJed Brown     const PetscReal h = (ctx->xmax - ctx->xmin) / Mx, xi = ctx->xmin + h / 2 + i * h;
1322c4762a1bSJed Brown     const PetscInt  N = 200;
1323c4762a1bSJed Brown     /* Integrate over cell i using trapezoid rule with N points. */
1324c4762a1bSJed Brown     for (k = 0; k < dof; k++) u[i * dof + k] = 0;
1325c4762a1bSJed Brown     for (j = 0; j < N + 1; j++) {
1326c4762a1bSJed Brown       PetscScalar xj = xi + h * (j - N / 2) / (PetscReal)N;
13279566063dSJacob Faibussowitsch       PetscCall((*ctx->physics.sample)(ctx->physics.user, ctx->initial, ctx->bctype, ctx->xmin, ctx->xmax, time, xj, uj));
1328c4762a1bSJed Brown       for (k = 0; k < dof; k++) u[i * dof + k] += ((j == 0 || j == N) ? 0.5 : 1.0) * uj[k] / N;
1329c4762a1bSJed Brown     }
1330c4762a1bSJed Brown   }
13319566063dSJacob Faibussowitsch   PetscCall(DMDAVecRestoreArray(da, U, &u));
13329566063dSJacob Faibussowitsch   PetscCall(PetscFree(uj));
13333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1334c4762a1bSJed Brown }
1335c4762a1bSJed Brown 
SolutionStatsView(DM da,Vec X,PetscViewer viewer)1336d71ae5a4SJacob Faibussowitsch static PetscErrorCode SolutionStatsView(DM da, Vec X, PetscViewer viewer)
1337d71ae5a4SJacob Faibussowitsch {
1338c4762a1bSJed Brown   PetscReal          xmin, xmax;
1339c4762a1bSJed Brown   PetscScalar        sum, tvsum, tvgsum;
1340c4762a1bSJed Brown   const PetscScalar *x;
1341c4762a1bSJed Brown   PetscInt           imin, imax, Mx, i, j, xs, xm, dof;
1342c4762a1bSJed Brown   Vec                Xloc;
13439f196a02SMartin Diehl   PetscBool          isascii;
1344c4762a1bSJed Brown 
1345c4762a1bSJed Brown   PetscFunctionBeginUser;
13469f196a02SMartin Diehl   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
1347*966bd95aSPierre Jolivet   PetscCheck(isascii, PETSC_COMM_SELF, PETSC_ERR_SUP, "Viewer type not supported");
1348c4762a1bSJed Brown   /* PETSc lacks a function to compute total variation norm (difficult in multiple dimensions), we do it here */
13499566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(da, &Xloc));
13509566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalBegin(da, X, INSERT_VALUES, Xloc));
13519566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalEnd(da, X, INSERT_VALUES, Xloc));
13529566063dSJacob Faibussowitsch   PetscCall(DMDAVecGetArrayRead(da, Xloc, (void *)&x));
13539566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(da, &xs, 0, 0, &xm, 0, 0));
13549566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(da, 0, &Mx, 0, 0, 0, 0, 0, &dof, 0, 0, 0, 0, 0));
1355c4762a1bSJed Brown   tvsum = 0;
1356c4762a1bSJed Brown   for (i = xs; i < xs + xm; i++) {
1357c4762a1bSJed Brown     for (j = 0; j < dof; j++) tvsum += PetscAbsScalar(x[i * dof + j] - x[(i - 1) * dof + j]);
1358c4762a1bSJed Brown   }
1359462c564dSBarry Smith   PetscCallMPI(MPIU_Allreduce(&tvsum, &tvgsum, 1, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)da)));
13609566063dSJacob Faibussowitsch   PetscCall(DMDAVecRestoreArrayRead(da, Xloc, (void *)&x));
13619566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(da, &Xloc));
1362c4762a1bSJed Brown 
13639566063dSJacob Faibussowitsch   PetscCall(VecMin(X, &imin, &xmin));
13649566063dSJacob Faibussowitsch   PetscCall(VecMax(X, &imax, &xmax));
13659566063dSJacob Faibussowitsch   PetscCall(VecSum(X, &sum));
136663a3b9bcSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPrintf(viewer, "Solution range [%8.5f,%8.5f] with extrema at %" PetscInt_FMT " and %" PetscInt_FMT ", mean %8.5f, ||x||_TV %8.5f\n", (double)xmin, (double)xmax, imin, imax, (double)(sum / Mx), (double)(tvgsum / Mx)));
13673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1368c4762a1bSJed Brown }
1369c4762a1bSJed Brown 
SolutionErrorNorms(FVCtx * ctx,DM da,PetscReal t,Vec X,PetscReal * nrm1,PetscReal * nrmsup)1370d71ae5a4SJacob Faibussowitsch static PetscErrorCode SolutionErrorNorms(FVCtx *ctx, DM da, PetscReal t, Vec X, PetscReal *nrm1, PetscReal *nrmsup)
1371d71ae5a4SJacob Faibussowitsch {
1372c4762a1bSJed Brown   Vec      Y;
1373c4762a1bSJed Brown   PetscInt Mx;
1374c4762a1bSJed Brown 
1375c4762a1bSJed Brown   PetscFunctionBeginUser;
13769566063dSJacob Faibussowitsch   PetscCall(VecGetSize(X, &Mx));
13779566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(X, &Y));
13789566063dSJacob Faibussowitsch   PetscCall(FVSample(ctx, da, t, Y));
13799566063dSJacob Faibussowitsch   PetscCall(VecAYPX(Y, -1, X));
13809566063dSJacob Faibussowitsch   PetscCall(VecNorm(Y, NORM_1, nrm1));
13819566063dSJacob Faibussowitsch   PetscCall(VecNorm(Y, NORM_INFINITY, nrmsup));
1382c4762a1bSJed Brown   *nrm1 /= Mx;
13839566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&Y));
13843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1385c4762a1bSJed Brown }
1386c4762a1bSJed Brown 
main(int argc,char * argv[])1387d71ae5a4SJacob Faibussowitsch int main(int argc, char *argv[])
1388d71ae5a4SJacob Faibussowitsch {
1389c4762a1bSJed Brown   char              lname[256] = "mc", physname[256] = "advect", final_fname[256] = "solution.m";
1390c4762a1bSJed Brown   PetscFunctionList limiters = 0, physics = 0;
1391c4762a1bSJed Brown   MPI_Comm          comm;
1392c4762a1bSJed Brown   TS                ts;
1393c4762a1bSJed Brown   DM                da;
1394c4762a1bSJed Brown   Vec               X, X0, R;
1395c4762a1bSJed Brown   Mat               B;
1396c4762a1bSJed Brown   FVCtx             ctx;
1397c4762a1bSJed Brown   PetscInt          i, dof, xs, xm, Mx, draw = 0;
1398c4762a1bSJed Brown   PetscBool         view_final = PETSC_FALSE;
1399c4762a1bSJed Brown   PetscReal         ptime;
1400c4762a1bSJed Brown 
1401327415f7SBarry Smith   PetscFunctionBeginUser;
14029566063dSJacob Faibussowitsch   PetscCall(PetscInitialize(&argc, &argv, 0, help));
1403c4762a1bSJed Brown   comm = PETSC_COMM_WORLD;
14049566063dSJacob Faibussowitsch   PetscCall(PetscMemzero(&ctx, sizeof(ctx)));
1405c4762a1bSJed Brown 
1406c4762a1bSJed Brown   /* Register limiters to be available on the command line */
14079566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&limiters, "upwind", Limit_Upwind));
14089566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&limiters, "lax-wendroff", Limit_LaxWendroff));
14099566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&limiters, "beam-warming", Limit_BeamWarming));
14109566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&limiters, "fromm", Limit_Fromm));
14119566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&limiters, "minmod", Limit_Minmod));
14129566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&limiters, "superbee", Limit_Superbee));
14139566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&limiters, "mc", Limit_MC));
14149566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&limiters, "vanleer", Limit_VanLeer));
14159566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&limiters, "vanalbada", Limit_VanAlbada));
14169566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&limiters, "vanalbadatvd", Limit_VanAlbadaTVD));
14179566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&limiters, "koren", Limit_Koren));
14189566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&limiters, "korensym", Limit_KorenSym));
14199566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&limiters, "koren3", Limit_Koren3));
14209566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&limiters, "cada-torrilhon2", Limit_CadaTorrilhon2));
14219566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&limiters, "cada-torrilhon3-r0p1", Limit_CadaTorrilhon3R0p1));
14229566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&limiters, "cada-torrilhon3-r1", Limit_CadaTorrilhon3R1));
14239566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&limiters, "cada-torrilhon3-r10", Limit_CadaTorrilhon3R10));
14249566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&limiters, "cada-torrilhon3-r100", Limit_CadaTorrilhon3R100));
1425c4762a1bSJed Brown 
1426c4762a1bSJed Brown   /* Register physical models to be available on the command line */
14279566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&physics, "advect", PhysicsCreate_Advect));
14289566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&physics, "burgers", PhysicsCreate_Burgers));
14299566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&physics, "traffic", PhysicsCreate_Traffic));
14309566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&physics, "acoustics", PhysicsCreate_Acoustics));
14319566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&physics, "isogas", PhysicsCreate_IsoGas));
14329566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&physics, "shallow", PhysicsCreate_Shallow));
1433c4762a1bSJed Brown 
1434c4762a1bSJed Brown   ctx.comm   = comm;
14359371c9d4SSatish Balay   ctx.cfl    = 0.9;
14369371c9d4SSatish Balay   ctx.bctype = FVBC_PERIODIC;
14379371c9d4SSatish Balay   ctx.xmin   = -1;
14389371c9d4SSatish Balay   ctx.xmax   = 1;
1439d0609cedSBarry Smith   PetscOptionsBegin(comm, NULL, "Finite Volume solver options", "");
14409566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-xmin", "X min", "", ctx.xmin, &ctx.xmin, NULL));
14419566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-xmax", "X max", "", ctx.xmax, &ctx.xmax, NULL));
14429566063dSJacob Faibussowitsch   PetscCall(PetscOptionsFList("-limit", "Name of flux limiter to use", "", limiters, lname, lname, sizeof(lname), NULL));
14439566063dSJacob Faibussowitsch   PetscCall(PetscOptionsFList("-physics", "Name of physics (Riemann solver and characteristics) to use", "", physics, physname, physname, sizeof(physname), NULL));
14449566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-draw", "Draw solution vector, bitwise OR of (1=initial,2=final,4=final error)", "", draw, &draw, NULL));
14459566063dSJacob 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));
14469566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-initial", "Initial condition (depends on the physics)", "", ctx.initial, &ctx.initial, NULL));
14479566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-exact", "Compare errors with exact solution", "", ctx.exact, &ctx.exact, NULL));
14489566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-cfl", "CFL number to time step at", "", ctx.cfl, &ctx.cfl, NULL));
14499566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEnum("-bc_type", "Boundary condition", "", FVBCTypes, (PetscEnum)ctx.bctype, (PetscEnum *)&ctx.bctype, NULL));
1450d0609cedSBarry Smith   PetscOptionsEnd();
1451c4762a1bSJed Brown 
1452c4762a1bSJed Brown   /* Choose the limiter from the list of registered limiters */
14539566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListFind(limiters, lname, &ctx.limit));
14543c633725SBarry Smith   PetscCheck(ctx.limit, PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "Limiter '%s' not found", lname);
1455c4762a1bSJed Brown 
1456c4762a1bSJed Brown   /* Choose the physics from the list of registered models */
1457c4762a1bSJed Brown   {
1458c4762a1bSJed Brown     PetscErrorCode (*r)(FVCtx *);
14599566063dSJacob Faibussowitsch     PetscCall(PetscFunctionListFind(physics, physname, &r));
14603c633725SBarry Smith     PetscCheck(r, PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "Physics '%s' not found", physname);
1461c4762a1bSJed Brown     /* Create the physics, will set the number of fields and their names */
14629566063dSJacob Faibussowitsch     PetscCall((*r)(&ctx));
1463c4762a1bSJed Brown   }
1464c4762a1bSJed Brown 
1465c4762a1bSJed Brown   /* Create a DMDA to manage the parallel grid */
14669566063dSJacob Faibussowitsch   PetscCall(DMDACreate1d(comm, DM_BOUNDARY_PERIODIC, 50, ctx.physics.dof, 2, NULL, &da));
14679566063dSJacob Faibussowitsch   PetscCall(DMSetFromOptions(da));
14689566063dSJacob Faibussowitsch   PetscCall(DMSetUp(da));
1469c4762a1bSJed Brown   /* Inform the DMDA of the field names provided by the physics. */
1470c4762a1bSJed Brown   /* The names will be shown in the title bars when run with -ts_monitor_draw_solution */
147148a46eb9SPierre Jolivet   for (i = 0; i < ctx.physics.dof; i++) PetscCall(DMDASetFieldName(da, i, ctx.physics.fieldname[i]));
14729566063dSJacob Faibussowitsch   PetscCall(DMDAGetInfo(da, 0, &Mx, 0, 0, 0, 0, 0, &dof, 0, 0, 0, 0, 0));
14739566063dSJacob Faibussowitsch   PetscCall(DMDAGetCorners(da, &xs, 0, 0, &xm, 0, 0));
1474c4762a1bSJed Brown 
1475c4762a1bSJed Brown   /* Set coordinates of cell centers */
14769566063dSJacob 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));
1477c4762a1bSJed Brown 
1478c4762a1bSJed Brown   /* Allocate work space for the Finite Volume solver (so it doesn't have to be reallocated on each function evaluation) */
14799566063dSJacob Faibussowitsch   PetscCall(PetscMalloc4(dof * dof, &ctx.R, dof * dof, &ctx.Rinv, 2 * dof, &ctx.cjmpLR, 1 * dof, &ctx.cslope));
14809566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(2 * dof, &ctx.uLR, dof, &ctx.flux, dof, &ctx.speeds));
1481c4762a1bSJed Brown 
1482c4762a1bSJed Brown   /* Create a vector to store the solution and to save the initial state */
14839566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(da, &X));
14849566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(X, &X0));
14859566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(X, &R));
1486c4762a1bSJed Brown 
14879566063dSJacob Faibussowitsch   PetscCall(DMCreateMatrix(da, &B));
1488c4762a1bSJed Brown 
1489c4762a1bSJed Brown   /* Create a time-stepping object */
14909566063dSJacob Faibussowitsch   PetscCall(TSCreate(comm, &ts));
14919566063dSJacob Faibussowitsch   PetscCall(TSSetDM(ts, da));
14929566063dSJacob Faibussowitsch   PetscCall(TSSetRHSFunction(ts, R, FVRHSFunction, &ctx));
14939566063dSJacob Faibussowitsch   PetscCall(TSSetIJacobian(ts, B, B, FVIJacobian, &ctx));
14949566063dSJacob Faibussowitsch   PetscCall(TSSetType(ts, TSSSP));
14959566063dSJacob Faibussowitsch   PetscCall(TSSetMaxTime(ts, 10));
14969566063dSJacob Faibussowitsch   PetscCall(TSSetExactFinalTime(ts, TS_EXACTFINALTIME_STEPOVER));
1497c4762a1bSJed Brown 
1498c4762a1bSJed Brown   /* Compute initial conditions and starting time step */
14999566063dSJacob Faibussowitsch   PetscCall(FVSample(&ctx, da, 0, X0));
15009566063dSJacob Faibussowitsch   PetscCall(FVRHSFunction(ts, 0, X0, X, (void *)&ctx)); /* Initial function evaluation, only used to determine max speed */
15019566063dSJacob Faibussowitsch   PetscCall(VecCopy(X0, X));                            /* The function value was not used so we set X=X0 again */
15029566063dSJacob Faibussowitsch   PetscCall(TSSetTimeStep(ts, ctx.cfl / ctx.cfl_idt));
15039566063dSJacob Faibussowitsch   PetscCall(TSSetFromOptions(ts)); /* Take runtime options */
15049566063dSJacob Faibussowitsch   PetscCall(SolutionStatsView(da, X, PETSC_VIEWER_STDOUT_WORLD));
1505c4762a1bSJed Brown   {
1506c4762a1bSJed Brown     PetscReal nrm1, nrmsup;
1507c4762a1bSJed Brown     PetscInt  steps;
1508c4762a1bSJed Brown 
15099566063dSJacob Faibussowitsch     PetscCall(TSSolve(ts, X));
15109566063dSJacob Faibussowitsch     PetscCall(TSGetSolveTime(ts, &ptime));
15119566063dSJacob Faibussowitsch     PetscCall(TSGetStepNumber(ts, &steps));
1512c4762a1bSJed Brown 
151363a3b9bcSJacob Faibussowitsch     PetscCall(PetscPrintf(comm, "Final time %8.5f, steps %" PetscInt_FMT "\n", (double)ptime, steps));
1514c4762a1bSJed Brown     if (ctx.exact) {
15159566063dSJacob Faibussowitsch       PetscCall(SolutionErrorNorms(&ctx, da, ptime, X, &nrm1, &nrmsup));
15169566063dSJacob Faibussowitsch       PetscCall(PetscPrintf(comm, "Error ||x-x_e||_1 %8.4e  ||x-x_e||_sup %8.4e\n", (double)nrm1, (double)nrmsup));
1517c4762a1bSJed Brown     }
1518c4762a1bSJed Brown   }
1519c4762a1bSJed Brown 
15209566063dSJacob Faibussowitsch   PetscCall(SolutionStatsView(da, X, PETSC_VIEWER_STDOUT_WORLD));
15219566063dSJacob Faibussowitsch   if (draw & 0x1) PetscCall(VecView(X0, PETSC_VIEWER_DRAW_WORLD));
15229566063dSJacob Faibussowitsch   if (draw & 0x2) PetscCall(VecView(X, PETSC_VIEWER_DRAW_WORLD));
1523c4762a1bSJed Brown   if (draw & 0x4) {
1524c4762a1bSJed Brown     Vec Y;
15259566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(X, &Y));
15269566063dSJacob Faibussowitsch     PetscCall(FVSample(&ctx, da, ptime, Y));
15279566063dSJacob Faibussowitsch     PetscCall(VecAYPX(Y, -1, X));
15289566063dSJacob Faibussowitsch     PetscCall(VecView(Y, PETSC_VIEWER_DRAW_WORLD));
15299566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&Y));
1530c4762a1bSJed Brown   }
1531c4762a1bSJed Brown 
1532c4762a1bSJed Brown   if (view_final) {
1533c4762a1bSJed Brown     PetscViewer viewer;
15349566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIOpen(PETSC_COMM_WORLD, final_fname, &viewer));
15359566063dSJacob Faibussowitsch     PetscCall(PetscViewerPushFormat(viewer, PETSC_VIEWER_ASCII_MATLAB));
15369566063dSJacob Faibussowitsch     PetscCall(VecView(X, viewer));
15379566063dSJacob Faibussowitsch     PetscCall(PetscViewerPopFormat(viewer));
15389566063dSJacob Faibussowitsch     PetscCall(PetscViewerDestroy(&viewer));
1539c4762a1bSJed Brown   }
1540c4762a1bSJed Brown 
1541c4762a1bSJed Brown   /* Clean up */
15429566063dSJacob Faibussowitsch   PetscCall((*ctx.physics.destroy)(ctx.physics.user));
15439566063dSJacob Faibussowitsch   for (i = 0; i < ctx.physics.dof; i++) PetscCall(PetscFree(ctx.physics.fieldname[i]));
15449566063dSJacob Faibussowitsch   PetscCall(PetscFree4(ctx.R, ctx.Rinv, ctx.cjmpLR, ctx.cslope));
15459566063dSJacob Faibussowitsch   PetscCall(PetscFree3(ctx.uLR, ctx.flux, ctx.speeds));
15469566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&X));
15479566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&X0));
15489566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&R));
15499566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&B));
15509566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&da));
15519566063dSJacob Faibussowitsch   PetscCall(TSDestroy(&ts));
15529566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListDestroy(&limiters));
15539566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListDestroy(&physics));
15549566063dSJacob Faibussowitsch   PetscCall(PetscFinalize());
1555b122ec5aSJacob Faibussowitsch   return 0;
1556c4762a1bSJed Brown }
1557c4762a1bSJed Brown 
1558c4762a1bSJed Brown /*TEST
1559c4762a1bSJed Brown 
1560c4762a1bSJed Brown     build:
1561f56ea12dSJed Brown       requires: !complex
1562c4762a1bSJed Brown 
1563c4762a1bSJed Brown     test:
1564c4762a1bSJed Brown       args: -da_grid_x 100 -initial 1 -xmin -2 -xmax 5 -exact -limit mc
1565c4762a1bSJed Brown       requires: !complex !single
1566c4762a1bSJed Brown 
1567c4762a1bSJed Brown     test:
1568c4762a1bSJed Brown       suffix: 2
1569c4762a1bSJed Brown       args: -da_grid_x 100 -initial 2 -xmin -2 -xmax 2 -exact -limit mc -physics burgers -bc_type outflow -ts_max_time 1
1570c4762a1bSJed Brown       filter:  sed "s/at 48/at 0/g"
1571c4762a1bSJed Brown       requires: !complex !single
1572c4762a1bSJed Brown 
1573c4762a1bSJed Brown     test:
1574c4762a1bSJed Brown       suffix: 3
1575c4762a1bSJed Brown       args: -da_grid_x 100 -initial 2 -xmin -2 -xmax 2 -exact -limit mc -physics burgers -bc_type outflow -ts_max_time 1
1576c4762a1bSJed Brown       nsize: 3
1577c4762a1bSJed Brown       filter:  sed "s/at 48/at 0/g"
1578c4762a1bSJed Brown       requires: !complex !single
1579c4762a1bSJed Brown 
1580c4762a1bSJed Brown TEST*/
1581